From a9c5dd5a4eab9f4132d62344cdbad24e077c650e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 24 Dec 2023 12:08:46 -0500 Subject: [PATCH 01/36] Remove sole entry for branches-ignore. Workaround for and closes jaraco/skeleton#103. --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a079bbfbe3..cf94f7d816 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,8 @@ on: merge_group: push: branches-ignore: - - gh-readonly-queue/** # Temporary merge queue-related GH-made branches + # disabled for jaraco/skeleton#103 + # - gh-readonly-queue/** # Temporary merge queue-related GH-made branches pull_request: permissions: From db0d581685d4fc2a16d392d4dedffe622e9a355c Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 26 Dec 2023 15:58:23 +0100 Subject: [PATCH 02/36] =?UTF-8?q?ruff:=20extended-ignore=20=E2=86=92=20ign?= =?UTF-8?q?ore=20(jaraco/skeleton#105)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies Repo-Review suggestion: RF201: Avoid using deprecated config settings extend-ignore deprecated, use ignore instead (identical) --- ruff.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruff.toml b/ruff.toml index 7ed133b790..795cca162a 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,5 @@ [lint] -extend-ignore = [ +ignore = [ # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules "W191", "E111", From 25c1b27813eda67e9c48a622bbca99eaa24cd5d4 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Thu, 4 Jan 2024 12:13:39 +0000 Subject: [PATCH 03/36] Add regression test for pkg_resources._mac_vers --- pkg_resources/tests/test_pkg_resources.py | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index a05aeb2603..0dd9c3c105 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -1,9 +1,11 @@ +import builtins import sys import tempfile import os import zipfile import datetime import time +import plistlib import subprocess import stat import distutils.dist @@ -323,6 +325,32 @@ def test_dist_info_is_not_dir(tmp_path, only): assert not pkg_resources.dist_factory(str(tmp_path), str(dist_info), only) +@pytest.mark.skipif(sys.version_info >= (3, 9), reason="requires Python < 3.9") +@pytest.mark.filterwarnings("ignore::DeprecationWarning") +def test_macos_vers_fallback(monkeypatch, tmp_path): + """Regression test for pkg_resources._macos_vers""" + orig_open = builtins.open + + # Pretend we need to use the plist file + monkeypatch.setattr('platform.mac_ver', mock.Mock(return_value=('', (), ''))) + + # Create fake content for the fake plist file + with open(tmp_path / 'fake.plist', 'wb') as fake_file: + plistlib.dump({"ProductVersion": "11.4"}, fake_file) + + # Pretend the fake file exists + monkeypatch.setattr('os.path.exists', mock.Mock(return_value=True)) + + def fake_open(file, *args, **kwargs): + return orig_open(tmp_path / 'fake.plist', *args, **kwargs) + + # Ensure that the _macos_vers works correctly + with mock.patch('builtins.open', mock.Mock(side_effect=fake_open)) as m: + assert pkg_resources._macos_vers([]) == ["11", "4"] + + m.assert_called() + + class TestDeepVersionLookupDistutils: @pytest.fixture def env(self, tmpdir): From b3935708f1b8857c45bb63abac390b013c450694 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 3 Jan 2024 22:29:11 +0100 Subject: [PATCH 04/36] =?UTF-8?q?`plistlib.readPlist()`=20is=20missing=20f?= =?UTF-8?q?rom=20Python=20=E2=89=A5=203.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function has been deprecated since Python 3.4, replaced by `plistlib.load()`. --- pkg_resources/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index ab6afe955d..584ce5bc4a 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -414,10 +414,10 @@ def _macos_vers(_cache=[]): if version == '': plist = '/System/Library/CoreServices/SystemVersion.plist' if os.path.exists(plist): - if hasattr(plistlib, 'readPlist'): - plist_content = plistlib.readPlist(plist) - if 'ProductVersion' in plist_content: - version = plist_content['ProductVersion'] + with open(plist, 'rb') as fh: + plist_content = plistlib.load(fh) + if 'ProductVersion' in plist_content: + version = plist_content['ProductVersion'] _cache.append(version.split('.')) return _cache[0] From 38fe69e54f30a7b67713ec19a0f856f433560147 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Thu, 4 Jan 2024 12:25:14 +0000 Subject: [PATCH 05/36] Remove pytest marks no longer necessary in regression test --- pkg_resources/tests/test_pkg_resources.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 0dd9c3c105..77d650a7d0 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -325,8 +325,6 @@ def test_dist_info_is_not_dir(tmp_path, only): assert not pkg_resources.dist_factory(str(tmp_path), str(dist_info), only) -@pytest.mark.skipif(sys.version_info >= (3, 9), reason="requires Python < 3.9") -@pytest.mark.filterwarnings("ignore::DeprecationWarning") def test_macos_vers_fallback(monkeypatch, tmp_path): """Regression test for pkg_resources._macos_vers""" orig_open = builtins.open From c534f2a4ecb90eda92dde7055d6b52618c75c5a6 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 5 Jan 2024 13:13:48 +0000 Subject: [PATCH 06/36] Update README removing broken link to PyPUG page --- README.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index c7387deb9f..f9f497d462 100644 --- a/README.rst +++ b/README.rst @@ -27,10 +27,9 @@ :target: https://discord.com/channels/803025117553754132/815945031150993468 :alt: Discord -See the `Installation Instructions -`_ in the Python Packaging -User's Guide for instructions on installing, upgrading, and uninstalling -Setuptools. +See the `Quickstart `_ +and the `User's Guide `_ for +instructions on how to use Setuptools. Questions and comments should be directed to `GitHub Discussions `_. From 0ff881e5516aad02bfb2351639853d050fa60335 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:22:44 +0100 Subject: [PATCH 07/36] Fix flake8-bugbear warning B015 Pointless comparison. Did you mean to assign a value? Otherwise, prepend `assert` or remove it. --- setuptools/tests/test_sdist.py | 2 +- setuptools/tests/test_setuptools.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py index 0adec70f04..5d597709ed 100644 --- a/setuptools/tests/test_sdist.py +++ b/setuptools/tests/test_sdist.py @@ -658,7 +658,7 @@ def test_sdist_with_latin1_encoded_filename(self): else: # The Latin-1 filename should have been skipped filename = filename.decode('latin-1') - filename not in cmd.filelist.files + assert filename not in cmd.filelist.files _EXAMPLE_DIRECTIVES = { "setup.cfg - long_description and version": """ diff --git a/setuptools/tests/test_setuptools.py b/setuptools/tests/test_setuptools.py index 1ca5523d20..0dc4769b93 100644 --- a/setuptools/tests/test_setuptools.py +++ b/setuptools/tests/test_setuptools.py @@ -61,13 +61,13 @@ def f1(): assert dep.extract_constant(fc, 'q', -1) is None # constant assigned - dep.extract_constant(fc, 'x', -1) == "test" + assert dep.extract_constant(fc, 'x', -1) == "test" # expression assigned - dep.extract_constant(fc, 'y', -1) == -1 + assert dep.extract_constant(fc, 'y', -1) == -1 # recognized name, not assigned - dep.extract_constant(fc, 'z', -1) is None + assert dep.extract_constant(fc, 'z', -1) is None def testFindModule(self): with pytest.raises(ImportError): From b320f39ff24dbf02eee2d58dc39a8328ea5b8982 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:26:46 +0100 Subject: [PATCH 08/36] Fix flake8-bugbear warning B010 Do not call `setattr` with a constant attribute value. It is not any safer than normal property access. --- setuptools/command/sdist.py | 2 +- setuptools/tests/config/test_setupcfg.py | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 5f45fb5dee..f0ffeba876 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -106,7 +106,7 @@ class NoValue: yield finally: if orig_val is not NoValue: - setattr(os, 'link', orig_val) + os.link = orig_val def add_defaults(self): super().add_defaults() diff --git a/setuptools/tests/config/test_setupcfg.py b/setuptools/tests/config/test_setupcfg.py index d2bb1212dc..d235478f7e 100644 --- a/setuptools/tests/config/test_setupcfg.py +++ b/setuptools/tests/config/test_setupcfg.py @@ -957,17 +957,13 @@ class TestExternalSetters: # pbr or something else setting these values. def _fake_distribution_init(self, dist, attrs): saved_dist_init(dist, attrs) - # see self._DISTUTUILS_UNSUPPORTED_METADATA - setattr(dist.metadata, 'long_description_content_type', 'text/something') + # see self._DISTUTILS_UNSUPPORTED_METADATA + dist.metadata.long_description_content_type = 'text/something' # Test overwrite setup() args - setattr( - dist.metadata, - 'project_urls', - { - 'Link One': 'https://example.com/one/', - 'Link Two': 'https://example.com/two/', - }, - ) + dist.metadata.project_urls = { + 'Link One': 'https://example.com/one/', + 'Link Two': 'https://example.com/two/', + } return None @patch.object(_Distribution, '__init__', autospec=True) From 4a351f5ad383029c83437355c6f04b62ce7e6a22 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:59:40 +0100 Subject: [PATCH 09/36] Fix flake8-bugbear warning B009 Do not call `getattr` with a constant attribute value. It is not any safer than normal property access. --- setuptools/command/build_ext.py | 2 +- setuptools/monkey.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py index 2e1954ab0f..ef2a4da84d 100644 --- a/setuptools/command/build_ext.py +++ b/setuptools/command/build_ext.py @@ -157,7 +157,7 @@ def get_ext_filename(self, fullname): if fullname in self.ext_map: ext = self.ext_map[fullname] - use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix() + use_abi3 = ext.py_limited_api and get_abi3_suffix() if use_abi3: filename = filename[: -len(so_ext)] so_ext = get_abi3_suffix() diff --git a/setuptools/monkey.py b/setuptools/monkey.py index 6c8a2f12f6..3d5edb6bd2 100644 --- a/setuptools/monkey.py +++ b/setuptools/monkey.py @@ -130,7 +130,7 @@ def patch_func(replacement, target_mod, func_name): def get_unpatched_function(candidate): - return getattr(candidate, 'unpatched') + return candidate.unpatched def patch_for_msvc_specialized_compiler(): From ca04bfc413135d5b5e774bc8c62ace8c9845889a Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 2 Jan 2024 19:05:32 +0100 Subject: [PATCH 10/36] Fix flake8-bugbear warning B033 Sets should not contain duplicate item `"anyOf"` --- setuptools/config/_validate_pyproject/error_reporting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/config/_validate_pyproject/error_reporting.py b/setuptools/config/_validate_pyproject/error_reporting.py index f78e4838fb..b6ce79f851 100644 --- a/setuptools/config/_validate_pyproject/error_reporting.py +++ b/setuptools/config/_validate_pyproject/error_reporting.py @@ -24,7 +24,7 @@ "must not be there", ) -_NEED_DETAILS = {"anyOf", "oneOf", "anyOf", "contains", "propertyNames", "not", "items"} +_NEED_DETAILS = {"anyOf", "oneOf", "contains", "propertyNames", "not", "items"} _CAMEL_CASE_SPLITTER = re.compile(r"\W+|([A-Z][^A-Z\W]*)") _IDENTIFIER = re.compile(r"^[\w_]+$", re.I) From f57229617de5a49750355e2ac55beaa71c266e1a Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 2 Jan 2024 19:35:46 +0100 Subject: [PATCH 11/36] Fix flake8-bugbear warning B006 Do not use mutable data structures for argument defaults --- pkg_resources/__init__.py | 7 ++++--- setuptools/command/build_py.py | 2 +- setuptools/command/test.py | 2 +- setuptools/tests/test_build_meta.py | 4 ++-- setuptools/tests/test_easy_install.py | 5 +++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 584ce5bc4a..7ce314d9cc 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -407,7 +407,7 @@ def get_provider(moduleOrReq): return _find_adapter(_provider_factories, loader)(module) -def _macos_vers(_cache=[]): +def _macos_vers(_cache=None): if not _cache: version = platform.mac_ver()[0] # fallback for MacPorts @@ -419,7 +419,7 @@ def _macos_vers(_cache=[]): if 'ProductVersion' in plist_content: version = plist_content['ProductVersion'] - _cache.append(version.split('.')) + _cache = [version.split('.')] return _cache[0] @@ -2422,7 +2422,8 @@ def _cygwin_patch(filename): # pragma: nocover return os.path.abspath(filename) if sys.platform == 'cygwin' else filename -def _normalize_cached(filename, _cache={}): +def _normalize_cached(filename, _cache=None): + _cache = _cache or {} try: return _cache[filename] except KeyError: diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py index cbdd05aab0..3f40b060b3 100644 --- a/setuptools/command/build_py.py +++ b/setuptools/command/build_py.py @@ -288,7 +288,7 @@ def exclude_data_files(self, package, src_dir, files): return list(unique_everseen(keepers)) @staticmethod - def _get_platform_patterns(spec, package, src_dir, extra_patterns=[]): + def _get_platform_patterns(spec, package, src_dir, extra_patterns=()): """ yield platform-specific path patterns (suitable for glob or fn_match) from a glob-based spec (such as diff --git a/setuptools/command/test.py b/setuptools/command/test.py index 5fce6660c0..0a128f2a7a 100644 --- a/setuptools/command/test.py +++ b/setuptools/command/test.py @@ -132,7 +132,7 @@ def with_project_on_sys_path(self, func): func() @contextlib.contextmanager - def project_on_sys_path(self, include_dists=[]): + def project_on_sys_path(self, include_dists=()): self.run_command('egg_info') # Build extensions in-place diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py index 429533229d..696e22c956 100644 --- a/setuptools/tests/test_build_meta.py +++ b/setuptools/tests/test_build_meta.py @@ -30,9 +30,9 @@ class BuildBackendBase: - def __init__(self, cwd='.', env={}, backend_name='setuptools.build_meta'): + def __init__(self, cwd='.', env=None, backend_name='setuptools.build_meta'): self.cwd = cwd - self.env = env + self.env = env or {} self.backend_name = backend_name diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index d0b95e09ea..e0ea1e8c99 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -1195,7 +1195,7 @@ def create_setup_requires_package( version='0.1', make_package=make_trivial_sdist, setup_py_template=None, - setup_attrs={}, + setup_attrs=None, use_setup_cfg=(), ): """Creates a source tree under path for a trivial test package that has a @@ -1213,7 +1213,8 @@ def create_setup_requires_package( 'setup_requires': ['%s==%s' % (distname, version)], 'dependency_links': [os.path.abspath(path)], } - test_setup_attrs.update(setup_attrs) + if setup_attrs: + test_setup_attrs.update(setup_attrs) test_pkg = os.path.join(path, 'test_pkg') os.mkdir(test_pkg) From 5a17b0e6f111861fce31c88f41ed5c0cce6b58aa Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 2 Jan 2024 19:58:01 +0100 Subject: [PATCH 12/36] Fix flake8-bugbear warning B904 Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling --- setuptools/build_meta.py | 4 ++-- setuptools/command/egg_info.py | 4 ++-- setuptools/config/setupcfg.py | 8 ++++---- tools/build_launchers.py | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 80ccceff3c..b656f47950 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -117,11 +117,11 @@ def _file_with_extension(directory, extension): matching = (f for f in os.listdir(directory) if f.endswith(extension)) try: (file,) = matching - except ValueError: + except ValueError as e: raise ValueError( 'No distribution was found. Ensure that `setup.py` ' 'is not empty and that it calls `setup()`.' - ) + ) from e return file diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 7169f33535..286e97a6b3 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -384,10 +384,10 @@ def process_template_line(self, line): try: process_action = action_map[action] - except KeyError: + except KeyError as e: raise DistutilsInternalError( "this cannot happen: invalid action '{action!s}'".format(action=action), - ) + ) from e # OK, now we know that the action is valid and we have the # right number of words on the line for that action -- so we diff --git a/setuptools/config/setupcfg.py b/setuptools/config/setupcfg.py index 44a2876c06..a7f02714cb 100644 --- a/setuptools/config/setupcfg.py +++ b/setuptools/config/setupcfg.py @@ -283,8 +283,8 @@ def __setitem__(self, option_name, value): try: current_value = getattr(target_obj, option_name) - except AttributeError: - raise KeyError(option_name) + except AttributeError as e: + raise KeyError(option_name) from e if current_value: # Already inhabited. Skipping. @@ -582,11 +582,11 @@ def _parse_version(self, value): # accidentally include newlines and other unintended content try: Version(version) - except InvalidVersion: + except InvalidVersion as e: raise OptionError( f'Version loaded from {value} does not ' f'comply with PEP 440: {version}' - ) + ) from e return version diff --git a/tools/build_launchers.py b/tools/build_launchers.py index 8d832b9c24..c673445365 100644 --- a/tools/build_launchers.py +++ b/tools/build_launchers.py @@ -118,8 +118,8 @@ def get_msbuild(): ] try: return subprocess.check_output(cmd, encoding='utf-8', text=True).strip() - except subprocess.CalledProcessError: - raise SystemExit("Unable to find MSBuild; check Visual Studio install") + except subprocess.CalledProcessError as e: + raise SystemExit("Unable to find MSBuild; check Visual Studio install") from e def do_build(arena, platform, target): From 17655dce0cfa5581fa653bce1f73ad9d024b30e4 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 3 Jan 2024 16:18:40 +0100 Subject: [PATCH 13/36] Update setuptools/monkey.py Co-authored-by: Anderson Bravalheri --- setuptools/monkey.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/monkey.py b/setuptools/monkey.py index 3d5edb6bd2..f3148e6832 100644 --- a/setuptools/monkey.py +++ b/setuptools/monkey.py @@ -130,7 +130,7 @@ def patch_func(replacement, target_mod, func_name): def get_unpatched_function(candidate): - return candidate.unpatched + return getattr(candidate, 'unpatched', None) def patch_for_msvc_specialized_compiler(): From d988bc590b2ab7de9ef65025e7557c0307d97956 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:40:12 +0100 Subject: [PATCH 14/36] Better error message in setuptools/command/egg_info.py Co-authored-by: Anderson Bravalheri --- setuptools/command/egg_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 286e97a6b3..ff1864241a 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -386,7 +386,7 @@ def process_template_line(self, line): process_action = action_map[action] except KeyError as e: raise DistutilsInternalError( - "this cannot happen: invalid action '{action!s}'".format(action=action), + f"Invalid MANIFEST.in: unknow action {action!r} in {line!r}" ) from e # OK, now we know that the action is valid and we have the From 10a21ec7887f32bb666d801be851ad958aeb34f9 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:40:36 +0100 Subject: [PATCH 15/36] Update setuptools/config/_validate_pyproject/error_reporting.py Co-authored-by: Anderson Bravalheri --- setuptools/config/_validate_pyproject/error_reporting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/config/_validate_pyproject/error_reporting.py b/setuptools/config/_validate_pyproject/error_reporting.py index b6ce79f851..d44e290e36 100644 --- a/setuptools/config/_validate_pyproject/error_reporting.py +++ b/setuptools/config/_validate_pyproject/error_reporting.py @@ -24,7 +24,7 @@ "must not be there", ) -_NEED_DETAILS = {"anyOf", "oneOf", "contains", "propertyNames", "not", "items"} +_NEED_DETAILS = {"anyOf", "oneOf", "allOf", "contains", "propertyNames", "not", "items"} _CAMEL_CASE_SPLITTER = re.compile(r"\W+|([A-Z][^A-Z\W]*)") _IDENTIFIER = re.compile(r"^[\w_]+$", re.I) From f7b7dfabf42486e51478b095ea1a85ab95e9b27c Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 3 Jan 2024 22:23:41 +0100 Subject: [PATCH 16/36] Proper fix for flake8-bugbear warning B006 The whole idea was to cache the result of a couple functions, do that explictly with @functools.cache. --- pkg_resources/__init__.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 7ce314d9cc..db7a38981e 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -407,20 +407,18 @@ def get_provider(moduleOrReq): return _find_adapter(_provider_factories, loader)(module) -def _macos_vers(_cache=None): - if not _cache: - version = platform.mac_ver()[0] - # fallback for MacPorts - if version == '': - plist = '/System/Library/CoreServices/SystemVersion.plist' - if os.path.exists(plist): - with open(plist, 'rb') as fh: - plist_content = plistlib.load(fh) - if 'ProductVersion' in plist_content: - version = plist_content['ProductVersion'] - - _cache = [version.split('.')] - return _cache[0] +@functools.cache +def _macos_vers(): + version = platform.mac_ver()[0] + # fallback for MacPorts + if version == '': + plist = '/System/Library/CoreServices/SystemVersion.plist' + if os.path.exists(plist): + with open(plist, 'rb') as fh: + plist_content = plistlib.load(fh) + if 'ProductVersion' in plist_content: + version = plist_content['ProductVersion'] + return version.split('.') def _macos_arch(machine): @@ -2422,13 +2420,9 @@ def _cygwin_patch(filename): # pragma: nocover return os.path.abspath(filename) if sys.platform == 'cygwin' else filename -def _normalize_cached(filename, _cache=None): - _cache = _cache or {} - try: - return _cache[filename] - except KeyError: - _cache[filename] = result = normalize_path(filename) - return result +@functools.cache +def _normalize_cached(filename): + return normalize_path(filename) def _is_egg_path(path): From 111d4ad94d6ca456cfae579dc16fe619cf792644 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 3 Jan 2024 23:02:02 +0100 Subject: [PATCH 17/36] Fix refurb warning FURB140 Use `itertools.starmap` instead of the generator --- setuptools/command/editable_wheel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index 73fa9fff52..76b7606ffc 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -19,7 +19,7 @@ from contextlib import suppress from enum import Enum from inspect import cleandoc -from itertools import chain +from itertools import chain, starmap from pathlib import Path from tempfile import TemporaryDirectory from typing import ( @@ -606,7 +606,7 @@ def _simple_layout( layout = {pkg: find_package_path(pkg, package_dir, project_dir) for pkg in packages} if not layout: return set(package_dir) in ({}, {""}) - parent = os.path.commonpath([_parent_path(k, v) for k, v in layout.items()]) + parent = os.path.commonpath([*starmap(_parent_path, layout.items())]) return all( _path.same_path(Path(parent, *key.split('.')), value) for key, value in layout.items() From 88df648f41ff712ab17ef575886f1232fca572ce Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 3 Jan 2024 23:04:10 +0100 Subject: [PATCH 18/36] Fix refurb warning FURB171 Membership test against single-item container --- setuptools/tests/test_msvc14.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/tests/test_msvc14.py b/setuptools/tests/test_msvc14.py index 619293cada..4b8344539f 100644 --- a/setuptools/tests/test_msvc14.py +++ b/setuptools/tests/test_msvc14.py @@ -57,7 +57,7 @@ def test_get_vc2017(self): # This function cannot be mocked, so pass it if we find VS 2017 # and mark it skipped if we do not. version, path = _msvccompiler._msvc14_find_vc2017() - if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') in ['Visual Studio 2017']: + if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2017': assert version if version: assert version >= 15 From 6020b7fd73100d50b0d4364e8715fbc53e5bee61 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 5 Jan 2024 14:47:08 +0000 Subject: [PATCH 19/36] Ensure test does not fail due to functools.lru_cache --- pkg_resources/tests/test_pkg_resources.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 77d650a7d0..c90dca7ff3 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -344,7 +344,9 @@ def fake_open(file, *args, **kwargs): # Ensure that the _macos_vers works correctly with mock.patch('builtins.open', mock.Mock(side_effect=fake_open)) as m: - assert pkg_resources._macos_vers([]) == ["11", "4"] + pkg_resources._macos_vers.cache_clear() + assert pkg_resources._macos_vers() == ["11", "4"] + pkg_resources._macos_vers.cache_clear() m.assert_called() From 0f08db8eaecb9ebcd5c6db7129e82f714ca4770f Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:31:37 +0100 Subject: [PATCH 20/36] Add pyupgrade rules to ruff config --- ruff.toml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ruff.toml b/ruff.toml index 795cca162a..791cfdc0a5 100644 --- a/ruff.toml +++ b/ruff.toml @@ -16,7 +16,25 @@ ignore = [ "ISC001", "ISC002", ] +extend-select = [ + "UP", # pyupgrade +] +extend-ignore = [ + "UP015", # redundant-open-modes, explicit is prefered + "UP030", # temporarily disabled + "UP031", # temporarily disabled + "UP032", # temporarily disabled + "UP036", # temporarily disabled +] +extend-exclude = [ + "**/_vendor", + "setuptools/_distutils", +] [format] +extend-exclude = [ + "**/_vendor", + "setuptools/_distutils", +] # https://docs.astral.sh/ruff/settings/#format-quote-style quote-style = "preserve" From ac3bf62dbca0d2284b990de7ae3cf02001f54542 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Mon, 20 Nov 2023 22:42:34 +0100 Subject: [PATCH 21/36] "yield from", instead of "yield" in a loop This is a suggestion from pyupgrade: https://github.com/asottile/pyupgrade#yield--yield-from --- setuptools/command/bdist_egg.py | 9 +++------ setuptools/command/easy_install.py | 6 ++---- setuptools/command/sdist.py | 3 +-- setuptools/dist.py | 6 ++---- setuptools/glob.py | 3 +-- setuptools/package_index.py | 8 +++----- 6 files changed, 12 insertions(+), 23 deletions(-) diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index e0947c6624..a4b683f66e 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -321,8 +321,7 @@ def walk_egg(egg_dir): if 'EGG-INFO' in dirs: dirs.remove('EGG-INFO') yield base, dirs, files - for bdf in walker: - yield bdf + yield from walker def analyze_egg(egg_dir, stubs): @@ -406,14 +405,12 @@ def scan_module(egg_dir, base, name, stubs): def iter_symbols(code): """Yield names and strings used by `code` and its nested code objects""" - for name in code.co_names: - yield name + yield from code.co_names for const in code.co_consts: if isinstance(const, str): yield const elif isinstance(const, CodeType): - for name in iter_symbols(const): - yield name + yield from iter_symbols(const) def can_scan(): diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 897ec6ad9b..3231650c5c 100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -1743,8 +1743,7 @@ class RewritePthDistributions(PthDistributions): @classmethod def _wrap_lines(cls, lines): yield cls.prelude - for line in lines: - yield line + yield from lines yield cls.postlude prelude = _one_liner( @@ -2180,8 +2179,7 @@ def get_args(cls, dist, header=None): cls._ensure_safe_name(name) script_text = cls.template % locals() args = cls._get_script_args(type_, name, header, script_text) - for res in args: - yield res + yield from args @staticmethod def _ensure_safe_name(name): diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 5f45fb5dee..95d325717a 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -14,8 +14,7 @@ def walk_revctrl(dirname=''): """Find all files under revision control""" for ep in metadata.entry_points(group='setuptools.file_finders'): - for item in ep.load()(dirname): - yield item + yield from ep.load()(dirname) class sdist(orig.sdist): diff --git a/setuptools/dist.py b/setuptools/dist.py index c9c8c77515..0d35583dbc 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -912,11 +912,9 @@ def get_cmdline_options(self): def iter_distribution_names(self): """Yield all packages, modules, and extension names in distribution""" - for pkg in self.packages or (): - yield pkg + yield from self.packages or () - for module in self.py_modules or (): - yield module + yield from self.py_modules or () for ext in self.ext_modules or (): if isinstance(ext, tuple): diff --git a/setuptools/glob.py b/setuptools/glob.py index 8dbf34972d..ac901d9253 100644 --- a/setuptools/glob.py +++ b/setuptools/glob.py @@ -113,8 +113,7 @@ def glob0(dirname, basename): def glob2(dirname, pattern): assert _isrecursive(pattern) yield pattern[:0] - for x in _rlistdir(dirname): - yield x + yield from _rlistdir(dirname) # Recursively yields relative pathnames inside a literal directory. diff --git a/setuptools/package_index.py b/setuptools/package_index.py index 3cedd5105c..c491ddb3cc 100644 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -112,15 +112,13 @@ def egg_info_for_url(url): def distros_for_url(url, metadata=None): """Yield egg or source distribution objects that might be found at a URL""" base, fragment = egg_info_for_url(url) - for dist in distros_for_location(url, base, metadata): - yield dist + yield from distros_for_location(url, base, metadata) if fragment: match = EGG_FRAGMENT.match(fragment) if match: - for dist in interpret_distro_name( + yield from interpret_distro_name( url, match.group(1), metadata, precedence=CHECKOUT_DIST - ): - yield dist + ) def distros_for_location(location, basename, metadata=None): From af41360fab5256b7d59118fdcda9b3246e000d02 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Mon, 20 Nov 2023 22:44:03 +0100 Subject: [PATCH 22/36] =?UTF-8?q?io.open()=20=E2=86=92=20open()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Python 3, io.open() is an alias for the builtin open() function. https://docs.python.org/3/library/io.html#io.open This is a suggestion from pyupgrade: https://github.com/asottile/pyupgrade#open-alias --- setuptools/msvc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setuptools/msvc.py b/setuptools/msvc.py index be373d176e..aa69db5810 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -12,7 +12,6 @@ """ import json -from io import open from os import listdir, pathsep from os.path import join, isfile, isdir, dirname from subprocess import CalledProcessError From bba79a0a3f1dd450eca23192810acf12d0f758c0 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Mon, 20 Nov 2023 22:48:49 +0100 Subject: [PATCH 23/36] Simplify super() calls See PEP 3135: https://peps.python.org/pep-3135/ This is a suggestion from pyupgrade: https://github.com/asottile/pyupgrade#super-calls --- pkg_resources/__init__.py | 4 ++-- setuptools/build_meta.py | 2 +- setuptools/package_index.py | 2 +- setuptools/tests/test_build_meta.py | 4 ++-- setuptools/tests/test_manifest.py | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index ab6afe955d..9adc214676 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -2901,7 +2901,7 @@ def __getattr__(self, attr): def __dir__(self): return list( - set(super(Distribution, self).__dir__()) + set(super().__dir__()) | set(attr for attr in self._provider.__dir__() if not attr.startswith('_')) ) @@ -3168,7 +3168,7 @@ class RequirementParseError(packaging.requirements.InvalidRequirement): class Requirement(packaging.requirements.Requirement): def __init__(self, requirement_string): """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" - super(Requirement, self).__init__(requirement_string) + super().__init__(requirement_string) self.unsafe_name = self.name project_name = safe_name(self.name) self.project_name, self.key = project_name, project_name.lower() diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 80ccceff3c..18ebb75c24 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -477,7 +477,7 @@ def run_setup(self, setup_script='setup.py'): sys.argv[0] = setup_script try: - super(_BuildMetaLegacyBackend, self).run_setup(setup_script=setup_script) + super().run_setup(setup_script=setup_script) finally: # While PEP 517 frontends should be calling each hook in a fresh # subprocess according to the standard (and thus it should not be diff --git a/setuptools/package_index.py b/setuptools/package_index.py index c491ddb3cc..1e535bc747 100644 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -514,7 +514,7 @@ def obtain(self, requirement, installer=None): if dist in requirement: return dist self.debug("%s does not match %s", requirement, dist) - return super(PackageIndex, self).obtain(requirement, installer) + return super().obtain(requirement, installer) def check_hash(self, checker, filename, tfp): """ diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py index 429533229d..1281eb52a2 100644 --- a/setuptools/tests/test_build_meta.py +++ b/setuptools/tests/test_build_meta.py @@ -40,7 +40,7 @@ class BuildBackend(BuildBackendBase): """PEP 517 Build Backend""" def __init__(self, *args, **kwargs): - super(BuildBackend, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.pool = futures.ProcessPoolExecutor(max_workers=1) def __getattr__(self, name): @@ -73,7 +73,7 @@ def _kill(self, pid): class BuildBackendCaller(BuildBackendBase): def __init__(self, *args, **kwargs): - super(BuildBackendCaller, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) (self.backend_name, _, self.backend_obj) = self.backend_name.partition(':') diff --git a/setuptools/tests/test_manifest.py b/setuptools/tests/test_manifest.py index 33d3250893..fbd21b1976 100644 --- a/setuptools/tests/test_manifest.py +++ b/setuptools/tests/test_manifest.py @@ -171,7 +171,7 @@ def teardown_method(self, method): class TestManifestTest(TempDirTestCase): def setup_method(self, method): - super(TestManifestTest, self).setup_method(method) + super().setup_method(method) f = open(os.path.join(self.temp_dir, 'setup.py'), 'w') f.write(SETUP_PY) From 1ddffe4946be0f6f08ea3c73b4efc5ebea74ad4b Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:39:47 +0100 Subject: [PATCH 24/36] Don't cast string literals with str() Fixed by running `ruff --select UP018 --fix .`: UP018 [*] Unnecessary `str` call (rewrite as a literal) Original suggestions from pyupgrade: https://github.com/asottile/pyupgrade#forced-strnative-literals --- setuptools/tests/test_dist.py | 4 +- setuptools/tests/test_easy_install.py | 70 +++++++++++++-------------- setuptools/tests/test_integration.py | 2 +- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py index 609932a9b3..99cd582501 100644 --- a/setuptools/tests/test_dist.py +++ b/setuptools/tests/test_dist.py @@ -116,7 +116,7 @@ def test_provides_extras_deterministic_order(): # Invalid value type. ( { - 'hello': str('*.msg'), + 'hello': '*.msg', }, ( "\"values of 'package_data' dict\" " @@ -142,7 +142,7 @@ def test_check_package_data(package_data, expected_message): assert check_package_data(None, 'package_data', package_data) is None else: with pytest.raises(DistutilsSetupError, match=re.escape(expected_message)): - check_package_data(None, str('package_data'), package_data) + check_package_data(None, 'package_data', package_data) def test_check_specifier(): diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index d0b95e09ea..c6e3bf039a 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -53,7 +53,7 @@ class FakeDist: def get_entry_map(self, group): if group != 'console_scripts': return {} - return {str('name'): 'ep'} + return {'name': 'ep'} def as_requirement(self): return 'spec' @@ -567,8 +567,8 @@ def test_setup_requires_honors_fetch_params(self, mock_index, monkeypatch): setup_requires, it should honor the fetch parameters (such as index-url, and find-links). """ - monkeypatch.setenv(str('PIP_RETRIES'), str('0')) - monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') monkeypatch.setenv('PIP_NO_INDEX', 'false') with contexts.quiet(): # create an sdist that has a build-time dependency. @@ -653,7 +653,7 @@ def test_setup_requires_overrides_version_conflict(self, use_setup_cfg): with contexts.quiet() as (stdout, stderr): # Don't even need to install the package, just # running the setup.py at all is sufficient - run_setup(test_setup_py, [str('--name')]) + run_setup(test_setup_py, ['--name']) lines = stdout.readlines() assert len(lines) > 0 @@ -716,7 +716,7 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg): try: # Don't even need to install the package, just # running the setup.py at all is sufficient - run_setup(test_setup_py, [str('--name')]) + run_setup(test_setup_py, ['--name']) except pkg_resources.VersionConflict: self.fail( 'Installing setup.py requirements ' @@ -766,16 +766,16 @@ def make_dependency_sdist(dist_path, distname, version): ) test_setup_py = os.path.join(test_pkg, 'setup.py') with contexts.quiet() as (stdout, stderr): - run_setup(test_setup_py, [str('--version')]) + run_setup(test_setup_py, ['--version']) lines = stdout.readlines() assert len(lines) > 0 assert lines[-1].strip() == '42' def test_setup_requires_honors_pip_env(self, mock_index, monkeypatch): - monkeypatch.setenv(str('PIP_RETRIES'), str('0')) - monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') monkeypatch.setenv('PIP_NO_INDEX', 'false') - monkeypatch.setenv(str('PIP_INDEX_URL'), mock_index.url) + monkeypatch.setenv('PIP_INDEX_URL', mock_index.url) with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: test_pkg = create_setup_requires_package( @@ -796,14 +796,14 @@ def test_setup_requires_honors_pip_env(self, mock_index, monkeypatch): ) test_setup_py = os.path.join(test_pkg, 'setup.py') with pytest.raises(distutils.errors.DistutilsError): - run_setup(test_setup_py, [str('--version')]) + run_setup(test_setup_py, ['--version']) assert len(mock_index.requests) == 1 assert mock_index.requests[0].path == '/python-xlib/' def test_setup_requires_with_pep508_url(self, mock_index, monkeypatch): - monkeypatch.setenv(str('PIP_RETRIES'), str('0')) - monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) - monkeypatch.setenv(str('PIP_INDEX_URL'), mock_index.url) + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') + monkeypatch.setenv('PIP_INDEX_URL', mock_index.url) with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: dep_sdist = os.path.join(temp_dir, 'dep.tar.gz') @@ -817,7 +817,7 @@ def test_setup_requires_with_pep508_url(self, mock_index, monkeypatch): setup_attrs=dict(setup_requires='dependency @ %s' % dep_url), ) test_setup_py = os.path.join(test_pkg, 'setup.py') - run_setup(test_setup_py, [str('--version')]) + run_setup(test_setup_py, ['--version']) assert len(mock_index.requests) == 0 def test_setup_requires_with_allow_hosts(self, mock_index): @@ -843,15 +843,15 @@ def test_setup_requires_with_allow_hosts(self, mock_index): path.build(files, prefix=temp_dir) setup_py = str(pathlib.Path(temp_dir, 'test_pkg', 'setup.py')) with pytest.raises(distutils.errors.DistutilsError): - run_setup(setup_py, [str('--version')]) + run_setup(setup_py, ['--version']) assert len(mock_index.requests) == 0 def test_setup_requires_with_python_requires(self, monkeypatch, tmpdir): """Check `python_requires` is honored.""" - monkeypatch.setenv(str('PIP_RETRIES'), str('0')) - monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) - monkeypatch.setenv(str('PIP_NO_INDEX'), str('1')) - monkeypatch.setenv(str('PIP_VERBOSE'), str('1')) + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') + monkeypatch.setenv('PIP_NO_INDEX', '1') + monkeypatch.setenv('PIP_VERBOSE', '1') dep_1_0_sdist = 'dep-1.0.tar.gz' dep_1_0_url = path_to_url(str(tmpdir / dep_1_0_sdist)) dep_1_0_python_requires = '>=2.7' @@ -898,7 +898,7 @@ def test_setup_requires_with_python_requires(self, monkeypatch, tmpdir): setup_attrs=dict(setup_requires='dep', dependency_links=[index_url]), ) test_setup_py = os.path.join(test_pkg, 'setup.py') - run_setup(test_setup_py, [str('--version')]) + run_setup(test_setup_py, ['--version']) eggs = list( map(str, pkg_resources.find_distributions(os.path.join(test_pkg, '.eggs'))) ) @@ -908,8 +908,8 @@ def test_setup_requires_with_python_requires(self, monkeypatch, tmpdir): def test_setup_requires_with_find_links_in_setup_cfg( self, monkeypatch, with_dependency_links_in_setup_py ): - monkeypatch.setenv(str('PIP_RETRIES'), str('0')) - monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: make_trivial_sdist( @@ -946,7 +946,7 @@ def test_setup_requires_with_find_links_in_setup_cfg( find_links=temp_dir, ) ) - run_setup(test_setup_py, [str('--version')]) + run_setup(test_setup_py, ['--version']) def test_setup_requires_with_transitive_extra_dependency(self, monkeypatch): """ @@ -979,7 +979,7 @@ def test_setup_requires_with_transitive_extra_dependency(self, monkeypatch): prefix=dep_pkg, ) # "Install" dep. - run_setup(os.path.join(dep_pkg, 'setup.py'), [str('dist_info')]) + run_setup(os.path.join(dep_pkg, 'setup.py'), ['dist_info']) working_set.add_entry(dep_pkg) # Create source tree for test package. test_pkg = os.path.join(temp_dir, 'test_pkg') @@ -995,11 +995,11 @@ def test_setup_requires_with_transitive_extra_dependency(self, monkeypatch): ) ) # Check... - monkeypatch.setenv(str('PIP_FIND_LINKS'), str(temp_dir)) - monkeypatch.setenv(str('PIP_NO_INDEX'), str('1')) - monkeypatch.setenv(str('PIP_RETRIES'), str('0')) - monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) - run_setup(test_setup_py, [str('--version')]) + monkeypatch.setenv('PIP_FIND_LINKS', str(temp_dir)) + monkeypatch.setenv('PIP_NO_INDEX', '1') + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') + run_setup(test_setup_py, ['--version']) def test_setup_requires_with_distutils_command_dep(self, monkeypatch): """ @@ -1063,7 +1063,7 @@ class epcmd(build_py): prefix=dep_pkg, ) # "Install" dep. - run_setup(os.path.join(dep_pkg, 'setup.py'), [str('dist_info')]) + run_setup(os.path.join(dep_pkg, 'setup.py'), ['dist_info']) working_set.add_entry(dep_pkg) # Create source tree for test package. test_pkg = os.path.join(temp_dir, 'test_pkg') @@ -1079,10 +1079,10 @@ class epcmd(build_py): ) ) # Check... - monkeypatch.setenv(str('PIP_FIND_LINKS'), str(temp_dir)) - monkeypatch.setenv(str('PIP_NO_INDEX'), str('1')) - monkeypatch.setenv(str('PIP_RETRIES'), str('0')) - monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) + monkeypatch.setenv('PIP_FIND_LINKS', str(temp_dir)) + monkeypatch.setenv('PIP_NO_INDEX', '1') + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') run_setup(test_setup_py, ['epcmd']) @@ -1286,7 +1286,7 @@ def test_get_script_header_non_ascii_exe(self): actual = ei.ScriptWriter.get_header( '#!/usr/bin/python', executable=self.non_ascii_exe ) - expected = str('#!%s -x\n') % self.non_ascii_exe + expected = '#!%s -x\n' % self.non_ascii_exe assert actual == expected def test_get_script_header_exe_with_spaces(self): diff --git a/setuptools/tests/test_integration.py b/setuptools/tests/test_integration.py index e17ffc5d5c..1aa16172b5 100644 --- a/setuptools/tests/test_integration.py +++ b/setuptools/tests/test_integration.py @@ -64,7 +64,7 @@ def fin(): monkeypatch.setattr('site.USER_BASE', user_base.strpath) monkeypatch.setattr('site.USER_SITE', user_site.strpath) monkeypatch.setattr('sys.path', sys.path + [install_dir.strpath]) - monkeypatch.setenv(str('PYTHONPATH'), str(os.path.pathsep.join(sys.path))) + monkeypatch.setenv('PYTHONPATH', str(os.path.pathsep.join(sys.path))) # Set up the command for performing the installation. dist = Distribution() From 8da168860bb7aa9d6209b10d5db6d5e61feabc81 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:44:35 +0100 Subject: [PATCH 25/36] =?UTF-8?q?os.error=20=E2=86=92=20OSError?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an alias for the built-in OSError exception: https://docs.python.org/3/library/os.html#os.error Fixed by running `ruff --select UP024 --fix .`: UP024 [*] Replace aliased errors with `OSError` --- pkg_resources/__init__.py | 4 ++-- setuptools/command/easy_install.py | 2 +- setuptools/glob.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 9adc214676..dc51076c3a 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -1895,7 +1895,7 @@ def _extract_resource(self, manager, zip_path): # noqa: C901 try: rename(tmpnam, real_path) - except os.error: + except OSError: if os.path.isfile(real_path): if self._is_current(real_path, zip_path): # the file became current since it was checked above, @@ -1908,7 +1908,7 @@ def _extract_resource(self, manager, zip_path): # noqa: C901 return real_path raise - except os.error: + except OSError: # report a user-friendly error manager.extraction_error() diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 3231650c5c..4de28bb98f 100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -2023,7 +2023,7 @@ def chmod(path, mode): log.debug("changing mode of %s to %o", path, mode) try: _chmod(path, mode) - except os.error as e: + except OSError as e: log.debug("chmod failed: %s", e) diff --git a/setuptools/glob.py b/setuptools/glob.py index ac901d9253..a184c0b643 100644 --- a/setuptools/glob.py +++ b/setuptools/glob.py @@ -125,7 +125,7 @@ def _rlistdir(dirname): dirname = os.curdir try: names = os.listdir(dirname) - except os.error: + except OSError: return for x in names: yield x From a628dc5dfb83f950c8810e65afe019b3760a7c1d Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:54:00 +0100 Subject: [PATCH 26/36] Use `capture_output` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Python ≥ 3.7, `capture_output` can be used instead of `stdout=PIPE` / `stderr=PIPE`. Fixed by running `ruff --select UP022 --fix --unsafe-fixes .`: UP022 Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output` --- setuptools/tests/integration/helpers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setuptools/tests/integration/helpers.py b/setuptools/tests/integration/helpers.py index 824dfdfe1a..62076bdf7d 100644 --- a/setuptools/tests/integration/helpers.py +++ b/setuptools/tests/integration/helpers.py @@ -15,8 +15,7 @@ def run(cmd, env=None): r = subprocess.run( cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, universal_newlines=True, env={**os.environ, **(env or {})}, # ^-- allow overwriting instead of discarding the current env From b5f07c9b52b3d35b72f4ab7f29ba574b60b24139 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:58:24 +0100 Subject: [PATCH 27/36] Remove extraneous pair of prentheses Fixed by running `ruff --select UP034 --fix .`: UP034 [*] Avoid extraneous parentheses --- setuptools/command/editable_wheel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index 73fa9fff52..57e35d53e4 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -400,7 +400,7 @@ def __init__(self, dist: Distribution, name: str, path_entries: List[Path]): self.path_entries = path_entries def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - entries = "\n".join((str(p.resolve()) for p in self.path_entries)) + entries = "\n".join(str(p.resolve()) for p in self.path_entries) contents = _encode_pth(f"{entries}\n") wheel.writestr(f"__editable__.{self.name}.pth", contents) From 86bb681be5e5e4e08b42f1bdf1bf48f1d41d8e0e Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:05:57 +0100 Subject: [PATCH 28/36] Get rid of one last `coding: utf-8` In Python 3, the source encodign is implict, UTF-8 by default. This is a suggestion from pyupgrade: https://github.com/asottile/pyupgrade#-coding--comment Fixed by running `ruff --select UP009 --fix .`: UP009 [*] UTF-8 encoding declaration is unnecessary --- setuptools/tests/test_archive_util.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/setuptools/tests/test_archive_util.py b/setuptools/tests/test_archive_util.py index 7f9962440c..06d7f05aa0 100644 --- a/setuptools/tests/test_archive_util.py +++ b/setuptools/tests/test_archive_util.py @@ -1,5 +1,3 @@ -# coding: utf-8 - import tarfile import io From 5ba5c2ed29ab165b8677aaa66e45e5b13c4abfba Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:08:47 +0100 Subject: [PATCH 29/36] Use byte literals instead of .encode() This is a suggestion from pyupgrade: https://github.com/asottile/pyupgrade#encode-to-bytes-literals Fixed by running `ruff --select UP012 --fix .`: UP012 [*] Unnecessary call to `encode` as UTF-8 --- setuptools/command/sdist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 95d325717a..71f695fd36 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -189,7 +189,7 @@ def _manifest_is_not_generated(self): with open(self.manifest, 'rb') as fp: first_line = fp.readline() - return first_line != '# file GENERATED by distutils, do NOT edit\n'.encode() + return first_line != b'# file GENERATED by distutils, do NOT edit\n' def read_manifest(self): """Read the manifest file (named by 'self.manifest') and use it to From a14299108147d551cba219908dc180e2a2b0eeb1 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:11:04 +0100 Subject: [PATCH 30/36] Use generator instead of list Fixed by running `ruff --select UP027 --fix .`: UP027 [*] Replace unpacked list comprehension with a generator expression --- pkg_resources/tests/test_working_set.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg_resources/tests/test_working_set.py b/pkg_resources/tests/test_working_set.py index f8e60e752a..57f62b5492 100644 --- a/pkg_resources/tests/test_working_set.py +++ b/pkg_resources/tests/test_working_set.py @@ -76,10 +76,10 @@ def parametrize_test_working_set_resolve(*test_list): requirements, expected1, expected2, - ) = [ + ) = ( strip_comments(s.lstrip()) for s in textwrap.dedent(test).lstrip().split('\n\n', 5) - ] + ) installed_dists = list(parse_distributions(installed_dists)) installable_dists = list(parse_distributions(installable_dists)) requirements = list(pkg_resources.parse_requirements(requirements)) From dc59f1882f2dcf1c28ba864ed248a97be5b4f716 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 5 Jan 2024 14:59:25 +0000 Subject: [PATCH 31/36] Use functools.lru_cache for 3.8 compatibility --- pkg_resources/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index db7a38981e..d8a915a5bb 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -407,7 +407,7 @@ def get_provider(moduleOrReq): return _find_adapter(_provider_factories, loader)(module) -@functools.cache +@functools.lru_cache(maxsize=None) def _macos_vers(): version = platform.mac_ver()[0] # fallback for MacPorts @@ -2420,7 +2420,7 @@ def _cygwin_patch(filename): # pragma: nocover return os.path.abspath(filename) if sys.platform == 'cygwin' else filename -@functools.cache +@functools.lru_cache(maxsize=None) def _normalize_cached(filename): return normalize_path(filename) From 356ea1b3b40bfd5191a025acae467c775f01e0fe Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 5 Jan 2024 19:11:26 +0000 Subject: [PATCH 32/36] Remove unecessary unpacking of iterator into list --- setuptools/command/editable_wheel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index 76b7606ffc..39ff4c7323 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -606,7 +606,7 @@ def _simple_layout( layout = {pkg: find_package_path(pkg, package_dir, project_dir) for pkg in packages} if not layout: return set(package_dir) in ({}, {""}) - parent = os.path.commonpath([*starmap(_parent_path, layout.items())]) + parent = os.path.commonpath(starmap(_parent_path, layout.items())) return all( _path.same_path(Path(parent, *key.split('.')), value) for key, value in layout.items() From baaef281d529ea430e5a20264d916807dbb1baae Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 5 Jan 2024 19:29:26 +0000 Subject: [PATCH 33/36] Hide unecessary parent exception --- setuptools/build_meta.py | 4 ++-- setuptools/command/egg_info.py | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index b656f47950..24210ded93 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -117,11 +117,11 @@ def _file_with_extension(directory, extension): matching = (f for f in os.listdir(directory) if f.endswith(extension)) try: (file,) = matching - except ValueError as e: + except ValueError: raise ValueError( 'No distribution was found. Ensure that `setup.py` ' 'is not empty and that it calls `setup()`.' - ) from e + ) from None return file diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index ff1864241a..62d2feea9b 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -384,10 +384,9 @@ def process_template_line(self, line): try: process_action = action_map[action] - except KeyError as e: - raise DistutilsInternalError( - f"Invalid MANIFEST.in: unknow action {action!r} in {line!r}" - ) from e + except KeyError: + msg = f"Invalid MANIFEST.in: unknown action {action!r} in {line!r}" + raise DistutilsInternalError(msg) from None # OK, now we know that the action is valid and we have the # right number of words on the line for that action -- so we From 2975a39609a6341d7cecc5018af26ccf99529e77 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 5 Jan 2024 19:45:51 +0000 Subject: [PATCH 34/36] Promote a cleaner error message if a function was never patched --- setuptools/monkey.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/monkey.py b/setuptools/monkey.py index f3148e6832..3d5edb6bd2 100644 --- a/setuptools/monkey.py +++ b/setuptools/monkey.py @@ -130,7 +130,7 @@ def patch_func(replacement, target_mod, func_name): def get_unpatched_function(candidate): - return getattr(candidate, 'unpatched', None) + return candidate.unpatched def patch_for_msvc_specialized_compiler(): From 07774d965eccd43bc2d46d24c7264276ca2bba3b Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 5 Jan 2024 19:55:10 +0000 Subject: [PATCH 35/36] Ignore path that are automatically generated --- ruff.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruff.toml b/ruff.toml index 791cfdc0a5..89c2910997 100644 --- a/ruff.toml +++ b/ruff.toml @@ -29,12 +29,14 @@ extend-ignore = [ extend-exclude = [ "**/_vendor", "setuptools/_distutils", + "setuptools/config/_validate_pyproject", ] [format] extend-exclude = [ "**/_vendor", "setuptools/_distutils", + "setuptools/config/_validate_pyproject", ] # https://docs.astral.sh/ruff/settings/#format-quote-style quote-style = "preserve" From eec302354da892ef140eb444903d215d74452fde Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Fri, 5 Jan 2024 21:40:19 +0100 Subject: [PATCH 36/36] =?UTF-8?q?ruff:=20extend-exclude=20=E2=86=92=20excl?= =?UTF-8?q?ude?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no such thing as extend-include, at least in ruff 0.1.11: ruff failed Cause: Failed to parse /path/to/ruff.toml Cause: TOML parse error at line 1, column 1 | 1 | [lint] | ^^^^^^ unknown field `extend-exclude` --- ruff.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruff.toml b/ruff.toml index 89c2910997..18776ab60a 100644 --- a/ruff.toml +++ b/ruff.toml @@ -26,14 +26,14 @@ extend-ignore = [ "UP032", # temporarily disabled "UP036", # temporarily disabled ] -extend-exclude = [ +exclude = [ "**/_vendor", "setuptools/_distutils", "setuptools/config/_validate_pyproject", ] [format] -extend-exclude = [ +exclude = [ "**/_vendor", "setuptools/_distutils", "setuptools/config/_validate_pyproject",