diff --git a/NEWS.rst b/NEWS.rst index 0f1b63a4..f4a37fdf 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,30 @@ +v8.4.0 +====== + +Features +-------- + +- Deferred import of inspect for import performance. (#499) + + +v8.3.0 +====== + +Features +-------- + +- Disallow passing of 'dist' to EntryPoints.select. + + +v8.2.0 +====== + +Features +-------- + +- Add SimplePath to importlib_metadata.__all__. (#494) + + v8.1.0 ====== diff --git a/conftest.py b/conftest.py index 779ac24b..762e66f3 100644 --- a/conftest.py +++ b/conftest.py @@ -13,13 +13,18 @@ def pytest_configure(): def remove_importlib_metadata(): """ - Because pytest imports importlib_metadata, the coverage - reports are broken (#322). So work around the issue by - undoing the changes made by pytest's import of - importlib_metadata (if any). + Ensure importlib_metadata is not imported yet. + + Because pytest or other modules might import + importlib_metadata, the coverage reports are broken (#322). + Work around the issue by undoing the changes made by a + previous import of importlib_metadata (if any). """ - if sys.meta_path[-1].__class__.__name__ == 'MetadataPathFinder': - del sys.meta_path[-1] + sys.meta_path[:] = [ + item + for item in sys.meta_path + if item.__class__.__name__ != 'MetadataPathFinder' + ] for mod in list(sys.modules): if mod.startswith('importlib_metadata'): del sys.modules[mod] diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index b9fc04f1..24587e68 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -8,7 +8,6 @@ import zipp import email import types -import inspect import pathlib import operator import textwrap @@ -39,6 +38,7 @@ 'DistributionFinder', 'PackageMetadata', 'PackageNotFoundError', + 'SimplePath', 'distribution', 'distributions', 'entry_points', @@ -226,9 +226,26 @@ def matches(self, **params): >>> ep.matches(attr='bong') True """ + self._disallow_dist(params) attrs = (getattr(self, param) for param in params) return all(map(operator.eq, params.values(), attrs)) + @staticmethod + def _disallow_dist(params): + """ + Querying by dist is not allowed (dist objects are not comparable). + >>> EntryPoint(name='fan', value='fav', group='fag').matches(dist='foo') + Traceback (most recent call last): + ... + ValueError: "dist" is not suitable for matching... + """ + if "dist" in params: + raise ValueError( + '"dist" is not suitable for matching. ' + "Instead, use Distribution.entry_points.select() on a " + "located distribution." + ) + def _key(self): return self.name, self.value, self.group @@ -372,6 +389,17 @@ def locate_file(self, path: str | os.PathLike[str]) -> SimplePath: """ Given a path to a file in this distribution, return a SimplePath to it. + + This method is used by callers of ``Distribution.files()`` to + locate files within the distribution. If it's possible for a + Distribution to represent files in the distribution as + ``SimplePath`` objects, it should implement this method + to resolve such objects. + + Some Distribution providers may elect not to resolve SimplePath + objects within the distribution by raising a + NotImplementedError, but consumers of such a Distribution would + be unable to invoke ``Distribution.files()``. """ @classmethod @@ -1077,11 +1105,10 @@ def _get_toplevel_name(name: PackagePath) -> str: >>> _get_toplevel_name(PackagePath('foo.dist-info')) 'foo.dist-info' """ - return _topmost(name) or ( - # python/typeshed#10328 - inspect.getmodulename(name) # type: ignore - or str(name) - ) + # Defer import of inspect for performance (python/cpython#118761) + import inspect + + return _topmost(name) or (inspect.getmodulename(name) or str(name)) def _top_level_inferred(dist):
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: