From 3a90a8d160074817f636271cafe1ae559225b1c3 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Thu, 2 May 2024 11:11:01 +0100 Subject: [PATCH 1/6] Use more realistic return types --- importlib_metadata/__init__.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index ed481355..2535aaa5 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -30,6 +30,7 @@ from contextlib import suppress from importlib import import_module +from importlib import metadata as _legacy from importlib.abc import MetaPathFinder from itertools import starmap from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast @@ -375,7 +376,7 @@ def locate_file(self, path: str | os.PathLike[str]) -> SimplePath: """ @classmethod - def from_name(cls, name: str) -> Distribution: + def from_name(cls, name: str) -> Distribution | _legacy.Distribution: """Return the Distribution for the given package name. :param name: The name of the distribution package to search for. @@ -395,7 +396,7 @@ def from_name(cls, name: str) -> Distribution: @classmethod def discover( cls, *, context: Optional[DistributionFinder.Context] = None, **kwargs - ) -> Iterable[Distribution]: + ) -> Iterable[Distribution | _legacy.Distribution]: """Return an iterable of Distribution objects for all packages. Pass a ``context`` or pass keyword arguments for constructing @@ -941,7 +942,7 @@ def _name_from_stem(stem): return name -def distribution(distribution_name: str) -> Distribution: +def distribution(distribution_name: str) -> Distribution | _legacy.Distribution: """Get the ``Distribution`` instance for the named package. :param distribution_name: The name of the distribution package as a string. @@ -950,7 +951,7 @@ def distribution(distribution_name: str) -> Distribution: return Distribution.from_name(distribution_name) -def distributions(**kwargs) -> Iterable[Distribution]: +def distributions(**kwargs) -> Iterable[Distribution | _legacy.Distribution]: """Get all ``Distribution`` instances in the current environment. :return: An iterable of ``Distribution`` instances. @@ -958,7 +959,7 @@ def distributions(**kwargs) -> Iterable[Distribution]: return Distribution.discover(**kwargs) -def metadata(distribution_name: str) -> _meta.PackageMetadata: +def metadata(distribution_name: str) -> _meta.PackageMetadata | email.message.Message: """Get the metadata for the named package. :param distribution_name: The name of the distribution package to query. @@ -1001,7 +1002,9 @@ def entry_points(**params) -> EntryPoints: return EntryPoints(eps).select(**params) -def files(distribution_name: str) -> Optional[List[PackagePath]]: +def files( + distribution_name: str, +) -> Optional[List[PackagePath] | List[_legacy.PackagePath]]: """Return a list of files for the named package. :param distribution_name: The name of the distribution package to query. From c1612ec7b9aeb5b1625998d80b0165aeb460d86b Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Thu, 2 May 2024 11:20:27 +0100 Subject: [PATCH 2/6] Use type check guard for legacy annotations --- importlib_metadata/__init__.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 2535aaa5..ceee9371 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -30,10 +30,25 @@ from contextlib import suppress from importlib import import_module -from importlib import metadata as _legacy from importlib.abc import MetaPathFinder from itertools import starmap -from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast +from typing import ( + TYPE_CHECKING, + Any, + Iterable, + List, + Mapping, + Match, + Optional, + Set, + cast, +) + + +if TYPE_CHECKING: + from importlib import metadata as _legacy + from email.message import Message as _legacy_Metadata + __all__ = [ 'Distribution', @@ -959,7 +974,7 @@ def distributions(**kwargs) -> Iterable[Distribution | _legacy.Distribution]: return Distribution.discover(**kwargs) -def metadata(distribution_name: str) -> _meta.PackageMetadata | email.message.Message: +def metadata(distribution_name: str) -> _meta.PackageMetadata | _legacy_Metadata: """Get the metadata for the named package. :param distribution_name: The name of the distribution package to query. From e30d8f7411cc4bf6dae71e6964608ab55994058d Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Thu, 2 May 2024 11:32:14 +0100 Subject: [PATCH 3/6] Fix type annotation for Python 3.10+ --- importlib_metadata/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index ceee9371..ae0b2522 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -47,7 +47,11 @@ if TYPE_CHECKING: from importlib import metadata as _legacy - from email.message import Message as _legacy_Metadata + + if sys.version_info >= (3, 10): + from importlib.metadata import PackageMetadata as _legacy_Metadata + else: + from email.message import Message as _legacy_Metadata __all__ = [ From 2044db14985aa1fb8fdceadef5511c3fe93e76cb Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Thu, 2 May 2024 11:59:31 +0100 Subject: [PATCH 4/6] Fix warnings in sphinx docs --- docs/conf.py | 4 ++++ importlib_metadata/__init__.py | 25 ++++++------------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 2cd8fb0c..acdc13f4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -69,4 +69,8 @@ ('py:class', 'importlib_metadata._meta._T'), # Workaround for #435 ('py:class', '_T'), + # importlib.metadata in stdlib does not have detailed API docs + ('py:class', 'importlib.metadata.Distribution'), + ('py:class', 'importlib.metadata.PackagePath'), + ('py:class', 'importlib.metadata._meta.PackageMetadata'), ] diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index ae0b2522..0d43d566 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -30,28 +30,15 @@ from contextlib import suppress from importlib import import_module +from importlib import metadata as _legacy from importlib.abc import MetaPathFinder from itertools import starmap -from typing import ( - TYPE_CHECKING, - Any, - Iterable, - List, - Mapping, - Match, - Optional, - Set, - cast, -) - - -if TYPE_CHECKING: - from importlib import metadata as _legacy +from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast - if sys.version_info >= (3, 10): - from importlib.metadata import PackageMetadata as _legacy_Metadata - else: - from email.message import Message as _legacy_Metadata +if sys.version_info >= (3, 10): + from importlib.metadata import PackageMetadata as _legacy_Metadata +else: + from email.message import Message as _legacy_Metadata __all__ = [ From 4fe96a47c28e257596808847666f7c1e1b81de96 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Mon, 24 Jun 2024 10:33:23 +0100 Subject: [PATCH 5/6] Move code specific to backport to compat module --- importlib_metadata/__init__.py | 20 +++++++------------- importlib_metadata/compat/stdlib.py | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 importlib_metadata/compat/stdlib.py diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 0d43d566..9c2a7bf9 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -18,7 +18,7 @@ import collections from . import _meta -from .compat import py39, py311 +from .compat import py39, py311, stdlib from ._collections import FreezableDefaultDict, Pair from ._compat import ( NullFinder, @@ -30,16 +30,10 @@ from contextlib import suppress from importlib import import_module -from importlib import metadata as _legacy from importlib.abc import MetaPathFinder from itertools import starmap from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast -if sys.version_info >= (3, 10): - from importlib.metadata import PackageMetadata as _legacy_Metadata -else: - from email.message import Message as _legacy_Metadata - __all__ = [ 'Distribution', @@ -382,7 +376,7 @@ def locate_file(self, path: str | os.PathLike[str]) -> SimplePath: """ @classmethod - def from_name(cls, name: str) -> Distribution | _legacy.Distribution: + def from_name(cls, name: str) -> stdlib._DistributionOrLegacy: """Return the Distribution for the given package name. :param name: The name of the distribution package to search for. @@ -402,7 +396,7 @@ def from_name(cls, name: str) -> Distribution | _legacy.Distribution: @classmethod def discover( cls, *, context: Optional[DistributionFinder.Context] = None, **kwargs - ) -> Iterable[Distribution | _legacy.Distribution]: + ) -> Iterable[stdlib._DistributionOrLegacy]: """Return an iterable of Distribution objects for all packages. Pass a ``context`` or pass keyword arguments for constructing @@ -948,7 +942,7 @@ def _name_from_stem(stem): return name -def distribution(distribution_name: str) -> Distribution | _legacy.Distribution: +def distribution(distribution_name: str) -> stdlib._DistributionOrLegacy: """Get the ``Distribution`` instance for the named package. :param distribution_name: The name of the distribution package as a string. @@ -957,7 +951,7 @@ def distribution(distribution_name: str) -> Distribution | _legacy.Distribution: return Distribution.from_name(distribution_name) -def distributions(**kwargs) -> Iterable[Distribution | _legacy.Distribution]: +def distributions(**kwargs) -> Iterable[stdlib._DistributionOrLegacy]: """Get all ``Distribution`` instances in the current environment. :return: An iterable of ``Distribution`` instances. @@ -965,7 +959,7 @@ def distributions(**kwargs) -> Iterable[Distribution | _legacy.Distribution]: return Distribution.discover(**kwargs) -def metadata(distribution_name: str) -> _meta.PackageMetadata | _legacy_Metadata: +def metadata(distribution_name: str) -> stdlib._PackageMetadataOrLegacy: """Get the metadata for the named package. :param distribution_name: The name of the distribution package to query. @@ -1010,7 +1004,7 @@ def entry_points(**params) -> EntryPoints: def files( distribution_name: str, -) -> Optional[List[PackagePath] | List[_legacy.PackagePath]]: +) -> Optional[stdlib._List_PackagePathOrLegacy]: """Return a list of files for the named package. :param distribution_name: The name of the distribution package to query. diff --git a/importlib_metadata/compat/stdlib.py b/importlib_metadata/compat/stdlib.py new file mode 100644 index 00000000..2db335de --- /dev/null +++ b/importlib_metadata/compat/stdlib.py @@ -0,0 +1,27 @@ +""" +Compatibility layer with stdlib. +Only needed when distributing via PyPI/3rd-party package. +""" + +import sys +from typing import TYPE_CHECKING, List, Union + +if TYPE_CHECKING: + # Avoid circular imports + + from importlib import metadata as _legacy + + from typing_extensions import TypeAlias + + from .. import Distribution, PackagePath, _meta + + if sys.version_info >= (3, 10): + from importlib.metadata import PackageMetadata as _legacy_Metadata + else: + from email.message import Message as _legacy_Metadata + + _PackageMetadataOrLegacy: TypeAlias = Union[_legacy_Metadata, _meta.PackageMetadata] + _DistributionOrLegacy: TypeAlias = Union[_legacy.Distribution, Distribution] + _List_PackagePathOrLegacy: TypeAlias = Union[ + List[_legacy.PackagePath], List[PackagePath] + ] From c86976d79bdf1809b99752e883924741d782740d Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Mon, 24 Jun 2024 10:52:29 +0100 Subject: [PATCH 6/6] Workaround sphinx limitations --- docs/conf.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index acdc13f4..a353eccf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,7 +70,8 @@ # Workaround for #435 ('py:class', '_T'), # importlib.metadata in stdlib does not have detailed API docs - ('py:class', 'importlib.metadata.Distribution'), - ('py:class', 'importlib.metadata.PackagePath'), - ('py:class', 'importlib.metadata._meta.PackageMetadata'), + # + `if TYPE_CHECKING` is not handled by sphinx: + ('py:class', 'stdlib._DistributionOrLegacy'), + ('py:class', 'stdlib._PackageMetadataOrLegacy'), + ('py:class', 'stdlib._List_PackagePathOrLegacy'), ]