Skip to content

Commit fbe834a

Browse files
committed
Merge branch 'main' into feature/distutils-ff11eed0c
2 parents 5ed9d93 + 53d5ac2 commit fbe834a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+242
-285
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
3-
rev: v0.7.1
3+
rev: v0.8.0
44
hooks:
55
- id: ruff
66
args: [--fix, --unsafe-fixes]

docs/userguide/extension.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ a non-``None`` value. Here's an example validation function::
122122
"""Verify that value is True, False, 0, or 1"""
123123
if bool(value) != value:
124124
raise SetupError(
125-
"%r must be a boolean value (got %r)" % (attr,value)
125+
f"{attr!r} must be a boolean value (got {value!r}"
126126
)
127127

128128
Your function should accept three arguments: the ``Distribution`` object,

mypy.ini

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,16 @@ ignore_missing_imports = True
5858

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

7272
# Even when excluding a module, import issues can show up due to following import
7373
# https://github.com/python/mypy/issues/11936#issuecomment-1466764006

newsfragments/4478.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Synced with pypa/distutils@c97a3db2f including better support for free threaded Python on Windows (pypa/distutils#310), improved typing support, and linter accommodations.

pkg_resources/__init__.py

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,9 @@ def get_supported_platform():
200200
m = macosVersionString.match(plat)
201201
if m is not None and sys.platform == "darwin":
202202
try:
203-
plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))
203+
major_minor = '.'.join(_macos_vers()[:2])
204+
build = m.group(3)
205+
plat = f'macosx-{major_minor}-{build}'
204206
except ValueError:
205207
# not macOS
206208
pass
@@ -449,12 +451,8 @@ def get_build_platform():
449451
if sys.platform == "darwin" and not plat.startswith('macosx-'):
450452
try:
451453
version = _macos_vers()
452-
machine = os.uname()[4].replace(" ", "_")
453-
return "macosx-%d.%d-%s" % (
454-
int(version[0]),
455-
int(version[1]),
456-
_macos_arch(machine),
457-
)
454+
machine = _macos_arch(os.uname()[4].replace(" ", "_"))
455+
return f"macosx-{version[0]}.{version[1]}-{machine}"
458456
except ValueError:
459457
# if someone is running a non-Mac darwin system, this will fall
460458
# through to the default implementation
@@ -492,7 +490,7 @@ def compatible_platforms(provided: str | None, required: str | None) -> bool:
492490
provDarwin = darwinVersionString.match(provided)
493491
if provDarwin:
494492
dversion = int(provDarwin.group(1))
495-
macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))
493+
macosversion = f"{reqMac.group(1)}.{reqMac.group(2)}"
496494
if (
497495
dversion == 7
498496
and macosversion >= "10.3"
@@ -1316,7 +1314,7 @@ def __iadd__(self, other: Distribution | Environment) -> Self:
13161314
for dist in other[project]:
13171315
self.add(dist)
13181316
else:
1319-
raise TypeError("Can't add %r to environment" % (other,))
1317+
raise TypeError(f"Can't add {other!r} to environment")
13201318
return self
13211319

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

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

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

20312029
@property
20322030
def zipinfo(self):
@@ -2729,15 +2727,16 @@ def __init__(
27292727
self.dist = dist
27302728

27312729
def __str__(self) -> str:
2732-
s = "%s = %s" % (self.name, self.module_name)
2730+
s = f"{self.name} = {self.module_name}"
27332731
if self.attrs:
27342732
s += ':' + '.'.join(self.attrs)
27352733
if self.extras:
2736-
s += ' [%s]' % ','.join(self.extras)
2734+
extras = ','.join(self.extras)
2735+
s += f' [{extras}]'
27372736
return s
27382737

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

27422741
@overload
27432742
def load(
@@ -3049,9 +3048,7 @@ def version(self):
30493048
version = self._get_version()
30503049
if version is None:
30513050
path = self._get_metadata_path_for_display(self.PKG_INFO)
3052-
msg = ("Missing 'Version:' header and/or {} file at path: {}").format(
3053-
self.PKG_INFO, path
3054-
)
3051+
msg = f"Missing 'Version:' header and/or {self.PKG_INFO} file at path: {path}"
30553052
raise ValueError(msg, self) from e
30563053

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

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

31513146
def egg_name(self):
31523147
"""Return what this distribution's standard .egg filename should be"""
3153-
filename = "%s-%s-py%s" % (
3154-
to_filename(self.project_name),
3155-
to_filename(self.version),
3156-
self.py_version or PY_MAJOR,
3157-
)
3148+
filename = f"{to_filename(self.project_name)}-{to_filename(self.version)}-py{self.py_version or PY_MAJOR}"
31583149

31593150
if self.platform:
31603151
filename += '-' + self.platform
31613152
return filename
31623153

31633154
def __repr__(self) -> str:
31643155
if self.location:
3165-
return "%s (%s)" % (self, self.location)
3156+
return f"{self} ({self.location})"
31663157
else:
31673158
return str(self)
31683159

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

31773168
def __getattr__(self, attr: str):
31783169
"""Delegate all unrecognized public attributes to .metadata provider"""
@@ -3200,17 +3191,17 @@ def from_filename(
32003191
def as_requirement(self):
32013192
"""Return a ``Requirement`` that matches this distribution exactly"""
32023193
if isinstance(self.parsed_version, packaging.version.Version):
3203-
spec = "%s==%s" % (self.project_name, self.parsed_version)
3194+
spec = f"{self.project_name}=={self.parsed_version}"
32043195
else:
3205-
spec = "%s===%s" % (self.project_name, self.parsed_version)
3196+
spec = f"{self.project_name}==={self.parsed_version}"
32063197

32073198
return Requirement.parse(spec)
32083199

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

32163207
@overload
@@ -3327,8 +3318,8 @@ def check_version_conflict(self):
33273318
):
33283319
continue
33293320
issue_warning(
3330-
"Module %s was already imported from %s, but %s is being added"
3331-
" to sys.path" % (modname, fn, self.location),
3321+
f"Module {modname} was already imported from {fn}, "
3322+
f"but {self.location} is being added to sys.path",
33323323
)
33333324

33343325
def has_version(self) -> bool:
@@ -3512,7 +3503,7 @@ def __hash__(self) -> int:
35123503
return self.__hash
35133504

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

35173508
@staticmethod
35183509
def parse(s: str | Iterable[str]) -> Requirement:

pkg_resources/tests/test_pkg_resources.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ def test_get_metadata__bad_utf8(tmpdir):
214214
"codec can't decode byte 0xe9 in position 1: "
215215
'invalid continuation byte in METADATA file at path: '
216216
)
217-
assert expected in actual, 'actual: {}'.format(actual)
218-
assert actual.endswith(metadata_path), 'actual: {}'.format(actual)
217+
assert expected in actual, f'actual: {actual}'
218+
assert actual.endswith(metadata_path), f'actual: {actual}'
219219

220220

221221
def make_distribution_no_version(tmpdir, basename):
@@ -252,11 +252,11 @@ def test_distribution_version_missing(
252252
"""
253253
Test Distribution.version when the "Version" header is missing.
254254
"""
255-
basename = 'foo.{}'.format(suffix)
255+
basename = f'foo.{suffix}'
256256
dist, dist_dir = make_distribution_no_version(tmpdir, basename)
257257

258-
expected_text = ("Missing 'Version:' header and/or {} file at path: ").format(
259-
expected_filename
258+
expected_text = (
259+
f"Missing 'Version:' header and/or {expected_filename} file at path: "
260260
)
261261
metadata_path = os.path.join(dist_dir, expected_filename)
262262

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ test = [
4444
"packaging>=24.2",
4545
"jaraco.envs>=2.2",
4646
"pytest-xdist>=3", # Dropped dependency on pytest-fork and py
47-
"jaraco.path>=3.2.0",
47+
"jaraco.path>=3.7.2", # Typing fixes
4848
"build[virtualenv]>=1.0.3",
4949
"filelock>=3.4.0",
5050
"ini2toml[lite]>=0.14",
@@ -114,8 +114,8 @@ check = [
114114

115115
# local
116116

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

121121
cover = [
@@ -135,7 +135,7 @@ type = [
135135
# pin mypy version so a new version doesn't suddenly cause the CI to fail,
136136
# until types-setuptools is removed from typeshed.
137137
# For help with static-typing issues, or mypy update, ping @Avasam
138-
"mypy>=1.12,<1.14",
138+
"mypy==1.14.*",
139139
# Typing fixes in version newer than we require at runtime
140140
"importlib_metadata>=7.0.2; python_version < '3.10'",
141141
# Imported unconditionally in tools/finalize.py

ruff.toml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,12 @@ extend-select = [
2929
]
3030
ignore = [
3131
"PERF203", # try-except-in-loop, micro-optimisation with many false-positive. Worth checking but don't block CI
32-
"PT004", # deprecated https://github.com/astral-sh/ruff/issues/8796#issuecomment-2057143531
33-
"PT005", # deprecated https://github.com/astral-sh/ruff/issues/8796#issuecomment-2057143531
3432
"PT007", # temporarily disabled, TODO: configure and standardize to preference
3533
"PT011", # temporarily disabled, TODO: tighten expected error
3634
"PT012", # pytest-raises-with-multiple-statements, avoid extra dummy methods for a few lines, sometimes we explicitly assert in case of no error
3735
"TRY003", # raise-vanilla-args, avoid multitude of exception classes
3836
"TRY301", # raise-within-try, it's handy
3937
"UP015", # redundant-open-modes, explicit is preferred
40-
"UP027", # unpacked-list-comprehension, is actually slower for cases relevant to unpacking, set for deprecation: https://github.com/astral-sh/ruff/issues/12754
41-
"UP030", # temporarily disabled
42-
"UP031", # temporarily disabled
43-
"UP032", # temporarily disabled
4438
"UP038", # Using `X | Y` in `isinstance` call is slower and more verbose https://github.com/astral-sh/ruff/issues/7871
4539
# Only enforcing return type annotations for public functions
4640
"ANN202", # missing-return-type-private-function

setuptools/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,7 @@ def _ensure_stringlike(self, option, what, default=None):
181181
setattr(self, option, default)
182182
return default
183183
elif not isinstance(val, str):
184-
raise DistutilsOptionError(
185-
"'%s' must be a %s (got `%s`)" % (option, what, val)
186-
)
184+
raise DistutilsOptionError(f"'{option}' must be a {what} (got `{val}`)")
187185
return val
188186

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

216214
@overload

setuptools/_core_metadata.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME
150150
version = self.get_metadata_version()
151151

152152
def write_field(key, value):
153-
file.write("%s: %s\n" % (key, value))
153+
file.write(f"{key}: {value}\n")
154154

155155
write_field('Metadata-Version', str(version))
156156
write_field('Name', self.get_name())
@@ -178,8 +178,8 @@ def write_field(key, value):
178178
if license:
179179
write_field('License', rfc822_escape(license))
180180

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

184184
keywords = ','.join(self.get_keywords())
185185
if keywords:
@@ -209,7 +209,7 @@ def write_field(key, value):
209209

210210
long_description = self.get_long_description()
211211
if long_description:
212-
file.write("\n%s" % long_description)
212+
file.write(f"\n{long_description}")
213213
if not long_description.endswith("\n"):
214214
file.write("\n")
215215

0 commit comments

Comments
 (0)