psutil

Форк
0
/
setup.py 
569 строк · 17.7 Кб
1
#!/usr/bin/env python3
2

3
# Copyright (c) 2009 Giampaolo Rodola'. All rights reserved.
4
# Use of this source code is governed by a BSD-style license that can be
5
# found in the LICENSE file.
6

7
"""Cross-platform lib for process and system monitoring in Python."""
8

9
from __future__ import print_function
10

11
import ast
12
import contextlib
13
import glob
14
import io
15
import os
16
import platform
17
import re
18
import shutil
19
import struct
20
import subprocess
21
import sys
22
import sysconfig
23
import tempfile
24
import warnings
25

26

27
with warnings.catch_warnings():
28
    warnings.simplefilter("ignore")
29
    try:
30
        import setuptools
31
        from setuptools import Extension
32
        from setuptools import setup
33
    except ImportError:
34
        setuptools = None
35
        from distutils.core import Extension
36
        from distutils.core import setup
37
    try:
38
        from wheel.bdist_wheel import bdist_wheel
39
    except ImportError:
40
        if "CIBUILDWHEEL" in os.environ:
41
            raise
42
        bdist_wheel = None
43

44
HERE = os.path.abspath(os.path.dirname(__file__))
45

46
# ...so we can import _common.py and _compat.py
47
sys.path.insert(0, os.path.join(HERE, "psutil"))
48

49
from _common import AIX  # NOQA
50
from _common import BSD  # NOQA
51
from _common import FREEBSD  # NOQA
52
from _common import LINUX  # NOQA
53
from _common import MACOS  # NOQA
54
from _common import NETBSD  # NOQA
55
from _common import OPENBSD  # NOQA
56
from _common import POSIX  # NOQA
57
from _common import SUNOS  # NOQA
58
from _common import WINDOWS  # NOQA
59
from _common import hilite  # NOQA
60
from _compat import PY3  # NOQA
61
from _compat import which  # NOQA
62

63

64
PYPY = '__pypy__' in sys.builtin_module_names
65
PY36_PLUS = sys.version_info[:2] >= (3, 6)
66
PY37_PLUS = sys.version_info[:2] >= (3, 7)
67
CP36_PLUS = PY36_PLUS and sys.implementation.name == "cpython"
68
CP37_PLUS = PY37_PLUS and sys.implementation.name == "cpython"
69
Py_GIL_DISABLED = sysconfig.get_config_var("Py_GIL_DISABLED")
70

71
macros = []
72
if POSIX:
73
    macros.append(("PSUTIL_POSIX", 1))
74
if BSD:
75
    macros.append(("PSUTIL_BSD", 1))
76

77
# Needed to determine _Py_PARSE_PID in case it's missing (Python 2, PyPy).
78
# Taken from Lib/test/test_fcntl.py.
79
# XXX: not bullet proof as the (long long) case is missing.
80
if struct.calcsize('l') <= 8:
81
    macros.append(('PSUTIL_SIZEOF_PID_T', '4'))  # int
82
else:
83
    macros.append(('PSUTIL_SIZEOF_PID_T', '8'))  # long
84

85

86
sources = ['psutil/_psutil_common.c']
87
if POSIX:
88
    sources.append('psutil/_psutil_posix.c')
89

90

91
extras_require = {
92
    "test": [
93
        "enum34; python_version <= '3.4'",
94
        "ipaddress; python_version < '3.0'",
95
        "mock; python_version < '3.0'",
96
    ]
97
}
98
if not PYPY:
99
    extras_require['test'].extend(
100
        ["pywin32; sys.platform == 'win32'", "wmi; sys.platform == 'win32'"]
101
    )
102

103

104
def get_version():
105
    INIT = os.path.join(HERE, 'psutil/__init__.py')
106
    with open(INIT) as f:
107
        for line in f:
108
            if line.startswith('__version__'):
109
                ret = ast.literal_eval(line.strip().split(' = ')[1])
110
                assert ret.count('.') == 2, ret
111
                for num in ret.split('.'):
112
                    assert num.isdigit(), ret
113
                return ret
114
        msg = "couldn't find version string"
115
        raise ValueError(msg)
116

117

118
VERSION = get_version()
119
macros.append(('PSUTIL_VERSION', int(VERSION.replace('.', ''))))
120

121
# Py_LIMITED_API lets us create a single wheel which works with multiple
122
# python versions, including unreleased ones.
123
if bdist_wheel and CP36_PLUS and (MACOS or LINUX) and not Py_GIL_DISABLED:
124
    py_limited_api = {"py_limited_api": True}
125
    macros.append(('Py_LIMITED_API', '0x03060000'))
126
elif bdist_wheel and CP37_PLUS and WINDOWS and not Py_GIL_DISABLED:
127
    # PyErr_SetFromWindowsErr / PyErr_SetFromWindowsErrWithFilename are
128
    # part of the stable API/ABI starting with CPython 3.7
129
    py_limited_api = {"py_limited_api": True}
130
    macros.append(('Py_LIMITED_API', '0x03070000'))
131
else:
132
    py_limited_api = {}
133

134

135
def get_long_description():
136
    script = os.path.join(HERE, "scripts", "internal", "convert_readme.py")
137
    readme = os.path.join(HERE, 'README.rst')
138
    p = subprocess.Popen(
139
        [sys.executable, script, readme],
140
        stdout=subprocess.PIPE,
141
        stderr=subprocess.PIPE,
142
        universal_newlines=True,
143
    )
144
    stdout, stderr = p.communicate()
145
    if p.returncode != 0:
146
        raise RuntimeError(stderr)
147
    return stdout
148

149

150
@contextlib.contextmanager
151
def silenced_output(stream_name):
152
    class DummyFile(io.BytesIO):
153
        # see: https://github.com/giampaolo/psutil/issues/678
154
        errors = "ignore"
155

156
        def write(self, s):
157
            pass
158

159
    orig = getattr(sys, stream_name)
160
    try:
161
        setattr(sys, stream_name, DummyFile())
162
        yield
163
    finally:
164
        setattr(sys, stream_name, orig)
165

166

167
def missdeps(cmdline):
168
    s = "psutil could not be installed from sources"
169
    if not SUNOS and not which("gcc"):
170
        s += " because gcc is not installed. "
171
    else:
172
        s += ". Perhaps Python header files are not installed. "
173
    s += "Try running:\n"
174
    s += "  %s" % cmdline
175
    print(hilite(s, color="red", bold=True), file=sys.stderr)
176

177

178
def unix_can_compile(c_code):
179
    from distutils.errors import CompileError
180
    from distutils.unixccompiler import UnixCCompiler
181

182
    with tempfile.NamedTemporaryFile(
183
        suffix='.c', delete=False, mode="wt"
184
    ) as f:
185
        f.write(c_code)
186

187
    tempdir = tempfile.mkdtemp()
188
    try:
189
        compiler = UnixCCompiler()
190
        # https://github.com/giampaolo/psutil/pull/1568
191
        if os.getenv('CC'):
192
            compiler.set_executable('compiler_so', os.getenv('CC'))
193
        with silenced_output('stderr'):
194
            with silenced_output('stdout'):
195
                compiler.compile([f.name], output_dir=tempdir)
196
    except CompileError:
197
        return False
198
    else:
199
        return True
200
    finally:
201
        os.remove(f.name)
202
        shutil.rmtree(tempdir)
203

204

205
if WINDOWS:
206

207
    def get_winver():
208
        maj, min = sys.getwindowsversion()[0:2]
209
        return '0x0%s' % ((maj * 100) + min)
210

211
    if sys.getwindowsversion()[0] < 6:
212
        msg = "this Windows version is too old (< Windows Vista); "
213
        msg += "psutil 3.4.2 is the latest version which supports Windows "
214
        msg += "2000, XP and 2003 server"
215
        raise RuntimeError(msg)
216

217
    macros.append(("PSUTIL_WINDOWS", 1))
218
    macros.extend([
219
        # be nice to mingw, see:
220
        # http://www.mingw.org/wiki/Use_more_recent_defined_functions
221
        ('_WIN32_WINNT', get_winver()),
222
        ('_AVAIL_WINVER_', get_winver()),
223
        ('_CRT_SECURE_NO_WARNINGS', None),
224
        # see: https://github.com/giampaolo/psutil/issues/348
225
        ('PSAPI_VERSION', 1),
226
    ])
227

228
    ext = Extension(
229
        'psutil._psutil_windows',
230
        sources=(
231
            sources
232
            + ["psutil/_psutil_windows.c"]
233
            + glob.glob("psutil/arch/windows/*.c")
234
        ),
235
        define_macros=macros,
236
        libraries=[
237
            "psapi",
238
            "kernel32",
239
            "advapi32",
240
            "shell32",
241
            "netapi32",
242
            "ws2_32",
243
            "PowrProf",
244
            "pdh",
245
        ],
246
        # extra_compile_args=["/W 4"],
247
        # extra_link_args=["/DEBUG"],
248
        # fmt: off
249
        # python 2.7 compatibility requires no comma
250
        **py_limited_api
251
        # fmt: on
252
    )
253

254
elif MACOS:
255
    macros.append(("PSUTIL_OSX", 1))
256
    ext = Extension(
257
        'psutil._psutil_osx',
258
        sources=(
259
            sources
260
            + ["psutil/_psutil_osx.c"]
261
            + glob.glob("psutil/arch/osx/*.c")
262
        ),
263
        define_macros=macros,
264
        extra_link_args=[
265
            '-framework',
266
            'CoreFoundation',
267
            '-framework',
268
            'IOKit',
269
        ],
270
        # fmt: off
271
        # python 2.7 compatibility requires no comma
272
        **py_limited_api
273
        # fmt: on
274
    )
275

276
elif FREEBSD:
277
    macros.append(("PSUTIL_FREEBSD", 1))
278
    ext = Extension(
279
        'psutil._psutil_bsd',
280
        sources=(
281
            sources
282
            + ["psutil/_psutil_bsd.c"]
283
            + glob.glob("psutil/arch/bsd/*.c")
284
            + glob.glob("psutil/arch/freebsd/*.c")
285
        ),
286
        define_macros=macros,
287
        libraries=["devstat"],
288
        # fmt: off
289
        # python 2.7 compatibility requires no comma
290
        **py_limited_api
291
        # fmt: on
292
    )
293

294
elif OPENBSD:
295
    macros.append(("PSUTIL_OPENBSD", 1))
296
    ext = Extension(
297
        'psutil._psutil_bsd',
298
        sources=(
299
            sources
300
            + ["psutil/_psutil_bsd.c"]
301
            + glob.glob("psutil/arch/bsd/*.c")
302
            + glob.glob("psutil/arch/openbsd/*.c")
303
        ),
304
        define_macros=macros,
305
        libraries=["kvm"],
306
        # fmt: off
307
        # python 2.7 compatibility requires no comma
308
        **py_limited_api
309
        # fmt: on
310
    )
311

312
elif NETBSD:
313
    macros.append(("PSUTIL_NETBSD", 1))
314
    ext = Extension(
315
        'psutil._psutil_bsd',
316
        sources=(
317
            sources
318
            + ["psutil/_psutil_bsd.c"]
319
            + glob.glob("psutil/arch/bsd/*.c")
320
            + glob.glob("psutil/arch/netbsd/*.c")
321
        ),
322
        define_macros=macros,
323
        libraries=["kvm"],
324
        # fmt: off
325
        # python 2.7 compatibility requires no comma
326
        **py_limited_api
327
        # fmt: on
328
    )
329

330
elif LINUX:
331
    # see: https://github.com/giampaolo/psutil/issues/659
332
    if not unix_can_compile("#include <linux/ethtool.h>"):
333
        macros.append(("PSUTIL_ETHTOOL_MISSING_TYPES", 1))
334

335
    macros.append(("PSUTIL_LINUX", 1))
336
    ext = Extension(
337
        'psutil._psutil_linux',
338
        sources=(
339
            sources
340
            + ["psutil/_psutil_linux.c"]
341
            + glob.glob("psutil/arch/linux/*.c")
342
        ),
343
        define_macros=macros,
344
        # fmt: off
345
        # python 2.7 compatibility requires no comma
346
        **py_limited_api
347
        # fmt: on
348
    )
349

350
elif SUNOS:
351
    macros.append(("PSUTIL_SUNOS", 1))
352
    ext = Extension(
353
        'psutil._psutil_sunos',
354
        sources=sources
355
        + [
356
            'psutil/_psutil_sunos.c',
357
            'psutil/arch/solaris/v10/ifaddrs.c',
358
            'psutil/arch/solaris/environ.c',
359
        ],
360
        define_macros=macros,
361
        libraries=['kstat', 'nsl', 'socket'],
362
        # fmt: off
363
        # python 2.7 compatibility requires no comma
364
        **py_limited_api
365
        # fmt: on
366
    )
367

368
elif AIX:
369
    macros.append(("PSUTIL_AIX", 1))
370
    ext = Extension(
371
        'psutil._psutil_aix',
372
        sources=sources
373
        + [
374
            'psutil/_psutil_aix.c',
375
            'psutil/arch/aix/net_connections.c',
376
            'psutil/arch/aix/common.c',
377
            'psutil/arch/aix/ifaddrs.c',
378
        ],
379
        libraries=['perfstat'],
380
        define_macros=macros,
381
        # fmt: off
382
        # python 2.7 compatibility requires no comma
383
        **py_limited_api
384
        # fmt: on
385
    )
386

387
else:
388
    sys.exit('platform %s is not supported' % sys.platform)
389

390

391
if POSIX:
392
    posix_extension = Extension(
393
        'psutil._psutil_posix',
394
        define_macros=macros,
395
        sources=sources,
396
        # fmt: off
397
        # python 2.7 compatibility requires no comma
398
        **py_limited_api
399
        # fmt: on
400
    )
401
    if SUNOS:
402

403
        def get_sunos_update():
404
            # See https://serverfault.com/q/524883
405
            # for an explanation of Solaris /etc/release
406
            with open('/etc/release') as f:
407
                update = re.search(r'(?<=s10s_u)[0-9]{1,2}', f.readline())
408
                return int(update.group(0)) if update else 0
409

410
        posix_extension.libraries.append('socket')
411
        if platform.release() == '5.10':
412
            # Detect Solaris 5.10, update >= 4, see:
413
            # https://github.com/giampaolo/psutil/pull/1638
414
            if get_sunos_update() >= 4:
415
                # MIB compliance starts with SunOS 5.10 Update 4:
416
                posix_extension.define_macros.append(('NEW_MIB_COMPLIANT', 1))
417
            posix_extension.sources.append('psutil/arch/solaris/v10/ifaddrs.c')
418
            posix_extension.define_macros.append(('PSUTIL_SUNOS10', 1))
419
        else:
420
            # Other releases are by default considered to be new mib compliant.
421
            posix_extension.define_macros.append(('NEW_MIB_COMPLIANT', 1))
422
    elif AIX:
423
        posix_extension.sources.append('psutil/arch/aix/ifaddrs.c')
424

425
    extensions = [ext, posix_extension]
426
else:
427
    extensions = [ext]
428

429
cmdclass = {}
430
if py_limited_api:
431

432
    class bdist_wheel_abi3(bdist_wheel):
433
        def get_tag(self):
434
            python, _abi, plat = bdist_wheel.get_tag(self)
435
            return python, "abi3", plat
436

437
    cmdclass["bdist_wheel"] = bdist_wheel_abi3
438

439

440
def main():
441
    kwargs = dict(
442
        name='psutil',
443
        version=VERSION,
444
        cmdclass=cmdclass,
445
        description=__doc__.replace('\n', ' ').strip() if __doc__ else '',
446
        long_description=get_long_description(),
447
        long_description_content_type='text/x-rst',
448
        # fmt: off
449
        keywords=[
450
            'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', 'tty',
451
            'ionice', 'uptime', 'taskmgr', 'process', 'df', 'iotop', 'iostat',
452
            'ifconfig', 'taskset', 'who', 'pidof', 'pmap', 'smem', 'pstree',
453
            'monitoring', 'ulimit', 'prlimit', 'smem', 'performance',
454
            'metrics', 'agent', 'observability',
455
        ],
456
        # fmt: on
457
        author='Giampaolo Rodola',
458
        author_email='g.rodola@gmail.com',
459
        url='https://github.com/giampaolo/psutil',
460
        platforms='Platform Independent',
461
        license='BSD-3-Clause',
462
        packages=['psutil', 'psutil.tests'],
463
        ext_modules=extensions,
464
        classifiers=[
465
            'Development Status :: 5 - Production/Stable',
466
            'Environment :: Console',
467
            'Environment :: Win32 (MS Windows)',
468
            'Intended Audience :: Developers',
469
            'Intended Audience :: Information Technology',
470
            'Intended Audience :: System Administrators',
471
            'License :: OSI Approved :: BSD License',
472
            'Operating System :: MacOS :: MacOS X',
473
            'Operating System :: Microsoft :: Windows :: Windows 10',
474
            'Operating System :: Microsoft :: Windows :: Windows 7',
475
            'Operating System :: Microsoft :: Windows :: Windows 8',
476
            'Operating System :: Microsoft :: Windows :: Windows 8.1',
477
            'Operating System :: Microsoft :: Windows :: Windows Server 2003',
478
            'Operating System :: Microsoft :: Windows :: Windows Server 2008',
479
            'Operating System :: Microsoft :: Windows :: Windows Vista',
480
            'Operating System :: Microsoft',
481
            'Operating System :: OS Independent',
482
            'Operating System :: POSIX :: AIX',
483
            'Operating System :: POSIX :: BSD :: FreeBSD',
484
            'Operating System :: POSIX :: BSD :: NetBSD',
485
            'Operating System :: POSIX :: BSD :: OpenBSD',
486
            'Operating System :: POSIX :: BSD',
487
            'Operating System :: POSIX :: Linux',
488
            'Operating System :: POSIX :: SunOS/Solaris',
489
            'Operating System :: POSIX',
490
            'Programming Language :: C',
491
            'Programming Language :: Python :: 2',
492
            'Programming Language :: Python :: 2.7',
493
            'Programming Language :: Python :: 3',
494
            'Programming Language :: Python :: Implementation :: CPython',
495
            'Programming Language :: Python :: Implementation :: PyPy',
496
            'Programming Language :: Python',
497
            'Topic :: Software Development :: Libraries :: Python Modules',
498
            'Topic :: Software Development :: Libraries',
499
            'Topic :: System :: Benchmark',
500
            'Topic :: System :: Hardware :: Hardware Drivers',
501
            'Topic :: System :: Hardware',
502
            'Topic :: System :: Monitoring',
503
            'Topic :: System :: Networking :: Monitoring :: Hardware Watchdog',
504
            'Topic :: System :: Networking :: Monitoring',
505
            'Topic :: System :: Networking',
506
            'Topic :: System :: Operating System',
507
            'Topic :: System :: Systems Administration',
508
            'Topic :: Utilities',
509
        ],
510
    )
511
    if setuptools is not None:
512
        kwargs.update(
513
            python_requires=(
514
                ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
515
            ),
516
            extras_require=extras_require,
517
            zip_safe=False,
518
        )
519
    success = False
520
    try:
521
        setup(**kwargs)
522
        success = True
523
    finally:
524
        cmd = sys.argv[1] if len(sys.argv) >= 2 else ''
525
        if (
526
            not success
527
            and POSIX
528
            and cmd.startswith(
529
                ("build", "install", "sdist", "bdist", "develop")
530
            )
531
        ):
532
            py3 = "3" if PY3 else ""
533
            if LINUX:
534
                pyimpl = "pypy" if PYPY else "python"
535
                if which('dpkg'):
536
                    missdeps(
537
                        "sudo apt-get install gcc %s%s-dev" % (pyimpl, py3)
538
                    )
539
                elif which('rpm'):
540
                    missdeps("sudo yum install gcc %s%s-devel" % (pyimpl, py3))
541
                elif which('apk'):
542
                    missdeps(
543
                        "sudo apk add gcc %s%s-dev musl-dev linux-headers"
544
                        % (pyimpl, py3)
545
                    )
546
            elif MACOS:
547
                msg = (
548
                    "XCode (https://developer.apple.com/xcode/)"
549
                    " is not installed"
550
                )
551
                print(hilite(msg, color="red"), file=sys.stderr)
552
            elif FREEBSD:
553
                if which('pkg'):
554
                    missdeps("pkg install gcc python%s" % py3)
555
                elif which('mport'):  # MidnightBSD
556
                    missdeps("mport install gcc python%s" % py3)
557
            elif OPENBSD:
558
                missdeps("pkg_add -v gcc python%s" % py3)
559
            elif NETBSD:
560
                missdeps("pkgin install gcc python%s" % py3)
561
            elif SUNOS:
562
                missdeps(
563
                    "sudo ln -s /usr/bin/gcc /usr/local/bin/cc && "
564
                    "pkg install gcc"
565
                )
566

567

568
if __name__ == '__main__':
569
    main()
570

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.