From 52042310c36e78162d3dac64b0191b5cdc91121d Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Mon, 9 Oct 2023 02:43:04 -0400 Subject: [PATCH 1/3] Correctly use the ExceptionGroup shim only when needed --- CHANGELOG.rst | 2 ++ src/packaging/metadata.py | 14 +++++++++----- tests/test_metadata.py | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f7b96d8d..b482458f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,8 @@ Changelog * Do specifier matching correctly when the specifier contains an epoch number and has more components than the version (:issue:`683`) +* Fix a bug preventing the use of the built in ``ExceptionGroup`` on versions of + Python that support it (:issue:`725`) 23.2 - 2023-10-01 ~~~~~~~~~~~~~~~~~ diff --git a/src/packaging/metadata.py b/src/packaging/metadata.py index 7b0e6a9c..b4ac3066 100644 --- a/src/packaging/metadata.py +++ b/src/packaging/metadata.py @@ -41,8 +41,8 @@ def __init_subclass__(*_args, **_kwargs): try: - ExceptionGroup = __builtins__.ExceptionGroup # type: ignore[attr-defined] -except AttributeError: + ExceptionGroup +except NameError: # pragma: no cover class ExceptionGroup(Exception): # type: ignore[no-redef] # noqa: N818 """A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11. @@ -61,6 +61,9 @@ def __init__(self, message: str, exceptions: List[Exception]) -> None: def __repr__(self) -> str: return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})" +else: # pragma: no cover + ExceptionGroup = ExceptionGroup + class InvalidMetadata(ValueError): """A metadata field contains invalid data.""" @@ -732,10 +735,10 @@ def from_email( If *validate* is true, the metadata will be validated. All exceptions related to validation will be gathered and raised as an :class:`ExceptionGroup`. """ - exceptions: list[InvalidMetadata] = [] raw, unparsed = parse_email(data) if validate: + exceptions: list[InvalidMetadata] = [] for unparsed_key in unparsed: if unparsed_key in _EMAIL_TO_RAW_MAPPING: message = f"{unparsed_key!r} has invalid data" @@ -749,8 +752,9 @@ def from_email( try: return cls.from_raw(raw, validate=validate) except ExceptionGroup as exc_group: - exceptions.extend(exc_group.exceptions) - raise ExceptionGroup("invalid or unparsed metadata", exceptions) from None + raise ExceptionGroup( + "invalid or unparsed metadata", exc_group.exceptions + ) from None metadata_version: _Validator[_MetadataVersion] = _Validator() """:external:ref:`core-metadata-metadata-version` diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 45c05230..1d80f9df 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -251,7 +251,7 @@ def test_attributes(self): individual_exception = Exception("not important") exc = metadata.ExceptionGroup("message", [individual_exception]) assert exc.message == "message" - assert exc.exceptions == [individual_exception] + assert list(exc.exceptions) == [individual_exception] def test_repr(self): individual_exception = RuntimeError("not important") From 80b00bcdd63620768e98879a1122f4a7f51faaa8 Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Mon, 9 Oct 2023 02:51:04 -0400 Subject: [PATCH 2/3] fix linting --- src/packaging/metadata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/packaging/metadata.py b/src/packaging/metadata.py index b4ac3066..0abd8b41 100644 --- a/src/packaging/metadata.py +++ b/src/packaging/metadata.py @@ -44,7 +44,7 @@ def __init_subclass__(*_args, **_kwargs): ExceptionGroup except NameError: # pragma: no cover - class ExceptionGroup(Exception): # type: ignore[no-redef] # noqa: N818 + class ExceptionGroup(Exception): """A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11. If :external:exc:`ExceptionGroup` is already defined by Python itself, @@ -680,7 +680,7 @@ def from_raw(cls, data: RawMetadata, *, validate: bool = True) -> "Metadata": ins._raw = data.copy() # Mutations occur due to caching enriched values. if validate: - exceptions: List[InvalidMetadata] = [] + exceptions: List[Exception] = [] try: metadata_version = ins.metadata_version metadata_age = _VALID_METADATA_VERSIONS.index(metadata_version) @@ -738,7 +738,7 @@ def from_email( raw, unparsed = parse_email(data) if validate: - exceptions: list[InvalidMetadata] = [] + exceptions: list[Exception] = [] for unparsed_key in unparsed: if unparsed_key in _EMAIL_TO_RAW_MAPPING: message = f"{unparsed_key!r} has invalid data" From e5f2ac621ae4b76f8383beaa6dc5da5e192c6dcd Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Mon, 9 Oct 2023 02:52:50 -0400 Subject: [PATCH 3/3] more linter --- src/packaging/metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packaging/metadata.py b/src/packaging/metadata.py index 0abd8b41..54dbab8b 100644 --- a/src/packaging/metadata.py +++ b/src/packaging/metadata.py @@ -44,7 +44,7 @@ def __init_subclass__(*_args, **_kwargs): ExceptionGroup except NameError: # pragma: no cover - class ExceptionGroup(Exception): + class ExceptionGroup(Exception): # noqa: N818 """A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11. If :external:exc:`ExceptionGroup` is already defined by Python itself,