]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-44246: Entry points performance improvements. (GH-26467)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Mon, 31 May 2021 16:12:32 +0000 (09:12 -0700)
committerGitHub <noreply@github.com>
Mon, 31 May 2021 16:12:32 +0000 (09:12 -0700)
From importlib_metadata 4.3.1.
(cherry picked from commit 410b70d39d9d77384f8b8597560f6731530149ca)

Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
Lib/importlib/metadata/__init__.py
Lib/test/test_importlib/test_zip.py
Misc/NEWS.d/next/Library/2021-05-31-11-28-03.bpo-44246.nhmt-v.rst [new file with mode: 0644]

index 94b83869a6855007f290662071e7977a28ef779d..2e3403e5a565cb939b7a07323f51f497e63a911b 100644 (file)
@@ -493,6 +493,11 @@ class Distribution:
         """Return the 'Name' metadata for the distribution package."""
         return self.metadata['Name']
 
+    @property
+    def _normalized_name(self):
+        """Return a normalized version of the name."""
+        return Prepared.normalize(self.name)
+
     @property
     def version(self):
         """Return the 'Version' metadata for the distribution package."""
@@ -795,6 +800,22 @@ class PathDistribution(Distribution):
     def locate_file(self, path):
         return self._path.parent / path
 
+    @property
+    def _normalized_name(self):
+        """
+        Performance optimization: where possible, resolve the
+        normalized name from the file system path.
+        """
+        stem = os.path.basename(str(self._path))
+        return self._name_from_stem(stem) or super()._normalized_name
+
+    def _name_from_stem(self, stem):
+        name, ext = os.path.splitext(stem)
+        if ext not in ('.dist-info', '.egg-info'):
+            return
+        name, sep, rest = stem.partition('-')
+        return name
+
 
 def distribution(distribution_name):
     """Get the ``Distribution`` instance for the named package.
@@ -849,7 +870,8 @@ def entry_points(**params) -> Union[EntryPoints, SelectableGroups]:
 
     :return: EntryPoints or SelectableGroups for all installed packages.
     """
-    unique = functools.partial(unique_everseen, key=operator.attrgetter('name'))
+    norm_name = operator.attrgetter('_normalized_name')
+    unique = functools.partial(unique_everseen, key=norm_name)
     eps = itertools.chain.from_iterable(
         dist.entry_points for dist in unique(distributions())
     )
index 83e041385e0e8c964de081f069a14ac8037d34f9..bf16a3b95e18c511743d11815a4b29bd020a1090 100644 (file)
@@ -76,3 +76,7 @@ class TestEgg(TestZip):
         for file in files('example'):
             path = str(file.dist.locate_file(file))
             assert '.egg/' in path, path
+
+    def test_normalized_name(self):
+        dist = distribution('example')
+        assert dist._normalized_name == 'example'
diff --git a/Misc/NEWS.d/next/Library/2021-05-31-11-28-03.bpo-44246.nhmt-v.rst b/Misc/NEWS.d/next/Library/2021-05-31-11-28-03.bpo-44246.nhmt-v.rst
new file mode 100644 (file)
index 0000000..727d9fd
--- /dev/null
@@ -0,0 +1,3 @@
+In importlib.metadata.entry_points, de-duplication of distributions no
+longer requires loading the full metadata for PathDistribution objects,
+improving entry point loading performance by ~10x.