Skip to content

Commit

Permalink
Merge branch 'main' into feature/distutils-ff11eed0c
Browse files Browse the repository at this point in the history
  • Loading branch information
jaraco committed Jan 5, 2025
2 parents 5ed9d93 + 53d5ac2 commit fbe834a
Show file tree
Hide file tree
Showing 45 changed files with 242 additions and 285 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.1
rev: v0.8.0
hooks:
- id: ruff
args: [--fix, --unsafe-fixes]
Expand Down
2 changes: 1 addition & 1 deletion docs/userguide/extension.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ a non-``None`` value. Here's an example validation function::
"""Verify that value is True, False, 0, or 1"""
if bool(value) != value:
raise SetupError(
"%r must be a boolean value (got %r)" % (attr,value)
f"{attr!r} must be a boolean value (got {value!r}"
)

Your function should accept three arguments: the ``Distribution`` object,
Expand Down
6 changes: 3 additions & 3 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ ignore_missing_imports = True

# - wheel: does not intend on exposing a programmatic API https://github.com/pypa/wheel/pull/610#issuecomment-2081687671
[mypy-wheel.*]
ignore_missing_imports = True
follow_untyped_imports = True
# - The following are not marked as py.typed:
# - jaraco: Since mypy 1.12, the root name of the untyped namespace package gets called-out too
# - jaraco.develop: https://github.com/jaraco/jaraco.develop/issues/22
# - jaraco.envs: https://github.com/jaraco/jaraco.envs/issues/7
# - jaraco.packaging: https://github.com/jaraco/jaraco.packaging/issues/20
# - jaraco.path: https://github.com/jaraco/jaraco.path/issues/2
# - jaraco.text: https://github.com/jaraco/jaraco.text/issues/17
[mypy-jaraco,jaraco.develop,jaraco.envs,jaraco.packaging.*,jaraco.path,jaraco.text]
ignore_missing_imports = True
[mypy-jaraco,jaraco.develop.*,jaraco.envs,jaraco.packaging.*,jaraco.path,jaraco.text]
follow_untyped_imports = True

# Even when excluding a module, import issues can show up due to following import
# https://github.com/python/mypy/issues/11936#issuecomment-1466764006
Expand Down
1 change: 1 addition & 0 deletions newsfragments/4478.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Synced with pypa/distutils@c97a3db2f including better support for free threaded Python on Windows (pypa/distutils#310), improved typing support, and linter accommodations.
59 changes: 25 additions & 34 deletions pkg_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ def get_supported_platform():
m = macosVersionString.match(plat)
if m is not None and sys.platform == "darwin":
try:
plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))
major_minor = '.'.join(_macos_vers()[:2])
build = m.group(3)
plat = f'macosx-{major_minor}-{build}'
except ValueError:
# not macOS
pass
Expand Down Expand Up @@ -449,12 +451,8 @@ def get_build_platform():
if sys.platform == "darwin" and not plat.startswith('macosx-'):
try:
version = _macos_vers()
machine = os.uname()[4].replace(" ", "_")
return "macosx-%d.%d-%s" % (
int(version[0]),
int(version[1]),
_macos_arch(machine),
)
machine = _macos_arch(os.uname()[4].replace(" ", "_"))
return f"macosx-{version[0]}.{version[1]}-{machine}"
except ValueError:
# if someone is running a non-Mac darwin system, this will fall
# through to the default implementation
Expand Down Expand Up @@ -492,7 +490,7 @@ def compatible_platforms(provided: str | None, required: str | None) -> bool:
provDarwin = darwinVersionString.match(provided)
if provDarwin:
dversion = int(provDarwin.group(1))
macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))
macosversion = f"{reqMac.group(1)}.{reqMac.group(2)}"
if (
dversion == 7
and macosversion >= "10.3"
Expand Down Expand Up @@ -1316,7 +1314,7 @@ def __iadd__(self, other: Distribution | Environment) -> Self:
for dist in other[project]:
self.add(dist)
else:
raise TypeError("Can't add %r to environment" % (other,))
raise TypeError(f"Can't add {other!r} to environment")
return self

def __add__(self, other: Distribution | Environment) -> Self:
Expand Down Expand Up @@ -1699,7 +1697,7 @@ def get_metadata(self, name: str) -> str:
except UnicodeDecodeError as exc:
# Include the path in the error message to simplify
# troubleshooting, and without changing the exception type.
exc.reason += ' in {} file at path: {}'.format(name, path)
exc.reason += f' in {name} file at path: {path}'
raise

def get_metadata_lines(self, name: str) -> Iterator[str]:
Expand Down Expand Up @@ -2018,15 +2016,15 @@ def _zipinfo_name(self, fspath):
return ''
if fspath.startswith(self.zip_pre):
return fspath[len(self.zip_pre) :]
raise AssertionError("%s is not a subpath of %s" % (fspath, self.zip_pre))
raise AssertionError(f"{fspath} is not a subpath of {self.zip_pre}")

def _parts(self, zip_path):
# Convert a zipfile subpath into an egg-relative path part list.
# pseudo-fs path
fspath = self.zip_pre + zip_path
if fspath.startswith(self.egg_root + os.sep):
return fspath[len(self.egg_root) + 1 :].split(os.sep)
raise AssertionError("%s is not a subpath of %s" % (fspath, self.egg_root))
raise AssertionError(f"{fspath} is not a subpath of {self.egg_root}")

@property
def zipinfo(self):
Expand Down Expand Up @@ -2729,15 +2727,16 @@ def __init__(
self.dist = dist

def __str__(self) -> str:
s = "%s = %s" % (self.name, self.module_name)
s = f"{self.name} = {self.module_name}"
if self.attrs:
s += ':' + '.'.join(self.attrs)
if self.extras:
s += ' [%s]' % ','.join(self.extras)
extras = ','.join(self.extras)
s += f' [{extras}]'
return s

def __repr__(self) -> str:
return "EntryPoint.parse(%r)" % str(self)
return f"EntryPoint.parse({str(self)!r})"

@overload
def load(
Expand Down Expand Up @@ -3049,9 +3048,7 @@ def version(self):
version = self._get_version()
if version is None:
path = self._get_metadata_path_for_display(self.PKG_INFO)
msg = ("Missing 'Version:' header and/or {} file at path: {}").format(
self.PKG_INFO, path
)
msg = f"Missing 'Version:' header and/or {self.PKG_INFO} file at path: {path}"
raise ValueError(msg, self) from e

return version
Expand Down Expand Up @@ -3107,9 +3104,7 @@ def requires(self, extras: Iterable[str] = ()) -> list[Requirement]:
try:
deps.extend(dm[safe_extra(ext)])
except KeyError as e:
raise UnknownExtra(
"%s has no such extra feature %r" % (self, ext)
) from e
raise UnknownExtra(f"{self} has no such extra feature {ext!r}") from e
return deps

def _get_metadata_path_for_display(self, name):
Expand Down Expand Up @@ -3150,19 +3145,15 @@ def activate(self, path: list[str] | None = None, replace: bool = False) -> None

def egg_name(self):
"""Return what this distribution's standard .egg filename should be"""
filename = "%s-%s-py%s" % (
to_filename(self.project_name),
to_filename(self.version),
self.py_version or PY_MAJOR,
)
filename = f"{to_filename(self.project_name)}-{to_filename(self.version)}-py{self.py_version or PY_MAJOR}"

if self.platform:
filename += '-' + self.platform
return filename

def __repr__(self) -> str:
if self.location:
return "%s (%s)" % (self, self.location)
return f"{self} ({self.location})"
else:
return str(self)

Expand All @@ -3172,7 +3163,7 @@ def __str__(self) -> str:
except ValueError:
version = None
version = version or "[unknown version]"
return "%s %s" % (self.project_name, version)
return f"{self.project_name} {version}"

def __getattr__(self, attr: str):
"""Delegate all unrecognized public attributes to .metadata provider"""
Expand Down Expand Up @@ -3200,17 +3191,17 @@ def from_filename(
def as_requirement(self):
"""Return a ``Requirement`` that matches this distribution exactly"""
if isinstance(self.parsed_version, packaging.version.Version):
spec = "%s==%s" % (self.project_name, self.parsed_version)
spec = f"{self.project_name}=={self.parsed_version}"
else:
spec = "%s===%s" % (self.project_name, self.parsed_version)
spec = f"{self.project_name}==={self.parsed_version}"

return Requirement.parse(spec)

def load_entry_point(self, group: str, name: str) -> _ResolvedEntryPoint:
"""Return the `name` entry point of `group` or raise ImportError"""
ep = self.get_entry_info(group, name)
if ep is None:
raise ImportError("Entry point %r not found" % ((group, name),))
raise ImportError(f"Entry point {(group, name)!r} not found")
return ep.load()

@overload
Expand Down Expand Up @@ -3327,8 +3318,8 @@ def check_version_conflict(self):
):
continue
issue_warning(
"Module %s was already imported from %s, but %s is being added"
" to sys.path" % (modname, fn, self.location),
f"Module {modname} was already imported from {fn}, "
f"but {self.location} is being added to sys.path",
)

def has_version(self) -> bool:
Expand Down Expand Up @@ -3512,7 +3503,7 @@ def __hash__(self) -> int:
return self.__hash

def __repr__(self) -> str:
return "Requirement.parse(%r)" % str(self)
return f"Requirement.parse({str(self)!r})"

@staticmethod
def parse(s: str | Iterable[str]) -> Requirement:
Expand Down
10 changes: 5 additions & 5 deletions pkg_resources/tests/test_pkg_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,8 @@ def test_get_metadata__bad_utf8(tmpdir):
"codec can't decode byte 0xe9 in position 1: "
'invalid continuation byte in METADATA file at path: '
)
assert expected in actual, 'actual: {}'.format(actual)
assert actual.endswith(metadata_path), 'actual: {}'.format(actual)
assert expected in actual, f'actual: {actual}'
assert actual.endswith(metadata_path), f'actual: {actual}'


def make_distribution_no_version(tmpdir, basename):
Expand Down Expand Up @@ -252,11 +252,11 @@ def test_distribution_version_missing(
"""
Test Distribution.version when the "Version" header is missing.
"""
basename = 'foo.{}'.format(suffix)
basename = f'foo.{suffix}'
dist, dist_dir = make_distribution_no_version(tmpdir, basename)

expected_text = ("Missing 'Version:' header and/or {} file at path: ").format(
expected_filename
expected_text = (
f"Missing 'Version:' header and/or {expected_filename} file at path: "
)
metadata_path = os.path.join(dist_dir, expected_filename)

Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ test = [
"packaging>=24.2",
"jaraco.envs>=2.2",
"pytest-xdist>=3", # Dropped dependency on pytest-fork and py
"jaraco.path>=3.2.0",
"jaraco.path>=3.7.2", # Typing fixes
"build[virtualenv]>=1.0.3",
"filelock>=3.4.0",
"ini2toml[lite]>=0.14",
Expand Down Expand Up @@ -114,8 +114,8 @@ check = [

# local

# changed defaults for PT001 and PT023 astral-sh/ruff#13292
"ruff >= 0.7.0; sys_platform != 'cygwin'",
# Removal of deprecated UP027, PT004 & PT005 astral-sh/ruff#14383
"ruff >= 0.8.0; sys_platform != 'cygwin'",
]

cover = [
Expand All @@ -135,7 +135,7 @@ type = [
# pin mypy version so a new version doesn't suddenly cause the CI to fail,
# until types-setuptools is removed from typeshed.
# For help with static-typing issues, or mypy update, ping @Avasam
"mypy>=1.12,<1.14",
"mypy==1.14.*",
# Typing fixes in version newer than we require at runtime
"importlib_metadata>=7.0.2; python_version < '3.10'",
# Imported unconditionally in tools/finalize.py
Expand Down
6 changes: 0 additions & 6 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,12 @@ extend-select = [
]
ignore = [
"PERF203", # try-except-in-loop, micro-optimisation with many false-positive. Worth checking but don't block CI
"PT004", # deprecated https://github.com/astral-sh/ruff/issues/8796#issuecomment-2057143531
"PT005", # deprecated https://github.com/astral-sh/ruff/issues/8796#issuecomment-2057143531
"PT007", # temporarily disabled, TODO: configure and standardize to preference
"PT011", # temporarily disabled, TODO: tighten expected error
"PT012", # pytest-raises-with-multiple-statements, avoid extra dummy methods for a few lines, sometimes we explicitly assert in case of no error
"TRY003", # raise-vanilla-args, avoid multitude of exception classes
"TRY301", # raise-within-try, it's handy
"UP015", # redundant-open-modes, explicit is preferred
"UP027", # unpacked-list-comprehension, is actually slower for cases relevant to unpacking, set for deprecation: https://github.com/astral-sh/ruff/issues/12754
"UP030", # temporarily disabled
"UP031", # temporarily disabled
"UP032", # temporarily disabled
"UP038", # Using `X | Y` in `isinstance` call is slower and more verbose https://github.com/astral-sh/ruff/issues/7871
# Only enforcing return type annotations for public functions
"ANN202", # missing-return-type-private-function
Expand Down
6 changes: 2 additions & 4 deletions setuptools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,7 @@ def _ensure_stringlike(self, option, what, default=None):
setattr(self, option, default)
return default
elif not isinstance(val, str):
raise DistutilsOptionError(
"'%s' must be a %s (got `%s`)" % (option, what, val)
)
raise DistutilsOptionError(f"'{option}' must be a {what} (got `{val}`)")
return val

def ensure_string_list(self, option: str) -> None:
Expand All @@ -210,7 +208,7 @@ def ensure_string_list(self, option: str) -> None:
ok = False
if not ok:
raise DistutilsOptionError(
"'%s' must be a list of strings (got %r)" % (option, val)
f"'{option}' must be a list of strings (got {val!r})"
)

@overload
Expand Down
8 changes: 4 additions & 4 deletions setuptools/_core_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME
version = self.get_metadata_version()

def write_field(key, value):
file.write("%s: %s\n" % (key, value))
file.write(f"{key}: {value}\n")

write_field('Metadata-Version', str(version))
write_field('Name', self.get_name())
Expand Down Expand Up @@ -178,8 +178,8 @@ def write_field(key, value):
if license:
write_field('License', rfc822_escape(license))

for project_url in self.project_urls.items():
write_field('Project-URL', '%s, %s' % project_url)
for label, url in self.project_urls.items():
write_field('Project-URL', f'{label}, {url}')

keywords = ','.join(self.get_keywords())
if keywords:
Expand Down Expand Up @@ -209,7 +209,7 @@ def write_field(key, value):

long_description = self.get_long_description()
if long_description:
file.write("\n%s" % long_description)
file.write(f"\n{long_description}")
if not long_description.endswith("\n"):
file.write("\n")

Expand Down
6 changes: 3 additions & 3 deletions setuptools/_imp.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def find_module(module, paths=None):
"""Just like 'imp.find_module()', but with package support"""
spec = find_spec(module, paths)
if spec is None:
raise ImportError("Can't find %s" % module)
raise ImportError(f"Can't find {module}")
if not spec.has_location and hasattr(spec, 'submodule_search_locations'):
spec = importlib.util.spec_from_loader('__init__.py', spec.loader)

Expand Down Expand Up @@ -76,12 +76,12 @@ def find_module(module, paths=None):
def get_frozen_object(module, paths=None):
spec = find_spec(module, paths)
if not spec:
raise ImportError("Can't find %s" % module)
raise ImportError(f"Can't find {module}")
return spec.loader.get_code(module)


def get_module(module, paths, info):
spec = find_spec(module, paths)
if not spec:
raise ImportError("Can't find %s" % module)
raise ImportError(f"Can't find {module}")
return module_from_spec(spec)
Loading

0 comments on commit fbe834a

Please sign in to comment.