Skip to content

Commit 0bda2fe

Browse files
committed
Extract Python 3.9 compatibility layer into its own file
1 parent a156b85 commit 0bda2fe

File tree

2 files changed

+53
-26
lines changed

2 files changed

+53
-26
lines changed

importlib_metadata/__init__.py

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import posixpath
1515
import collections
1616

17-
from . import _adapters, _meta
17+
from . import _adapters, _meta, _py39compat
1818
from ._collections import FreezableDefaultDict, Pair
1919
from ._compat import (
2020
NullFinder,
@@ -29,7 +29,7 @@
2929
from importlib import import_module
3030
from importlib.abc import MetaPathFinder
3131
from itertools import starmap
32-
from typing import List, Mapping, Optional, Tuple, Union
32+
from typing import List, Mapping, Optional, Union
3333

3434

3535
__all__ = [
@@ -382,8 +382,8 @@ def select(self, **params):
382382
Select entry points from self that match the
383383
given parameters (typically group and/or name).
384384
"""
385-
candidates = (_ep_matches(ep, **params) for ep in self)
386-
return EntryPoints(ep for ep, ep_matches in candidates if ep_matches)
385+
candidates = (_py39compat.ep_matches(ep, **params) for ep in self)
386+
return EntryPoints(ep for ep, predicate in candidates if predicate)
387387

388388
@property
389389
def names(self):
@@ -415,15 +415,6 @@ def _from_text(text):
415415
)
416416

417417

418-
def _ep_matches(ep: EntryPoint, **params) -> Tuple[EntryPoint, bool]:
419-
"""Compatibility layer for EntryPoint objects in Python 3.8/3.9 stdlib."""
420-
try:
421-
return ep, ep.matches(**params)
422-
except AttributeError:
423-
_ep = EntryPoint(ep.name, ep.value, ep.group)
424-
return _ep, _ep.matches(**params)
425-
426-
427418
class Deprecated:
428419
"""
429420
Compatibility add-in for mapping to indicate that
@@ -1029,21 +1020,9 @@ def version(distribution_name):
10291020
return distribution(distribution_name).version
10301021

10311022

1032-
def _compat_normalized_name(dist: Distribution) -> Optional[str]:
1033-
"""
1034-
Compatibility shim to honor name normalization for distributions
1035-
that don't provide ``_normalized_name``
1036-
(as in ``importlib.metadata`` for Python 3.8/3.9).
1037-
"""
1038-
try:
1039-
return dist._normalized_name
1040-
except AttributeError:
1041-
return Prepared.normalize(getattr(dist, "name", None) or dist.metadata['Name'])
1042-
1043-
10441023
_unique = functools.partial(
10451024
unique_everseen,
1046-
key=_compat_normalized_name,
1025+
key=_py39compat.normalized_name,
10471026
)
10481027
"""
10491028
Wrapper for ``distributions`` to return unique distributions by name.

importlib_metadata/_py39compat.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
Compatibility layer with Python 3.8/3.9
3+
"""
4+
from typing import TYPE_CHECKING, Any, Optional, Tuple
5+
6+
7+
if TYPE_CHECKING:
8+
from . import Distribution, EntryPoint
9+
else:
10+
Distribution = EntryPoint = Any
11+
12+
13+
def normalized_name(dist: Distribution) -> Optional[str]:
14+
"""
15+
Honor name normalization for distributions that don't provide ``_normalized_name``.
16+
"""
17+
try:
18+
return dist._normalized_name
19+
except AttributeError:
20+
from . import Prepared
21+
22+
return Prepared.normalize(getattr(dist, "name", None) or dist.metadata['Name'])
23+
24+
25+
def ep_matches(ep: EntryPoint, **params) -> Tuple[EntryPoint, bool]:
26+
"""
27+
Workaround for ``EntryPoint`` objects without the ``matches`` method.
28+
For the sake of convenience, a tuple is returned containing not only the
29+
boolean value corresponding to the predicate evalutation, but also a compatible
30+
``EntryPoint`` object that can be safely used at a later stage.
31+
32+
For example, the following sequences of expressions should be compatible:
33+
34+
# Sequence 1: using the compatibility layer
35+
candidates = (_py39compat.ep_matches(ep, **params) for ep in entry_points)
36+
[ep for ep, predicate in candidates if predicate]
37+
38+
# Sequence 2: using Python 3.9+
39+
[ep for ep in entry_points if ep.matches(**params)]
40+
"""
41+
try:
42+
return ep, ep.matches(**params)
43+
except AttributeError:
44+
from . import EntryPoint
45+
46+
# Reconstruct the EntryPoint object to make sure it is compatible.
47+
_ep = EntryPoint(ep.name, ep.value, ep.group)
48+
return _ep, _ep.matches(**params)

0 commit comments

Comments
 (0)