| #!/usr/bin/env python3 |
| |
| # Copyright (c) 2009 Giampaolo Rodola'. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Cross-platform lib for process and system monitoring in Python. |
| |
| NOTE: the syntax of this script MUST be kept compatible with Python 2.7. |
| """ |
| |
| from __future__ import print_function |
| |
| import ast |
| import contextlib |
| import glob |
| import io |
| import os |
| import platform |
| import re |
| import shutil |
| import struct |
| import subprocess |
| import sys |
| import sysconfig |
| import tempfile |
| import textwrap |
| import warnings |
| |
| |
| if sys.version_info[0] == 2: |
| sys.exit(textwrap.dedent("""\ |
| As of version 7.0.0 psutil no longer supports Python 2.7, see: |
| https://github.com/giampaolo/psutil/issues/2480 |
| Latest version supporting Python 2.7 is psutil 6.1.X. |
| Install it with: |
| |
| python2 -m pip install psutil==6.1.*\ |
| """)) |
| |
| |
| with warnings.catch_warnings(): |
| warnings.simplefilter("ignore") |
| try: |
| import setuptools |
| from setuptools import Extension |
| from setuptools import setup |
| except ImportError: |
| if "CIBUILDWHEEL" in os.environ: |
| raise |
| setuptools = None |
| from distutils.core import Extension |
| from distutils.core import setup |
| |
| |
| HERE = os.path.abspath(os.path.dirname(__file__)) |
| |
| # ...so we can import _common.py |
| sys.path.insert(0, os.path.join(HERE, "psutil")) |
| |
| from _common import AIX # noqa: E402 |
| from _common import BSD # noqa: E402 |
| from _common import FREEBSD # noqa: E402 |
| from _common import LINUX # noqa: E402 |
| from _common import MACOS # noqa: E402 |
| from _common import NETBSD # noqa: E402 |
| from _common import OPENBSD # noqa: E402 |
| from _common import POSIX # noqa: E402 |
| from _common import SUNOS # noqa: E402 |
| from _common import WINDOWS # noqa: E402 |
| from _common import hilite # noqa: E402 |
| |
| |
| PYPY = '__pypy__' in sys.builtin_module_names |
| PY36_PLUS = sys.version_info[:2] >= (3, 6) |
| PY37_PLUS = sys.version_info[:2] >= (3, 7) |
| CP36_PLUS = PY36_PLUS and sys.implementation.name == "cpython" |
| CP37_PLUS = PY37_PLUS and sys.implementation.name == "cpython" |
| Py_GIL_DISABLED = sysconfig.get_config_var("Py_GIL_DISABLED") |
| |
| # Test deps, installable via `pip install .[test]` or |
| # `make install-pydeps-test`. |
| TEST_DEPS = [ |
| "pytest", |
| "pytest-subtests", |
| "pytest-xdist", |
| "setuptools", |
| "pywin32 ; os_name == 'nt' and platform_python_implementation != 'PyPy'", |
| "wheel ; os_name == 'nt' and platform_python_implementation != 'PyPy'", |
| "wmi ; os_name == 'nt' and platform_python_implementation != 'PyPy'", |
| ] |
| |
| # Development deps, installable via `pip install .[dev]` or |
| # `make install-pydeps-dev`. |
| DEV_DEPS = TEST_DEPS + [ |
| "abi3audit", |
| "black==24.10.0", |
| "check-manifest", |
| "coverage", |
| "packaging", |
| "pylint", |
| "pyperf", |
| "pypinfo", |
| "pytest-cov", |
| "requests", |
| "rstcheck", |
| "ruff", |
| "sphinx", |
| "sphinx_rtd_theme", |
| "toml-sort", |
| "twine", |
| "virtualenv", |
| "vulture", |
| "wheel", |
| "pyreadline ; os_name == 'nt'", |
| "pdbpp ; os_name == 'nt'", |
| ] |
| |
| macros = [] |
| if POSIX: |
| macros.append(("PSUTIL_POSIX", 1)) |
| if BSD: |
| macros.append(("PSUTIL_BSD", 1)) |
| |
| # Needed to determine _Py_PARSE_PID in case it's missing (PyPy). |
| # Taken from Lib/test/test_fcntl.py. |
| # XXX: not bullet proof as the (long long) case is missing. |
| if struct.calcsize('l') <= 8: |
| macros.append(('PSUTIL_SIZEOF_PID_T', '4')) # int |
| else: |
| macros.append(('PSUTIL_SIZEOF_PID_T', '8')) # long |
| |
| |
| sources = ['psutil/_psutil_common.c'] |
| if POSIX: |
| sources.append('psutil/_psutil_posix.c') |
| |
| |
| def get_version(): |
| INIT = os.path.join(HERE, 'psutil/__init__.py') |
| with open(INIT) as f: |
| for line in f: |
| if line.startswith('__version__'): |
| ret = ast.literal_eval(line.strip().split(' = ')[1]) |
| assert ret.count('.') == 2, ret |
| for num in ret.split('.'): |
| assert num.isdigit(), ret |
| return ret |
| msg = "couldn't find version string" |
| raise ValueError(msg) |
| |
| |
| VERSION = get_version() |
| macros.append(('PSUTIL_VERSION', int(VERSION.replace('.', '')))) |
| |
| # Py_LIMITED_API lets us create a single wheel which works with multiple |
| # python versions, including unreleased ones. |
| if setuptools and CP36_PLUS and (MACOS or LINUX) and not Py_GIL_DISABLED: |
| py_limited_api = {"py_limited_api": True} |
| options = {"bdist_wheel": {"py_limited_api": "cp36"}} |
| macros.append(('Py_LIMITED_API', '0x03060000')) |
| elif setuptools and CP37_PLUS and WINDOWS and not Py_GIL_DISABLED: |
| # PyErr_SetFromWindowsErr / PyErr_SetFromWindowsErrWithFilename are |
| # part of the stable API/ABI starting with CPython 3.7 |
| py_limited_api = {"py_limited_api": True} |
| options = {"bdist_wheel": {"py_limited_api": "cp37"}} |
| macros.append(('Py_LIMITED_API', '0x03070000')) |
| else: |
| py_limited_api = {} |
| options = {} |
| |
| |
| def get_long_description(): |
| script = os.path.join(HERE, "scripts", "internal", "convert_readme.py") |
| readme = os.path.join(HERE, 'README.rst') |
| p = subprocess.Popen( |
| [sys.executable, script, readme], |
| stdout=subprocess.PIPE, |
| stderr=subprocess.PIPE, |
| universal_newlines=True, |
| ) |
| stdout, stderr = p.communicate() |
| if p.returncode != 0: |
| raise RuntimeError(stderr) |
| return stdout |
| |
| |
| @contextlib.contextmanager |
| def silenced_output(stream_name): |
| class DummyFile(io.BytesIO): |
| # see: https://github.com/giampaolo/psutil/issues/678 |
| errors = "ignore" |
| |
| def write(self, s): |
| pass |
| |
| orig = getattr(sys, stream_name) |
| try: |
| setattr(sys, stream_name, DummyFile()) |
| yield |
| finally: |
| setattr(sys, stream_name, orig) |
| |
| |
| def missdeps(cmdline): |
| s = "psutil could not be installed from sources" |
| if not SUNOS and not shutil.which("gcc"): |
| s += " because gcc is not installed. " |
| else: |
| s += ". Perhaps Python header files are not installed. " |
| s += "Try running:\n" |
| s += " {}".format(cmdline) |
| print(hilite(s, color="red", bold=True), file=sys.stderr) |
| |
| |
| def print_install_instructions(): |
| if LINUX: |
| pyimpl = "pypy" if PYPY else "python" |
| if shutil.which("dpkg"): |
| missdeps("sudo apt-get install gcc {}3-dev".format(pyimpl)) |
| elif shutil.which("rpm"): |
| missdeps("sudo yum install gcc {}3-devel".format(pyimpl)) |
| elif shutil.which("apk"): |
| missdeps( |
| "sudo apk add gcc {}3-dev musl-dev linux-headers".format( |
| *pyimpl |
| ) |
| ) |
| elif MACOS: |
| msg = "XCode (https://developer.apple.com/xcode/) is not installed" |
| print(hilite(msg, color="red"), file=sys.stderr) |
| elif FREEBSD: |
| if shutil.which("pkg"): |
| missdeps("pkg install gcc python3") |
| elif shutil.which("mport"): # MidnightBSD |
| missdeps("mport install gcc python3") |
| elif OPENBSD: |
| missdeps("pkg_add -v gcc python3") |
| elif NETBSD: |
| missdeps("pkgin install gcc python3") |
| elif SUNOS: |
| missdeps( |
| "sudo ln -s /usr/bin/gcc /usr/local/bin/cc && pkg install gcc" |
| ) |
| |
| |
| def unix_can_compile(c_code): |
| from distutils.errors import CompileError |
| from distutils.unixccompiler import UnixCCompiler |
| |
| with tempfile.NamedTemporaryFile( |
| suffix='.c', delete=False, mode="wt" |
| ) as f: |
| f.write(c_code) |
| |
| tempdir = tempfile.mkdtemp() |
| try: |
| compiler = UnixCCompiler() |
| # https://github.com/giampaolo/psutil/pull/1568 |
| if os.getenv('CC'): |
| compiler.set_executable('compiler_so', os.getenv('CC')) |
| with silenced_output('stderr'): |
| with silenced_output('stdout'): |
| compiler.compile([f.name], output_dir=tempdir) |
| except CompileError: |
| return False |
| else: |
| return True |
| finally: |
| os.remove(f.name) |
| shutil.rmtree(tempdir) |
| |
| |
| if WINDOWS: |
| |
| def get_winver(): |
| maj, min = sys.getwindowsversion()[0:2] |
| return "0x0{}".format((maj * 100) + min) |
| |
| if sys.getwindowsversion()[0] < 6: |
| msg = "this Windows version is too old (< Windows Vista); " |
| msg += "psutil 3.4.2 is the latest version which supports Windows " |
| msg += "2000, XP and 2003 server" |
| raise RuntimeError(msg) |
| |
| macros.append(("PSUTIL_WINDOWS", 1)) |
| macros.extend([ |
| # be nice to mingw, see: |
| # http://www.mingw.org/wiki/Use_more_recent_defined_functions |
| ('_WIN32_WINNT', get_winver()), |
| ('_AVAIL_WINVER_', get_winver()), |
| ('_CRT_SECURE_NO_WARNINGS', None), |
| # see: https://github.com/giampaolo/psutil/issues/348 |
| ('PSAPI_VERSION', 1), |
| ]) |
| |
| if Py_GIL_DISABLED: |
| macros.append(('Py_GIL_DISABLED', 1)) |
| |
| ext = Extension( |
| 'psutil._psutil_windows', |
| sources=( |
| sources |
| + ["psutil/_psutil_windows.c"] |
| + glob.glob("psutil/arch/windows/*.c") |
| ), |
| define_macros=macros, |
| libraries=[ |
| "psapi", |
| "kernel32", |
| "advapi32", |
| "shell32", |
| "netapi32", |
| "ws2_32", |
| "PowrProf", |
| "pdh", |
| ], |
| # extra_compile_args=["/W 4"], |
| # extra_link_args=["/DEBUG"], |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| |
| elif MACOS: |
| macros.append(("PSUTIL_OSX", 1)) |
| ext = Extension( |
| 'psutil._psutil_osx', |
| sources=( |
| sources |
| + ["psutil/_psutil_osx.c"] |
| + glob.glob("psutil/arch/osx/*.c") |
| ), |
| define_macros=macros, |
| extra_link_args=[ |
| '-framework', |
| 'CoreFoundation', |
| '-framework', |
| 'IOKit', |
| ], |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| |
| elif FREEBSD: |
| macros.append(("PSUTIL_FREEBSD", 1)) |
| ext = Extension( |
| 'psutil._psutil_bsd', |
| sources=( |
| sources |
| + ["psutil/_psutil_bsd.c"] |
| + glob.glob("psutil/arch/bsd/*.c") |
| + glob.glob("psutil/arch/freebsd/*.c") |
| ), |
| define_macros=macros, |
| libraries=["devstat"], |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| |
| elif OPENBSD: |
| macros.append(("PSUTIL_OPENBSD", 1)) |
| ext = Extension( |
| 'psutil._psutil_bsd', |
| sources=( |
| sources |
| + ["psutil/_psutil_bsd.c"] |
| + glob.glob("psutil/arch/bsd/*.c") |
| + glob.glob("psutil/arch/openbsd/*.c") |
| ), |
| define_macros=macros, |
| libraries=["kvm"], |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| |
| elif NETBSD: |
| macros.append(("PSUTIL_NETBSD", 1)) |
| ext = Extension( |
| 'psutil._psutil_bsd', |
| sources=( |
| sources |
| + ["psutil/_psutil_bsd.c"] |
| + glob.glob("psutil/arch/bsd/*.c") |
| + glob.glob("psutil/arch/netbsd/*.c") |
| ), |
| define_macros=macros, |
| libraries=["kvm"], |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| |
| elif LINUX: |
| # see: https://github.com/giampaolo/psutil/issues/659 |
| if not unix_can_compile("#include <linux/ethtool.h>"): |
| macros.append(("PSUTIL_ETHTOOL_MISSING_TYPES", 1)) |
| |
| macros.append(("PSUTIL_LINUX", 1)) |
| ext = Extension( |
| 'psutil._psutil_linux', |
| sources=( |
| sources |
| + ["psutil/_psutil_linux.c"] |
| + glob.glob("psutil/arch/linux/*.c") |
| ), |
| define_macros=macros, |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| |
| elif SUNOS: |
| macros.append(("PSUTIL_SUNOS", 1)) |
| ext = Extension( |
| 'psutil._psutil_sunos', |
| sources=sources |
| + [ |
| 'psutil/_psutil_sunos.c', |
| 'psutil/arch/solaris/v10/ifaddrs.c', |
| 'psutil/arch/solaris/environ.c', |
| ], |
| define_macros=macros, |
| libraries=['kstat', 'nsl', 'socket'], |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| |
| elif AIX: |
| macros.append(("PSUTIL_AIX", 1)) |
| ext = Extension( |
| 'psutil._psutil_aix', |
| sources=sources |
| + [ |
| 'psutil/_psutil_aix.c', |
| 'psutil/arch/aix/net_connections.c', |
| 'psutil/arch/aix/common.c', |
| 'psutil/arch/aix/ifaddrs.c', |
| ], |
| libraries=['perfstat'], |
| define_macros=macros, |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| |
| else: |
| sys.exit("platform {} is not supported".format(sys.platform)) |
| |
| |
| if POSIX: |
| posix_extension = Extension( |
| 'psutil._psutil_posix', |
| define_macros=macros, |
| sources=sources, |
| # fmt: off |
| # python 2.7 compatibility requires no comma |
| **py_limited_api |
| # fmt: on |
| ) |
| if SUNOS: |
| |
| def get_sunos_update(): |
| # See https://serverfault.com/q/524883 |
| # for an explanation of Solaris /etc/release |
| with open('/etc/release') as f: |
| update = re.search(r'(?<=s10s_u)[0-9]{1,2}', f.readline()) |
| return int(update.group(0)) if update else 0 |
| |
| posix_extension.libraries.append('socket') |
| if platform.release() == '5.10': |
| # Detect Solaris 5.10, update >= 4, see: |
| # https://github.com/giampaolo/psutil/pull/1638 |
| if get_sunos_update() >= 4: |
| # MIB compliance starts with SunOS 5.10 Update 4: |
| posix_extension.define_macros.append(('NEW_MIB_COMPLIANT', 1)) |
| posix_extension.sources.append('psutil/arch/solaris/v10/ifaddrs.c') |
| posix_extension.define_macros.append(('PSUTIL_SUNOS10', 1)) |
| else: |
| # Other releases are by default considered to be new mib compliant. |
| posix_extension.define_macros.append(('NEW_MIB_COMPLIANT', 1)) |
| elif AIX: |
| posix_extension.sources.append('psutil/arch/aix/ifaddrs.c') |
| |
| extensions = [ext, posix_extension] |
| else: |
| extensions = [ext] |
| |
| |
| def main(): |
| kwargs = dict( |
| name='psutil', |
| version=VERSION, |
| description=__doc__.replace('\n', ' ').strip() if __doc__ else '', |
| long_description=get_long_description(), |
| long_description_content_type='text/x-rst', |
| # fmt: off |
| keywords=[ |
| 'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', 'tty', |
| 'ionice', 'uptime', 'taskmgr', 'process', 'df', 'iotop', 'iostat', |
| 'ifconfig', 'taskset', 'who', 'pidof', 'pmap', 'smem', 'pstree', |
| 'monitoring', 'ulimit', 'prlimit', 'smem', 'performance', |
| 'metrics', 'agent', 'observability', |
| ], |
| # fmt: on |
| author='Giampaolo Rodola', |
| author_email='[email protected]', |
| url='https://github.com/giampaolo/psutil', |
| platforms='Platform Independent', |
| license='BSD-3-Clause', |
| packages=['psutil', 'psutil.tests'], |
| ext_modules=extensions, |
| options=options, |
| classifiers=[ |
| 'Development Status :: 5 - Production/Stable', |
| 'Environment :: Console', |
| 'Environment :: Win32 (MS Windows)', |
| 'Intended Audience :: Developers', |
| 'Intended Audience :: Information Technology', |
| 'Intended Audience :: System Administrators', |
| 'License :: OSI Approved :: BSD License', |
| 'Operating System :: MacOS :: MacOS X', |
| 'Operating System :: Microsoft :: Windows :: Windows 10', |
| 'Operating System :: Microsoft :: Windows :: Windows 7', |
| 'Operating System :: Microsoft :: Windows :: Windows 8', |
| 'Operating System :: Microsoft :: Windows :: Windows 8.1', |
| 'Operating System :: Microsoft :: Windows :: Windows Server 2003', |
| 'Operating System :: Microsoft :: Windows :: Windows Server 2008', |
| 'Operating System :: Microsoft :: Windows :: Windows Vista', |
| 'Operating System :: Microsoft', |
| 'Operating System :: OS Independent', |
| 'Operating System :: POSIX :: AIX', |
| 'Operating System :: POSIX :: BSD :: FreeBSD', |
| 'Operating System :: POSIX :: BSD :: NetBSD', |
| 'Operating System :: POSIX :: BSD :: OpenBSD', |
| 'Operating System :: POSIX :: BSD', |
| 'Operating System :: POSIX :: Linux', |
| 'Operating System :: POSIX :: SunOS/Solaris', |
| 'Operating System :: POSIX', |
| 'Programming Language :: C', |
| 'Programming Language :: Python :: 3', |
| 'Programming Language :: Python :: Implementation :: CPython', |
| 'Programming Language :: Python :: Implementation :: PyPy', |
| 'Programming Language :: Python', |
| 'Topic :: Software Development :: Libraries :: Python Modules', |
| 'Topic :: Software Development :: Libraries', |
| 'Topic :: System :: Benchmark', |
| 'Topic :: System :: Hardware :: Hardware Drivers', |
| 'Topic :: System :: Hardware', |
| 'Topic :: System :: Monitoring', |
| 'Topic :: System :: Networking :: Monitoring :: Hardware Watchdog', |
| 'Topic :: System :: Networking :: Monitoring', |
| 'Topic :: System :: Networking', |
| 'Topic :: System :: Operating System', |
| 'Topic :: System :: Systems Administration', |
| 'Topic :: Utilities', |
| ], |
| ) |
| if setuptools is not None: |
| extras_require = { |
| "dev": DEV_DEPS, |
| "test": TEST_DEPS, |
| } |
| kwargs.update( |
| python_requires=">=3.6", |
| extras_require=extras_require, |
| zip_safe=False, |
| ) |
| success = False |
| try: |
| setup(**kwargs) |
| success = True |
| finally: |
| cmd = sys.argv[1] if len(sys.argv) >= 2 else '' |
| if ( |
| not success |
| and POSIX |
| and cmd.startswith( |
| ("build", "install", "sdist", "bdist", "develop") |
| ) |
| ): |
| print_install_instructions() |
| |
| |
| if __name__ == '__main__': |
| main() |