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__':