diff options
author | robot-piglet <[email protected]> | 2025-03-03 01:22:13 +0300 |
---|---|---|
committer | robot-piglet <[email protected]> | 2025-03-03 01:34:11 +0300 |
commit | e4edb481962c16c208a1f0f2d7fd698f86f98525 (patch) | |
tree | bad447ca4778aedf9d8b83079f275a9a2a2a9727 /contrib/python | |
parent | 6678165e016ba474f1b8dd6d49af92b0d46350b9 (diff) |
Intermediate changes
commit_hash:7c10655440be1add16ba4307493e0143ef552dbf
Diffstat (limited to 'contrib/python')
27 files changed, 680 insertions, 1672 deletions
diff --git a/contrib/python/psutil/py3/.dist-info/METADATA b/contrib/python/psutil/py3/.dist-info/METADATA index eced53b9c36..685d2e23f38 100644 --- a/contrib/python/psutil/py3/.dist-info/METADATA +++ b/contrib/python/psutil/py3/.dist-info/METADATA @@ -1,7 +1,7 @@ Metadata-Version: 2.1 Name: psutil -Version: 6.1.1 -Summary: Cross-platform lib for process and system monitoring in Python. +Version: 7.0.0 +Summary: Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7. Home-page: https://github.com/giampaolo/psutil Author: Giampaolo Rodola Author-email: [email protected] @@ -34,8 +34,6 @@ Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: POSIX :: SunOS/Solaris Classifier: Operating System :: POSIX Classifier: Programming Language :: C -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy @@ -52,12 +50,15 @@ Classifier: Topic :: System :: Networking Classifier: Topic :: System :: Operating System Classifier: Topic :: System :: Systems Administration Classifier: Topic :: Utilities -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.* +Requires-Python: >=3.6 Description-Content-Type: text/x-rst License-File: LICENSE Provides-Extra: dev +Requires-Dist: pytest ; extra == 'dev' +Requires-Dist: pytest-xdist ; extra == 'dev' +Requires-Dist: setuptools ; extra == 'dev' Requires-Dist: abi3audit ; extra == 'dev' -Requires-Dist: black ; extra == 'dev' +Requires-Dist: black (==24.10.0) ; extra == 'dev' Requires-Dist: check-manifest ; extra == 'dev' Requires-Dist: coverage ; extra == 'dev' Requires-Dist: packaging ; extra == 'dev' @@ -82,7 +83,7 @@ Requires-Dist: setuptools ; extra == 'test' | |downloads| |stars| |forks| |contributors| |coverage| | |version| |py-versions| |packages| |license| -| |github-actions-wheels| |github-actions-bsd| |appveyor| |doc| |twitter| |tidelift| +| |github-actions-wheels| |github-actions-bsd| |doc| |twitter| |tidelift| .. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg :target: https://pepy.tech/project/psutil @@ -108,10 +109,6 @@ Requires-Dist: setuptools ; extra == 'test' :target: https://github.com/giampaolo/psutil/actions?query=workflow%3Absd-tests :alt: FreeBSD, NetBSD, OpenBSD -.. |appveyor| image:: https://img.shields.io/appveyor/build/giampaolo/psutil/master.svg?maxAge=3600&label=Windows%20(py2) - :target: https://ci.appveyor.com/project/giampaolo/psutil - :alt: Windows (Appveyor) - .. |coverage| image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master :target: https://coveralls.io/github/giampaolo/psutil?branch=master :alt: Test coverage (coverall.io) @@ -177,8 +174,9 @@ psutil currently supports the following platforms: - **Sun Solaris** - **AIX** -Supported Python versions are **2.7**, **3.6+** and -`PyPy <http://pypy.org/>`__. +Supported Python versions are cPython 3.6+ and `PyPy <https://pypy.org/>`__. +Latest psutil version supporting Python 2.7 is +`psutil 6.1.1 <https://pypi.org/project/psutil/6.1.1/>`__. Funding ======= diff --git a/contrib/python/psutil/py3/README.rst b/contrib/python/psutil/py3/README.rst index 3fc6e601b12..16c756c50e2 100644 --- a/contrib/python/psutil/py3/README.rst +++ b/contrib/python/psutil/py3/README.rst @@ -1,6 +1,6 @@ | |downloads| |stars| |forks| |contributors| |coverage| | |version| |py-versions| |packages| |license| -| |github-actions-wheels| |github-actions-bsd| |appveyor| |doc| |twitter| |tidelift| +| |github-actions-wheels| |github-actions-bsd| |doc| |twitter| |tidelift| .. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg :target: https://pepy.tech/project/psutil @@ -26,10 +26,6 @@ :target: https://github.com/giampaolo/psutil/actions?query=workflow%3Absd-tests :alt: FreeBSD, NetBSD, OpenBSD -.. |appveyor| image:: https://img.shields.io/appveyor/build/giampaolo/psutil/master.svg?maxAge=3600&label=Windows%20(py2) - :target: https://ci.appveyor.com/project/giampaolo/psutil - :alt: Windows (Appveyor) - .. |coverage| image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master :target: https://coveralls.io/github/giampaolo/psutil?branch=master :alt: Test coverage (coverall.io) @@ -98,8 +94,9 @@ psutil currently supports the following platforms: - **Sun Solaris** - **AIX** -Supported Python versions are **2.7**, **3.6+** and -`PyPy <http://pypy.org/>`__. +Supported Python versions are cPython 3.6+ and `PyPy <https://pypy.org/>`__. +Latest psutil version supporting Python 2.7 is +`psutil 6.1.1 <https://pypi.org/project/psutil/6.1.1/>`__. Funding ======= diff --git a/contrib/python/psutil/py3/patches/01-arcadia.patch b/contrib/python/psutil/py3/patches/01-arcadia.patch index 54b53d1db5c..6a0b3aff1df 100644 --- a/contrib/python/psutil/py3/patches/01-arcadia.patch +++ b/contrib/python/psutil/py3/patches/01-arcadia.patch @@ -1,17 +1,3 @@ ---- contrib/python/psutil/py3/psutil/_pslinux.py (index) -+++ contrib/python/psutil/py3/psutil/_pslinux.py (working tree) -@@ -322,7 +322,10 @@ try: - except ImportError: - import ctypes - -- libc = ctypes.CDLL(None, use_errno=True) -+ try: -+ libc = ctypes.CDLL(None, use_errno=True) -+ except: -+ libc = None - - if hasattr(libc, "prlimit"): - --- contrib/python/psutil/py3/psutil/arch/windows/disk.c (index) +++ contrib/python/psutil/py3/psutil/arch/windows/disk.c (working tree) @@ -7,6 +7,7 @@ diff --git a/contrib/python/psutil/py3/psutil/__init__.py b/contrib/python/psutil/py3/psutil/__init__.py index 56483393827..cf4a58057f9 100644 --- a/contrib/python/psutil/py3/psutil/__init__.py +++ b/contrib/python/psutil/py3/psutil/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # 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. @@ -17,17 +15,16 @@ sensors) in Python. Supported platforms: - Sun Solaris - AIX -Works with Python versions 2.7 and 3.6+. +Supported Python versions are cPython 3.6+ and PyPy. """ -from __future__ import division - import collections import contextlib import datetime import functools import os import signal +import socket import subprocess import sys import threading @@ -54,16 +51,16 @@ from ._common import CONN_NONE from ._common import CONN_SYN_RECV from ._common import CONN_SYN_SENT from ._common import CONN_TIME_WAIT -from ._common import FREEBSD # NOQA +from ._common import FREEBSD from ._common import LINUX from ._common import MACOS -from ._common import NETBSD # NOQA +from ._common import NETBSD from ._common import NIC_DUPLEX_FULL from ._common import NIC_DUPLEX_HALF from ._common import NIC_DUPLEX_UNKNOWN -from ._common import OPENBSD # NOQA +from ._common import OPENBSD from ._common import OSX # deprecated alias -from ._common import POSIX # NOQA +from ._common import POSIX from ._common import POWER_TIME_UNKNOWN from ._common import POWER_TIME_UNLIMITED from ._common import STATUS_DEAD @@ -88,11 +85,6 @@ from ._common import ZombieProcess from ._common import debug from ._common import memoize_when_activated from ._common import wrap_numbers as _wrap_numbers -from ._compat import PY3 as _PY3 -from ._compat import PermissionError -from ._compat import ProcessLookupError -from ._compat import SubprocessTimeoutExpired as _SubprocessTimeoutExpired -from ._compat import long if LINUX: @@ -101,24 +93,24 @@ if LINUX: PROCFS_PATH = "/proc" from . import _pslinux as _psplatform - from ._pslinux import IOPRIO_CLASS_BE # NOQA - from ._pslinux import IOPRIO_CLASS_IDLE # NOQA - from ._pslinux import IOPRIO_CLASS_NONE # NOQA - from ._pslinux import IOPRIO_CLASS_RT # NOQA + from ._pslinux import IOPRIO_CLASS_BE # noqa: F401 + from ._pslinux import IOPRIO_CLASS_IDLE # noqa: F401 + from ._pslinux import IOPRIO_CLASS_NONE # noqa: F401 + from ._pslinux import IOPRIO_CLASS_RT # noqa: F401 elif WINDOWS: from . import _pswindows as _psplatform - from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS # NOQA - from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS # NOQA - from ._psutil_windows import HIGH_PRIORITY_CLASS # NOQA - from ._psutil_windows import IDLE_PRIORITY_CLASS # NOQA - from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA - from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA - from ._pswindows import CONN_DELETE_TCB # NOQA - from ._pswindows import IOPRIO_HIGH # NOQA - from ._pswindows import IOPRIO_LOW # NOQA - from ._pswindows import IOPRIO_NORMAL # NOQA - from ._pswindows import IOPRIO_VERYLOW # NOQA + from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS # noqa: F401 + from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS # noqa: F401 + from ._psutil_windows import HIGH_PRIORITY_CLASS # noqa: F401 + from ._psutil_windows import IDLE_PRIORITY_CLASS # noqa: F401 + from ._psutil_windows import NORMAL_PRIORITY_CLASS # noqa: F401 + from ._psutil_windows import REALTIME_PRIORITY_CLASS # noqa: F401 + from ._pswindows import CONN_DELETE_TCB # noqa: F401 + from ._pswindows import IOPRIO_HIGH # noqa: F401 + from ._pswindows import IOPRIO_LOW # noqa: F401 + from ._pswindows import IOPRIO_NORMAL # noqa: F401 + from ._pswindows import IOPRIO_VERYLOW # noqa: F401 elif MACOS: from . import _psosx as _psplatform @@ -128,8 +120,8 @@ elif BSD: elif SUNOS: from . import _pssunos as _psplatform - from ._pssunos import CONN_BOUND # NOQA - from ._pssunos import CONN_IDLE # NOQA + from ._pssunos import CONN_BOUND # noqa: F401 + from ._pssunos import CONN_IDLE # noqa: F401 # This is public writable API which is read from _pslinux.py and # _pssunos.py via sys.modules. @@ -143,7 +135,8 @@ elif AIX: PROCFS_PATH = "/proc" else: # pragma: no cover - raise NotImplementedError('platform %s is not supported' % sys.platform) + msg = f"platform {sys.platform} is not supported" + raise NotImplementedError(msg) # fmt: off @@ -214,8 +207,8 @@ if hasattr(_psplatform.Process, "rlimit"): AF_LINK = _psplatform.AF_LINK __author__ = "Giampaolo Rodola'" -__version__ = "6.1.1" -version_info = tuple([int(num) for num in __version__.split('.')]) +__version__ = "7.0.0" +version_info = tuple(int(num) for num in __version__.split('.')) _timer = getattr(time, 'monotonic', time.time) _TOTAL_PHYMEM = None @@ -231,22 +224,19 @@ _SENTINEL = object() if int(__version__.replace('.', '')) != getattr( _psplatform.cext, 'version', None ): - msg = "version conflict: %r C extension " % _psplatform.cext.__file__ + msg = f"version conflict: {_psplatform.cext.__file__!r} C extension " msg += "module was built for another version of psutil" if hasattr(_psplatform.cext, 'version'): - msg += " (%s instead of %s)" % ( - '.'.join([x for x in str(_psplatform.cext.version)]), - __version__, - ) + v = ".".join(list(str(_psplatform.cext.version))) + msg += f" ({v} instead of {__version__})" else: - msg += " (different than %s)" % __version__ - msg += "; you may try to 'pip uninstall psutil', manually remove %s" % ( - getattr( - _psplatform.cext, - "__file__", - "the existing psutil install directory", - ) + msg += f" (different than {__version__})" + what = getattr( + _psplatform.cext, + "__file__", + "the existing psutil install directory", ) + msg += f"; you may try to 'pip uninstall psutil', manually remove {what}" msg += " or clean the virtual env somehow, then reinstall" raise ImportError(msg) @@ -282,12 +272,20 @@ def _pprint_secs(secs): return datetime.datetime.fromtimestamp(secs).strftime(fmt) +def _check_conn_kind(kind): + """Check net_connections()'s `kind` parameter.""" + kinds = tuple(_common.conn_tmap) + if kind not in kinds: + msg = f"invalid kind argument {kind!r}; valid ones are: {kinds}" + raise ValueError(msg) + + # ===================================================================== # --- Process class # ===================================================================== -class Process(object): # noqa: UP004 +class Process: """Represents an OS process with the given PID. If PID is omitted current process PID (os.getpid()) is used. Raise NoSuchProcess if PID does not exist. @@ -322,17 +320,14 @@ class Process(object): # noqa: UP004 if pid is None: pid = os.getpid() else: - if not _PY3 and not isinstance(pid, (int, long)): - msg = "pid must be an integer (got %r)" % pid - raise TypeError(msg) if pid < 0: - msg = "pid must be a positive integer (got %s)" % pid + msg = f"pid must be a positive integer (got {pid})" raise ValueError(msg) try: _psplatform.cext.check_pid_range(pid) - except OverflowError: - msg = "process PID out of range (got %s)" % pid - raise NoSuchProcess(pid, msg=msg) + except OverflowError as err: + msg = "process PID out of range" + raise NoSuchProcess(pid, msg=msg) from err self._pid = pid self._name = None @@ -365,9 +360,8 @@ class Process(object): # noqa: UP004 except NoSuchProcess: if not _ignore_nsp: msg = "process PID not found" - raise NoSuchProcess(pid, msg=msg) - else: - self._gone = True + raise NoSuchProcess(pid, msg=msg) from None + self._gone = True def _get_ident(self): """Return a (pid, uid) tuple which is supposed to identify a @@ -419,10 +413,10 @@ class Process(object): # noqa: UP004 if self._create_time is not None: info['started'] = _pprint_secs(self._create_time) - return "%s.%s(%s)" % ( + return "{}.{}({})".format( self.__class__.__module__, self.__class__.__name__, - ", ".join(["%s=%r" % (k, v) for k, v in info.items()]), + ", ".join([f"{k}={v!r}" for k, v in info.items()]), ) __repr__ = __str__ @@ -556,12 +550,12 @@ class Process(object): # noqa: UP004 valid_names = _as_dict_attrnames if attrs is not None: if not isinstance(attrs, (list, tuple, set, frozenset)): - msg = "invalid attrs type %s" % type(attrs) + msg = f"invalid attrs type {type(attrs)}" raise TypeError(msg) attrs = set(attrs) invalid_names = attrs - valid_names if invalid_names: - msg = "invalid attr name%s %s" % ( + msg = "invalid attr name{} {}".format( "s" if len(invalid_names) > 1 else "", ", ".join(map(repr, invalid_names)), ) @@ -1049,7 +1043,7 @@ class Process(object): # noqa: UP004 """ blocking = interval is not None and interval > 0.0 if interval is not None and interval < 0: - msg = "interval is not positive (got %r)" % interval + msg = f"interval is not positive (got {interval!r})" raise ValueError(msg) num_cpus = cpu_count() or 1 @@ -1127,10 +1121,6 @@ class Process(object): # noqa: UP004 """ return self._proc.memory_info() - @_common.deprecated_method(replacement="memory_info") - def memory_info_ex(self): - return self.memory_info() - def memory_full_info(self): """This method returns the same information as memory_info(), plus, on some platform (Linux, macOS, Windows), also provides @@ -1159,9 +1149,9 @@ class Process(object): # noqa: UP004 """ valid_types = list(_psplatform.pfullmem._fields) if memtype not in valid_types: - msg = "invalid memtype %r; valid types are %r" % ( - memtype, - tuple(valid_types), + msg = ( + f"invalid memtype {memtype!r}; valid types are" + f" {tuple(valid_types)!r}" ) raise ValueError(msg) fun = ( @@ -1178,7 +1168,7 @@ class Process(object): # noqa: UP004 # we should never get here msg = ( "can't calculate process memory percent because total physical" - " system memory is not positive (%r)" % (total_phymem) + f" system memory is not positive ({total_phymem!r})" ) raise ValueError(msg) return (value / float(total_phymem)) * 100 @@ -1203,11 +1193,11 @@ class Process(object): # noqa: UP004 path = tupl[2] nums = tupl[3:] try: - d[path] = map(lambda x, y: x + y, d[path], nums) + d[path] = list(map(lambda x, y: x + y, d[path], nums)) except KeyError: d[path] = nums nt = _psplatform.pmmap_grouped - return [nt(path, *d[path]) for path in d] # NOQA + return [nt(path, *d[path]) for path in d] else: nt = _psplatform.pmmap_ext return [nt(*x) for x in it] @@ -1241,6 +1231,7 @@ class Process(object): # noqa: UP004 | all | the sum of all the possible families and protocols | +------------+----------------------------------------------------+ """ + _check_conn_kind(kind) return self._proc.net_connections(kind) @_common.deprecated_method(replacement="net_connections") @@ -1254,7 +1245,9 @@ class Process(object): # noqa: UP004 def _send_signal(self, sig): assert not self.pid < 0, self.pid self._raise_if_pid_reused() - if self.pid == 0: + + pid, ppid, name = self.pid, self._ppid, self._name + if pid == 0: # see "man 2 kill" msg = ( "preventing sending signal to process with PID 0 as it " @@ -1263,17 +1256,16 @@ class Process(object): # noqa: UP004 ) raise ValueError(msg) try: - os.kill(self.pid, sig) - except ProcessLookupError: - if OPENBSD and pid_exists(self.pid): + os.kill(pid, sig) + except ProcessLookupError as err: + if OPENBSD and pid_exists(pid): # We do this because os.kill() lies in case of # zombie processes. - raise ZombieProcess(self.pid, self._name, self._ppid) - else: - self._gone = True - raise NoSuchProcess(self.pid, self._name) - except PermissionError: - raise AccessDenied(self.pid, self._name) + raise ZombieProcess(pid, name, ppid) from err + self._gone = True + raise NoSuchProcess(pid, name) from err + except PermissionError as err: + raise AccessDenied(pid, name) from err def send_signal(self, sig): """Send a signal *sig* to process pre-emptively checking @@ -1358,11 +1350,12 @@ class Process(object): # noqa: UP004 # The valid attr names which can be processed by Process.as_dict(). # fmt: off -_as_dict_attrnames = set( - [x for x in dir(Process) if not x.startswith('_') and x not in +_as_dict_attrnames = { + x for x in dir(Process) if not x.startswith("_") and x not in {'send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', 'is_running', 'as_dict', 'parent', 'parents', 'children', 'rlimit', - 'memory_info_ex', 'connections', 'oneshot'}]) + 'connections', 'oneshot'} +} # fmt: on @@ -1439,16 +1432,13 @@ class Popen(Process): try: return object.__getattribute__(self.__subproc, name) except AttributeError: - msg = "%s instance has no attribute '%s'" % ( - self.__class__.__name__, - name, - ) - raise AttributeError(msg) + msg = f"{self.__class__!r} has no attribute {name!r}" + raise AttributeError(msg) from None def wait(self, timeout=None): if self.__subproc.returncode is not None: return self.__subproc.returncode - ret = super(Popen, self).wait(timeout) # noqa + ret = super().wait(timeout) self.__subproc.returncode = ret return ret @@ -1525,7 +1515,7 @@ def process_iter(attrs=None, ad_value=None): remove(pid) while _pids_reused: pid = _pids_reused.pop() - debug("refreshing Process instance for reused PID %s" % pid) + debug(f"refreshing Process instance for reused PID {pid}") remove(pid) try: ls = sorted(list(pmap.items()) + list(dict.fromkeys(new_pids).items())) @@ -1542,7 +1532,7 @@ def process_iter(attrs=None, ad_value=None): _pmap = pmap -process_iter.cache_clear = lambda: _pmap.clear() # noqa +process_iter.cache_clear = lambda: _pmap.clear() # noqa: PLW0108 process_iter.cache_clear.__doc__ = "Clear process_iter() internal cache." @@ -1586,9 +1576,7 @@ def wait_procs(procs, timeout=None, callback=None): def check_gone(proc, timeout): try: returncode = proc.wait(timeout=timeout) - except TimeoutExpired: - pass - except _SubprocessTimeoutExpired: + except (TimeoutExpired, subprocess.TimeoutExpired): pass else: if returncode is not None or not proc.is_running(): @@ -1599,12 +1587,12 @@ def wait_procs(procs, timeout=None, callback=None): callback(proc) if timeout is not None and not timeout >= 0: - msg = "timeout must be a positive integer, got %s" % timeout + msg = f"timeout must be a positive integer, got {timeout}" raise ValueError(msg) gone = set() alive = set(procs) if callback is not None and not callable(callback): - msg = "callback %r is not a callable" % callback + msg = f"callback {callback!r} is not a callable" raise TypeError(msg) if timeout is not None: deadline = _timer() + timeout @@ -1627,7 +1615,7 @@ def wait_procs(procs, timeout=None, callback=None): check_gone(proc, timeout) else: check_gone(proc, max_timeout) - alive = alive - gone # noqa PLR6104 + alive = alive - gone # noqa: PLR6104 if alive: # Last attempt over processes survived so far. @@ -1646,7 +1634,7 @@ def wait_procs(procs, timeout=None, callback=None): def cpu_count(logical=True): """Return the number of logical CPUs in the system (same as - os.cpu_count() in Python 3.4). + os.cpu_count()). If *logical* is False return the number of physical cores only (e.g. hyper thread CPUs are excluded). @@ -1804,7 +1792,7 @@ def cpu_percent(interval=None, percpu=False): tid = threading.current_thread().ident blocking = interval is not None and interval > 0.0 if interval is not None and interval < 0: - msg = "interval is not positive (got %r)" % interval + msg = f"interval is not positive (got {interval})" raise ValueError(msg) def calculate(t1, t2): @@ -1864,7 +1852,7 @@ def cpu_times_percent(interval=None, percpu=False): tid = threading.current_thread().ident blocking = interval is not None and interval > 0.0 if interval is not None and interval < 0: - msg = "interval is not positive (got %r)" % interval + msg = f"interval is not positive (got {interval!r})" raise ValueError(msg) def calculate(t1, t2): @@ -2202,6 +2190,7 @@ def net_connections(kind='inet'): On macOS this function requires root privileges. """ + _check_conn_kind(kind) return _psplatform.net_connections(kind) @@ -2223,35 +2212,46 @@ def net_if_addrs(): Note: you can have more than one address of the same family associated with each interface. """ - has_enums = _PY3 - if has_enums: - import socket rawlist = _psplatform.net_if_addrs() rawlist.sort(key=lambda x: x[1]) # sort by family ret = collections.defaultdict(list) for name, fam, addr, mask, broadcast, ptp in rawlist: - if has_enums: - try: - fam = socket.AddressFamily(fam) - except ValueError: - if WINDOWS and fam == -1: - fam = _psplatform.AF_LINK - elif ( - hasattr(_psplatform, "AF_LINK") - and fam == _psplatform.AF_LINK - ): - # Linux defines AF_LINK as an alias for AF_PACKET. - # We re-set the family here so that repr(family) - # will show AF_LINK rather than AF_PACKET - fam = _psplatform.AF_LINK + try: + fam = socket.AddressFamily(fam) + except ValueError: + if WINDOWS and fam == -1: + fam = _psplatform.AF_LINK + elif ( + hasattr(_psplatform, "AF_LINK") and fam == _psplatform.AF_LINK + ): + # Linux defines AF_LINK as an alias for AF_PACKET. + # We re-set the family here so that repr(family) + # will show AF_LINK rather than AF_PACKET + fam = _psplatform.AF_LINK + if fam == _psplatform.AF_LINK: # The underlying C function may return an incomplete MAC # address in which case we fill it with null bytes, see: # https://github.com/giampaolo/psutil/issues/786 separator = ":" if POSIX else "-" while addr.count(separator) < 5: - addr += "%s00" % separator - ret[name].append(_common.snicaddr(fam, addr, mask, broadcast, ptp)) + addr += f"{separator}00" + + nt = _common.snicaddr(fam, addr, mask, broadcast, ptp) + + # On Windows broadcast is None, so we determine it via + # ipaddress module. + if WINDOWS and fam in {socket.AF_INET, socket.AF_INET6}: + try: + broadcast = _common.broadcast_addr(nt) + except Exception as err: # noqa: BLE001 + debug(err) + else: + if broadcast is not None: + nt._replace(broadcast=broadcast) + + ret[name].append(nt) + return dict(ret) @@ -2404,83 +2404,4 @@ def _set_debug(value): _psplatform.cext.set_debug(bool(value)) -def test(): # pragma: no cover - from ._common import bytes2human - from ._compat import get_terminal_size - - today_day = datetime.date.today() - # fmt: off - templ = "%-10s %5s %5s %7s %7s %5s %6s %6s %6s %s" - attrs = ['pid', 'memory_percent', 'name', 'cmdline', 'cpu_times', - 'create_time', 'memory_info', 'status', 'nice', 'username'] - print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "NICE", # NOQA - "STATUS", "START", "TIME", "CMDLINE")) - # fmt: on - for p in process_iter(attrs, ad_value=None): - if p.info['create_time']: - ctime = datetime.datetime.fromtimestamp(p.info['create_time']) - if ctime.date() == today_day: - ctime = ctime.strftime("%H:%M") - else: - ctime = ctime.strftime("%b%d") - else: - ctime = '' - if p.info['cpu_times']: - cputime = time.strftime( - "%M:%S", time.localtime(sum(p.info['cpu_times'])) - ) - else: - cputime = '' - - user = p.info['username'] or '' - if not user and POSIX: - try: - user = p.uids()[0] - except Error: - pass - if user and WINDOWS and '\\' in user: - user = user.split('\\')[1] - user = user[:9] - vms = ( - bytes2human(p.info['memory_info'].vms) - if p.info['memory_info'] is not None - else '' - ) - rss = ( - bytes2human(p.info['memory_info'].rss) - if p.info['memory_info'] is not None - else '' - ) - memp = ( - round(p.info['memory_percent'], 1) - if p.info['memory_percent'] is not None - else '' - ) - nice = int(p.info['nice']) if p.info['nice'] else '' - if p.info['cmdline']: - cmdline = ' '.join(p.info['cmdline']) - else: - cmdline = p.info['name'] - status = p.info['status'][:5] if p.info['status'] else '' - - line = templ % ( - user[:10], - p.info['pid'], - memp, - vms, - rss, - nice, - status, - ctime, - cputime, - cmdline, - ) - print(line[: get_terminal_size()[0]]) # NOQA - - -del memoize_when_activated, division -if sys.version_info[0] < 3: - del num, x # noqa - -if __name__ == "__main__": - test() +del memoize_when_activated diff --git a/contrib/python/psutil/py3/psutil/_common.py b/contrib/python/psutil/py3/psutil/_common.py index 4b99b093e30..4096c0a18c8 100644 --- a/contrib/python/psutil/py3/psutil/_common.py +++ b/contrib/python/psutil/py3/psutil/_common.py @@ -2,17 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""Common objects shared by __init__.py and _ps*.py modules.""" +"""Common objects shared by __init__.py and _ps*.py modules. -# Note: this module is imported by setup.py so it should not import -# psutil or third-party modules. - -from __future__ import division -from __future__ import print_function +Note: this module is imported by setup.py, so it should not import +psutil or third-party modules. +""" import collections -import contextlib -import errno +import enum import functools import os import socket @@ -36,14 +33,6 @@ except ImportError: AF_UNIX = None -# can't take it from _common.py as this script is imported by setup.py -PY3 = sys.version_info[0] >= 3 -if PY3: - import enum -else: - enum = None - - PSUTIL_DEBUG = bool(os.getenv('PSUTIL_DEBUG')) _DEFAULT = object() @@ -57,7 +46,7 @@ __all__ = [ 'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN', 'CONN_NONE', 'CONN_SYN_RECV', 'CONN_SYN_SENT', 'CONN_TIME_WAIT', # net constants - 'NIC_DUPLEX_FULL', 'NIC_DUPLEX_HALF', 'NIC_DUPLEX_UNKNOWN', + 'NIC_DUPLEX_FULL', 'NIC_DUPLEX_HALF', 'NIC_DUPLEX_UNKNOWN', # noqa: F822 # process status constants 'STATUS_DEAD', 'STATUS_DISK_SLEEP', 'STATUS_IDLE', 'STATUS_LOCKED', 'STATUS_RUNNING', 'STATUS_SLEEPING', 'STATUS_STOPPED', 'STATUS_SUSPENDED', @@ -134,42 +123,29 @@ CONN_LISTEN = "LISTEN" CONN_CLOSING = "CLOSING" CONN_NONE = "NONE" + # net_if_stats() -if enum is None: +class NicDuplex(enum.IntEnum): NIC_DUPLEX_FULL = 2 NIC_DUPLEX_HALF = 1 NIC_DUPLEX_UNKNOWN = 0 -else: - class NicDuplex(enum.IntEnum): - NIC_DUPLEX_FULL = 2 - NIC_DUPLEX_HALF = 1 - NIC_DUPLEX_UNKNOWN = 0 - globals().update(NicDuplex.__members__) +globals().update(NicDuplex.__members__) + # sensors_battery() -if enum is None: +class BatteryTime(enum.IntEnum): POWER_TIME_UNKNOWN = -1 POWER_TIME_UNLIMITED = -2 -else: - class BatteryTime(enum.IntEnum): - POWER_TIME_UNKNOWN = -1 - POWER_TIME_UNLIMITED = -2 - globals().update(BatteryTime.__members__) +globals().update(BatteryTime.__members__) # --- others ENCODING = sys.getfilesystemencoding() -if not PY3: - ENCODING_ERRS = "replace" -else: - try: - ENCODING_ERRS = sys.getfilesystemencodeerrors() # py 3.6 - except AttributeError: - ENCODING_ERRS = "surrogateescape" if POSIX else "replace" +ENCODING_ERRS = sys.getfilesystemencodeerrors() # =================================================================== @@ -273,7 +249,7 @@ if AF_INET6 is not None: "udp6": ([AF_INET6], [SOCK_DGRAM]), }) -if AF_UNIX is not None: +if AF_UNIX is not None and not SUNOS: conn_tmap.update({"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM])}) @@ -293,9 +269,7 @@ class Error(Exception): info = collections.OrderedDict() for name in attrs: value = getattr(self, name, None) - if value: # noqa - info[name] = value - elif name == "pid" and value == 0: + if value or (name == "pid" and value == 0): info[name] = value return info @@ -303,8 +277,8 @@ class Error(Exception): # invoked on `raise Error` info = self._infodict(("pid", "ppid", "name")) if info: - details = "(%s)" % ", ".join( - ["%s=%r" % (k, v) for k, v in info.items()] + details = "({})".format( + ", ".join([f"{k}={v!r}" for k, v in info.items()]) ) else: details = None @@ -313,8 +287,8 @@ class Error(Exception): def __repr__(self): # invoked on `repr(Error)` info = self._infodict(("pid", "ppid", "name", "seconds", "msg")) - details = ", ".join(["%s=%r" % (k, v) for k, v in info.items()]) - return "psutil.%s(%s)" % (self.__class__.__name__, details) + details = ", ".join([f"{k}={v!r}" for k, v in info.items()]) + return f"psutil.{self.__class__.__name__}({details})" class NoSuchProcess(Error): @@ -380,7 +354,7 @@ class TimeoutExpired(Error): self.seconds = seconds self.pid = pid self.name = name - self.msg = "timeout after %s seconds" % seconds + self.msg = f"timeout after {seconds} seconds" def __reduce__(self): return (self.__class__, (self.seconds, self.pid, self.name)) @@ -391,26 +365,6 @@ class TimeoutExpired(Error): # =================================================================== -# This should be in _compat.py rather than here, but does not work well -# with setup.py importing this module via a sys.path trick. -if PY3: - if isinstance(__builtins__, dict): # cpython - exec_ = __builtins__["exec"] - else: # pypy - exec_ = getattr(__builtins__, "exec") # noqa - - exec_("""def raise_from(value, from_value): - try: - raise value from from_value - finally: - value = None - """) -else: - - def raise_from(value, from_value): - raise value - - def usage_percent(used, total, round_=None): """Calculate percentage usage of 'used' against 'total'.""" try: @@ -456,7 +410,7 @@ def memoize(fun): try: ret = cache[key] = fun(*args, **kwargs) except Exception as err: # noqa: BLE001 - raise raise_from(err, None) + raise err from None return ret def cache_clear(): @@ -505,14 +459,14 @@ def memoize_when_activated(fun): try: return fun(self) except Exception as err: # noqa: BLE001 - raise raise_from(err, None) + raise err from None except KeyError: # case 3: we entered oneshot() ctx but there's no cache # for this entry yet try: ret = fun(self) except Exception as err: # noqa: BLE001 - raise raise_from(err, None) + raise err from None try: self._cache[fun] = ret except AttributeError: @@ -546,9 +500,9 @@ def isfile_strict(path): """ try: st = os.stat(path) - except OSError as err: - if err.errno in {errno.EPERM, errno.EACCES}: - raise + except PermissionError: + raise + except OSError: return False else: return stat.S_ISREG(st.st_mode) @@ -561,9 +515,9 @@ def path_exists_strict(path): """ try: os.stat(path) - except OSError as err: - if err.errno in {errno.EPERM, errno.EACCES}: - raise + except PermissionError: + raise + except OSError: return False else: return True @@ -575,11 +529,10 @@ def supports_ipv6(): if not socket.has_ipv6 or AF_INET6 is None: return False try: - sock = socket.socket(AF_INET6, socket.SOCK_STREAM) - with contextlib.closing(sock): + with socket.socket(AF_INET6, socket.SOCK_STREAM) as sock: sock.bind(("::1", 0)) return True - except socket.error: + except OSError: return False @@ -615,26 +568,20 @@ def sockfam_to_enum(num): """Convert a numeric socket family value to an IntEnum member. If it's not a known member, return the numeric value itself. """ - if enum is None: + try: + return socket.AddressFamily(num) + except ValueError: return num - else: # pragma: no cover - try: - return socket.AddressFamily(num) - except ValueError: - return num def socktype_to_enum(num): """Convert a numeric socket type value to an IntEnum member. If it's not a known member, return the numeric value itself. """ - if enum is None: + try: + return socket.SocketKind(num) + except ValueError: return num - else: # pragma: no cover - try: - return socket.SocketKind(num) - except ValueError: - return num def conn_to_ntuple(fd, fam, type_, laddr, raddr, status, status_map, pid=None): @@ -656,15 +603,37 @@ def conn_to_ntuple(fd, fam, type_, laddr, raddr, status, status_map, pid=None): return sconn(fd, fam, type_, laddr, raddr, status, pid) +def broadcast_addr(addr): + """Given the address ntuple returned by ``net_if_addrs()`` + calculates the broadcast address. + """ + import ipaddress + + if not addr.address or not addr.netmask: + return None + if addr.family == socket.AF_INET: + return str( + ipaddress.IPv4Network( + f"{addr.address}/{addr.netmask}", strict=False + ).broadcast_address + ) + if addr.family == socket.AF_INET6: + return str( + ipaddress.IPv6Network( + f"{addr.address}/{addr.netmask}", strict=False + ).broadcast_address + ) + + def deprecated_method(replacement): """A decorator which can be used to mark a method as deprecated 'replcement' is the method name which will be called instead. """ def outer(fun): - msg = "%s() is deprecated and will be removed; use %s() instead" % ( - fun.__name__, - replacement, + msg = ( + f"{fun.__name__}() is deprecated and will be removed; use" + f" {replacement}() instead" ) if fun.__doc__ is None: fun.__doc__ = msg @@ -789,8 +758,6 @@ wrap_numbers.cache_info = _wn.cache_info # is 8K. We use a bigger buffer (32K) in order to have more consistent # results when reading /proc pseudo files on Linux, see: # https://github.com/giampaolo/psutil/issues/2050 -# On Python 2 this also speeds up the reading of big files: -# (namely /proc/{pid}/smaps and /proc/net/*): # https://github.com/giampaolo/psutil/issues/708 FILE_READ_BUFFER_SIZE = 32 * 1024 @@ -800,17 +767,13 @@ def open_binary(fname): def open_text(fname): - """On Python 3 opens a file in text mode by using fs encoding and - a proper en/decoding errors handler. - On Python 2 this is just an alias for open(name, 'rt'). + """Open a file in text mode by using the proper FS encoding and + en/decoding error handlers. """ - if not PY3: - return open(fname, buffering=FILE_READ_BUFFER_SIZE) - # See: # https://github.com/giampaolo/psutil/issues/675 # https://github.com/giampaolo/psutil/pull/733 - fobj = open( + fobj = open( # noqa: SIM115 fname, buffering=FILE_READ_BUFFER_SIZE, encoding=ENCODING, @@ -842,7 +805,7 @@ def cat(fname, fallback=_DEFAULT, _open=open_text): try: with _open(fname) as f: return f.read() - except (IOError, OSError): + except OSError: return fallback @@ -852,7 +815,7 @@ def bcat(fname, fallback=_DEFAULT): def bytes2human(n, format="%(value).1f%(symbol)s"): - """Used by various scripts. See: http://goo.gl/zeJZl. + """Used by various scripts. See: https://code.activestate.com/recipes/578019-bytes-to-human-human-to-bytes-converter/?in=user-4178764. >>> bytes2human(10000) '9.8K' @@ -875,15 +838,8 @@ def get_procfs_path(): return sys.modules['psutil'].PROCFS_PATH -if PY3: - - def decode(s): - return s.decode(encoding=ENCODING, errors=ENCODING_ERRS) - -else: - - def decode(s): - return s +def decode(s): + return s.decode(encoding=ENCODING, errors=ENCODING_ERRS) # ===================================================================== @@ -927,13 +883,12 @@ def hilite(s, color=None, bold=False): # pragma: no cover try: color = colors[color] except KeyError: - raise ValueError( - "invalid color %r; choose between %s" % (list(colors.keys())) - ) + msg = f"invalid color {color!r}; choose amongst {list(colors.keys())}" + raise ValueError(msg) from None attr.append(color) if bold: attr.append('1') - return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), s) + return f"\x1b[{';'.join(attr)}m{s}\x1b[0m" def print_color( @@ -941,9 +896,9 @@ def print_color( ): # pragma: no cover """Print a colorized version of string.""" if not term_supports_colors(): - print(s, file=file) # NOQA + print(s, file=file) elif POSIX: - print(hilite(s, color, bold), file=file) # NOQA + print(hilite(s, color, bold), file=file) else: import ctypes @@ -958,10 +913,11 @@ def print_color( try: color = colors[color] except KeyError: - raise ValueError( - "invalid color %r; choose between %r" - % (color, list(colors.keys())) + msg = ( + f"invalid color {color!r}; choose between" + f" {list(colors.keys())!r}" ) + raise ValueError(msg) from None if bold and color <= 7: color += 8 @@ -970,7 +926,7 @@ def print_color( handle = GetStdHandle(handle_id) SetConsoleTextAttribute(handle, color) try: - print(s, file=file) # NOQA + print(s, file=file) finally: SetConsoleTextAttribute(handle, DEFAULT_COLOR) @@ -984,11 +940,11 @@ def debug(msg): inspect.currentframe().f_back ) if isinstance(msg, Exception): - if isinstance(msg, (OSError, IOError, EnvironmentError)): + if isinstance(msg, OSError): # ...because str(exc) may contain info about the file name - msg = "ignoring %s" % msg + msg = f"ignoring {msg}" else: - msg = "ignoring %r" % msg - print( # noqa - "psutil-debug [%s:%s]> %s" % (fname, lineno, msg), file=sys.stderr + msg = f"ignoring {msg!r}" + print( # noqa: T201 + f"psutil-debug [{fname}:{lineno}]> {msg}", file=sys.stderr ) diff --git a/contrib/python/psutil/py3/psutil/_compat.py b/contrib/python/psutil/py3/psutil/_compat.py deleted file mode 100644 index 92e01713c3f..00000000000 --- a/contrib/python/psutil/py3/psutil/_compat.py +++ /dev/null @@ -1,477 +0,0 @@ -# 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. - -"""Module which provides compatibility with older Python versions. -This is more future-compatible rather than the opposite (prefer latest -Python 3 way of doing things). -""" - -import collections -import contextlib -import errno -import functools -import os -import sys -import types - - -# fmt: off -__all__ = [ - # constants - "PY3", - # builtins - "long", "range", "super", "unicode", "basestring", - # literals - "b", - # collections module - "lru_cache", - # shutil module - "which", "get_terminal_size", - # contextlib module - "redirect_stderr", - # python 3 exceptions - "FileNotFoundError", "PermissionError", "ProcessLookupError", - "InterruptedError", "ChildProcessError", "FileExistsError", -] -# fmt: on - - -PY3 = sys.version_info[0] >= 3 -_SENTINEL = object() - -if PY3: - long = int - xrange = range - unicode = str - basestring = str - range = range - - def b(s): - return s.encode("latin-1") - -else: - long = long - range = xrange - unicode = unicode - basestring = basestring - - def b(s): - return s - - -# --- builtins - - -# Python 3 super(). -# Taken from "future" package. -# Credit: Ryan Kelly -if PY3: - super = super -else: - _builtin_super = super - - def super(type_=_SENTINEL, type_or_obj=_SENTINEL, framedepth=1): - """Like Python 3 builtin super(). If called without any arguments - it attempts to infer them at runtime. - """ - if type_ is _SENTINEL: - f = sys._getframe(framedepth) - try: - # Get the function's first positional argument. - type_or_obj = f.f_locals[f.f_code.co_varnames[0]] - except (IndexError, KeyError): - msg = 'super() used in a function with no args' - raise RuntimeError(msg) - try: - # Get the MRO so we can crawl it. - mro = type_or_obj.__mro__ - except (AttributeError, RuntimeError): - try: - mro = type_or_obj.__class__.__mro__ - except AttributeError: - msg = 'super() used in a non-newstyle class' - raise RuntimeError(msg) - for type_ in mro: - # Find the class that owns the currently-executing method. - for meth in type_.__dict__.values(): - # Drill down through any wrappers to the underlying func. - # This handles e.g. classmethod() and staticmethod(). - try: - while not isinstance(meth, types.FunctionType): - if isinstance(meth, property): - # Calling __get__ on the property will invoke - # user code which might throw exceptions or - # have side effects - meth = meth.fget - else: - try: - meth = meth.__func__ - except AttributeError: - meth = meth.__get__(type_or_obj, type_) - except (AttributeError, TypeError): - continue - if meth.func_code is f.f_code: - break # found - else: - # Not found. Move onto the next class in MRO. - continue - break # found - else: - msg = 'super() called outside a method' - raise RuntimeError(msg) - - # Dispatch to builtin super(). - if type_or_obj is not _SENTINEL: - return _builtin_super(type_, type_or_obj) - return _builtin_super(type_) - - -# --- exceptions - - -if PY3: - FileNotFoundError = FileNotFoundError # NOQA - PermissionError = PermissionError # NOQA - ProcessLookupError = ProcessLookupError # NOQA - InterruptedError = InterruptedError # NOQA - ChildProcessError = ChildProcessError # NOQA - FileExistsError = FileExistsError # NOQA -else: - # https://github.com/PythonCharmers/python-future/blob/exceptions/ - # src/future/types/exceptions/pep3151.py - import platform - - def _instance_checking_exception(base_exception=Exception): - def wrapped(instance_checker): - class TemporaryClass(base_exception): - def __init__(self, *args, **kwargs): - if len(args) == 1 and isinstance(args[0], TemporaryClass): - unwrap_me = args[0] - for attr in dir(unwrap_me): - if not attr.startswith('__'): - setattr(self, attr, getattr(unwrap_me, attr)) - else: - super(TemporaryClass, self).__init__( # noqa - *args, **kwargs - ) - - class __metaclass__(type): - def __instancecheck__(cls, inst): - return instance_checker(inst) - - def __subclasscheck__(cls, classinfo): - value = sys.exc_info()[1] - return isinstance(value, cls) - - TemporaryClass.__name__ = instance_checker.__name__ - TemporaryClass.__doc__ = instance_checker.__doc__ - return TemporaryClass - - return wrapped - - @_instance_checking_exception(EnvironmentError) - def FileNotFoundError(inst): - return getattr(inst, 'errno', _SENTINEL) == errno.ENOENT - - @_instance_checking_exception(EnvironmentError) - def ProcessLookupError(inst): - return getattr(inst, 'errno', _SENTINEL) == errno.ESRCH - - @_instance_checking_exception(EnvironmentError) - def PermissionError(inst): - return getattr(inst, 'errno', _SENTINEL) in {errno.EACCES, errno.EPERM} - - @_instance_checking_exception(EnvironmentError) - def InterruptedError(inst): - return getattr(inst, 'errno', _SENTINEL) == errno.EINTR - - @_instance_checking_exception(EnvironmentError) - def ChildProcessError(inst): - return getattr(inst, 'errno', _SENTINEL) == errno.ECHILD - - @_instance_checking_exception(EnvironmentError) - def FileExistsError(inst): - return getattr(inst, 'errno', _SENTINEL) == errno.EEXIST - - if platform.python_implementation() != "CPython": - try: - raise OSError(errno.EEXIST, "perm") - except FileExistsError: - pass - except OSError: - msg = ( - "broken or incompatible Python implementation, see: " - "https://github.com/giampaolo/psutil/issues/1659" - ) - raise RuntimeError(msg) - - -# --- stdlib additions - - -# py 3.2 functools.lru_cache -# Taken from: http://code.activestate.com/recipes/578078 -# Credit: Raymond Hettinger -try: - from functools import lru_cache -except ImportError: - try: - from threading import RLock - except ImportError: - from dummy_threading import RLock - - _CacheInfo = collections.namedtuple( - "CacheInfo", ["hits", "misses", "maxsize", "currsize"] - ) - - class _HashedSeq(list): # noqa: FURB189 - __slots__ = ('hashvalue',) - - def __init__(self, tup, hash=hash): - self[:] = tup - self.hashvalue = hash(tup) - - def __hash__(self): - return self.hashvalue - - def _make_key( - args, - kwds, - typed, - kwd_mark=(_SENTINEL,), - fasttypes=set((int, str, frozenset, type(None))), # noqa - sorted=sorted, - tuple=tuple, - type=type, - len=len, - ): - key = args - if kwds: - sorted_items = sorted(kwds.items()) - key += kwd_mark - for item in sorted_items: - key += item - if typed: - key += tuple(type(v) for v in args) - if kwds: - key += tuple(type(v) for k, v in sorted_items) - elif len(key) == 1 and type(key[0]) in fasttypes: - return key[0] - return _HashedSeq(key) - - def lru_cache(maxsize=100, typed=False): - """Least-recently-used cache decorator, see: - http://docs.python.org/3/library/functools.html#functools.lru_cache. - """ - - def decorating_function(user_function): - cache = {} - stats = [0, 0] - HITS, MISSES = 0, 1 - make_key = _make_key - cache_get = cache.get - _len = len - lock = RLock() - root = [] - root[:] = [root, root, None, None] - nonlocal_root = [root] - PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 - if maxsize == 0: - - def wrapper(*args, **kwds): - result = user_function(*args, **kwds) - stats[MISSES] += 1 - return result - - elif maxsize is None: - - def wrapper(*args, **kwds): - key = make_key(args, kwds, typed) - result = cache_get(key, root) - if result is not root: - stats[HITS] += 1 - return result - result = user_function(*args, **kwds) - cache[key] = result - stats[MISSES] += 1 - return result - - else: - - def wrapper(*args, **kwds): - if kwds or typed: - key = make_key(args, kwds, typed) - else: - key = args - lock.acquire() - try: - link = cache_get(key) - if link is not None: - (root,) = nonlocal_root - link_prev, link_next, key, result = link - link_prev[NEXT] = link_next - link_next[PREV] = link_prev - last = root[PREV] - last[NEXT] = root[PREV] = link - link[PREV] = last - link[NEXT] = root - stats[HITS] += 1 - return result - finally: - lock.release() - result = user_function(*args, **kwds) - lock.acquire() - try: - (root,) = nonlocal_root - if key in cache: - pass - elif _len(cache) >= maxsize: - oldroot = root - oldroot[KEY] = key - oldroot[RESULT] = result - root = nonlocal_root[0] = oldroot[NEXT] - oldkey = root[KEY] - root[KEY] = root[RESULT] = None - del cache[oldkey] - cache[key] = oldroot - else: - last = root[PREV] - link = [last, root, key, result] - last[NEXT] = root[PREV] = cache[key] = link - stats[MISSES] += 1 - finally: - lock.release() - return result - - def cache_info(): - """Report cache statistics.""" - lock.acquire() - try: - return _CacheInfo( - stats[HITS], stats[MISSES], maxsize, len(cache) - ) - finally: - lock.release() - - def cache_clear(): - """Clear the cache and cache statistics.""" - lock.acquire() - try: - cache.clear() - root = nonlocal_root[0] - root[:] = [root, root, None, None] - stats[:] = [0, 0] - finally: - lock.release() - - wrapper.__wrapped__ = user_function - wrapper.cache_info = cache_info - wrapper.cache_clear = cache_clear - return functools.update_wrapper(wrapper, user_function) - - return decorating_function - - -# python 3.3 -try: - from shutil import which -except ImportError: - - def which(cmd, mode=os.F_OK | os.X_OK, path=None): - """Given a command, mode, and a PATH string, return the path which - conforms to the given mode on the PATH, or None if there is no such - file. - - `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result - of os.environ.get("PATH"), or can be overridden with a custom search - path. - """ - - def _access_check(fn, mode): - return ( - os.path.exists(fn) - and os.access(fn, mode) - and not os.path.isdir(fn) - ) - - if os.path.dirname(cmd): - if _access_check(cmd, mode): - return cmd - return None - - if path is None: - path = os.environ.get("PATH", os.defpath) - if not path: - return None - path = path.split(os.pathsep) - - if sys.platform == "win32": - if os.curdir not in path: - path.insert(0, os.curdir) - - pathext = os.environ.get("PATHEXT", "").split(os.pathsep) - if any(cmd.lower().endswith(ext.lower()) for ext in pathext): - files = [cmd] - else: - files = [cmd + ext for ext in pathext] - else: - files = [cmd] - - seen = set() - for dir in path: - normdir = os.path.normcase(dir) - if normdir not in seen: - seen.add(normdir) - for thefile in files: - name = os.path.join(dir, thefile) - if _access_check(name, mode): - return name - return None - - -# python 3.3 -try: - from shutil import get_terminal_size -except ImportError: - - def get_terminal_size(fallback=(80, 24)): - try: - import fcntl - import struct - import termios - except ImportError: - return fallback - else: - try: - # This should work on Linux. - res = struct.unpack( - 'hh', fcntl.ioctl(1, termios.TIOCGWINSZ, '1234') - ) - return (res[1], res[0]) - except Exception: # noqa: BLE001 - return fallback - - -# python 3.3 -try: - from subprocess import TimeoutExpired as SubprocessTimeoutExpired -except ImportError: - - class SubprocessTimeoutExpired(Exception): - pass - - -# python 3.5 -try: - from contextlib import redirect_stderr -except ImportError: - - @contextlib.contextmanager - def redirect_stderr(new_target): - original = sys.stderr - try: - sys.stderr = new_target - yield new_target - finally: - sys.stderr = original diff --git a/contrib/python/psutil/py3/psutil/_psaix.py b/contrib/python/psutil/py3/psutil/_psaix.py index 2ccc638bcea..ba2725fdc10 100644 --- a/contrib/python/psutil/py3/psutil/_psaix.py +++ b/contrib/python/psutil/py3/psutil/_psaix.py @@ -28,10 +28,6 @@ from ._common import conn_to_ntuple from ._common import get_procfs_path from ._common import memoize_when_activated from ._common import usage_percent -from ._compat import PY3 -from ._compat import FileNotFoundError -from ._compat import PermissionError -from ._compat import ProcessLookupError __extra__all__ = ["PROCFS_PATH"] @@ -148,12 +144,10 @@ def cpu_count_cores(): cmd = ["lsdev", "-Cc", "processor"] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() - if PY3: - stdout, stderr = ( - x.decode(sys.stdout.encoding) for x in (stdout, stderr) - ) + stdout, stderr = (x.decode(sys.stdout.encoding) for x in (stdout, stderr)) if p.returncode != 0: - raise RuntimeError("%r command error\n%s" % (cmd, stderr)) + msg = f"{cmd!r} command error\n{stderr}" + raise RuntimeError(msg) processors = stdout.strip().splitlines() return len(processors) or None @@ -211,12 +205,6 @@ def net_connections(kind, _pid=-1): """Return socket connections. If pid == -1 return system-wide connections (as opposed to connections opened by one process only). """ - cmap = _common.conn_tmap - if kind not in cmap: - raise ValueError( - "invalid %r kind argument; choose between %s" - % (kind, ', '.join([repr(x) for x in cmap])) - ) families, types = _common.conn_tmap[kind] rawlist = cext.net_connections(_pid) ret = [] @@ -243,7 +231,7 @@ def net_connections(kind, _pid=-1): def net_if_stats(): """Get NIC stats (isup, duplex, speed, mtu).""" duplex_map = {"Full": NIC_DUPLEX_FULL, "Half": NIC_DUPLEX_HALF} - names = set([x[0] for x in net_if_addrs()]) + names = {x[0] for x in net_if_addrs()} ret = {} for name in names: mtu = cext_posix.net_if_mtu(name) @@ -260,10 +248,9 @@ def net_if_stats(): stderr=subprocess.PIPE, ) stdout, stderr = p.communicate() - if PY3: - stdout, stderr = ( - x.decode(sys.stdout.encoding) for x in (stdout, stderr) - ) + stdout, stderr = ( + x.decode(sys.stdout.encoding) for x in (stdout, stderr) + ) if p.returncode == 0: re_result = re.search( r"Running: (\d+) Mbps.*?(\w+) Duplex", stdout @@ -330,18 +317,18 @@ def wrap_exceptions(fun): @functools.wraps(fun) def wrapper(self, *args, **kwargs): + pid, ppid, name = self.pid, self._ppid, self._name try: return fun(self, *args, **kwargs) - except (FileNotFoundError, ProcessLookupError): + except (FileNotFoundError, ProcessLookupError) as err: # ENOENT (no such file or directory) gets raised on open(). # ESRCH (no such process) can get raised on read() if # process is gone in meantime. - if not pid_exists(self.pid): - raise NoSuchProcess(self.pid, self._name) - else: - raise ZombieProcess(self.pid, self._name, self._ppid) - except PermissionError: - raise AccessDenied(self.pid, self._name) + if not pid_exists(pid): + raise NoSuchProcess(pid, name) from err + raise ZombieProcess(pid, name, ppid) from err + except PermissionError as err: + raise AccessDenied(pid, name) from err return wrapper @@ -444,7 +431,7 @@ class Process: # is no longer there. if not retlist: # will raise NSP if process is gone - os.stat('%s/%s' % (self._procfs_path, self.pid)) + os.stat(f"{self._procfs_path}/{self.pid}") return retlist @wrap_exceptions @@ -457,7 +444,7 @@ class Process: # is no longer there. if not ret: # will raise NSP if process is gone - os.stat('%s/%s' % (self._procfs_path, self.pid)) + os.stat(f"{self._procfs_path}/{self.pid}") return ret @wrap_exceptions @@ -503,10 +490,10 @@ class Process: def cwd(self): procfs_path = self._procfs_path try: - result = os.readlink("%s/%s/cwd" % (procfs_path, self.pid)) + result = os.readlink(f"{procfs_path}/{self.pid}/cwd") return result.rstrip('/') except FileNotFoundError: - os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD + os.stat(f"{procfs_path}/{self.pid}") # raise NSP or AD return "" @wrap_exceptions @@ -533,10 +520,9 @@ class Process: stderr=subprocess.PIPE, ) stdout, stderr = p.communicate() - if PY3: - stdout, stderr = ( - x.decode(sys.stdout.encoding) for x in (stdout, stderr) - ) + stdout, stderr = ( + x.decode(sys.stdout.encoding) for x in (stdout, stderr) + ) if "no such process" in stderr.lower(): raise NoSuchProcess(self.pid, self._name) procfiles = re.findall(r"(\d+): S_IFREG.*name:(.*)\n", stdout) @@ -554,7 +540,7 @@ class Process: def num_fds(self): if self.pid == 0: # no /proc/0/fd return 0 - return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid))) + return len(os.listdir(f"{self._procfs_path}/{self.pid}/fd")) @wrap_exceptions def num_ctx_switches(self): @@ -570,10 +556,10 @@ class Process: def io_counters(self): try: rc, wc, rb, wb = cext.proc_io_counters(self.pid) - except OSError: + except OSError as err: # if process is terminated, proc_io_counters returns OSError # instead of NSP if not pid_exists(self.pid): - raise NoSuchProcess(self.pid, self._name) + raise NoSuchProcess(self.pid, self._name) from err raise return _common.pio(rc, wc, rb, wb) diff --git a/contrib/python/psutil/py3/psutil/_psbsd.py b/contrib/python/psutil/py3/psutil/_psbsd.py index 77b99c0fd8b..13bd926fabf 100644 --- a/contrib/python/psutil/py3/psutil/_psbsd.py +++ b/contrib/python/psutil/py3/psutil/_psbsd.py @@ -10,7 +10,7 @@ import functools import os from collections import defaultdict from collections import namedtuple -from xml.etree import ElementTree # noqa ICN001 +from xml.etree import ElementTree # noqa: ICN001 from . import _common from . import _psposix @@ -28,10 +28,6 @@ from ._common import debug from ._common import memoize from ._common import memoize_when_activated from ._common import usage_percent -from ._compat import FileNotFoundError -from ._compat import PermissionError -from ._compat import ProcessLookupError -from ._compat import which __extra__all__ = [] @@ -196,8 +192,8 @@ def virtual_memory(): # #2233), so zabbix seems to be wrong. Htop calculates it # differently, and the used value seem more realistic, so let's # match htop. - # https://github.com/htop-dev/htop/blob/e7f447b/netbsd/NetBSDProcessList.c#L162 # noqa - # https://github.com/zabbix/zabbix/blob/af5e0f8/src/libs/zbxsysinfo/netbsd/memory.c#L135 # noqa + # https://github.com/htop-dev/htop/blob/e7f447b/netbsd/NetBSDProcessList.c#L162 + # https://github.com/zabbix/zabbix/blob/af5e0f8/src/libs/zbxsysinfo/netbsd/memory.c#L135 used = active + wired avail = total - used else: @@ -206,7 +202,7 @@ def virtual_memory(): # * https://people.freebsd.org/~rse/dist/freebsd-memory # * https://www.cyberciti.biz/files/scripts/freebsd-memory.pl.txt # matches zabbix: - # * https://github.com/zabbix/zabbix/blob/af5e0f8/src/libs/zbxsysinfo/freebsd/memory.c#L143 # noqa + # * https://github.com/zabbix/zabbix/blob/af5e0f8/src/libs/zbxsysinfo/freebsd/memory.c#L143 avail = inactive + cached + free used = active + wired + cached @@ -439,14 +435,8 @@ def net_if_stats(): def net_connections(kind): """System-wide network connections.""" - if kind not in _common.conn_tmap: - raise ValueError( - "invalid %r kind argument; choose between %s" - % (kind, ', '.join([repr(x) for x in conn_tmap])) - ) families, types = conn_tmap[kind] ret = set() - if OPENBSD: rawlist = cext.net_connections(-1, families, types) elif NETBSD: @@ -495,7 +485,7 @@ if FREEBSD: current, high = cext.sensors_cpu_temperature(cpu) if high <= 0: high = None - name = "Core %s" % cpu + name = f"Core {cpu}" ret["coretemp"].append( _common.shwtemp(name, current, high, high) ) @@ -600,21 +590,18 @@ def wrap_exceptions(fun): @functools.wraps(fun) def wrapper(self, *args, **kwargs): + pid, ppid, name = self.pid, self._ppid, self._name try: return fun(self, *args, **kwargs) - except ProcessLookupError: - if is_zombie(self.pid): - raise ZombieProcess(self.pid, self._name, self._ppid) - else: - raise NoSuchProcess(self.pid, self._name) - except PermissionError: - raise AccessDenied(self.pid, self._name) - except OSError: - if self.pid == 0: - if 0 in pids(): - raise AccessDenied(self.pid, self._name) - else: - raise + except ProcessLookupError as err: + if is_zombie(pid): + raise ZombieProcess(pid, name, ppid) from err + raise NoSuchProcess(pid, name) from err + except PermissionError as err: + raise AccessDenied(pid, name) from err + except OSError as err: + if pid == 0 and 0 in pids(): + raise AccessDenied(pid, name) from err raise return wrapper @@ -623,18 +610,19 @@ def wrap_exceptions(fun): @contextlib.contextmanager def wrap_exceptions_procfs(inst): """Same as above, for routines relying on reading /proc fs.""" + pid, name, ppid = inst.pid, inst._name, inst._ppid try: yield - except (ProcessLookupError, FileNotFoundError): + except (ProcessLookupError, FileNotFoundError) as err: # ENOENT (no such file or directory) gets raised on open(). # ESRCH (no such process) can get raised on read() if # process is gone in meantime. if is_zombie(inst.pid): - raise ZombieProcess(inst.pid, inst._name, inst._ppid) + raise ZombieProcess(pid, name, ppid) from err else: - raise NoSuchProcess(inst.pid, inst._name) - except PermissionError: - raise AccessDenied(inst.pid, inst._name) + raise NoSuchProcess(pid, name) from err + except PermissionError as err: + raise AccessDenied(pid, name) from err class Process: @@ -683,16 +671,18 @@ class Process: # /proc/0 dir exists but /proc/0/exe doesn't return "" with wrap_exceptions_procfs(self): - return os.readlink("/proc/%s/exe" % self.pid) + return os.readlink(f"/proc/{self.pid}/exe") else: # OpenBSD: exe cannot be determined; references: # https://chromium.googlesource.com/chromium/src/base/+/ # master/base_paths_posix.cc # We try our best guess by using which against the first # cmdline arg (may return None). + import shutil + cmdline = self.cmdline() if cmdline: - return which(cmdline[0]) or "" + return shutil.which(cmdline[0]) or "" else: return "" @@ -709,15 +699,15 @@ class Process: return cext.proc_cmdline(self.pid) except OSError as err: if err.errno == errno.EINVAL: + pid, name, ppid = self.pid, self._name, self._ppid if is_zombie(self.pid): - raise ZombieProcess(self.pid, self._name, self._ppid) - elif not pid_exists(self.pid): - raise NoSuchProcess(self.pid, self._name, self._ppid) - else: - # XXX: this happens with unicode tests. It means the C - # routine is unable to decode invalid unicode chars. - debug("ignoring %r and returning an empty list" % err) - return [] + raise ZombieProcess(pid, name, ppid) from err + if not pid_exists(self.pid): + raise NoSuchProcess(pid, name, ppid) from err + # XXX: this happens with unicode tests. It means the C + # routine is unable to decode invalid unicode chars. + debug(f"ignoring {err!r} and returning an empty list") + return [] else: raise else: @@ -822,11 +812,6 @@ class Process: @wrap_exceptions def net_connections(self, kind='inet'): - if kind not in conn_tmap: - raise ValueError( - "invalid %r kind argument; choose between %s" - % (kind, ', '.join([repr(x) for x in conn_tmap])) - ) families, types = conn_tmap[kind] ret = [] @@ -945,12 +930,11 @@ class Process: # Pre-emptively check if CPUs are valid because the C # function has a weird behavior in case of invalid CPUs, # see: https://github.com/giampaolo/psutil/issues/586 - allcpus = tuple(range(len(per_cpu_times()))) + allcpus = set(range(len(per_cpu_times()))) for cpu in cpus: if cpu not in allcpus: - raise ValueError( - "invalid CPU #%i (choose between %s)" % (cpu, allcpus) - ) + msg = f"invalid CPU {cpu!r} (choose between {allcpus})" + raise ValueError(msg) try: cext.proc_cpu_affinity_set(self.pid, cpus) except OSError as err: @@ -961,10 +945,11 @@ class Process: if err.errno in {errno.EINVAL, errno.EDEADLK}: for cpu in cpus: if cpu not in allcpus: - raise ValueError( - "invalid CPU #%i (choose between %s)" - % (cpu, allcpus) + msg = ( + f"invalid CPU {cpu!r} (choose between" + f" {allcpus})" ) + raise ValueError(msg) from err raise @wrap_exceptions @@ -977,9 +962,10 @@ class Process: return cext.proc_getrlimit(self.pid, resource) else: if len(limits) != 2: - raise ValueError( - "second argument must be a (soft, hard) tuple, got %s" - % repr(limits) + msg = ( + "second argument must be a (soft, hard) tuple, got" + f" {limits!r}" ) + raise ValueError(msg) soft, hard = limits return cext.proc_setrlimit(self.pid, resource, soft, hard) diff --git a/contrib/python/psutil/py3/psutil/_pslinux.py b/contrib/python/psutil/py3/psutil/_pslinux.py index 3e7f3e402a7..8cc64e9a100 100644 --- a/contrib/python/psutil/py3/psutil/_pslinux.py +++ b/contrib/python/psutil/py3/psutil/_pslinux.py @@ -4,15 +4,16 @@ """Linux platform implementation.""" -from __future__ import division import base64 import collections +import enum import errno import functools import glob import os import re +import resource import socket import struct import sys @@ -24,6 +25,7 @@ from . import _common from . import _psposix from . import _psutil_linux as cext from . import _psutil_posix as cext_posix +from ._common import ENCODING from ._common import NIC_DUPLEX_FULL from ._common import NIC_DUPLEX_HALF from ._common import NIC_DUPLEX_UNKNOWN @@ -44,18 +46,6 @@ from ._common import parse_environ_block from ._common import path_exists_strict from ._common import supports_ipv6 from ._common import usage_percent -from ._compat import PY3 -from ._compat import FileNotFoundError -from ._compat import PermissionError -from ._compat import ProcessLookupError -from ._compat import b -from ._compat import basestring - - -if PY3: - import enum -else: - enum = None # fmt: off @@ -69,6 +59,11 @@ __extra__all__ = [ "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", ] + +if hasattr(resource, "prlimit"): + __extra__all__.extend( + [x for x in dir(cext) if x.startswith('RLIM') and x.isupper()] + ) # fmt: on @@ -78,8 +73,8 @@ __extra__all__ = [ POWER_SUPPLY_PATH = "/sys/class/power_supply" -HAS_PROC_SMAPS = os.path.exists('/proc/%s/smaps' % os.getpid()) -HAS_PROC_SMAPS_ROLLUP = os.path.exists('/proc/%s/smaps_rollup' % os.getpid()) +HAS_PROC_SMAPS = os.path.exists(f"/proc/{os.getpid()}/smaps") +HAS_PROC_SMAPS_ROLLUP = os.path.exists(f"/proc/{os.getpid()}/smaps_rollup") HAS_PROC_IO_PRIORITY = hasattr(cext, "proc_ioprio_get") HAS_CPU_AFFINITY = hasattr(cext, "proc_cpu_affinity_get") @@ -102,29 +97,21 @@ LITTLE_ENDIAN = sys.byteorder == 'little' # * https://lkml.org/lkml/2015/8/17/234 DISK_SECTOR_SIZE = 512 -if enum is None: - AF_LINK = socket.AF_PACKET -else: - AddressFamily = enum.IntEnum( - 'AddressFamily', {'AF_LINK': int(socket.AF_PACKET)} - ) - AF_LINK = AddressFamily.AF_LINK +AddressFamily = enum.IntEnum( + 'AddressFamily', {'AF_LINK': int(socket.AF_PACKET)} +) +AF_LINK = AddressFamily.AF_LINK + # ioprio_* constants http://linux.die.net/man/2/ioprio_get -if enum is None: +class IOPriority(enum.IntEnum): IOPRIO_CLASS_NONE = 0 IOPRIO_CLASS_RT = 1 IOPRIO_CLASS_BE = 2 IOPRIO_CLASS_IDLE = 3 -else: - class IOPriority(enum.IntEnum): - IOPRIO_CLASS_NONE = 0 - IOPRIO_CLASS_RT = 1 - IOPRIO_CLASS_BE = 2 - IOPRIO_CLASS_IDLE = 3 - globals().update(IOPriority.__members__) +globals().update(IOPriority.__members__) # See: # https://github.com/torvalds/linux/blame/master/fs/proc/array.c @@ -211,7 +198,7 @@ pcputimes = namedtuple('pcputimes', def readlink(path): """Wrapper around os.readlink().""" - assert isinstance(path, basestring), path + assert isinstance(path, str), path path = os.readlink(path) # readlink() might return paths containing null bytes ('\x00') # resulting in "TypeError: must be encoded string without NULL @@ -255,9 +242,9 @@ def is_storage_device(name): name = name.replace('/', '!') including_virtual = True if including_virtual: - path = "/sys/block/%s" % name + path = f"/sys/block/{name}" else: - path = "/sys/block/%s/device" % name + path = f"/sys/block/{name}/device" return os.access(path, os.F_OK) @@ -270,7 +257,7 @@ def set_scputimes_ntuple(procfs_path): Used by cpu_times() function. """ global scputimes - with open_binary('%s/stat' % procfs_path) as f: + with open_binary(f"{procfs_path}/stat") as f: values = f.readline().split()[1:] fields = ['user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq'] vlen = len(values) @@ -290,66 +277,11 @@ try: set_scputimes_ntuple("/proc") except Exception as err: # noqa: BLE001 # Don't want to crash at import time. - debug("ignoring exception on import: %r" % err) + debug(f"ignoring exception on import: {err!r}") scputimes = namedtuple('scputimes', 'user system idle')(0.0, 0.0, 0.0) # ===================================================================== -# --- prlimit -# ===================================================================== - -# Backport of resource.prlimit() for Python 2. Originally this was done -# in C, but CentOS-6 which we use to create manylinux wheels is too old -# and does not support prlimit() syscall. As such the resulting wheel -# would not include prlimit(), even when installed on newer systems. -# This is the only part of psutil using ctypes. - -prlimit = None -try: - from resource import prlimit # python >= 3.4 -except ImportError: - import ctypes - - try: - libc = ctypes.CDLL(None, use_errno=True) - except: - libc = None - - if hasattr(libc, "prlimit"): - - def prlimit(pid, resource_, limits=None): - class StructRlimit(ctypes.Structure): - _fields_ = [ - ('rlim_cur', ctypes.c_longlong), - ('rlim_max', ctypes.c_longlong), - ] - - current = StructRlimit() - if limits is None: - # get - ret = libc.prlimit(pid, resource_, None, ctypes.byref(current)) - else: - # set - new = StructRlimit() - new.rlim_cur = limits[0] - new.rlim_max = limits[1] - ret = libc.prlimit( - pid, resource_, ctypes.byref(new), ctypes.byref(current) - ) - - if ret != 0: - errno_ = ctypes.get_errno() - raise OSError(errno_, os.strerror(errno_)) - return (current.rlim_cur, current.rlim_max) - - -if prlimit is not None: - __extra__all__.extend( - [x for x in dir(cext) if x.startswith('RLIM') and x.isupper()] - ) - - -# ===================================================================== # --- system memory # ===================================================================== @@ -392,14 +324,13 @@ def calculate_avail_vmem(mems): slab_reclaimable = mems[b'SReclaimable:'] except KeyError as err: debug( - "%s is missing from /proc/meminfo; using an approximation for " - "calculating available memory" - % err.args[0] + f"{err.args[0]} is missing from /proc/meminfo; using an" + " approximation for calculating available memory" ) return fallback try: - f = open_binary('%s/zoneinfo' % get_procfs_path()) - except IOError: + f = open_binary(f"{get_procfs_path()}/zoneinfo") + except OSError: return fallback # kernel 2.6.13 watermark_low = 0 @@ -428,7 +359,7 @@ def virtual_memory(): """ missing_fields = [] mems = {} - with open_binary('%s/meminfo' % get_procfs_path()) as f: + with open_binary(f"{get_procfs_path()}/meminfo") as f: for line in f: fields = line.split() mems[fields[0]] = int(fields[1]) * 1024 @@ -530,7 +461,7 @@ def virtual_memory(): # Warn about missing metrics which are set to 0. if missing_fields: - msg = "%s memory stats couldn't be determined and %s set to 0" % ( + msg = "{} memory stats couldn't be determined and {} set to 0".format( ", ".join(missing_fields), "was" if len(missing_fields) == 1 else "were", ) @@ -554,7 +485,7 @@ def virtual_memory(): def swap_memory(): """Return swap memory metrics.""" mems = {} - with open_binary('%s/meminfo' % get_procfs_path()) as f: + with open_binary(f"{get_procfs_path()}/meminfo") as f: for line in f: fields = line.split() mems[fields[0]] = int(fields[1]) * 1024 @@ -574,12 +505,12 @@ def swap_memory(): percent = usage_percent(used, total, round_=1) # get pgin/pgouts try: - f = open_binary("%s/vmstat" % get_procfs_path()) - except IOError as err: + f = open_binary(f"{get_procfs_path()}/vmstat") + except OSError as err: # see https://github.com/giampaolo/psutil/issues/722 msg = ( "'sin' and 'sout' swap memory stats couldn't " - + "be determined and were set to 0 (%s)" % str(err) + f"be determined and were set to 0 ({err})" ) warnings.warn(msg, RuntimeWarning, stacklevel=2) sin = sout = 0 @@ -620,7 +551,7 @@ def cpu_times(): """ procfs_path = get_procfs_path() set_scputimes_ntuple(procfs_path) - with open_binary('%s/stat' % procfs_path) as f: + with open_binary(f"{procfs_path}/stat") as f: values = f.readline().split() fields = values[1 : len(scputimes._fields) + 1] fields = [float(x) / CLOCK_TICKS for x in fields] @@ -634,7 +565,7 @@ def per_cpu_times(): procfs_path = get_procfs_path() set_scputimes_ntuple(procfs_path) cpus = [] - with open_binary('%s/stat' % procfs_path) as f: + with open_binary(f"{procfs_path}/stat") as f: # get rid of the first line which refers to system wide CPU stats f.readline() for line in f: @@ -654,7 +585,7 @@ def cpu_count_logical(): except ValueError: # as a second fallback we try to parse /proc/cpuinfo num = 0 - with open_binary('%s/cpuinfo' % get_procfs_path()) as f: + with open_binary(f"{get_procfs_path()}/cpuinfo") as f: for line in f: if line.lower().startswith(b'processor'): num += 1 @@ -664,7 +595,7 @@ def cpu_count_logical(): # try to parse /proc/stat as a last resort if num == 0: search = re.compile(r'cpu\d') - with open_text('%s/stat' % get_procfs_path()) as f: + with open_text(f"{get_procfs_path()}/stat") as f: for line in f: line = line.split(' ')[0] if search.match(line): @@ -697,7 +628,7 @@ def cpu_count_cores(): # Method #2 mapping = {} current_info = {} - with open_binary('%s/cpuinfo' % get_procfs_path()) as f: + with open_binary(f"{get_procfs_path()}/cpuinfo") as f: for line in f: line = line.strip().lower() if not line: @@ -720,7 +651,7 @@ def cpu_count_cores(): def cpu_stats(): """Return various CPU stats as a named tuple.""" - with open_binary('%s/stat' % get_procfs_path()) as f: + with open_binary(f"{get_procfs_path()}/stat") as f: ctx_switches = None interrupts = None soft_interrupts = None @@ -745,12 +676,12 @@ def cpu_stats(): def _cpu_get_cpuinfo_freq(): """Return current CPU frequency from cpuinfo if available.""" - ret = [] - with open_binary('%s/cpuinfo' % get_procfs_path()) as f: - for line in f: - if line.lower().startswith(b'cpu mhz'): - ret.append(float(line.split(b':', 1)[1])) - return ret + with open_binary(f"{get_procfs_path()}/cpuinfo") as f: + return [ + float(line.split(b':', 1)[1]) + for line in f + if line.lower().startswith(b'cpu mhz') + ] if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or os.path.exists( @@ -781,9 +712,7 @@ if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or os.path.exists( # https://github.com/giampaolo/psutil/issues/1071 curr = bcat(pjoin(path, "cpuinfo_cur_freq"), fallback=None) if curr is None: - online_path = ( - "/sys/devices/system/cpu/cpu{}/online".format(i) - ) + online_path = f"/sys/devices/system/cpu/cpu{i}/online" # if cpu core is offline, set to all zeroes if cat(online_path, fallback=None) == "0\n": ret.append(_common.scpufreq(0.0, 0.0, 0.0)) @@ -854,12 +783,12 @@ class NetConnections: def get_proc_inodes(self, pid): inodes = defaultdict(list) - for fd in os.listdir("%s/%s/fd" % (self._procfs_path, pid)): + for fd in os.listdir(f"{self._procfs_path}/{pid}/fd"): try: - inode = readlink("%s/%s/fd/%s" % (self._procfs_path, pid, fd)) + inode = readlink(f"{self._procfs_path}/{pid}/fd/{fd}") except (FileNotFoundError, ProcessLookupError): # ENOENT == file which is gone in the meantime; - # os.stat('/proc/%s' % self.pid) will be done later + # os.stat(f"/proc/{self.pid}") will be done later # to force NSP (if it's the case) continue except OSError as err: @@ -917,8 +846,7 @@ class NetConnections: # no end-points connected if not port: return () - if PY3: - ip = ip.encode('ascii') + ip = ip.encode('ascii') if family == socket.AF_INET: # see: https://github.com/giampaolo/psutil/issues/201 if LITTLE_ENDIAN: @@ -942,9 +870,8 @@ class NetConnections: except ValueError: # see: https://github.com/giampaolo/psutil/issues/623 if not supports_ipv6(): - raise _Ipv6UnsupportedError - else: - raise + raise _Ipv6UnsupportedError from None + raise return _common.addr(ip, port) @staticmethod @@ -961,10 +888,11 @@ class NetConnections: line.split()[:10] ) except ValueError: - raise RuntimeError( - "error while parsing %s; malformed line %s %r" - % (file, lineno, line) + msg = ( + f"error while parsing {file}; malformed line" + f" {lineno} {line!r}" ) + raise RuntimeError(msg) from None if inode in inodes: # # We assume inet sockets are unique, so we error # # out if there are multiple references to the @@ -1002,11 +930,11 @@ class NetConnections: if ' ' not in line: # see: https://github.com/giampaolo/psutil/issues/766 continue - raise RuntimeError( - "error while parsing %s; malformed line %r" - % (file, line) + msg = ( + f"error while parsing {file}; malformed line {line!r}" ) - if inode in inodes: # noqa + raise RuntimeError(msg) # noqa: B904 + if inode in inodes: # noqa: SIM108 # With UNIX sockets we can have a single inode # referencing many file descriptors. pairs = inodes[inode] @@ -1026,11 +954,6 @@ class NetConnections: yield (fd, family, type_, path, raddr, status, pid) def retrieve(self, kind, pid=None): - if kind not in self.tmap: - raise ValueError( - "invalid %r kind argument; choose between %s" - % (kind, ', '.join([repr(x) for x in self.tmap])) - ) self._procfs_path = get_procfs_path() if pid is not None: inodes = self.get_proc_inodes(pid) @@ -1041,7 +964,7 @@ class NetConnections: inodes = self.get_all_inodes() ret = set() for proto_name, family, type_ in self.tmap[kind]: - path = "%s/net/%s" % (self._procfs_path, proto_name) + path = f"{self._procfs_path}/net/{proto_name}" if family in {socket.AF_INET, socket.AF_INET6}: ls = self.process_inet( path, family, type_, inodes, filter_pid=pid @@ -1073,7 +996,7 @@ def net_io_counters(): """Return network I/O statistics for every network interface installed on the system as a dict of raw tuples. """ - with open_text("%s/net/dev" % get_procfs_path()) as f: + with open_text(f"{get_procfs_path()}/net/dev") as f: lines = f.readlines() retdict = {} for line in lines[2:]: @@ -1134,8 +1057,7 @@ def net_if_stats(): # https://github.com/giampaolo/psutil/issues/1279 if err.errno != errno.ENODEV: raise - else: - debug(err) + debug(err) else: output_flags = ','.join(flags) isup = 'running' in flags @@ -1175,7 +1097,7 @@ def disk_io_counters(perdisk=False): # See: # https://www.kernel.org/doc/Documentation/iostats.txt # https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats - with open_text("%s/diskstats" % get_procfs_path()) as f: + with open_text(f"{get_procfs_path()}/diskstats") as f: lines = f.readlines() for line in lines: fields = line.split() @@ -1198,7 +1120,8 @@ def disk_io_counters(perdisk=False): reads, rbytes, writes, wbytes = map(int, fields[3:]) rtime = wtime = reads_merged = writes_merged = busy_time = 0 else: - raise ValueError("not sure how to interpret line %r" % line) + msg = f"not sure how to interpret line {line!r}" + raise ValueError(msg) yield (name, reads, writes, rbytes, wbytes, rtime, wtime, reads_merged, writes_merged, busy_time) # fmt: on @@ -1218,16 +1141,16 @@ def disk_io_counters(perdisk=False): wtime, reads_merged, writes_merged, busy_time) # fmt: on - if os.path.exists('%s/diskstats' % get_procfs_path()): + if os.path.exists(f"{get_procfs_path()}/diskstats"): gen = read_procfs() elif os.path.exists('/sys/block'): gen = read_sysfs() else: - raise NotImplementedError( - "%s/diskstats nor /sys/block filesystem are available on this " - "system" - % get_procfs_path() + msg = ( + f"{get_procfs_path()}/diskstats nor /sys/block are available on" + " this system" ) + raise NotImplementedError(msg) retdict = {} for entry in gen: @@ -1273,7 +1196,7 @@ class RootFsDeviceFinder: self.minor = os.minor(dev) def ask_proc_partitions(self): - with open_text("%s/partitions" % get_procfs_path()) as f: + with open_text(f"{get_procfs_path()}/partitions") as f: for line in f.readlines()[2:]: fields = line.split() if len(fields) < 4: # just for extra safety @@ -1283,19 +1206,19 @@ class RootFsDeviceFinder: name = fields[3] if major == self.major and minor == self.minor: if name: # just for extra safety - return "/dev/%s" % name + return f"/dev/{name}" def ask_sys_dev_block(self): - path = "/sys/dev/block/%s:%s/uevent" % (self.major, self.minor) + path = f"/sys/dev/block/{self.major}:{self.minor}/uevent" with open_text(path) as f: for line in f: if line.startswith("DEVNAME="): name = line.strip().rpartition("DEVNAME=")[2] if name: # just for extra safety - return "/dev/%s" % name + return f"/dev/{name}" def ask_sys_class_block(self): - needle = "%s:%s" % (self.major, self.minor) + needle = f"{self.major}:{self.minor}" files = glob.iglob("/sys/class/block/*/dev") for file in files: try: @@ -1307,24 +1230,24 @@ class RootFsDeviceFinder: data = f.read().strip() if data == needle: name = os.path.basename(os.path.dirname(file)) - return "/dev/%s" % name + return f"/dev/{name}" def find(self): path = None if path is None: try: path = self.ask_proc_partitions() - except (IOError, OSError) as err: + except OSError as err: debug(err) if path is None: try: path = self.ask_sys_dev_block() - except (IOError, OSError) as err: + except OSError as err: debug(err) if path is None: try: path = self.ask_sys_class_block() - except (IOError, OSError) as err: + except OSError as err: debug(err) # We use exists() because the "/dev/*" part of the path is hard # coded, so we want to be sure. @@ -1337,7 +1260,7 @@ def disk_partitions(all=False): fstypes = set() procfs_path = get_procfs_path() if not all: - with open_text("%s/filesystems" % procfs_path) as f: + with open_text(f"{procfs_path}/filesystems") as f: for line in f: line = line.strip() if not line.startswith("nodev"): @@ -1352,7 +1275,7 @@ def disk_partitions(all=False): if procfs_path == "/proc" and os.path.isfile('/etc/mtab'): mounts_path = os.path.realpath("/etc/mtab") else: - mounts_path = os.path.realpath("%s/self/mounts" % procfs_path) + mounts_path = os.path.realpath(f"{procfs_path}/self/mounts") retlist = [] partitions = cext.disk_partitions(mounts_path) @@ -1395,7 +1318,7 @@ def sensors_temperatures(): # https://github.com/giampaolo/psutil/issues/971 # https://github.com/nicolargo/glances/issues/1060 basenames.extend(glob.glob('/sys/class/hwmon/hwmon*/device/temp*_*')) - basenames = sorted(set([x.split('_')[0] for x in basenames])) + basenames = sorted({x.split('_')[0] for x in basenames}) # Only add the coretemp hwmon entries if they're not already in # /sys/class/hwmon/ @@ -1404,7 +1327,7 @@ def sensors_temperatures(): basenames2 = glob.glob( '/sys/devices/platform/coretemp.*/hwmon/hwmon*/temp*_*' ) - repl = re.compile('/sys/devices/platform/coretemp.*/hwmon/') + repl = re.compile(r"/sys/devices/platform/coretemp.*/hwmon/") for name in basenames2: altname = repl.sub('/sys/class/hwmon/', name) if altname not in basenames: @@ -1416,7 +1339,7 @@ def sensors_temperatures(): current = float(bcat(path)) / 1000.0 path = os.path.join(os.path.dirname(base), 'name') unit_name = cat(path).strip() - except (IOError, OSError, ValueError): + except (OSError, ValueError): # A lot of things can go wrong here, so let's just skip the # whole entry. Sure thing is Linux's /sys/class/hwmon really # is a stinky broken mess. @@ -1455,15 +1378,15 @@ def sensors_temperatures(): current = float(bcat(path)) / 1000.0 path = os.path.join(base, 'type') unit_name = cat(path).strip() - except (IOError, OSError, ValueError) as err: + except (OSError, ValueError) as err: debug(err) continue trip_paths = glob.glob(base + '/trip_point*') - trip_points = set([ + trip_points = { '_'.join(os.path.basename(p).split('_')[0:3]) for p in trip_paths - ]) + } critical = None high = None for trip_point in trip_points: @@ -1511,11 +1434,11 @@ def sensors_fans(): # https://github.com/giampaolo/psutil/issues/971 basenames = glob.glob('/sys/class/hwmon/hwmon*/device/fan*_*') - basenames = sorted(set([x.split('_')[0] for x in basenames])) + basenames = sorted({x.split("_")[0] for x in basenames}) for base in basenames: try: current = int(bcat(base + '_input')) - except (IOError, OSError) as err: + except OSError as err: debug(err) continue unit_name = cat(os.path.join(os.path.dirname(base), 'name')).strip() @@ -1557,7 +1480,7 @@ def sensors_battery(): # Get the first available battery. Usually this is "BAT0", except # some rare exceptions: # https://github.com/giampaolo/psutil/issues/1238 - root = os.path.join(POWER_SUPPLY_PATH, sorted(bats)[0]) + root = os.path.join(POWER_SUPPLY_PATH, min(bats)) # Base metrics. energy_now = multi_bcat(root + "/energy_now", root + "/charge_now") @@ -1634,14 +1557,15 @@ def users(): def boot_time(): """Return the system boot time expressed in seconds since the epoch.""" global BOOT_TIME - path = '%s/stat' % get_procfs_path() + path = f"{get_procfs_path()}/stat" with open_binary(path) as f: for line in f: if line.startswith(b'btime'): ret = float(line.strip().split()[1]) BOOT_TIME = ret return ret - raise RuntimeError("line 'btime' not found in %s" % path) + msg = f"line 'btime' not found in {path}" + raise RuntimeError(msg) # ===================================================================== @@ -1651,7 +1575,8 @@ def boot_time(): def pids(): """Returns a list of PIDs currently running on the system.""" - return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()] + path = get_procfs_path().encode(ENCODING) + return [int(x) for x in os.listdir(path) if x.isdigit()] def pid_exists(pid): @@ -1673,7 +1598,7 @@ def pid_exists(pid): # Note: already checked that this is faster than using a # regular expr. Also (a lot) faster than doing # 'return pid in pids()' - path = "%s/%s/status" % (get_procfs_path(), pid) + path = f"{get_procfs_path()}/{pid}/status" with open_binary(path) as f: for line in f: if line.startswith(b"Tgid:"): @@ -1681,8 +1606,9 @@ def pid_exists(pid): # If tgid and pid are the same then we're # dealing with a process PID. return tgid == pid - raise ValueError("'Tgid' line not found in %s" % path) - except (EnvironmentError, ValueError): + msg = f"'Tgid' line not found in {path}" + raise ValueError(msg) + except (OSError, ValueError): return pid in pids() @@ -1694,7 +1620,7 @@ def ppid_map(): procfs_path = get_procfs_path() for pid in pids(): try: - with open_binary("%s/%s/stat" % (procfs_path, pid)) as f: + with open_binary(f"{procfs_path}/{pid}/stat") as f: data = f.read() except (FileNotFoundError, ProcessLookupError): # Note: we should be able to access /stat for all processes @@ -1709,28 +1635,27 @@ def ppid_map(): def wrap_exceptions(fun): - """Decorator which translates bare OSError and IOError exceptions + """Decorator which translates bare OSError and OSError exceptions into NoSuchProcess and AccessDenied. """ @functools.wraps(fun) def wrapper(self, *args, **kwargs): + pid, name = self.pid, self._name try: return fun(self, *args, **kwargs) - except PermissionError: - raise AccessDenied(self.pid, self._name) - except ProcessLookupError: + except PermissionError as err: + raise AccessDenied(pid, name) from err + except ProcessLookupError as err: self._raise_if_zombie() - raise NoSuchProcess(self.pid, self._name) - except FileNotFoundError: + raise NoSuchProcess(pid, name) from err + except FileNotFoundError as err: self._raise_if_zombie() # /proc/PID directory may still exist, but the files within # it may not, indicating the process is gone, see: # https://github.com/giampaolo/psutil/issues/2418 - if not os.path.exists( - "%s/%s/stat" % (self._procfs_path, self.pid) - ): - raise NoSuchProcess(self.pid, self._name) + if not os.path.exists(f"{self._procfs_path}/{pid}/stat"): + raise NoSuchProcess(pid, name) from err raise return wrapper @@ -1755,8 +1680,8 @@ class Process: # it's empty. Instead of returning a "null" value we'll raise an # exception. try: - data = bcat("%s/%s/stat" % (self._procfs_path, self.pid)) - except (IOError, OSError): + data = bcat(f"{self._procfs_path}/{self.pid}/stat") + except OSError: return False else: rpar = data.rfind(b')') @@ -1771,7 +1696,7 @@ class Process: """Raise NSP if the process disappeared on us.""" # For those C function who do not raise NSP, possibly returning # incorrect or incomplete result. - os.stat('%s/%s' % (self._procfs_path, self.pid)) + os.stat(f"{self._procfs_path}/{self.pid}") @wrap_exceptions @memoize_when_activated @@ -1784,7 +1709,7 @@ class Process: The return value is cached in case oneshot() ctx manager is in use. """ - data = bcat("%s/%s/stat" % (self._procfs_path, self.pid)) + data = bcat(f"{self._procfs_path}/{self.pid}/stat") # Process name is between parentheses. It can contain spaces and # other parentheses. This is taken into account by looking for # the first occurrence of "(" and the last occurrence of ")". @@ -1819,13 +1744,13 @@ class Process: The return value is cached in case oneshot() ctx manager is in use. """ - with open_binary("%s/%s/status" % (self._procfs_path, self.pid)) as f: + with open_binary(f"{self._procfs_path}/{self.pid}/status") as f: return f.read() @wrap_exceptions @memoize_when_activated def _read_smaps_file(self): - with open_binary("%s/%s/smaps" % (self._procfs_path, self.pid)) as f: + with open_binary(f"{self._procfs_path}/{self.pid}/smaps") as f: return f.read().strip() def oneshot_enter(self): @@ -1840,28 +1765,25 @@ class Process: @wrap_exceptions def name(self): - name = self._parse_stat_file()['name'] - if PY3: - name = decode(name) # XXX - gets changed later and probably needs refactoring - return name + return decode(self._parse_stat_file()['name']) @wrap_exceptions def exe(self): try: - return readlink("%s/%s/exe" % (self._procfs_path, self.pid)) + return readlink(f"{self._procfs_path}/{self.pid}/exe") except (FileNotFoundError, ProcessLookupError): self._raise_if_zombie() # no such file error; might be raised also if the # path actually exists for system processes with # low pids (about 0-20) - if os.path.lexists("%s/%s" % (self._procfs_path, self.pid)): + if os.path.lexists(f"{self._procfs_path}/{self.pid}"): return "" raise @wrap_exceptions def cmdline(self): - with open_text("%s/%s/cmdline" % (self._procfs_path, self.pid)) as f: + with open_text(f"{self._procfs_path}/{self.pid}/cmdline") as f: data = f.read() if not data: # may happen in case of zombie process @@ -1887,7 +1809,7 @@ class Process: @wrap_exceptions def environ(self): - with open_text("%s/%s/environ" % (self._procfs_path, self.pid)) as f: + with open_text(f"{self._procfs_path}/{self.pid}/environ") as f: data = f.read() return parse_environ_block(data) @@ -1901,11 +1823,11 @@ class Process: return None # May not be available on old kernels. - if os.path.exists('/proc/%s/io' % os.getpid()): + if os.path.exists(f"/proc/{os.getpid()}/io"): @wrap_exceptions def io_counters(self): - fname = "%s/%s/io" % (self._procfs_path, self.pid) + fname = f"{self._procfs_path}/{self.pid}/io" fields = {} with open_binary(fname) as f: for line in f: @@ -1920,7 +1842,8 @@ class Process: else: fields[name] = int(value) if not fields: - raise RuntimeError("%s file was empty" % fname) + msg = f"{fname} file was empty" + raise RuntimeError(msg) try: return pio( fields[b'syscr'], # read syscalls @@ -1931,10 +1854,11 @@ class Process: fields[b'wchar'], # write chars ) except KeyError as err: - raise ValueError( - "%r field was not found in %s; found fields are %r" - % (err.args[0], fname, fields) + msg = ( + f"{err.args[0]!r} field was not found in {fname}; found" + f" fields are {fields!r}" ) + raise ValueError(msg) from None @wrap_exceptions def cpu_times(self): @@ -1979,7 +1903,7 @@ class Process: # | data | data + stack | drs | DATA | # | dirty | dirty pages (unused in Linux 2.6) | dt | | # ============================================================ - with open_binary("%s/%s/statm" % (self._procfs_path, self.pid)) as f: + with open_binary(f"{self._procfs_path}/{self.pid}/statm") as f: vms, rss, shared, text, lib, data, dirty = ( int(x) * PAGESIZE for x in f.readline().split()[:7] ) @@ -1998,7 +1922,7 @@ class Process: # compared to /proc/pid/smaps_rollup. uss = pss = swap = 0 with open_binary( - "{}/{}/smaps_rollup".format(self._procfs_path, self.pid) + f"{self._procfs_path}/{self.pid}/smaps_rollup" ) as f: for line in f: if line.startswith(b"Private_"): @@ -2023,8 +1947,6 @@ class Process: # Note: using 3 regexes is faster than reading the file # line by line. - # XXX: on Python 3 the 2 regexes are 30% slower than on - # Python 2 though. Figure out why. # # You might be tempted to calculate USS by subtracting # the "shared" value from the "resident" value in @@ -2062,7 +1984,7 @@ class Process: def memory_maps(self): """Return process's mapped memory regions as a list of named tuples. Fields are explained in 'man proc'; here is an updated - (Apr 2012) version: http://goo.gl/fmebo. + (Apr 2012) version: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/filesystems/proc.txt?id=b76437579d1344b612cf1851ae610c636cec7db0. /proc/{PID}/smaps does not exist on kernels < 2.6.14 or if CONFIG_MMU kernel configuration option is not enabled. @@ -2083,11 +2005,8 @@ class Process: if fields[0].startswith(b'VmFlags:'): # see issue #369 continue - else: - raise ValueError( - "don't know how to interpret line %r" - % line - ) + msg = f"don't know how to interpret line {line!r}" + raise ValueError(msg) from None yield (current_block.pop(), data) data = self._read_smaps_file() @@ -2109,8 +2028,7 @@ class Process: if not path: path = '[anon]' else: - if PY3: - path = decode(path) + path = decode(path) path = path.strip() if path.endswith(' (deleted)') and not path_exists_strict( path @@ -2136,7 +2054,7 @@ class Process: @wrap_exceptions def cwd(self): - return readlink("%s/%s/cwd" % (self._procfs_path, self.pid)) + return readlink(f"{self._procfs_path}/{self.pid}/cwd") @wrap_exceptions def num_ctx_switches( @@ -2145,34 +2063,29 @@ class Process: data = self._read_status_file() ctxsw = _ctxsw_re.findall(data) if not ctxsw: - raise NotImplementedError( - "'voluntary_ctxt_switches' and 'nonvoluntary_ctxt_switches'" - "lines were not found in %s/%s/status; the kernel is " - "probably older than 2.6.23" % (self._procfs_path, self.pid) + msg = ( + "'voluntary_ctxt_switches' and" + " 'nonvoluntary_ctxt_switches'lines were not found in" + f" {self._procfs_path}/{self.pid}/status; the kernel is" + " probably older than 2.6.23" ) - else: - return _common.pctxsw(int(ctxsw[0]), int(ctxsw[1])) + raise NotImplementedError(msg) + return _common.pctxsw(int(ctxsw[0]), int(ctxsw[1])) @wrap_exceptions def num_threads(self, _num_threads_re=re.compile(br'Threads:\t(\d+)')): - # Note: on Python 3 using a re is faster than iterating over file - # line by line. On Python 2 is the exact opposite, and iterating - # over a file on Python 3 is slower than on Python 2. + # Using a re is faster than iterating over file line by line. data = self._read_status_file() return int(_num_threads_re.findall(data)[0]) @wrap_exceptions def threads(self): - thread_ids = os.listdir("%s/%s/task" % (self._procfs_path, self.pid)) + thread_ids = os.listdir(f"{self._procfs_path}/{self.pid}/task") thread_ids.sort() retlist = [] hit_enoent = False for thread_id in thread_ids: - fname = "%s/%s/task/%s/stat" % ( - self._procfs_path, - self.pid, - thread_id, - ) + fname = f"{self._procfs_path}/{self.pid}/task/{thread_id}/stat" try: with open_binary(fname) as f: st = f.read().strip() @@ -2194,7 +2107,7 @@ class Process: @wrap_exceptions def nice_get(self): - # with open_text('%s/%s/stat' % (self._procfs_path, self.pid)) as f: + # with open_text(f"{self._procfs_path}/{self.pid}/stat") as f: # data = f.read() # return int(data.split()[18]) @@ -2233,15 +2146,17 @@ class Process: all_cpus = tuple(range(len(per_cpu_times()))) for cpu in cpus: if cpu not in all_cpus: - raise ValueError( - "invalid CPU number %r; choose between %s" - % (cpu, eligible_cpus) + msg = ( + f"invalid CPU {cpu!r}; choose between" + f" {eligible_cpus!r}" ) + raise ValueError(msg) from None if cpu not in eligible_cpus: - raise ValueError( - "CPU number %r is not eligible; choose " - "between %s" % (cpu, eligible_cpus) + msg = ( + f"CPU number {cpu} is not eligible; choose" + f" between {eligible_cpus}" ) + raise ValueError(msg) from err raise # only starting from kernel 2.6.13 @@ -2250,22 +2165,25 @@ class Process: @wrap_exceptions def ionice_get(self): ioclass, value = cext.proc_ioprio_get(self.pid) - if enum is not None: - ioclass = IOPriority(ioclass) + ioclass = IOPriority(ioclass) return _common.pionice(ioclass, value) @wrap_exceptions def ionice_set(self, ioclass, value): if value is None: value = 0 - if value and ioclass in {IOPRIO_CLASS_IDLE, IOPRIO_CLASS_NONE}: - raise ValueError("%r ioclass accepts no value" % ioclass) + if value and ioclass in { + IOPriority.IOPRIO_CLASS_IDLE, + IOPriority.IOPRIO_CLASS_NONE, + }: + msg = f"{ioclass!r} ioclass accepts no value" + raise ValueError(msg) if value < 0 or value > 7: msg = "value not in 0-7 range" raise ValueError(msg) return cext.proc_ioprio_set(self.pid, ioclass, value) - if prlimit is not None: + if hasattr(resource, "prlimit"): @wrap_exceptions def rlimit(self, resource_, limits=None): @@ -2278,16 +2196,16 @@ class Process: try: if limits is None: # get - return prlimit(self.pid, resource_) + return resource.prlimit(self.pid, resource_) else: # set if len(limits) != 2: msg = ( "second argument must be a (soft, hard) " - + "tuple, got %s" % repr(limits) + f"tuple, got {limits!r}" ) raise ValueError(msg) - prlimit(self.pid, resource_, limits) + resource.prlimit(self.pid, resource_, limits) except OSError as err: if err.errno == errno.ENOSYS: # I saw this happening on Travis: @@ -2298,18 +2216,17 @@ class Process: @wrap_exceptions def status(self): letter = self._parse_stat_file()['status'] - if PY3: - letter = letter.decode() + letter = letter.decode() # XXX is '?' legit? (we're not supposed to return it anyway) return PROC_STATUSES.get(letter, '?') @wrap_exceptions def open_files(self): retlist = [] - files = os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)) + files = os.listdir(f"{self._procfs_path}/{self.pid}/fd") hit_enoent = False for fd in files: - file = "%s/%s/fd/%s" % (self._procfs_path, self.pid, fd) + file = f"{self._procfs_path}/{self.pid}/fd/{fd}" try: path = readlink(file) except (FileNotFoundError, ProcessLookupError): @@ -2332,11 +2249,7 @@ class Process: # absolute path though. if path.startswith('/') and isfile_strict(path): # Get file position and flags. - file = "%s/%s/fdinfo/%s" % ( - self._procfs_path, - self.pid, - fd, - ) + file = f"{self._procfs_path}/{self.pid}/fdinfo/{fd}" try: with open_binary(file) as f: pos = int(f.readline().split()[1]) @@ -2363,7 +2276,7 @@ class Process: @wrap_exceptions def num_fds(self): - return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid))) + return len(os.listdir(f"{self._procfs_path}/{self.pid}/fd")) @wrap_exceptions def ppid(self): diff --git a/contrib/python/psutil/py3/psutil/_psosx.py b/contrib/python/psutil/py3/psutil/_psosx.py index ed9b319de7f..620497b30a0 100644 --- a/contrib/python/psutil/py3/psutil/_psosx.py +++ b/contrib/python/psutil/py3/psutil/_psosx.py @@ -22,8 +22,6 @@ from ._common import isfile_strict from ._common import memoize_when_activated from ._common import parse_environ_block from ._common import usage_percent -from ._compat import PermissionError -from ._compat import ProcessLookupError __extra__all__ = [] @@ -114,8 +112,7 @@ def virtual_memory(): """System virtual memory as a namedtuple.""" total, active, inactive, wired, free, speculative = cext.virtual_mem() # This is how Zabbix calculate avail and used mem: - # https://github.com/zabbix/zabbix/blob/trunk/src/libs/zbxsysinfo/ - # osx/memory.c + # https://github.com/zabbix/zabbix/blob/master/src/libs/zbxsysinfo/osx/memory.c # Also see: https://github.com/giampaolo/psutil/issues/1277 avail = inactive + free used = active + wired @@ -345,15 +342,15 @@ def wrap_exceptions(fun): @functools.wraps(fun) def wrapper(self, *args, **kwargs): + pid, ppid, name = self.pid, self._ppid, self._name try: return fun(self, *args, **kwargs) - except ProcessLookupError: - if is_zombie(self.pid): - raise ZombieProcess(self.pid, self._name, self._ppid) - else: - raise NoSuchProcess(self.pid, self._name) - except PermissionError: - raise AccessDenied(self.pid, self._name) + except ProcessLookupError as err: + if is_zombie(pid): + raise ZombieProcess(pid, name, ppid) from err + raise NoSuchProcess(pid, name) from err + except PermissionError as err: + raise AccessDenied(pid, name) from err return wrapper @@ -502,11 +499,6 @@ class Process: @wrap_exceptions def net_connections(self, kind='inet'): - if kind not in conn_tmap: - raise ValueError( - "invalid %r kind argument; choose between %s" - % (kind, ', '.join([repr(x) for x in conn_tmap])) - ) families, types = conn_tmap[kind] rawlist = cext.proc_net_connections(self.pid, families, types) ret = [] diff --git a/contrib/python/psutil/py3/psutil/_psposix.py b/contrib/python/psutil/py3/psutil/_psposix.py index 42bdfa7ef6c..88703fdbd26 100644 --- a/contrib/python/psutil/py3/psutil/_psposix.py +++ b/contrib/python/psutil/py3/psutil/_psposix.py @@ -4,10 +4,10 @@ """Routines common to all posix systems.""" +import enum import glob import os import signal -import sys import time from ._common import MACOS @@ -15,25 +15,12 @@ from ._common import TimeoutExpired from ._common import memoize from ._common import sdiskusage from ._common import usage_percent -from ._compat import PY3 -from ._compat import ChildProcessError -from ._compat import FileNotFoundError -from ._compat import InterruptedError -from ._compat import PermissionError -from ._compat import ProcessLookupError -from ._compat import unicode if MACOS: from . import _psutil_osx -if PY3: - import enum -else: - enum = None - - __all__ = ['pid_exists', 'wait_pid', 'disk_usage', 'get_terminal_map'] @@ -59,23 +46,16 @@ def pid_exists(pid): return True -# Python 3.5 signals enum (contributed by me ^^): -# https://bugs.python.org/issue21076 -if enum is not None and hasattr(signal, "Signals"): - Negsignal = enum.IntEnum( - 'Negsignal', dict([(x.name, -x.value) for x in signal.Signals]) - ) - - def negsig_to_enum(num): - """Convert a negative signal value to an enum.""" - try: - return Negsignal(num) - except ValueError: - return num +Negsignal = enum.IntEnum( + 'Negsignal', {x.name: -x.value for x in signal.Signals} +) -else: # pragma: no cover - def negsig_to_enum(num): +def negsig_to_enum(num): + """Convert a negative signal value to an enum.""" + try: + return Negsignal(num) + except ValueError: return num @@ -139,7 +119,7 @@ def wait_pid( # can't determine its exit status code. while _pid_exists(pid): interval = sleep(interval) - return + return None else: if retpid == 0: # WNOHANG flag was used and PID is still running. @@ -171,7 +151,8 @@ def wait_pid( # continue else: # Should never happen. - raise ValueError("unknown process exit status %r" % status) + msg = f"unknown process exit status {status!r}" + raise ValueError(msg) def disk_usage(path): @@ -181,24 +162,7 @@ def disk_usage(path): total and used disk space whereas "free" and "percent" represent the "free" and "used percent" user disk space. """ - if PY3: - st = os.statvfs(path) - else: # pragma: no cover - # os.statvfs() does not support unicode on Python 2: - # - https://github.com/giampaolo/psutil/issues/416 - # - http://bugs.python.org/issue18695 - try: - st = os.statvfs(path) - except UnicodeEncodeError: - if isinstance(path, unicode): - try: - path = path.encode(sys.getfilesystemencoding()) - except UnicodeEncodeError: - pass - st = os.statvfs(path) - else: - raise - + st = os.statvfs(path) # Total space which is only available to root (unless changed # at system level). total = st.f_blocks * st.f_frsize diff --git a/contrib/python/psutil/py3/psutil/_pssunos.py b/contrib/python/psutil/py3/psutil/_pssunos.py index a38d939d793..78d941cc5ff 100644 --- a/contrib/python/psutil/py3/psutil/_pssunos.py +++ b/contrib/python/psutil/py3/psutil/_pssunos.py @@ -18,6 +18,7 @@ from . import _psposix from . import _psutil_posix as cext_posix from . import _psutil_sunos as cext from ._common import AF_INET6 +from ._common import ENCODING from ._common import AccessDenied from ._common import NoSuchProcess from ._common import ZombieProcess @@ -28,11 +29,6 @@ from ._common import memoize_when_activated from ._common import sockfam_to_enum from ._common import socktype_to_enum from ._common import usage_percent -from ._compat import PY3 -from ._compat import FileNotFoundError -from ._compat import PermissionError -from ._compat import ProcessLookupError -from ._compat import b __extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"] @@ -147,17 +143,17 @@ def swap_memory(): p = subprocess.Popen( [ '/usr/bin/env', - 'PATH=/usr/sbin:/sbin:%s' % os.environ['PATH'], + f"PATH=/usr/sbin:/sbin:{os.environ['PATH']}", 'swap', '-l', ], stdout=subprocess.PIPE, ) stdout, _ = p.communicate() - if PY3: - stdout = stdout.decode(sys.stdout.encoding) + stdout = stdout.decode(sys.stdout.encoding) if p.returncode != 0: - raise RuntimeError("'swap -l' failed (retcode=%s)" % p.returncode) + msg = f"'swap -l' failed (retcode={p.returncode})" + raise RuntimeError(msg) lines = stdout.strip().split('\n')[1:] if not lines: @@ -244,7 +240,7 @@ def disk_partitions(all=False): continue except OSError as err: # https://github.com/giampaolo/psutil/issues/1674 - debug("skipping %r: %s" % (mountpoint, err)) + debug(f"skipping {mountpoint!r}: {err}") continue ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) retlist.append(ntuple) @@ -265,14 +261,6 @@ def net_connections(kind, _pid=-1): connections (as opposed to connections opened by one process only). Only INET sockets are returned (UNIX are not). """ - cmap = _common.conn_tmap.copy() - if _pid == -1: - cmap.pop('unix', 0) - if kind not in cmap: - raise ValueError( - "invalid %r kind argument; choose between %s" - % (kind, ', '.join([repr(x) for x in cmap])) - ) families, types = _common.conn_tmap[kind] rawlist = cext.net_connections(_pid) ret = set() @@ -346,7 +334,8 @@ def users(): def pids(): """Returns a list of PIDs currently running on the system.""" - return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()] + path = get_procfs_path().encode(ENCODING) + return [int(x) for x in os.listdir(path) if x.isdigit()] def pid_exists(pid): @@ -361,24 +350,23 @@ def wrap_exceptions(fun): @functools.wraps(fun) def wrapper(self, *args, **kwargs): + pid, ppid, name = self.pid, self._ppid, self._name try: return fun(self, *args, **kwargs) - except (FileNotFoundError, ProcessLookupError): + except (FileNotFoundError, ProcessLookupError) as err: # ENOENT (no such file or directory) gets raised on open(). # ESRCH (no such process) can get raised on read() if # process is gone in meantime. - if not pid_exists(self.pid): - raise NoSuchProcess(self.pid, self._name) - else: - raise ZombieProcess(self.pid, self._name, self._ppid) - except PermissionError: - raise AccessDenied(self.pid, self._name) - except OSError: - if self.pid == 0: + if not pid_exists(pid): + raise NoSuchProcess(pid, name) from err + raise ZombieProcess(pid, name, ppid) from err + except PermissionError as err: + raise AccessDenied(pid, name) from err + except OSError as err: + if pid == 0: if 0 in pids(): - raise AccessDenied(self.pid, self._name) - else: - raise + raise AccessDenied(pid, name) from err + raise raise return wrapper @@ -399,7 +387,7 @@ class Process: """Raise NSP if the process disappeared on us.""" # For those C function who do not raise NSP, possibly returning # incorrect or incomplete result. - os.stat('%s/%s' % (self._procfs_path, self.pid)) + os.stat(f"{self._procfs_path}/{self.pid}") def oneshot_enter(self): self._proc_name_and_args.cache_activate(self) @@ -420,7 +408,7 @@ class Process: @memoize_when_activated def _proc_basic_info(self): if self.pid == 0 and not os.path.exists( - '%s/%s/psinfo' % (self._procfs_path, self.pid) + f"{self._procfs_path}/{self.pid}/psinfo" ): raise AccessDenied(self.pid) ret = cext.proc_basic_info(self.pid, self._procfs_path) @@ -440,9 +428,7 @@ class Process: @wrap_exceptions def exe(self): try: - return os.readlink( - "%s/%s/path/a.out" % (self._procfs_path, self.pid) - ) + return os.readlink(f"{self._procfs_path}/{self.pid}/path/a.out") except OSError: pass # continue and guess the exe name from the cmdline # Will be guessed later from cmdline but we want to explicitly @@ -539,9 +525,7 @@ class Process: if tty != cext.PRNODEV: for x in (0, 1, 2, 255): try: - return os.readlink( - '%s/%d/path/%d' % (procfs_path, self.pid, x) - ) + return os.readlink(f"{procfs_path}/{self.pid}/path/{x}") except FileNotFoundError: hit_enoent = True continue @@ -553,12 +537,12 @@ class Process: # /proc/PID/path/cwd may not be resolved by readlink() even if # it exists (ls shows it). If that's the case and the process # is still alive return None (we can return None also on BSD). - # Reference: http://goo.gl/55XgO + # Reference: https://groups.google.com/g/comp.unix.solaris/c/tcqvhTNFCAs procfs_path = self._procfs_path try: - return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid)) + return os.readlink(f"{procfs_path}/{self.pid}/path/cwd") except FileNotFoundError: - os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD + os.stat(f"{procfs_path}/{self.pid}") # raise NSP or AD return "" @wrap_exceptions @@ -580,7 +564,7 @@ class Process: def threads(self): procfs_path = self._procfs_path ret = [] - tids = os.listdir('%s/%d/lwp' % (procfs_path, self.pid)) + tids = os.listdir(f"{procfs_path}/{self.pid}/lwp") hit_enoent = False for tid in tids: tid = int(tid) @@ -588,7 +572,7 @@ class Process: utime, stime = cext.query_process_thread( self.pid, tid, procfs_path ) - except EnvironmentError as err: + except OSError as err: if err.errno == errno.EOVERFLOW and not IS_64_BIT: # We may get here if we attempt to query a 64bit process # with a 32bit python. @@ -615,8 +599,8 @@ class Process: retlist = [] hit_enoent = False procfs_path = self._procfs_path - pathdir = '%s/%d/path' % (procfs_path, self.pid) - for fd in os.listdir('%s/%d/fd' % (procfs_path, self.pid)): + pathdir = f"{procfs_path}/{self.pid}/path" + for fd in os.listdir(f"{procfs_path}/{self.pid}/fd"): path = os.path.join(pathdir, fd) if os.path.islink(path): try: @@ -640,16 +624,16 @@ class Process: cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout, stderr = p.communicate() - if PY3: - stdout, stderr = ( - x.decode(sys.stdout.encoding) for x in (stdout, stderr) - ) + stdout, stderr = ( + x.decode(sys.stdout.encoding) for x in (stdout, stderr) + ) if p.returncode != 0: if 'permission denied' in stderr.lower(): raise AccessDenied(self.pid, self._name) if 'no such process' in stderr.lower(): raise NoSuchProcess(self.pid, self._name) - raise RuntimeError("%r command error\n%s" % (cmd, stderr)) + msg = f"{cmd!r} command error\n{stderr}" + raise RuntimeError(msg) lines = stdout.split('\n')[2:] for i, line in enumerate(lines): @@ -675,7 +659,7 @@ class Process: # is no longer there. if not ret: # will raise NSP if process is gone - os.stat('%s/%s' % (self._procfs_path, self.pid)) + os.stat(f"{self._procfs_path}/{self.pid}") # UNIX sockets if kind in {'all', 'unix'}: @@ -691,9 +675,8 @@ class Process: @wrap_exceptions def memory_maps(self): def toaddr(start, end): - return '%s-%s' % ( - hex(start)[2:].strip('L'), - hex(end)[2:].strip('L'), + return "{}-{}".format( + hex(start)[2:].strip('L'), hex(end)[2:].strip('L') ) procfs_path = self._procfs_path @@ -718,9 +701,7 @@ class Process: addr = toaddr(addr, addrsize) if not name.startswith('['): try: - name = os.readlink( - '%s/%s/path/%s' % (procfs_path, self.pid, name) - ) + name = os.readlink(f"{procfs_path}/{self.pid}/path/{name}") except OSError as err: if err.errno == errno.ENOENT: # sometimes the link may not be resolved by @@ -729,7 +710,7 @@ class Process: # unresolved link path. # This seems an inconsistency with /proc similar # to: http://goo.gl/55XgO - name = '%s/%s/path/%s' % (procfs_path, self.pid, name) + name = f"{procfs_path}/{self.pid}/path/{name}" hit_enoent = True else: raise @@ -740,7 +721,7 @@ class Process: @wrap_exceptions def num_fds(self): - return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid))) + return len(os.listdir(f"{self._procfs_path}/{self.pid}/fd")) @wrap_exceptions def num_ctx_switches(self): diff --git a/contrib/python/psutil/py3/psutil/_psutil_common.c b/contrib/python/psutil/py3/psutil/_psutil_common.c index 941f6bff1b9..2a56ae0f4aa 100644 --- a/contrib/python/psutil/py3/psutil/_psutil_common.c +++ b/contrib/python/psutil/py3/psutil/_psutil_common.c @@ -69,15 +69,6 @@ PyErr_SetExcFromWindowsErrWithFilenameObject(PyObject *type, return PyErr_SetFromWindowsErrWithFilename(ierr, NULL); } #endif // !defined(PyErr_SetExcFromWindowsErrWithFilenameObject) - - -// PyPy 2.7 -#if !defined(PyErr_SetFromWindowsErr) -PyObject * -PyErr_SetFromWindowsErr(int winerr) { - return PyErr_SetFromWindowsErrWithFilename(winerr, ""); -} -#endif // !defined(PyErr_SetFromWindowsErr) #endif // defined(PSUTIL_WINDOWS) && defined(PYPY_VERSION) diff --git a/contrib/python/psutil/py3/psutil/_psutil_common.h b/contrib/python/psutil/py3/psutil/_psutil_common.h index 2cdfa9d4d67..024452630f3 100644 --- a/contrib/python/psutil/py3/psutil/_psutil_common.h +++ b/contrib/python/psutil/py3/psutil/_psutil_common.h @@ -23,14 +23,6 @@ static const int PSUTIL_CONN_NONE = 128; // --- Backward compatibility with missing Python.h APIs // ==================================================================== -#if PY_MAJOR_VERSION < 3 - // On Python 2 we just return a plain byte string, which is never - // supposed to raise decoding errors, see: - // https://github.com/giampaolo/psutil/issues/1040 - #define PyUnicode_DecodeFSDefault PyString_FromString - #define PyUnicode_DecodeFSDefaultAndSize PyString_FromStringAndSize -#endif - #if defined(PSUTIL_WINDOWS) && defined(PYPY_VERSION) #if !defined(PyErr_SetFromWindowsErrWithFilename) PyObject *PyErr_SetFromWindowsErrWithFilename(int ierr, @@ -45,7 +37,6 @@ static const int PSUTIL_CONN_NONE = 128; // --- _Py_PARSE_PID // SIZEOF_INT|LONG is missing on Linux + PyPy (only?). -// SIZEOF_PID_T is missing on Windows + Python2. // In this case we guess it from setup.py. It's not 100% bullet proof, // If wrong we'll probably get compiler warnings. // FWIW on all UNIX platforms I've seen pid_t is defined as an int. @@ -60,8 +51,8 @@ static const int PSUTIL_CONN_NONE = 128; #define SIZEOF_PID_T PSUTIL_SIZEOF_PID_T // set as a macro in setup.py #endif -// _Py_PARSE_PID is Python 3 only, but since it's private make sure it's -// always present. +// _Py_PARSE_PID was added in Python 3, but since it's private we make +// sure it's always present. #ifndef _Py_PARSE_PID #if SIZEOF_PID_T == SIZEOF_INT #define _Py_PARSE_PID "i" @@ -75,14 +66,10 @@ static const int PSUTIL_CONN_NONE = 128; #endif #endif -// Python 2 or PyPy on Windows +// PyPy on Windows #ifndef PyLong_FromPid #if ((SIZEOF_PID_T == SIZEOF_INT) || (SIZEOF_PID_T == SIZEOF_LONG)) - #if PY_MAJOR_VERSION >= 3 - #define PyLong_FromPid PyLong_FromLong - #else - #define PyLong_FromPid PyInt_FromLong - #endif + #define PyLong_FromPid PyLong_FromLong #elif defined(SIZEOF_LONG_LONG) && SIZEOF_PID_T == SIZEOF_LONG_LONG #define PyLong_FromPid PyLong_FromLongLong #else diff --git a/contrib/python/psutil/py3/psutil/_psutil_linux.c b/contrib/python/psutil/py3/psutil/_psutil_linux.c index 46244c57920..fcd886bfb61 100644 --- a/contrib/python/psutil/py3/psutil/_psutil_linux.c +++ b/contrib/python/psutil/py3/psutil/_psutil_linux.c @@ -19,6 +19,13 @@ #include "arch/linux/proc.h" #include "arch/linux/users.h" +// May happen on old RedHat versions, see: +// https://github.com/giampaolo/psutil/issues/607 +#ifndef DUPLEX_UNKNOWN + #define DUPLEX_UNKNOWN 0xff +#endif + +#define INITERR return NULL static PyMethodDef mod_methods[] = { // --- per-process functions @@ -41,40 +48,24 @@ static PyMethodDef mod_methods[] = { {"set_debug", psutil_set_debug, METH_VARARGS}, {NULL, NULL, 0, NULL} }; -// May happen on old RedHat versions, see: -// https://github.com/giampaolo/psutil/issues/607 -#ifndef DUPLEX_UNKNOWN - #define DUPLEX_UNKNOWN 0xff -#endif - -#if PY_MAJOR_VERSION >= 3 - #define INITERR return NULL - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_psutil_linux", - NULL, - -1, - mod_methods, - NULL, - NULL, - NULL, - NULL - }; +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "_psutil_linux", + NULL, + -1, + mod_methods, + NULL, + NULL, + NULL, + NULL +}; - PyObject *PyInit__psutil_linux(void) -#else /* PY_MAJOR_VERSION */ - #define INITERR return - void init_psutil_linux(void) -#endif /* PY_MAJOR_VERSION */ -{ -#if PY_MAJOR_VERSION >= 3 +PyObject * +PyInit__psutil_linux(void) { PyObject *mod = PyModule_Create(&moduledef); -#else - PyObject *mod = Py_InitModule("_psutil_linux", mod_methods); -#endif if (mod == NULL) INITERR; @@ -91,7 +82,5 @@ static PyMethodDef mod_methods[] = { if (mod == NULL) INITERR; -#if PY_MAJOR_VERSION >= 3 return mod; -#endif } diff --git a/contrib/python/psutil/py3/psutil/_psutil_osx.c b/contrib/python/psutil/py3/psutil/_psutil_osx.c index 09fa267a983..b16103379be 100644 --- a/contrib/python/psutil/py3/psutil/_psutil_osx.c +++ b/contrib/python/psutil/py3/psutil/_psutil_osx.c @@ -7,6 +7,7 @@ */ #include <Python.h> +#include <sys/time.h> // needed for old macOS versions #include <sys/proc.h> #include <netinet/tcp_fsm.h> @@ -20,6 +21,8 @@ #include "arch/osx/sys.h" +#define INITERR return NULL + static PyMethodDef mod_methods[] = { // --- per-process functions {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS}, @@ -61,33 +64,22 @@ static PyMethodDef mod_methods[] = { }; -#if PY_MAJOR_VERSION >= 3 - #define INITERR return NULL - - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_psutil_osx", - NULL, - -1, - mod_methods, - NULL, - NULL, - NULL, - NULL - }; - - PyObject *PyInit__psutil_osx(void) -#else /* PY_MAJOR_VERSION */ - #define INITERR return - - void init_psutil_osx(void) -#endif /* PY_MAJOR_VERSION */ -{ -#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "_psutil_osx", + NULL, + -1, + mod_methods, + NULL, + NULL, + NULL, + NULL +}; + + +PyObject * +PyInit__psutil_osx(void) { PyObject *mod = PyModule_Create(&moduledef); -#else - PyObject *mod = Py_InitModule("_psutil_osx", mod_methods); -#endif if (mod == NULL) INITERR; @@ -140,7 +132,5 @@ static PyMethodDef mod_methods[] = { if (mod == NULL) INITERR; -#if PY_MAJOR_VERSION >= 3 return mod; -#endif } diff --git a/contrib/python/psutil/py3/psutil/_psutil_posix.c b/contrib/python/psutil/py3/psutil/_psutil_posix.c index 7e6eaac46c0..de10f7854a8 100644 --- a/contrib/python/psutil/py3/psutil/_psutil_posix.c +++ b/contrib/python/psutil/py3/psutil/_psutil_posix.c @@ -52,6 +52,9 @@ #include "_psutil_common.h" +#define INITERR return NULL + + // ==================================================================== // --- Utils // ==================================================================== @@ -434,11 +437,7 @@ append_flag(PyObject *py_retlist, const char * flag_name) { PyObject *py_str = NULL; -#if PY_MAJOR_VERSION >= 3 py_str = PyUnicode_FromString(flag_name); -#else - py_str = PyString_FromString(flag_name); -#endif if (! py_str) return 0; if (PyList_Append(py_retlist, py_str)) { @@ -883,33 +882,21 @@ static PyMethodDef mod_methods[] = { }; -#if PY_MAJOR_VERSION >= 3 - #define INITERR return NULL - - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_psutil_posix", - NULL, - -1, - mod_methods, - NULL, - NULL, - NULL, - NULL - }; - - PyObject *PyInit__psutil_posix(void) -#else /* PY_MAJOR_VERSION */ - #define INITERR return +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "_psutil_posix", + NULL, + -1, + mod_methods, + NULL, + NULL, + NULL, + NULL +}; - void init_psutil_posix(void) -#endif /* PY_MAJOR_VERSION */ -{ -#if PY_MAJOR_VERSION >= 3 +PyObject * +PyInit__psutil_posix(void) { PyObject *mod = PyModule_Create(&moduledef); -#else - PyObject *mod = Py_InitModule("_psutil_posix", mod_methods); -#endif if (mod == NULL) INITERR; @@ -1022,9 +1009,7 @@ static PyMethodDef mod_methods[] = { if (mod == NULL) INITERR; -#if PY_MAJOR_VERSION >= 3 return mod; -#endif } #ifdef __cplusplus diff --git a/contrib/python/psutil/py3/psutil/_psutil_windows.c b/contrib/python/psutil/py3/psutil/_psutil_windows.c index 0c221bdc236..0af18f3e263 100644 --- a/contrib/python/psutil/py3/psutil/_psutil_windows.c +++ b/contrib/python/psutil/py3/psutil/_psutil_windows.c @@ -34,6 +34,10 @@ #include "arch/windows/wmi.h" +#define INITERROR return NULL +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) + + // ------------------------ Python init --------------------------- static PyMethodDef @@ -116,21 +120,15 @@ struct module_state { PyObject *error; }; -#if PY_MAJOR_VERSION >= 3 -#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) -#else -#define GETSTATE(m) (&_state) -static struct module_state _state; -#endif - -#if PY_MAJOR_VERSION >= 3 -static int psutil_windows_traverse(PyObject *m, visitproc visit, void *arg) { +static int +psutil_windows_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } -static int psutil_windows_clear(PyObject *m) { +static int +psutil_windows_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } @@ -147,21 +145,12 @@ static struct PyModuleDef moduledef = { NULL }; -#define INITERROR return NULL - -PyMODINIT_FUNC PyInit__psutil_windows(void) -#else -#define INITERROR return -void init_psutil_windows(void) -#endif -{ +PyMODINIT_FUNC +PyInit__psutil_windows(void) { struct module_state *st = NULL; -#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); -#else - PyObject *module = Py_InitModule("_psutil_windows", PsutilMethods); -#endif if (module == NULL) INITERROR; @@ -283,7 +272,5 @@ void init_psutil_windows(void) PyModule_AddIntConstant( module, "WINDOWS_10", PSUTIL_WINDOWS_10); -#if PY_MAJOR_VERSION >= 3 return module; -#endif } diff --git a/contrib/python/psutil/py3/psutil/_pswindows.py b/contrib/python/psutil/py3/psutil/_pswindows.py index e39ba711fab..e5af3c90f43 100644 --- a/contrib/python/psutil/py3/psutil/_pswindows.py +++ b/contrib/python/psutil/py3/psutil/_pswindows.py @@ -5,7 +5,7 @@ """Windows platform implementation.""" import contextlib -import errno +import enum import functools import os import signal @@ -15,7 +15,6 @@ from collections import namedtuple from . import _common from ._common import ENCODING -from ._common import ENCODING_ERRS from ._common import AccessDenied from ._common import NoSuchProcess from ._common import TimeoutExpired @@ -27,11 +26,6 @@ from ._common import memoize from ._common import memoize_when_activated from ._common import parse_environ_block from ._common import usage_percent -from ._compat import PY3 -from ._compat import long -from ._compat import lru_cache -from ._compat import range -from ._compat import unicode from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS from ._psutil_windows import HIGH_PRIORITY_CLASS @@ -54,14 +48,10 @@ except ImportError as err: 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) + raise RuntimeError(msg) from err else: raise -if PY3: - import enum -else: - enum = None # process priority constants, import from __init__.py: # http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx @@ -88,11 +78,8 @@ CONN_DELETE_TCB = "DELETE_TCB" ERROR_PARTIAL_COPY = 299 PYPY = '__pypy__' in sys.builtin_module_names -if enum is None: - AF_LINK = -1 -else: - AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1}) - AF_LINK = AddressFamily.AF_LINK +AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1}) +AF_LINK = AddressFamily.AF_LINK TCP_STATUSES = { cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED, @@ -110,32 +97,27 @@ TCP_STATUSES = { cext.PSUTIL_CONN_NONE: _common.CONN_NONE, } -if enum is not None: - class Priority(enum.IntEnum): - ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS - BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS - HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS - IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS - NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS - REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS +class Priority(enum.IntEnum): + ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS + BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS + HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS + IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS + NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS + REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS - globals().update(Priority.__members__) -if enum is None: +globals().update(Priority.__members__) + + +class IOPriority(enum.IntEnum): IOPRIO_VERYLOW = 0 IOPRIO_LOW = 1 IOPRIO_NORMAL = 2 IOPRIO_HIGH = 3 -else: - class IOPriority(enum.IntEnum): - IOPRIO_VERYLOW = 0 - IOPRIO_LOW = 1 - IOPRIO_NORMAL = 2 - IOPRIO_HIGH = 3 - globals().update(IOPriority.__members__) +globals().update(IOPriority.__members__) pinfo_map = dict( num_handles=0, @@ -199,7 +181,7 @@ pio = namedtuple('pio', ['read_count', 'write_count', # ===================================================================== -@lru_cache(maxsize=512) [email protected]_cache(maxsize=512) def convert_dos_path(s): r"""Convert paths using native DOS format like: "\Device\HarddiskVolume1\Windows\systemew\file.txt" @@ -212,18 +194,6 @@ def convert_dos_path(s): return os.path.join(driveletter, remainder) -def py2_strencode(s): - """Encode a unicode string to a byte string by using the default fs - encoding + "replace" error handler. - """ - if PY3: - return s - if isinstance(s, str): - return s - else: - return s.encode(ENCODING, ENCODING_ERRS) - - @memoize def getpagesize(): return cext.getpagesize() @@ -282,7 +252,7 @@ disk_io_counters = cext.disk_io_counters def disk_usage(path): """Return disk usage associated with path.""" - if PY3 and isinstance(path, bytes): + if isinstance(path, bytes): # XXX: do we want to use "strict"? Probably yes, in order # to fail immediately. After all we are accepting input here... path = path.decode(ENCODING, errors="strict") @@ -367,7 +337,7 @@ def getloadavg(): # Drop to 2 decimal points which is what Linux does raw_loads = cext.getloadavg() - return tuple([round(load, 2) for load in raw_loads]) + return tuple(round(load, 2) for load in raw_loads) # ===================================================================== @@ -379,11 +349,6 @@ def net_connections(kind, _pid=-1): """Return socket connections. If pid == -1 return system-wide connections (as opposed to connections opened by one process only). """ - if kind not in conn_tmap: - raise ValueError( - "invalid %r kind argument; choose between %s" - % (kind, ', '.join([repr(x) for x in conn_tmap])) - ) families, types = conn_tmap[kind] rawlist = cext.net_connections(_pid, families, types) ret = set() @@ -408,9 +373,6 @@ def net_if_stats(): ret = {} rawdict = cext.net_if_stats() for name, items in rawdict.items(): - if not PY3: - assert isinstance(name, unicode), type(name) - name = py2_strencode(name) isup, duplex, speed, mtu = items if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) @@ -422,18 +384,12 @@ def net_io_counters(): """Return network I/O statistics for every network interface installed on the system as a dict of raw tuples. """ - ret = cext.net_io_counters() - return dict([(py2_strencode(k), v) for k, v in ret.items()]) + return cext.net_io_counters() def net_if_addrs(): """Return the addresses associated to each NIC.""" - ret = [] - for items in cext.net_if_addrs(): - items = list(items) - items[0] = py2_strencode(items[0]) - ret.append(items) - return ret + return cext.net_if_addrs() # ===================================================================== @@ -489,7 +445,6 @@ def users(): rawlist = cext.users() for item in rawlist: user, hostname, tstamp = item - user = py2_strencode(user) nt = _common.suser(user, None, hostname, tstamp, None) retlist.append(nt) return retlist @@ -503,7 +458,7 @@ def users(): def win_service_iter(): """Yields a list of WindowsService instances.""" for name, display_name in cext.winservice_enumerate(): - yield WindowsService(py2_strencode(name), py2_strencode(display_name)) + yield WindowsService(name, display_name) def win_service_get(name): @@ -521,14 +476,11 @@ class WindowsService: # noqa: PLW1641 self._display_name = display_name def __str__(self): - details = "(name=%r, display_name=%r)" % ( - self._name, - self._display_name, - ) - return "%s%s" % (self.__class__.__name__, details) + details = f"(name={self._name!r}, display_name={self._display_name!r})" + return f"{self.__class__.__name__}{details}" def __repr__(self): - return "<%s at %s>" % (self.__str__(), id(self)) + return f"<{self.__str__()} at {id(self)}>" def __eq__(self, other): # Test for equality with another WindosService object based @@ -547,10 +499,10 @@ class WindowsService: # noqa: PLW1641 ) # XXX - update _self.display_name? return dict( - display_name=py2_strencode(display_name), - binpath=py2_strencode(binpath), - username=py2_strencode(username), - start_type=py2_strencode(start_type), + display_name=display_name, + binpath=binpath, + username=username, + start_type=start_type, ) def _query_status(self): @@ -568,18 +520,18 @@ class WindowsService: # noqa: PLW1641 try: yield except OSError as err: + name = self._name if is_permission_err(err): msg = ( - "service %r is not querable (not enough privileges)" - % self._name + f"service {name!r} is not querable (not enough privileges)" ) - raise AccessDenied(pid=None, name=self._name, msg=msg) + raise AccessDenied(pid=None, name=name, msg=msg) from err elif err.winerror in { cext.ERROR_INVALID_NAME, cext.ERROR_SERVICE_DOES_NOT_EXIST, }: - msg = "service %r does not exist" % self._name - raise NoSuchProcess(pid=None, name=self._name, msg=msg) + msg = f"service {name!r} does not exist" + raise NoSuchProcess(pid=None, name=name, msg=msg) from err else: raise @@ -628,7 +580,7 @@ class WindowsService: # noqa: PLW1641 def description(self): """Service long description.""" - return py2_strencode(cext.winservice_query_descr(self.name())) + return cext.winservice_query_descr(self.name()) # utils @@ -696,12 +648,7 @@ ppid_map = cext.ppid_map # used internally by Process.children() def is_permission_err(exc): """Return True if this is a permission error.""" assert isinstance(exc, OSError), exc - if exc.errno in {errno.EPERM, errno.EACCES}: - return True - # On Python 2 OSError doesn't always have 'winerror'. Sometimes - # it does, in which case the original exception was WindowsError - # (which is a subclass of OSError). - return getattr(exc, "winerror", -1) in { + return isinstance(exc, PermissionError) or exc.winerror in { cext.ERROR_ACCESS_DENIED, cext.ERROR_PRIVILEGE_NOT_HELD, } @@ -712,7 +659,7 @@ def convert_oserror(exc, pid=None, name=None): assert isinstance(exc, OSError), exc if is_permission_err(exc): return AccessDenied(pid=pid, name=name) - if exc.errno == errno.ESRCH: + if isinstance(exc, ProcessLookupError): return NoSuchProcess(pid=pid, name=name) raise exc @@ -725,7 +672,7 @@ def wrap_exceptions(fun): try: return fun(self, *args, **kwargs) except OSError as err: - raise convert_oserror(err, pid=self.pid, name=self._name) + raise convert_oserror(err, pid=self.pid, name=self._name) from err return wrapper @@ -742,7 +689,7 @@ def retry_error_partial_copy(fun): for _ in range(times): # retries for roughly 1 second try: return fun(self, *args, **kwargs) - except WindowsError as _: + except OSError as _: err = _ if err.winerror == ERROR_PARTIAL_COPY: time.sleep(delay) @@ -750,8 +697,8 @@ def retry_error_partial_copy(fun): continue raise msg = ( - "{} retried {} times, converted to AccessDenied as it's still" - "returning {}".format(fun, times, err) + f"{fun} retried {times} times, converted to AccessDenied as it's " + f"still returning {err}" ) raise AccessDenied(pid=self.pid, name=self._name, msg=msg) @@ -805,17 +752,15 @@ class Process: if PYPY: try: exe = cext.proc_exe(self.pid) - except WindowsError as err: + except OSError as err: # 24 = ERROR_TOO_MANY_OPEN_FILES. Not sure why this happens # (perhaps PyPy's JIT delaying garbage collection of files?). if err.errno == 24: - debug("%r translated into AccessDenied" % err) - raise AccessDenied(self.pid, self._name) + debug(f"{err!r} translated into AccessDenied") + raise AccessDenied(self.pid, self._name) from err raise else: exe = cext.proc_exe(self.pid) - if not PY3: - exe = py2_strencode(exe) if exe.startswith('\\'): return convert_dos_path(exe) return exe # May be "Registry", "MemCompression", ... @@ -827,32 +772,26 @@ class Process: # PEB method detects cmdline changes but requires more # privileges: https://github.com/giampaolo/psutil/pull/1398 try: - ret = cext.proc_cmdline(self.pid, use_peb=True) + return cext.proc_cmdline(self.pid, use_peb=True) except OSError as err: if is_permission_err(err): - ret = cext.proc_cmdline(self.pid, use_peb=False) + return cext.proc_cmdline(self.pid, use_peb=False) else: raise else: - ret = cext.proc_cmdline(self.pid, use_peb=True) - if PY3: - return ret - else: - return [py2_strencode(s) for s in ret] + return cext.proc_cmdline(self.pid, use_peb=True) @wrap_exceptions @retry_error_partial_copy def environ(self): - ustr = cext.proc_environ(self.pid) - if ustr and not PY3: - assert isinstance(ustr, unicode), type(ustr) - return parse_environ_block(py2_strencode(ustr)) + s = cext.proc_environ(self.pid) + return parse_environ_block(s) def ppid(self): try: return ppid_map()[self.pid] except KeyError: - raise NoSuchProcess(self.pid, self._name) + raise NoSuchProcess(self.pid, self._name) from None def _get_raw_meminfo(self): try: @@ -900,12 +839,10 @@ class Process: except OSError as err: # XXX - can't use wrap_exceptions decorator as we're # returning a generator; probably needs refactoring. - raise convert_oserror(err, self.pid, self._name) + raise convert_oserror(err, self.pid, self._name) from err else: for addr, perm, path, rss in raw: path = convert_dos_path(path) - if not PY3: - path = py2_strencode(path) addr = hex(addr) yield (addr, perm, path, rss) @@ -917,11 +854,7 @@ class Process: def send_signal(self, sig): if sig == signal.SIGTERM: cext.proc_kill(self.pid) - # py >= 2.7 - elif sig in { - getattr(signal, "CTRL_C_EVENT", object()), - getattr(signal, "CTRL_BREAK_EVENT", object()), - }: + elif sig in {signal.CTRL_C_EVENT, signal.CTRL_BREAK_EVENT}: os.kill(self.pid, sig) else: msg = ( @@ -946,9 +879,9 @@ class Process: # May also be None if OpenProcess() failed with # ERROR_INVALID_PARAMETER, meaning PID is already gone. exit_code = cext.proc_wait(self.pid, cext_timeout) - except cext.TimeoutExpired: + except cext.TimeoutExpired as err: # WaitForSingleObject() returned WAIT_TIMEOUT. Just raise. - raise TimeoutExpired(timeout, self.pid, self._name) + raise TimeoutExpired(timeout, self.pid, self._name) from err except cext.TimeoutAbandoned: # WaitForSingleObject() returned WAIT_ABANDONED, see: # https://github.com/giampaolo/psutil/issues/1224 @@ -978,7 +911,7 @@ class Process: if self.pid in {0, 4}: return 'NT AUTHORITY\\SYSTEM' domain, user = cext.proc_username(self.pid) - return py2_strencode(domain) + '\\' + py2_strencode(user) + return f"{domain}\\{user}" @wrap_exceptions def create_time(self, fast_only=False): @@ -1038,7 +971,7 @@ class Process: # return a normalized pathname since the native C function appends # "\\" at the and of the path path = cext.proc_cwd(self.pid) - return py2_strencode(os.path.normpath(path)) + return os.path.normpath(path) @wrap_exceptions def open_files(self): @@ -1050,12 +983,10 @@ class Process: # Convert the first part in the corresponding drive letter # (e.g. "C:\") by using Windows's QueryDosDevice() raw_file_names = cext.proc_open_files(self.pid) - for _file in raw_file_names: - _file = convert_dos_path(_file) - if isfile_strict(_file): - if not PY3: - _file = py2_strencode(_file) - ntuple = _common.popenfile(_file, -1) + for file in raw_file_names: + file = convert_dos_path(file) + if isfile_strict(file): + ntuple = _common.popenfile(file, -1) ret.add(ntuple) return list(ret) @@ -1066,8 +997,7 @@ class Process: @wrap_exceptions def nice_get(self): value = cext.proc_priority_get(self.pid) - if enum is not None: - value = Priority(value) + value = Priority(value) return value @wrap_exceptions @@ -1077,8 +1007,7 @@ class Process: @wrap_exceptions def ionice_get(self): ret = cext.proc_io_priority_get(self.pid) - if enum is not None: - ret = IOPriority(ret) + ret = IOPriority(ret) return ret @wrap_exceptions @@ -1087,12 +1016,13 @@ class Process: msg = "value argument not accepted on Windows" raise TypeError(msg) if ioclass not in { - IOPRIO_VERYLOW, - IOPRIO_LOW, - IOPRIO_NORMAL, - IOPRIO_HIGH, + IOPriority.IOPRIO_VERYLOW, + IOPriority.IOPRIO_LOW, + IOPriority.IOPRIO_NORMAL, + IOPriority.IOPRIO_HIGH, }: - raise ValueError("%s is not a valid priority" % ioclass) + msg = f"{ioclass} is not a valid priority" + raise ValueError(msg) cext.proc_io_priority_set(self.pid, ioclass) @wrap_exceptions @@ -1134,7 +1064,8 @@ class Process: def cpu_affinity_set(self, value): def to_bitmask(ls): if not ls: - raise ValueError("invalid argument %r" % ls) + msg = f"invalid argument {ls!r}" + raise ValueError(msg) out = 0 for b in ls: out |= 2**b @@ -1146,12 +1077,11 @@ class Process: allcpus = list(range(len(per_cpu_times()))) for cpu in value: if cpu not in allcpus: - if not isinstance(cpu, (int, long)): - raise TypeError( - "invalid CPU %r; an integer is required" % cpu - ) - else: - raise ValueError("invalid CPU %r" % cpu) + if not isinstance(cpu, int): + msg = f"invalid CPU {cpu!r}; an integer is required" + raise TypeError(msg) + msg = f"invalid CPU {cpu!r}" + raise ValueError(msg) bitmask = to_bitmask(value) cext.proc_cpu_affinity_set(self.pid, bitmask) diff --git a/contrib/python/psutil/py3/psutil/arch/linux/proc.c b/contrib/python/psutil/py3/psutil/arch/linux/proc.c index b58a3ce2a24..f8230ee75b0 100644 --- a/contrib/python/psutil/py3/psutil/arch/linux/proc.c +++ b/contrib/python/psutil/py3/psutil/arch/linux/proc.c @@ -118,11 +118,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { cpucount_s = CPU_COUNT_S(setsize, mask); for (cpu = 0, count = cpucount_s; count; cpu++) { if (CPU_ISSET_S(cpu, setsize, mask)) { -#if PY_MAJOR_VERSION >= 3 PyObject *cpu_num = PyLong_FromLong(cpu); -#else - PyObject *cpu_num = PyInt_FromLong(cpu); -#endif if (cpu_num == NULL) goto error; if (PyList_Append(py_list, cpu_num)) { @@ -159,11 +155,7 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { if (!PySequence_Check(py_cpu_set)) { return PyErr_Format( PyExc_TypeError, -#if PY_MAJOR_VERSION >= 3 "sequence argument expected, got %R", Py_TYPE(py_cpu_set) -#else - "sequence argument expected, got %s", Py_TYPE(py_cpu_set)->tp_name -#endif ); } @@ -177,11 +169,7 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { if (!item) { return NULL; } -#if PY_MAJOR_VERSION >= 3 long value = PyLong_AsLong(item); -#else - long value = PyInt_AsLong(item); -#endif Py_XDECREF(item); if ((value == -1) || PyErr_Occurred()) { if (!PyErr_Occurred()) diff --git a/contrib/python/psutil/py3/psutil/arch/osx/disk.c b/contrib/python/psutil/py3/psutil/arch/osx/disk.c index d02cf794d5d..e1a8f5a4927 100644 --- a/contrib/python/psutil/py3/psutil/arch/osx/disk.c +++ b/contrib/python/psutil/py3/psutil/arch/osx/disk.c @@ -168,7 +168,6 @@ psutil_disk_usage_used(PyObject *self, PyObject *args) { PyObject *py_mount_point_bytes = NULL; char* mount_point; -#if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTuple(args, "O&O", PyUnicode_FSConverter, &py_mount_point_bytes, &py_default_value)) { return NULL; } @@ -177,11 +176,6 @@ psutil_disk_usage_used(PyObject *self, PyObject *args) { Py_XDECREF(py_mount_point_bytes); return NULL; } -#else - if (!PyArg_ParseTuple(args, "sO", &mount_point, &py_default_value)) { - return NULL; - } -#endif #ifdef ATTR_VOL_SPACEUSED /* Call getattrlist(ATTR_VOL_SPACEUSED) to get used space info. */ diff --git a/contrib/python/psutil/py3/psutil/arch/osx/mem.c b/contrib/python/psutil/py3/psutil/arch/osx/mem.c index 53493065c27..8103876070a 100644 --- a/contrib/python/psutil/py3/psutil/arch/osx/mem.c +++ b/contrib/python/psutil/py3/psutil/arch/osx/mem.c @@ -8,6 +8,9 @@ // from psutil/_psutil_osx.c in 2023. This is the GIT blame before the move: // https://github.com/giampaolo/psutil/blame/efd7ed3/psutil/_psutil_osx.c +// See: +// https://github.com/apple-open-source/macos/blob/master/system_cmds/vm_stat/vm_stat.c + #include <Python.h> #include <mach/host_info.h> #include <sys/sysctl.h> @@ -17,12 +20,12 @@ static int -psutil_sys_vminfo(vm_statistics_data_t *vmstat) { +psutil_sys_vminfo(vm_statistics64_t vmstat) { kern_return_t ret; - mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t); + unsigned int count = HOST_VM_INFO64_COUNT; mach_port_t mport = mach_host_self(); - ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)vmstat, &count); + ret = host_statistics64(mport, HOST_VM_INFO64, (host_info64_t)vmstat, &count); if (ret != KERN_SUCCESS) { PyErr_Format( PyExc_RuntimeError, @@ -46,7 +49,7 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { int mib[2]; uint64_t total; size_t len = sizeof(total); - vm_statistics_data_t vm; + vm_statistics64_data_t vm; long pagesize = psutil_getpagesize(); // physical mem mib[0] = CTL_HW; @@ -86,7 +89,7 @@ psutil_swap_mem(PyObject *self, PyObject *args) { int mib[2]; size_t size; struct xsw_usage totals; - vm_statistics_data_t vmstat; + vm_statistics64_data_t vmstat; long pagesize = psutil_getpagesize(); mib[0] = CTL_VM; diff --git a/contrib/python/psutil/py3/psutil/arch/osx/proc.c b/contrib/python/psutil/py3/psutil/arch/osx/proc.c index 136311ecee4..681642c3ad9 100644 --- a/contrib/python/psutil/py3/psutil/arch/osx/proc.c +++ b/contrib/python/psutil/py3/psutil/arch/osx/proc.c @@ -763,7 +763,7 @@ error: /* * Return process open files as a Python tuple. * References: - * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd + * - lsof source code: https://github.com/apple-opensource/lsof/blob/28/lsof/dialects/darwin/libproc/dproc.c#L342 * - /usr/include/sys/proc_info.h */ PyObject * @@ -854,7 +854,7 @@ error: * Return process TCP and UDP connections as a list of tuples. * Raises NSP in case of zombie process. * References: - * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0 + * - lsof source code: https://github.com/apple-opensource/lsof/blob/28/lsof/dialects/darwin/libproc/dproc.c#L342 * - /usr/include/sys/proc_info.h */ PyObject * diff --git a/contrib/python/psutil/py3/psutil/arch/windows/disk.c b/contrib/python/psutil/py3/psutil/arch/windows/disk.c index 88469e3a617..d0405a98f84 100644 --- a/contrib/python/psutil/py3/psutil/arch/windows/disk.c +++ b/contrib/python/psutil/py3/psutil/arch/windows/disk.c @@ -45,33 +45,6 @@ PyObject * psutil_disk_usage(PyObject *self, PyObject *args) { BOOL retval; ULARGE_INTEGER _, total, free; - -#if PY_MAJOR_VERSION <= 2 - char *path; - - if (PyArg_ParseTuple(args, "u", &path)) { - Py_BEGIN_ALLOW_THREADS - retval = GetDiskFreeSpaceExW((LPCWSTR)path, &_, &total, &free); - Py_END_ALLOW_THREADS - goto return_; - } - - // on Python 2 we also want to accept plain strings other - // than Unicode - PyErr_Clear(); // drop the argument parsing error - if (PyArg_ParseTuple(args, "s", &path)) { - Py_BEGIN_ALLOW_THREADS - retval = GetDiskFreeSpaceEx(path, &_, &total, &free); - Py_END_ALLOW_THREADS - goto return_; - } - - return NULL; - -return_: - if (retval == 0) - return PyErr_SetFromWindowsErrWithFilename(0, path); -#else PyObject *py_path; wchar_t *path; @@ -92,7 +65,7 @@ return_: if (retval == 0) return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, py_path); -#endif + return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); } diff --git a/contrib/python/psutil/py3/psutil/arch/windows/net.c b/contrib/python/psutil/py3/psutil/arch/windows/net.c index 8d8f7d1c0aa..9a5634b0693 100644 --- a/contrib/python/psutil/py3/psutil/arch/windows/net.c +++ b/contrib/python/psutil/py3/psutil/arch/windows/net.c @@ -255,21 +255,14 @@ psutil_net_if_addrs(PyObject *self, PyObject *args) { continue; } -#if PY_MAJOR_VERSION >= 3 py_address = PyUnicode_FromString(buff_addr); -#else - py_address = PyString_FromString(buff_addr); -#endif if (py_address == NULL) goto error; if (netmaskIntRet != NULL) { -#if PY_MAJOR_VERSION >= 3 py_netmask = PyUnicode_FromString(buff_netmask); -#else - py_netmask = PyString_FromString(buff_netmask); -#endif - } else { + } + else { Py_INCREF(Py_None); py_netmask = Py_None; } diff --git a/contrib/python/psutil/py3/psutil/arch/windows/proc.c b/contrib/python/psutil/py3/psutil/arch/windows/proc.c index 05fb5025579..41fa9dda680 100644 --- a/contrib/python/psutil/py3/psutil/arch/windows/proc.c +++ b/contrib/python/psutil/py3/psutil/arch/windows/proc.c @@ -192,11 +192,7 @@ psutil_proc_wait(PyObject *self, PyObject *args) { CloseHandle(hProcess); -#if PY_MAJOR_VERSION >= 3 return PyLong_FromLong((long) ExitCode); -#else - return PyInt_FromLong((long) ExitCode); -#endif } diff --git a/contrib/python/psutil/py3/ya.make b/contrib/python/psutil/py3/ya.make index c81c1dffb82..fd48170ac2b 100644 --- a/contrib/python/psutil/py3/ya.make +++ b/contrib/python/psutil/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(6.1.1) +VERSION(7.0.0) LICENSE(BSD-3-Clause) @@ -27,7 +27,7 @@ NO_CHECK_IMPORTS( NO_UTIL() CFLAGS( - -DPSUTIL_VERSION=611 + -DPSUTIL_VERSION=700 ) SRCS( @@ -125,7 +125,6 @@ PY_SRCS( TOP_LEVEL psutil/__init__.py psutil/_common.py - psutil/_compat.py psutil/_psaix.py psutil/_psbsd.py psutil/_pslinux.py |