diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index fa2a6023d..2e08c0122 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -59,7 +59,7 @@ jobs:
if: matrix.archs == 'aarch64'
- name: Create wheels + run tests
- uses: pypa/cibuildwheel@v2.16.2
+ uses: pypa/cibuildwheel@v2.16.5
with:
config-file: "./cibuildwheel.toml"
env:
diff --git a/CREDITS b/CREDITS
index 59715ac76..a3206bb9a 100644
--- a/CREDITS
+++ b/CREDITS
@@ -817,3 +817,11 @@ I: 2010
N: Oliver Tomé
W: https://github.com/snom3ad
I: 2222
+
+N: Ryan Carsten Schmidt
+W: https://github.com/ryandesign
+I: 2361
+
+N: Shade Gladden
+W: https://github.com/shadeyg56
+I: 2376
\ No newline at end of file
diff --git a/HISTORY.rst b/HISTORY.rst
index e0316f66c..ed4223374 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,10 +1,24 @@
*Bug tracker at https://github.com/giampaolo/psutil/issues*
-5.9.8 (IN DEVELOPMENT)
+5.9.9 (IN DEVELOPMENT)
======================
**Enhancements**
+- 2366_, [Windows]: log debug message when using slower process APIs.
+
+**Bug fixes**
+
+- 2360_, [macOS]: can't compile on macOS < 10.13. (patch by Ryan Schmidt)
+- 2254_, [Linux]: offline cpus raise NotImplementedError in cpu_freq() (patch by Shade Gladden)
+
+5.9.8
+=====
+
+2024-01-19
+
+**Enhancements**
+
- 2343_, [FreeBSD]: filter `net_connections()`_ returned list in C instead of
Python, and avoid to retrieve unnecessary connection types unless explicitly
asked. E.g., on an IDLE system with few IPv6 connections this will run around
@@ -19,7 +33,7 @@
It could either leak memory or core dump.
- 2340_, [NetBSD]: if process is terminated, `Process.cwd()`_ will return an
empty string instead of raising `NoSuchProcess`_.
-- 2345_, [Linux]: fix compilation on older compiler missing DUPLEX_UNKNOWN
+- 2345_, [Linux]: fix compilation on older compiler missing DUPLEX_UNKNOWN.
- 2222_, [macOS]: `cpu_freq()` now returns fixed values for `min` and `max`
frequencies in all Apple Silicon chips.
diff --git a/Makefile b/Makefile
index 34279c90a..1ab660119 100644
--- a/Makefile
+++ b/Makefile
@@ -103,11 +103,13 @@ install-pip: ## Install pip (no-op if already installed).
@$(PYTHON) -c \
"import sys, ssl, os, pkgutil, tempfile, atexit; \
sys.exit(0) if pkgutil.find_loader('pip') else None; \
- pyexc = 'from urllib.request import urlopen' if sys.version_info[0] == 3 else 'from urllib2 import urlopen'; \
+ PY3 = sys.version_info[0] == 3; \
+ pyexc = 'from urllib.request import urlopen' if PY3 else 'from urllib2 import urlopen'; \
exec(pyexc); \
ctx = ssl._create_unverified_context() if hasattr(ssl, '_create_unverified_context') else None; \
+ url = 'https://bootstrap.pypa.io/pip/2.7/get-pip.py' if not PY3 else 'https://bootstrap.pypa.io/get-pip.py'; \
kw = dict(context=ctx) if ctx else {}; \
- req = urlopen('https://bootstrap.pypa.io/get-pip.py', **kw); \
+ req = urlopen(url, **kw); \
data = req.read(); \
f = tempfile.NamedTemporaryFile(suffix='.py'); \
atexit.register(f.close); \
diff --git a/README.rst b/README.rst
index 65f53aeca..e739c75a2 100644
--- a/README.rst
+++ b/README.rst
@@ -171,6 +171,7 @@ Supporters
+
add your avatar
diff --git a/docs/conf.py b/docs/conf.py
index f2b05483c..3ebc64178 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,5 +1,9 @@
# -*- 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.
+
# psutil documentation build configuration file, created by
# sphinx-quickstart on Wed Oct 19 21:54:30 2016.
#
diff --git a/docs/index.rst b/docs/index.rst
index cc0f7dcca..fc4cddc24 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -2650,9 +2650,13 @@ PyPy3.
Timeline
========
+- 2024-01-19:
+ `5.9.8 `__ -
+ `what's new `__ -
+ `diff `__
- 2023-12-17:
`5.9.7 `__ -
- `what's new `__ -
+ `what's new `__ -
`diff `__
- 2023-10-15:
`5.9.6 `__ -
diff --git a/psutil/_compat.py b/psutil/_compat.py
index 3db56c601..6070c2a04 100644
--- a/psutil/_compat.py
+++ b/psutil/_compat.py
@@ -23,7 +23,7 @@
# builtins
"long", "range", "super", "unicode", "basestring",
# literals
- "u", "b",
+ "b",
# collections module
"lru_cache",
# shutil module
@@ -47,9 +47,6 @@
basestring = str
range = range
- def u(s):
- return s
-
def b(s):
return s.encode("latin-1")
@@ -59,9 +56,6 @@ def b(s):
unicode = unicode
basestring = basestring
- def u(s):
- return unicode(s, "unicode_escape")
-
def b(s):
return s
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index 798dd3651..2a59bfe13 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -60,7 +60,6 @@
# fmt: off
__extra__all__ = [
- #
'PROCFS_PATH',
# io prio constants
"IOPRIO_CLASS_NONE", "IOPRIO_CLASS_RT", "IOPRIO_CLASS_BE",
@@ -780,6 +779,13 @@ def cpu_freq():
# 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)
+ )
+ # 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))
+ continue
msg = "can't find current frequency file"
raise NotImplementedError(msg)
curr = int(curr) / 1000
@@ -1355,7 +1361,7 @@ def disk_partitions(all=False):
if device in ("/dev/root", "rootfs"):
device = RootFsDeviceFinder().find() or device
if not all:
- if device == '' or fstype not in fstypes:
+ if not device or fstype not in fstypes:
continue
maxfile = maxpath = None # set later
ntuple = _common.sdiskpart(
@@ -2101,7 +2107,7 @@ def get_blocks(lines, current_block):
path
):
path = path[:-10]
- ls.append((
+ item = (
decode(addr),
decode(perms),
path,
@@ -2115,7 +2121,8 @@ def get_blocks(lines, current_block):
data.get(b'Referenced:', 0),
data.get(b'Anonymous:', 0),
data.get(b'Swap:', 0),
- ))
+ )
+ ls.append(item)
return ls
@wrap_exceptions
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index 2d3a0c9fd..8db66f0a0 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -239,7 +239,6 @@ def virtual_memory():
"""System virtual memory as a namedtuple."""
mem = cext.virtual_mem()
totphys, availphys, totsys, availsys = mem
- #
total = totphys
avail = availphys
free = availphys
@@ -515,7 +514,7 @@ def win_service_get(name):
return service
-class WindowsService:
+class WindowsService: # noqa: PLW1641
"""Represents an installed Windows service."""
def __init__(self, name, display_name):
@@ -865,6 +864,7 @@ def _get_raw_meminfo(self):
if is_permission_err(err):
# TODO: the C ext can probably be refactored in order
# to get this from cext.proc_info()
+ debug("attempting memory_info() fallback (slower)")
info = self._proc_info()
return (
info[pinfo_map['num_page_faults']],
@@ -992,6 +992,7 @@ def create_time(self):
return created
except OSError as err:
if is_permission_err(err):
+ debug("attempting create_time() fallback (slower)")
return self._proc_info()[pinfo_map['create_time']]
raise
@@ -1015,6 +1016,7 @@ def cpu_times(self):
except OSError as err:
if not is_permission_err(err):
raise
+ debug("attempting cpu_times() fallback (slower)")
info = self._proc_info()
user = info[pinfo_map['user_time']]
system = info[pinfo_map['kernel_time']]
@@ -1101,6 +1103,7 @@ def io_counters(self):
except OSError as err:
if not is_permission_err(err):
raise
+ debug("attempting io_counters() fallback (slower)")
info = self._proc_info()
ret = (
info[pinfo_map['io_rcount']],
@@ -1160,6 +1163,7 @@ def num_handles(self):
return cext.proc_num_handles(self.pid)
except OSError as err:
if is_permission_err(err):
+ debug("attempting num_handles() fallback (slower)")
return self._proc_info()[pinfo_map['num_handles']]
raise
diff --git a/psutil/arch/osx/net.c b/psutil/arch/osx/net.c
index e9cc61e9b..24ce1b834 100644
--- a/psutil/arch/osx/net.c
+++ b/psutil/arch/osx/net.c
@@ -9,11 +9,11 @@
// https://github.com/giampaolo/psutil/blame/efd7ed3/psutil/_psutil_osx.c
#include
+#include
#include
#include
#include
#include
-#include
#include "../../_psutil_common.h"
diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py
index a900da2ae..ea91d870c 100644
--- a/psutil/tests/__init__.py
+++ b/psutil/tests/__init__.py
@@ -56,7 +56,6 @@
from psutil._compat import FileNotFoundError
from psutil._compat import range
from psutil._compat import super
-from psutil._compat import u
from psutil._compat import unicode
from psutil._compat import which
@@ -192,7 +191,7 @@ def macos_version():
TESTFN_PREFIX = '$psutil-%s-' % os.getpid()
else:
TESTFN_PREFIX = '@psutil-%s-' % os.getpid()
-UNICODE_SUFFIX = u("-ƒőő")
+UNICODE_SUFFIX = u"-ƒőő"
# An invalid unicode string.
if PY3:
INVALID_UNICODE_SUFFIX = b"f\xc0\x80".decode('utf8', 'surrogateescape')
@@ -358,7 +357,7 @@ def wrapper(*args, **kwargs):
@_reap_children_on_err
def spawn_testproc(cmd=None, **kwds):
- """Creates a python subprocess which does nothing for 60 secs and
+ """Create a python subprocess which does nothing for some secs and
return it as a subprocess.Popen instance.
If "cmd" is specified that is used instead of python.
By default stdin and stdout are redirected to /dev/null.
@@ -377,13 +376,13 @@ def spawn_testproc(cmd=None, **kwds):
CREATE_NO_WINDOW = 0x8000000
kwds.setdefault("creationflags", CREATE_NO_WINDOW)
if cmd is None:
- testfn = get_testfn()
+ testfn = get_testfn(dir=os.getcwd())
try:
safe_rmpath(testfn)
pyline = (
- "from time import sleep;"
+ "import time;"
+ "open(r'%s', 'w').close();" % testfn
- + "[sleep(0.1) for x in range(100)];" # 10 secs
+ + "[time.sleep(0.1) for x in range(100)];" # 10 secs
)
cmd = [PYTHON_EXE, "-c", pyline]
sproc = subprocess.Popen(cmd, **kwds)
@@ -743,9 +742,9 @@ def wrapper(*args, **kwargs):
self.sleep()
continue
if PY3:
- raise exc
+ raise exc # noqa: PLE0704
else:
- raise
+ raise # noqa: PLE0704
# This way the user of the decorated function can change config
# parameters.
@@ -766,9 +765,6 @@ def wait_for_pid(pid):
if pid not in psutil.pids():
raise psutil.NoSuchProcess(pid)
psutil.Process(pid)
- if WINDOWS:
- # give it some more time to allow better initialization
- time.sleep(0.01)
@retry(
@@ -1953,7 +1949,7 @@ def is_namedtuple(x):
"""Check if object is an instance of namedtuple."""
t = type(x)
b = t.__bases__
- if len(b) != 1 or b[0] != tuple:
+ if len(b) != 1 or b[0] is not tuple:
return False
f = getattr(t, '_fields', None)
if not isinstance(f, tuple):
diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py
index 6c74d337c..360ba25b0 100755
--- a/psutil/tests/test_linux.py
+++ b/psutil/tests/test_linux.py
@@ -28,7 +28,6 @@
from psutil._compat import PY3
from psutil._compat import FileNotFoundError
from psutil._compat import basestring
-from psutil._compat import u
from psutil.tests import GITHUB_ACTIONS
from psutil.tests import GLOBAL_TIMEOUT
from psutil.tests import HAS_BATTERY
@@ -122,7 +121,7 @@ def get_ipv4_broadcast(ifname):
def get_ipv6_addresses(ifname):
with open("/proc/net/if_inet6") as f:
all_fields = []
- for line in f.readlines():
+ for line in f:
fields = line.split()
if fields[-1] == ifname:
all_fields.append(fields)
@@ -1220,7 +1219,7 @@ def test_zfs_fs(self):
raise self.fail("couldn't find any ZFS partition")
else:
# No ZFS partitions on this system. Let's fake one.
- fake_file = io.StringIO(u("nodev\tzfs\n"))
+ fake_file = io.StringIO(u"nodev\tzfs\n")
with mock.patch(
'psutil._common.open', return_value=fake_file, create=True
) as m1:
@@ -1344,7 +1343,6 @@ def test_emulate_exclude_partitions(self):
ret = psutil.disk_io_counters(perdisk=False, nowrap=False)
self.assertIsNone(ret)
- #
def is_storage_device(name):
return name == 'nvme0n1'
@@ -1657,7 +1655,7 @@ def open_mock(name, *args, **kwargs):
if name.endswith(('AC0/online', 'AC/online')):
raise IOError(errno.ENOENT, "")
elif name.endswith("/status"):
- return io.StringIO(u("charging"))
+ return io.StringIO(u"charging")
else:
return orig_open(name, *args, **kwargs)
@@ -1688,7 +1686,7 @@ def open_mock(name, *args, **kwargs):
if name.endswith(('AC0/online', 'AC/online')):
raise IOError(errno.ENOENT, "")
elif name.endswith("/status"):
- return io.StringIO(u("discharging"))
+ return io.StringIO(u"discharging")
else:
return orig_open(name, *args, **kwargs)
@@ -1762,11 +1760,11 @@ class TestSensorsBatteryEmulated(PsutilTestCase):
def test_it(self):
def open_mock(name, *args, **kwargs):
if name.endswith("/energy_now"):
- return io.StringIO(u("60000000"))
+ return io.StringIO(u"60000000")
elif name.endswith("/power_now"):
- return io.StringIO(u("0"))
+ return io.StringIO(u"0")
elif name.endswith("/energy_full"):
- return io.StringIO(u("60000001"))
+ return io.StringIO(u"60000001")
else:
return orig_open(name, *args, **kwargs)
@@ -1784,9 +1782,9 @@ class TestSensorsTemperatures(PsutilTestCase):
def test_emulate_class_hwmon(self):
def open_mock(name, *args, **kwargs):
if name.endswith('/name'):
- return io.StringIO(u("name"))
+ return io.StringIO(u"name")
elif name.endswith('/temp1_label'):
- return io.StringIO(u("label"))
+ return io.StringIO(u"label")
elif name.endswith('/temp1_input'):
return io.BytesIO(b"30000")
elif name.endswith('/temp1_max'):
@@ -1816,9 +1814,9 @@ def open_mock(name, *args, **kwargs):
elif name.endswith('temp'):
return io.BytesIO(b"30000")
elif name.endswith('0_type'):
- return io.StringIO(u("critical"))
+ return io.StringIO(u"critical")
elif name.endswith('type'):
- return io.StringIO(u("name"))
+ return io.StringIO(u"name")
else:
return orig_open(name, *args, **kwargs)
@@ -1852,11 +1850,11 @@ class TestSensorsFans(PsutilTestCase):
def test_emulate_data(self):
def open_mock(name, *args, **kwargs):
if name.endswith('/name'):
- return io.StringIO(u("name"))
+ return io.StringIO(u"name")
elif name.endswith('/fan1_label'):
- return io.StringIO(u("label"))
+ return io.StringIO(u"label")
elif name.endswith('/fan1_input'):
- return io.StringIO(u("2000"))
+ return io.StringIO(u"2000")
else:
return orig_open(name, *args, **kwargs)
@@ -1938,7 +1936,6 @@ def get_test_file(fname):
break
raise RuntimeError("timeout looking for test file")
- #
testfn = self.get_testfn()
with open(testfn, "w"):
self.assertEqual(get_test_file(testfn).mode, "w")
@@ -1946,7 +1943,6 @@ def get_test_file(fname):
self.assertEqual(get_test_file(testfn).mode, "r")
with open(testfn, "a"):
self.assertEqual(get_test_file(testfn).mode, "a")
- #
with open(testfn, "r+"):
self.assertEqual(get_test_file(testfn).mode, "r+")
with open(testfn, "w+"):
@@ -2038,13 +2034,13 @@ def test_terminal_mocked(self):
def test_cmdline_mocked(self):
# see: https://github.com/giampaolo/psutil/issues/639
p = psutil.Process()
- fake_file = io.StringIO(u('foo\x00bar\x00'))
+ fake_file = io.StringIO(u'foo\x00bar\x00')
with mock.patch(
'psutil._common.open', return_value=fake_file, create=True
) as m:
self.assertEqual(p.cmdline(), ['foo', 'bar'])
assert m.called
- fake_file = io.StringIO(u('foo\x00bar\x00\x00'))
+ fake_file = io.StringIO(u'foo\x00bar\x00\x00')
with mock.patch(
'psutil._common.open', return_value=fake_file, create=True
) as m:
@@ -2054,13 +2050,13 @@ def test_cmdline_mocked(self):
def test_cmdline_spaces_mocked(self):
# see: https://github.com/giampaolo/psutil/issues/1179
p = psutil.Process()
- fake_file = io.StringIO(u('foo bar '))
+ fake_file = io.StringIO(u'foo bar ')
with mock.patch(
'psutil._common.open', return_value=fake_file, create=True
) as m:
self.assertEqual(p.cmdline(), ['foo', 'bar'])
assert m.called
- fake_file = io.StringIO(u('foo bar '))
+ fake_file = io.StringIO(u'foo bar ')
with mock.patch(
'psutil._common.open', return_value=fake_file, create=True
) as m:
@@ -2071,7 +2067,7 @@ def test_cmdline_mixed_separators(self):
# https://github.com/giampaolo/psutil/issues/
# 1179#issuecomment-552984549
p = psutil.Process()
- fake_file = io.StringIO(u('foo\x20bar\x00'))
+ fake_file = io.StringIO(u'foo\x20bar\x00')
with mock.patch(
'psutil._common.open', return_value=fake_file, create=True
) as m:
diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py
index 0b12e77f5..0dd433db7 100755
--- a/psutil/tests/test_process.py
+++ b/psutil/tests/test_process.py
@@ -758,7 +758,7 @@ def test_cmdline(self):
def test_long_cmdline(self):
cmdline = [PYTHON_EXE]
cmdline.extend(["-v"] * 50)
- cmdline.extend(["-c", "time.sleep(10)"])
+ cmdline.extend(["-c", "import time; time.sleep(10)"])
p = self.spawn_psproc(cmdline)
if OPENBSD:
# XXX: for some reason the test process may turn into a
@@ -782,7 +782,7 @@ def test_name(self):
@unittest.skipIf(QEMU_USER, "unreliable on QEMU user")
def test_long_name(self):
pyexe = create_py_exe(self.get_testfn(suffix="0123456789" * 2))
- cmdline = [pyexe, "-c", "time.sleep(10)"]
+ cmdline = [pyexe, "-c", "import time; time.sleep(10)"]
p = self.spawn_psproc(cmdline)
if OPENBSD:
# XXX: for some reason the test process may turn into a
@@ -812,7 +812,7 @@ def test_prog_w_funky_name(self):
# with funky chars such as spaces and ")", see:
# https://github.com/giampaolo/psutil/issues/628
pyexe = create_py_exe(self.get_testfn(suffix='foo bar )'))
- cmdline = [pyexe, "-c", "time.sleep(10)"]
+ cmdline = [pyexe, "-c", "import time; time.sleep(10)"]
p = self.spawn_psproc(cmdline)
self.assertEqual(p.cmdline(), cmdline)
self.assertEqual(p.name(), os.path.basename(pyexe))
@@ -979,7 +979,7 @@ def test_cpu_affinity(self):
self.assertEqual(
p.cpu_affinity(), list(os.sched_getaffinity(p.pid))
)
- #
+
self.assertRaises(TypeError, p.cpu_affinity, 1)
p.cpu_affinity(initial)
# it should work with all iterables, not only lists
@@ -1359,7 +1359,7 @@ def assert_raises_nsp(fun, fun_name):
@unittest.skipIf(not POSIX, 'POSIX only')
def test_zombie_process(self):
- parent, zombie = self.spawn_zombie()
+ _parent, zombie = self.spawn_zombie()
self.assertProcessZombie(zombie)
@unittest.skipIf(not POSIX, 'POSIX only')
diff --git a/psutil/tests/test_process_all.py b/psutil/tests/test_process_all.py
index f6e821e0d..8b915deb3 100755
--- a/psutil/tests/test_process_all.py
+++ b/psutil/tests/test_process_all.py
@@ -28,6 +28,7 @@
from psutil import POSIX
from psutil import WINDOWS
from psutil._compat import PY3
+from psutil._compat import FileNotFoundError
from psutil._compat import long
from psutil._compat import unicode
from psutil.tests import CI_TESTING
diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py
index 8c2d988dd..6707082f6 100755
--- a/psutil/tests/test_system.py
+++ b/psutil/tests/test_system.py
@@ -345,7 +345,7 @@ def test_cpu_count_logical(self):
self.assertIsNotNone(logical)
self.assertEqual(logical, len(psutil.cpu_times(percpu=True)))
self.assertGreaterEqual(logical, 1)
- #
+
if os.path.exists("/proc/cpuinfo"):
with open("/proc/cpuinfo") as fd:
cpuinfo_data = fd.read()
diff --git a/psutil/tests/test_unicode.py b/psutil/tests/test_unicode.py
index ab06cebed..d09003d27 100755
--- a/psutil/tests/test_unicode.py
+++ b/psutil/tests/test_unicode.py
@@ -85,7 +85,6 @@
from psutil import WINDOWS
from psutil._compat import PY3
from psutil._compat import super
-from psutil._compat import u
from psutil.tests import APPVEYOR
from psutil.tests import ASCII_FS
from psutil.tests import CI_TESTING
@@ -190,7 +189,7 @@ class TestFSAPIs(BaseUnicodeTest):
def expect_exact_path_match(self):
# Do not expect psutil to correctly handle unicode paths on
# Python 2 if os.listdir() is not able either.
- here = '.' if isinstance(self.funky_name, str) else u('.')
+ here = '.' if isinstance(self.funky_name, str) else u'.'
with warnings.catch_warnings():
warnings.simplefilter("ignore")
return self.funky_name in os.listdir(here)
@@ -198,7 +197,7 @@ def expect_exact_path_match(self):
# ---
def test_proc_exe(self):
- cmd = [self.funky_name, "-c", "time.sleep(10)"]
+ cmd = [self.funky_name, "-c", "import time; time.sleep(10)"]
subp = self.spawn_testproc(cmd)
p = psutil.Process(subp.pid)
exe = p.exe()
@@ -209,7 +208,7 @@ def test_proc_exe(self):
)
def test_proc_name(self):
- cmd = [self.funky_name, "-c", "time.sleep(10)"]
+ cmd = [self.funky_name, "-c", "import time; time.sleep(10)"]
subp = self.spawn_testproc(cmd)
name = psutil.Process(subp.pid).name()
self.assertIsInstance(name, str)
@@ -217,7 +216,7 @@ def test_proc_name(self):
self.assertEqual(name, os.path.basename(self.funky_name))
def test_proc_cmdline(self):
- cmd = [self.funky_name, "-c", "time.sleep(10)"]
+ cmd = [self.funky_name, "-c", "import time; time.sleep(10)"]
subp = self.spawn_testproc(cmd)
p = psutil.Process(subp.pid)
cmdline = p.cmdline()
diff --git a/pyproject.toml b/pyproject.toml
index 677722dbe..0625af1fd 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,13 +1,18 @@
[tool.black]
+target-version = ["py37"]
line-length = 79
skip-string-normalization = true
+# https://black.readthedocs.io/en/stable/the_black_code_style/future_style.html
preview = true
-target-version = ["py37"]
+enable-unstable-feature = ["hug_parens_with_braces_and_square_brackets", "multiline_string_handling", "string_processing", "wrap_long_dict_values_in_parens"]
[tool.ruff]
# https://beta.ruff.rs/docs/settings/
+preview = true
target-version = "py37"
line-length = 79
+
+[tool.ruff.lint]
select = [
# To get a list of all values: `python3 -m ruff linter`.
"ALL",
@@ -29,15 +34,22 @@ ignore = [
"ARG002", # unused-method-argument
"B007", # Loop control variable `x` not used within loop body
"B904", # Within an `except` clause, raise exceptions with `raise ... from err` (PYTHON2.7 COMPAT)
+ "B904", # Use `raise from` to specify exception cause (PYTHON2.7 COMPAT)
"C4", # flake8-comprehensions (PYTHON2.7 COMPAT)
"C90", # mccabe (function `X` is too complex)
"COM812", # Trailing comma missing
"D", # pydocstyle
"DTZ", # flake8-datetimez
"ERA001", # Found commented-out code
+ "F841", # Local variable `parent` is assigned to but never used
"FBT", # flake8-boolean-trap (makes zero sense)
"FIX", # Line contains TODO / XXX / ..., consider resolving the issue
"FLY", # flynt (PYTHON2.7 COMPAT)
+ "FURB101", # `open` and `read` should be replaced by `Path(src).read_text()`
+ "FURB113", # Use `x.extend(('a', 'b', 'c'))` instead of repeatedly calling `x.append()`
+ "FURB118", # [*] Use `operator.add` instead of defining a lambda
+ "FURB140", # [*] Use `itertools.starmap` instead of the generator
+ "FURB145", # [*] Prefer `copy` method over slicing (PYTHON2.7 COMPAT)
"INP", # flake8-no-pep420
"N801", # Class name `async_chat` should use CapWords convention (ASYNCORE COMPAT)
"N802", # Function name X should be lowercase.
@@ -45,13 +57,23 @@ ignore = [
"N818", # Exception name `FooBar` should be named with an Error suffix
"PERF", # Perflint
"PGH004", # Use specific rule codes when using `noqa`
+ "PLC0415", # `import` should be at the top-level of a file
+ "PLC2701", # Private name import `x` from external module `y`
+ "PLR0904", # Too many public methods (x > y)
"PLR0911", # Too many return statements (8 > 6)
"PLR0912", # Too many branches (x > y)
"PLR0913", # Too many arguments in function definition (x > y)
- "PLR0915", # Too many statements (92 > 50)
+ "PLR0914", # Too many local variables (x/y)
+ "PLR0915", # Too many statements (x > y)
+ "PLR0917", # Too many positional arguments (x/y)
+ "PLR1702", # Too many nested blocks (x > y)
+ "PLR1704", # Redefining argument with the local name `type_`
"PLR2004", # Magic value used in comparison, consider replacing X with a constant variable
"PLR5501", # Use `elif` instead of `else` then `if`, to reduce indentation
+ "PLR6201", # Use a `set` literal when testing for membership
+ "PLR6301", # Method `x` could be a function, class method, or static method
"PLW0603", # Using the global statement to update `lineno` is discouraged
+ "PLW1514", # `open` in text mode without explicit `encoding` argument
"PLW2901", # `for` loop variable `x` overwritten by assignment target
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
@@ -66,18 +88,18 @@ ignore = [
"SIM117", # Use a single `with` statement with multiple contexts instead of nested `with` statements
"SLF", # flake8-self
"TD", # all TODOs, XXXs, etc.
- "TRY200", # Use `raise from` to specify exception cause (PYTHON2.7 COMPAT)
"TRY300", # Consider moving this statement to an `else` block
"TRY301", # Abstract `raise` to an inner function
"UP009", # [*] UTF-8 encoding declaration is unnecessary (PYTHON2.7 COMPAT)
"UP010", # [*] Unnecessary `__future__` import `print_function` for target Python version (PYTHON2.7 COMPAT)
"UP024", # [*] Replace aliased errors with `OSError` (PYTHON2.7 COMPAT)
+ "UP025", # [*] Remove unicode literals from strings (PYTHON2.7 COMPAT)
"UP028", # [*] Replace `yield` over `for` loop with `yield from` (PYTHON2.7 COMPAT)
"UP031", # [*] Use format specifiers instead of percent format
"UP032", # [*] Use f-string instead of `format` call (PYTHON2.7 COMPAT)
]
-[tool.ruff.per-file-ignores]
+[tool.ruff.lint.per-file-ignores]
# T201 == print(), T203 == pprint()
# EM101 == raw-string-in-exception
# TRY003 == raise-vanilla-args
@@ -89,7 +111,7 @@ ignore = [
"scripts/internal/*" = ["T201", "T203"]
"setup.py" = ["T201", "T203"]
-[tool.ruff.isort]
+[tool.ruff.lint.isort]
# https://beta.ruff.rs/docs/settings/#isort
force-single-line = true # one import per line
lines-after-imports = 2
diff --git a/scripts/disk_usage.py b/scripts/disk_usage.py
index 934b24a1c..c75c4f61d 100755
--- a/scripts/disk_usage.py
+++ b/scripts/disk_usage.py
@@ -12,6 +12,7 @@
/dev/sda6 345.9G 83.8G 244.5G 24% ext4 /home
/dev/sda1 296.0M 43.1M 252.9M 14% vfat /boot/efi
/dev/sda2 600.0M 312.4M 287.6M 52% fuseblk /media/Recovery
+
"""
import os
@@ -26,7 +27,7 @@ def main():
print(templ % ("Device", "Total", "Used", "Free", "Use ", "Type", "Mount"))
for part in psutil.disk_partitions(all=False):
if os.name == 'nt':
- if 'cdrom' in part.opts or part.fstype == '':
+ if 'cdrom' in part.opts or not part.fstype:
# skip cd-rom drives with no disk in it; they may raise
# ENOENT, pop-up a Windows GUI error for a non-ready
# partition or just hang.
diff --git a/scripts/ifconfig.py b/scripts/ifconfig.py
index 4b4246aaa..e23472ba9 100755
--- a/scripts/ifconfig.py
+++ b/scripts/ifconfig.py
@@ -111,7 +111,7 @@ def main():
print(" netmask : %s" % addr.netmask)
if addr.ptp:
print(" p2p : %s" % addr.ptp)
- print("")
+ print()
if __name__ == '__main__':
diff --git a/scripts/internal/download_wheels_appveyor.py b/scripts/internal/download_wheels_appveyor.py
index e8b0c54e0..0e6490b39 100755
--- a/scripts/internal/download_wheels_appveyor.py
+++ b/scripts/internal/download_wheels_appveyor.py
@@ -65,7 +65,7 @@ def get_file_urls():
print_color("no artifacts found", 'red')
sys.exit(1)
else:
- for url in sorted(urls, key=lambda x: os.path.basename(x)):
+ for url in sorted(urls, key=os.path.basename):
yield url
diff --git a/scripts/internal/print_announce.py b/scripts/internal/print_announce.py
index 9f89f635a..68201d7fc 100755
--- a/scripts/internal/print_announce.py
+++ b/scripts/internal/print_announce.py
@@ -6,6 +6,7 @@
"""Prints release announce based on HISTORY.rst file content.
See: https://pip.pypa.io/en/stable/reference/pip_install/#hash-checking-mode.
+
"""
import os
diff --git a/scripts/internal/print_api_speed.py b/scripts/internal/print_api_speed.py
index adbaa89a0..786644b5a 100755
--- a/scripts/internal/print_api_speed.py
+++ b/scripts/internal/print_api_speed.py
@@ -181,7 +181,7 @@ def main():
print_timings()
# --- process
- print("")
+ print()
print_header("PROCESS APIS")
ignore = [
'send_signal',
diff --git a/scripts/internal/print_downloads.py b/scripts/internal/print_downloads.py
index 09169984d..b453f15b9 100755
--- a/scripts/internal/print_downloads.py
+++ b/scripts/internal/print_downloads.py
@@ -141,7 +141,7 @@ def main():
downs = downloads()
print("# Download stats")
- print("")
+ print()
s = "psutil download statistics of the last %s days (last update " % DAYS
s += "*%s*).\n" % LAST_UPDATE
s += "Generated via [pypistats.py](%s) script.\n" % GITHUB_SCRIPT_URL
diff --git a/scripts/internal/winmake.py b/scripts/internal/winmake.py
index 43db68fd9..b789aa80d 100755
--- a/scripts/internal/winmake.py
+++ b/scripts/internal/winmake.py
@@ -138,7 +138,7 @@ def safe_rmtree(path):
def onerror(fun, path, excinfo):
exc = excinfo[1]
if exc.errno != errno.ENOENT:
- raise
+ raise # noqa: PLE0704
existed = os.path.isdir(path)
shutil.rmtree(path, onerror=onerror)
@@ -181,7 +181,7 @@ def safe_rmtree(path):
def onerror(fun, path, excinfo):
exc = excinfo[1]
if exc.errno != errno.ENOENT:
- raise
+ raise # noqa: PLE0704
existed = os.path.isdir(path)
shutil.rmtree(path, onerror=onerror)
diff --git a/scripts/procsmem.py b/scripts/procsmem.py
index 54e89b05e..eec5cd51a 100755
--- a/scripts/procsmem.py
+++ b/scripts/procsmem.py
@@ -32,6 +32,7 @@
20513 giampao /opt/sublime_text/sublime_text 65.8M 73.0M 0B 87.9M
3976 giampao compiz 115.0M 117.0M 0B 130.9M
32486 giampao skype 145.1M 147.5M 0B 149.6M
+
"""
from __future__ import print_function
@@ -89,8 +90,8 @@ def main():
p.pid,
p._info["username"][:7] if p._info["username"] else "",
convert_bytes(p._uss),
- convert_bytes(p._pss) if p._pss != "" else "",
- convert_bytes(p._swap) if p._swap != "" else "",
+ convert_bytes(p._pss) if p._pss else "",
+ convert_bytes(p._swap) if p._swap else "",
convert_bytes(p._rss),
cmd,
)
diff --git a/scripts/winservices.py b/scripts/winservices.py
index 8d941d532..216d0a652 100755
--- a/scripts/winservices.py
+++ b/scripts/winservices.py
@@ -52,7 +52,7 @@ def main():
)
print(s)
print("binpath: %s" % info['binpath'])
- print("")
+ print()
if __name__ == '__main__':