diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 1e4136a002..288280c78d 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=[]): - 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.append(version.split('.')) - return _cache[0] +@functools.lru_cache(maxsize=None) +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,12 +2420,9 @@ def _cygwin_patch(filename): # pragma: nocover return os.path.abspath(filename) if sys.platform == 'cygwin' else filename -def _normalize_cached(filename, _cache={}): - try: - return _cache[filename] - except KeyError: - _cache[filename] = result = normalize_path(filename) - return result +@functools.lru_cache(maxsize=None) +def _normalize_cached(filename): + return normalize_path(filename) def _is_egg_path(path): 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() diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 18ebb75c24..62954b3b77 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -121,7 +121,7 @@ def _file_with_extension(directory, extension): raise ValueError( 'No distribution was found. Ensure that `setup.py` ' 'is not empty and that it calls `setup()`.' - ) + ) from None return file 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/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/editable_wheel.py b/setuptools/command/editable_wheel.py index 57e35d53e4..c1f9899dfe 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() diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 7169f33535..62d2feea9b 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -385,9 +385,8 @@ def process_template_line(self, line): try: process_action = action_map[action] except KeyError: - raise DistutilsInternalError( - "this cannot happen: invalid action '{action!s}'".format(action=action), - ) + 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 diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 71f695fd36..86ec048280 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -105,7 +105,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/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/config/_validate_pyproject/error_reporting.py b/setuptools/config/_validate_pyproject/error_reporting.py index f78e4838fb..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", "anyOf", "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) 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/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(): 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) diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py index 1281eb52a2..b912194805 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 c6e3bf039a..ef85978ecb 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) 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 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): 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):