Skip to content

Commit 8df18dd

Browse files
authored
Merge branch 'main' into refactor/canonicalize-reuse
2 parents d91bc42 + c385b58 commit 8df18dd

19 files changed

+89
-102
lines changed

.github/workflows/codeql.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535

3636
# Initializes the CodeQL tools for scanning.
3737
- name: Initialize CodeQL
38-
uses: github/codeql-action/init@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
38+
uses: github/codeql-action/init@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15
3939
with:
4040
languages: ${{ matrix.language }}
4141
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -47,9 +47,9 @@ jobs:
4747

4848
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
4949
- name: Autobuild
50-
uses: github/codeql-action/autobuild@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
50+
uses: github/codeql-action/autobuild@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15
5151

5252
- name: Perform CodeQL Analysis
53-
uses: github/codeql-action/analyze@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
53+
uses: github/codeql-action/analyze@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15
5454
with:
5555
category: "/language:${{matrix.language}}"

.github/workflows/docs.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
steps:
2626
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
2727

28-
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
28+
- uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1
2929
name: Install Python
3030
with:
3131
python-version: "3.9"

.github/workflows/lint.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
steps:
2828
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
2929

30-
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
30+
- uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1
3131
name: Install Python
3232
with:
3333
python-version: "3.9"
@@ -52,7 +52,7 @@ jobs:
5252
run: pipx run build
5353

5454
- name: Archive files
55-
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
55+
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
5656
with:
5757
name: dist
5858
path: dist

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
steps:
3232
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
3333

34-
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
34+
- uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1
3535
name: Install Python ${{ matrix.python_version }}
3636
with:
3737
python-version: ${{ matrix.python_version }}

CHANGELOG.rst

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ No unreleased changes.
3838
* Make ``utils.parse_sdist_filename()`` and ``utils.parse_wheel_filename()``
3939
raise ``InvalidSdistFilename`` and ``InvalidWheelFilename``, respectively,
4040
when the version component of the name is invalid
41+
* Remove support for Python 3.7 (:issue:`783`)
4142

4243
23.1 - 2023-04-12
4344
~~~~~~~~~~~~~~~~~

docs/utils.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,12 @@ Reference
5656
>>> is_normalized_name("Django")
5757
False
5858

59-
.. function:: canonicalize_version(version)
59+
.. function:: canonicalize_version(version, strip_trailing_zero=True)
6060

6161
This function takes a string representing a package version (or a
6262
:class:`~packaging.version.Version` instance), and returns the
63-
normalized form of it.
63+
normalized form of it. By default, it strips trailing zeros from
64+
the release segment.
6465

6566
:param str version: The version to normalize.
6667

pyproject.toml

+3-6
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,15 @@ extend-select = [
7070
"I",
7171
"N",
7272
"UP",
73+
"RUF",
7374
"W"
7475
]
7576
ignore = [
76-
"B009",
77-
"B015",
78-
"B018",
7977
"B027",
80-
"B028",
81-
"B904",
8278
"N818",
79+
"RUF003",
80+
"RUF012",
8381
"UP032",
84-
"UP030",
8582
# https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
8683
"W191",
8784
"E111",

src/packaging/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
__email__ = "donald@stufft.io"
1313

1414
__license__ = "BSD-2-Clause or Apache-2.0"
15-
__copyright__ = "2014 %s" % __author__
15+
__copyright__ = f"2014 {__author__}"

src/packaging/_elffile.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ def __init__(self, f: IO[bytes]) -> None:
4848

4949
try:
5050
ident = self._read("16B")
51-
except struct.error:
52-
raise ELFInvalid("unable to parse identification")
51+
except struct.error as e:
52+
raise ELFInvalid("unable to parse identification") from e
5353
magic = bytes(ident[:4])
5454
if magic != b"\x7fELF":
5555
raise ELFInvalid(f"invalid magic: {magic!r}")
@@ -67,11 +67,11 @@ def __init__(self, f: IO[bytes]) -> None:
6767
(2, 1): ("<HHIQQQIHHH", "<IIQQQQQQ", (0, 2, 5)), # 64-bit LSB.
6868
(2, 2): (">HHIQQQIHHH", ">IIQQQQQQ", (0, 2, 5)), # 64-bit MSB.
6969
}[(self.capacity, self.encoding)]
70-
except KeyError:
70+
except KeyError as e:
7171
raise ELFInvalid(
7272
f"unrecognized capacity ({self.capacity}) or "
7373
f"encoding ({self.encoding})"
74-
)
74+
) from e
7575

7676
try:
7777
(

src/packaging/_manylinux.py

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ def _parse_glibc_version(version_str: str) -> tuple[int, int]:
164164
f"Expected glibc version with 2 components major.minor,"
165165
f" got: {version_str}",
166166
RuntimeWarning,
167+
stacklevel=2,
167168
)
168169
return -1, -1
169170
return int(m.group("major")), int(m.group("minor"))

src/packaging/markers.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
__all__ = [
2020
"InvalidMarker",
21+
"Marker",
2122
"UndefinedComparison",
2223
"UndefinedEnvironmentName",
23-
"Marker",
2424
"default_environment",
2525
]
2626

@@ -232,7 +232,7 @@ def _evaluate_markers(markers: MarkerList, environment: dict[str, str]) -> bool:
232232

233233

234234
def format_full_version(info: sys._version_info) -> str:
235-
version = "{0.major}.{0.minor}.{0.micro}".format(info)
235+
version = f"{info.major}.{info.minor}.{info.micro}"
236236
kind = info.releaselevel
237237
if kind != "final":
238238
version += kind[0] + str(info.serial)
@@ -309,17 +309,23 @@ def evaluate(self, environment: dict[str, str] | None = None) -> bool:
309309
"""
310310
current_environment = cast("dict[str, str]", default_environment())
311311
current_environment["extra"] = ""
312-
# Work around platform.python_version() returning something that is not PEP 440
313-
# compliant for non-tagged Python builds. We preserve default_environment()'s
314-
# behavior of returning platform.python_version() verbatim, and leave it to the
315-
# caller to provide a syntactically valid version if they want to override it.
316-
if current_environment["python_full_version"].endswith("+"):
317-
current_environment["python_full_version"] += "local"
318312
if environment is not None:
319313
current_environment.update(environment)
320314
# The API used to allow setting extra to None. We need to handle this
321315
# case for backwards compatibility.
322316
if current_environment["extra"] is None:
323317
current_environment["extra"] = ""
324318

325-
return _evaluate_markers(self._markers, current_environment)
319+
return _evaluate_markers(
320+
self._markers, _repair_python_full_version(current_environment)
321+
)
322+
323+
324+
def _repair_python_full_version(env: dict[str, str]) -> dict[str, str]:
325+
"""
326+
Work around platform.python_version() returning something that is not PEP 440
327+
compliant for non-tagged Python builds.
328+
"""
329+
if env["python_full_version"].endswith("+"):
330+
env["python_full_version"] += "local"
331+
return env

src/packaging/metadata.py

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import builtins
34
import email.feedparser
45
import email.header
56
import email.message
@@ -21,9 +22,9 @@
2122
T = typing.TypeVar("T")
2223

2324

24-
try:
25-
ExceptionGroup
26-
except NameError: # pragma: no cover
25+
if "ExceptionGroup" in builtins.__dict__: # pragma: no cover
26+
ExceptionGroup = ExceptionGroup
27+
else: # pragma: no cover
2728

2829
class ExceptionGroup(Exception):
2930
"""A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11.
@@ -42,9 +43,6 @@ def __init__(self, message: str, exceptions: list[Exception]) -> None:
4243
def __repr__(self) -> str:
4344
return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})"
4445

45-
else: # pragma: no cover
46-
ExceptionGroup = ExceptionGroup
47-
4846

4947
class InvalidMetadata(ValueError):
5048
"""A metadata field contains invalid data."""
@@ -167,7 +165,7 @@ class RawMetadata(TypedDict, total=False):
167165

168166

169167
def _parse_keywords(data: str) -> list[str]:
170-
"""Split a string of comma-separate keyboards into a list of keywords."""
168+
"""Split a string of comma-separated keywords into a list of keywords."""
171169
return [k.strip() for k in data.split(",")]
172170

173171

@@ -224,8 +222,8 @@ def _get_payload(msg: email.message.Message, source: bytes | str) -> str:
224222
bpayload: bytes = msg.get_payload(decode=True)
225223
try:
226224
return bpayload.decode("utf8", "strict")
227-
except UnicodeDecodeError:
228-
raise ValueError("payload in an invalid encoding")
225+
except UnicodeDecodeError as exc:
226+
raise ValueError("payload in an invalid encoding") from exc
229227

230228

231229
# The various parse_FORMAT functions here are intended to be as lenient as
@@ -535,7 +533,7 @@ def _process_name(self, value: str) -> str:
535533
except utils.InvalidName as exc:
536534
raise self._invalid_metadata(
537535
f"{value!r} is invalid for {{field}}", cause=exc
538-
)
536+
) from exc
539537
else:
540538
return value
541539

@@ -547,7 +545,7 @@ def _process_version(self, value: str) -> version_module.Version:
547545
except version_module.InvalidVersion as exc:
548546
raise self._invalid_metadata(
549547
f"{value!r} is invalid for {{field}}", cause=exc
550-
)
548+
) from exc
551549

552550
def _process_summary(self, value: str) -> str:
553551
"""Check the field contains no newlines."""
@@ -608,7 +606,7 @@ def _process_provides_extra(
608606
except utils.InvalidName as exc:
609607
raise self._invalid_metadata(
610608
f"{name!r} is invalid for {{field}}", cause=exc
611-
)
609+
) from exc
612610
else:
613611
return normalized_names
614612

@@ -618,7 +616,7 @@ def _process_requires_python(self, value: str) -> specifiers.SpecifierSet:
618616
except specifiers.InvalidSpecifier as exc:
619617
raise self._invalid_metadata(
620618
f"{value!r} is invalid for {{field}}", cause=exc
621-
)
619+
) from exc
622620

623621
def _process_requires_dist(
624622
self,
@@ -629,7 +627,9 @@ def _process_requires_dist(
629627
for req in value:
630628
reqs.append(requirements.Requirement(req))
631629
except requirements.InvalidRequirement as exc:
632-
raise self._invalid_metadata(f"{req!r} is invalid for {{field}}", cause=exc)
630+
raise self._invalid_metadata(
631+
f"{req!r} is invalid for {{field}}", cause=exc
632+
) from exc
633633
else:
634634
return reqs
635635

@@ -688,8 +688,8 @@ def from_raw(cls, data: RawMetadata, *, validate: bool = True) -> Metadata:
688688
field = _RAW_TO_EMAIL_MAPPING[key]
689689
exc = InvalidMetadata(
690690
field,
691-
"{field} introduced in metadata version "
692-
"{field_metadata_version}, not {metadata_version}",
691+
f"{field} introduced in metadata version "
692+
f"{field_metadata_version}, not {metadata_version}",
693693
)
694694
exceptions.append(exc)
695695
continue

src/packaging/tags.py

+14-24
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class Tag:
4747
is also supported.
4848
"""
4949

50-
__slots__ = ["_interpreter", "_abi", "_platform", "_hash"]
50+
__slots__ = ["_abi", "_hash", "_interpreter", "_platform"]
5151

5252
def __init__(self, interpreter: str, abi: str, platform: str) -> None:
5353
self._interpreter = interpreter.lower()
@@ -235,9 +235,8 @@ def cpython_tags(
235235
if use_abi3:
236236
for minor_version in range(python_version[1] - 1, 1, -1):
237237
for platform_ in platforms:
238-
interpreter = "cp{version}".format(
239-
version=_version_nodot((python_version[0], minor_version))
240-
)
238+
version = _version_nodot((python_version[0], minor_version))
239+
interpreter = f"cp{version}"
241240
yield Tag(interpreter, "abi3", platform_)
242241

243242

@@ -435,24 +434,22 @@ def mac_platforms(
435434
if (10, 0) <= version and version < (11, 0):
436435
# Prior to Mac OS 11, each yearly release of Mac OS bumped the
437436
# "minor" version number. The major version was always 10.
437+
major_version = 10
438438
for minor_version in range(version[1], -1, -1):
439-
compat_version = 10, minor_version
439+
compat_version = major_version, minor_version
440440
binary_formats = _mac_binary_formats(compat_version, arch)
441441
for binary_format in binary_formats:
442-
yield "macosx_{major}_{minor}_{binary_format}".format(
443-
major=10, minor=minor_version, binary_format=binary_format
444-
)
442+
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
445443

446444
if version >= (11, 0):
447445
# Starting with Mac OS 11, each yearly release bumps the major version
448446
# number. The minor versions are now the midyear updates.
447+
minor_version = 0
449448
for major_version in range(version[0], 10, -1):
450-
compat_version = major_version, 0
449+
compat_version = major_version, minor_version
451450
binary_formats = _mac_binary_formats(compat_version, arch)
452451
for binary_format in binary_formats:
453-
yield "macosx_{major}_{minor}_{binary_format}".format(
454-
major=major_version, minor=0, binary_format=binary_format
455-
)
452+
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
456453

457454
if version >= (11, 0):
458455
# Mac OS 11 on x86_64 is compatible with binaries from previous releases.
@@ -462,25 +459,18 @@ def mac_platforms(
462459
# However, the "universal2" binary format can have a
463460
# macOS version earlier than 11.0 when the x86_64 part of the binary supports
464461
# that version of macOS.
462+
major_version = 10
465463
if arch == "x86_64":
466464
for minor_version in range(16, 3, -1):
467-
compat_version = 10, minor_version
465+
compat_version = major_version, minor_version
468466
binary_formats = _mac_binary_formats(compat_version, arch)
469467
for binary_format in binary_formats:
470-
yield "macosx_{major}_{minor}_{binary_format}".format(
471-
major=compat_version[0],
472-
minor=compat_version[1],
473-
binary_format=binary_format,
474-
)
468+
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
475469
else:
476470
for minor_version in range(16, 3, -1):
477-
compat_version = 10, minor_version
471+
compat_version = major_version, minor_version
478472
binary_format = "universal2"
479-
yield "macosx_{major}_{minor}_{binary_format}".format(
480-
major=compat_version[0],
481-
minor=compat_version[1],
482-
binary_format=binary_format,
483-
)
473+
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
484474

485475

486476
def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]:

0 commit comments

Comments
 (0)