From cc78a7dbea47c37476b26891b5e3e83587287e99 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Thu, 10 Mar 2022 13:21:11 +0000 Subject: [PATCH 01/22] entry_points no longer returns a sequence keyed by group --- docs/using.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 5d8f0a3c..bb025782 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -42,9 +42,9 @@ You can get the version string for ``wheel`` by running the following:: >>> version('wheel') '0.32.3' -You can also get the set of entry points keyed by group, such as +You can also get a collection of entry points selectable by group, such as ``console_scripts``, ``distutils.commands`` and others. Each group contains a -sequence of :ref:`EntryPoint ` objects. +collection of :ref:`EntryPoint ` objects. You can get the :ref:`metadata for a distribution `:: @@ -79,7 +79,7 @@ Query all entry points:: >>> eps = entry_points() The ``entry_points()`` function returns an ``EntryPoints`` object, -a sequence of all ``EntryPoint`` objects with ``names`` and ``groups`` +a collection of all ``EntryPoint`` objects with ``names`` and ``groups`` attributes for convenience:: >>> sorted(eps.groups) From 0ae0bfa6533123c72431a4e34974501eaab0c45e Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sun, 13 Mar 2022 15:04:18 +0000 Subject: [PATCH 02/22] Update docs/using.rst --- docs/using.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index bb025782..daab6396 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -42,7 +42,7 @@ You can get the version string for ``wheel`` by running the following:: >>> version('wheel') '0.32.3' -You can also get a collection of entry points selectable by group, such as +You can also get a collection of entry points selectable by properties of the EntryPoint (typically 'group' or 'name'), such as ``console_scripts``, ``distutils.commands`` and others. Each group contains a collection of :ref:`EntryPoint ` objects. From 467dba53dd48709722bf5ac626e663f557b90022 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 7 Mar 2022 19:55:41 -0800 Subject: [PATCH 03/22] importlib.metadata: Remove empty footnote section (GH-30451) --- docs/using.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 5d8f0a3c..a48c559a 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -315,6 +315,3 @@ a custom finder, return instances of this derived ``Distribution`` in the .. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points .. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api .. _`finders`: https://docs.python.org/3/reference/import.html#finders-and-loaders - - -.. rubric:: Footnotes From 4212eed378ffc1409f0df911d8bfe95d49aaf68c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 19 Mar 2022 14:56:40 -0400 Subject: [PATCH 04/22] Update documentation to capture existing behavior. Closes #372. --- docs/using.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/using.rst b/docs/using.rst index ddd31990..947d066b 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -274,6 +274,15 @@ The full set of available metadata is not described here. See :pep:`566` for additional details. +Distribution Discovery +====================== + +By default, this package provides built-in support for discovery of metadata for file system and zip file packages. This metadata finder search defaults to ``sys.path``, but varies slightly in how it interprets those values from how other import machinery does. In particular: + +- ``importlib_metadata`` does not honor :type:`bytes` objects on ``sys.path``. +- ``importlib_metadata`` will incidentally honor :py:class:`pathlib.Path` objects on ``sys.path`` even though such values will be ignored for imports. + + Extending the search algorithm ============================== From 2b2676a3299752193658d2941641a20096a15416 Mon Sep 17 00:00:00 2001 From: Saaket Prakash Date: Sun, 20 Mar 2022 11:26:09 +0530 Subject: [PATCH 05/22] Add note about PackageMetadata protocol in the docs. --- docs/using.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/using.rst b/docs/using.rst index 947d066b..5bb870cb 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -162,6 +162,12 @@ all the metadata in a JSON-compatible form per PEP 566:: >>> wheel_metadata.json['requires_python'] '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' +.. note:: + + The actual type of the object returned by ``metadata()`` is an + implementation detail, it should be accessed only through the interface + described by the ``PackageMetadata`` protocol documented here and at + https://importlib-metadata.readthedocs.io/en/latest/api.html#importlib_metadata.PackageMetadata .. _version: From 39510a5b424f84f6c322cbc953a5557fd62193cf Mon Sep 17 00:00:00 2001 From: Saaket Prakash Date: Sun, 20 Mar 2022 11:42:39 +0530 Subject: [PATCH 06/22] Add a See Also: section with link to importlib_metadata docs. --- docs/using.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/using.rst b/docs/using.rst index 5bb870cb..74ef169a 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -23,6 +23,13 @@ By default, package metadata can live on the file system or in zip archives on anywhere. +.. seealso:: + + https://importlib-metadata.readthedocs.io/ + The documentation for ``importlib_metadata``, which supplies a + backport of ``importlib.metadata``. + + Overview ======== From 5f375a9bd6cbe6ab74f48659173f45377031ca7e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 20 Mar 2022 09:50:14 -0400 Subject: [PATCH 07/22] Avoid comma splice and use a hyperlink to reference the protocol. --- docs/using.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 74ef169a..3bea65d8 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -172,9 +172,10 @@ all the metadata in a JSON-compatible form per PEP 566:: .. note:: The actual type of the object returned by ``metadata()`` is an - implementation detail, it should be accessed only through the interface - described by the ``PackageMetadata`` protocol documented here and at - https://importlib-metadata.readthedocs.io/en/latest/api.html#importlib_metadata.PackageMetadata + implementation detail and should be accessed only through the interface + described by the + `PackageMetadata protocol `. + .. _version: From 28ee235148866ac4d310206b00c152d861621ead Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 20 Mar 2022 09:54:42 -0400 Subject: [PATCH 08/22] Fix docs build error (class, not type). --- docs/using.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index 947d066b..c1d39eac 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -279,7 +279,7 @@ Distribution Discovery By default, this package provides built-in support for discovery of metadata for file system and zip file packages. This metadata finder search defaults to ``sys.path``, but varies slightly in how it interprets those values from how other import machinery does. In particular: -- ``importlib_metadata`` does not honor :type:`bytes` objects on ``sys.path``. +- ``importlib_metadata`` does not honor :class:`bytes` objects on ``sys.path``. - ``importlib_metadata`` will incidentally honor :py:class:`pathlib.Path` objects on ``sys.path`` even though such values will be ignored for imports. From c68e382f7c1a5a1240fd5cc7d17e8e9240a26b1c Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 19 May 2022 16:48:44 +0100 Subject: [PATCH 09/22] gh-92417: `importlib` docs: remove references to unsupported Python versions (GH-92424) Co-authored-by: CAM Gerlach --- docs/using.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 0bbc0df8..4c6c961b 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -8,9 +8,9 @@ package metadata. Built in part on Python's import system, this library intends to replace similar functionality in the `entry point API`_ and `metadata API`_ of ``pkg_resources``. Along with -:mod:`importlib.resources` in Python 3.7 -and newer (backported as :doc:`importlib_resources ` for older versions of -Python), this can eliminate the need to use the older and less efficient +:mod:`importlib.resources` (with new features backported to the +`importlib_resources`_ package), this can eliminate the need to use the older +and less efficient ``pkg_resources`` package. By "installed package" we generally mean a third-party package installed into From b06c3826ec2765c433dd773c27a5263969bd7799 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 10:57:05 -0400 Subject: [PATCH 10/22] Removed shadowed variable and make _name_from_stem a staticmethod. --- importlib_metadata/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 5ac8be23..122eed40 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -958,8 +958,9 @@ def _normalized_name(self): 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) + @staticmethod + def _name_from_stem(stem): + _, ext = os.path.splitext(stem) if ext not in ('.dist-info', '.egg-info'): return name, sep, rest = stem.partition('-') From 4461855128600c120032a446624b7872ffe7cc70 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 10:58:13 -0400 Subject: [PATCH 11/22] Add some (failing) tests for _name_from_stem. Ref #377 --- importlib_metadata/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 122eed40..75dc9dfe 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -960,6 +960,14 @@ def _normalized_name(self): @staticmethod def _name_from_stem(stem): + """ + >>> PathDistribution._name_from_stem('foo-3.0.egg-info') + 'foo' + >>> PathDistribution._name_from_stem('CherryPy-3.0.dist-info') + 'CherryPy' + >>> PathDistribution._name_from_stem('face.egg-info') + 'face' + """ _, ext = os.path.splitext(stem) if ext not in ('.dist-info', '.egg-info'): return From 01843df1917d6b3b1a2b4a466c211919abc4de0e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 11:00:20 -0400 Subject: [PATCH 12/22] Fix issue when metadata on the file system has no version. No more egg on face. Ref #377. --- importlib_metadata/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 75dc9dfe..e4e3a506 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -968,10 +968,10 @@ def _name_from_stem(stem): >>> PathDistribution._name_from_stem('face.egg-info') 'face' """ - _, ext = os.path.splitext(stem) + filename, ext = os.path.splitext(stem) if ext not in ('.dist-info', '.egg-info'): return - name, sep, rest = stem.partition('-') + name, sep, rest = filename.partition('-') return name From 9deee509e7f2d32e4305bded506883c1c84d6f5e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 11:01:29 -0400 Subject: [PATCH 13/22] Update changelog. Ref #377. --- CHANGES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 91e3bcba..4f941897 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,9 @@ +v4.11.4 +======= + +* #377: In ``PathDistribution._name_from_stem``, avoid including + parts of the extension in the result. + v4.11.3 ======= From 4c7ef61e6e83bd93e497307abc3484fb3d038262 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 11:14:19 -0400 Subject: [PATCH 14/22] Add another test for _name_from_stem. --- importlib_metadata/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index e4e3a506..98fc639c 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -967,6 +967,7 @@ def _name_from_stem(stem): 'CherryPy' >>> PathDistribution._name_from_stem('face.egg-info') 'face' + >>> PathDistribution._name_from_stem('foo.bar') """ filename, ext = os.path.splitext(stem) if ext not in ('.dist-info', '.egg-info'): From 6eb6f7176f59850aa9dbb7c7bbb3de6891d0f0e1 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 11:31:30 -0400 Subject: [PATCH 15/22] Add test expanding expectation on unique packages to include normalization. Ref #377. --- tests/test_api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 26731884..3f75cebb 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -89,15 +89,15 @@ def test_entry_points_distribution(self): self.assertIn(ep.dist.name, ('distinfo-pkg', 'egginfo-pkg')) self.assertEqual(ep.dist.version, "1.0.0") - def test_entry_points_unique_packages(self): + def test_entry_points_unique_packages_normalized(self): """ Entry points should only be exposed for the first package - on sys.path with a given name. + on sys.path with a given name (even when normalized). """ alt_site_dir = self.fixtures.enter_context(fixtures.tempdir()) self.fixtures.enter_context(self.add_sys_path(alt_site_dir)) alt_pkg = { - "distinfo_pkg-1.1.0.dist-info": { + "DistInfo_pkg-1.1.0.dist-info": { "METADATA": """ Name: distinfo-pkg Version: 1.1.0 From 45b8841aa0113366a11a1367d0fc332e8b580afc Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Thu, 12 May 2022 21:15:45 +0200 Subject: [PATCH 16/22] fix `PathDistribution._normalized_name` implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - apply PEP 503 normalization to the extracted names (e.g.: `zope..inter_face-4.2.dist-info` must yield the name `zope_inter_face`) `entry_points(…)` can yield the entry-points of a shadowed distribution. For example: with a version of `mypkg` in the system' site-packages directory when working from another development checkout of the same package (with a `mypkg.egg-info` directory mishandled by the first bug). --- importlib_metadata/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 98fc639c..b1db5a6e 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -956,7 +956,10 @@ def _normalized_name(self): normalized name from the file system path. """ stem = os.path.basename(str(self._path)) - return self._name_from_stem(stem) or super()._normalized_name + return ( + pass_none(Prepared.normalize)(self._name_from_stem(stem)) + or super()._normalized_name + ) @staticmethod def _name_from_stem(stem): From 21bacb91565b109a8154f6632b79e49c07750d17 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 11:41:52 -0400 Subject: [PATCH 17/22] Update changelog. --- CHANGES.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 4f941897..7e98644d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,6 +3,10 @@ v4.11.4 * #377: In ``PathDistribution._name_from_stem``, avoid including parts of the extension in the result. +# #381: In ``PathDistribution._normalized_name``, ensure names + loaded from the stem of the filename are also normalized, ensuring + duplicate entry points by packages varying only by non-normalized + name are hidden. v4.11.3 ======= From 1d840cbf3ebaba37f02dcfb3906e98fac968f486 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 11:46:15 -0400 Subject: [PATCH 18/22] Reference the main PR where the change occurred. --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 7e98644d..6fbcfd7c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,7 @@ v4.11.4 ======= -* #377: In ``PathDistribution._name_from_stem``, avoid including +* #379: In ``PathDistribution._name_from_stem``, avoid including parts of the extension in the result. # #381: In ``PathDistribution._normalized_name``, ensure names loaded from the stem of the filename are also normalized, ensuring From 9c80e090cc24c0fbaf6ba2e8716afebb72768289 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 11:54:02 -0400 Subject: [PATCH 19/22] Use build_files for rendering fixtures in test_main. --- tests/test_main.py | 52 ++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 1a64af56..bba2624b 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,7 +1,6 @@ import re import json import pickle -import textwrap import unittest import warnings import importlib @@ -82,11 +81,12 @@ def pkg_with_dashes(site_dir): Create minimal metadata for a package with dashes in the name (and thus underscores in the filename). """ - metadata_dir = site_dir / 'my_pkg.dist-info' - metadata_dir.mkdir() - metadata = metadata_dir / 'METADATA' - with metadata.open('w', encoding='utf-8') as strm: - strm.write('Version: 1.0\n') + contents = { + 'my_pkg.dist-info': { + 'METADATA': 'VERSION: 1.0\n', + }, + } + fixtures.build_files(contents, site_dir) return 'my-pkg' def test_dashes_in_dist_name_found_as_underscores(self): @@ -103,11 +103,12 @@ def pkg_with_mixed_case(site_dir): Create minimal metadata for a package with mixed case in the name. """ - metadata_dir = site_dir / 'CherryPy.dist-info' - metadata_dir.mkdir() - metadata = metadata_dir / 'METADATA' - with metadata.open('w', encoding='utf-8') as strm: - strm.write('Version: 1.0\n') + contents = { + 'CherryPy.dist-info': { + 'METADATA': 'VERSION: 1.0\n', + }, + } + fixtures.build_files(contents, site_dir) return 'CherryPy' def test_dist_name_found_as_any_case(self): @@ -127,11 +128,12 @@ def pkg_with_non_ascii_description(site_dir): Create minimal metadata for a package with non-ASCII in the description. """ - metadata_dir = site_dir / 'portend.dist-info' - metadata_dir.mkdir() - metadata = metadata_dir / 'METADATA' - with metadata.open('w', encoding='utf-8') as fp: - fp.write('Description: pôrˈtend') + contents = { + 'portend.dist-info': { + 'METADATA': 'Description: pôrˈtend', + }, + } + fixtures.build_files(contents, site_dir) return 'portend' @staticmethod @@ -140,19 +142,15 @@ def pkg_with_non_ascii_description_egg_info(site_dir): Create minimal metadata for an egg-info package with non-ASCII in the description. """ - metadata_dir = site_dir / 'portend.dist-info' - metadata_dir.mkdir() - metadata = metadata_dir / 'METADATA' - with metadata.open('w', encoding='utf-8') as fp: - fp.write( - textwrap.dedent( - """ + contents = { + 'portend.dist-info': { + 'METADATA': """ Name: portend - pôrˈtend - """ - ).strip() - ) + pôrˈtend""", + }, + } + fixtures.build_files(contents, site_dir) return 'portend' def test_metadata_loads(self): From 2df8b5a1e6d641f96627c82483caab940be42263 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 12:04:28 -0400 Subject: [PATCH 20/22] Consolidate logic for generating minimal metadata. --- tests/test_main.py | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index bba2624b..c88ce35a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -76,46 +76,31 @@ def test_resolve_without_attr(self): class NameNormalizationTests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase): @staticmethod - def pkg_with_dashes(site_dir): + def make_pkg(name): """ - Create minimal metadata for a package with dashes - in the name (and thus underscores in the filename). + Create minimal metadata for a dist-info package with + the indicated name on the file system. """ - contents = { - 'my_pkg.dist-info': { + return { + f'{name}.dist-info': { 'METADATA': 'VERSION: 1.0\n', }, } - fixtures.build_files(contents, site_dir) - return 'my-pkg' def test_dashes_in_dist_name_found_as_underscores(self): """ For a package with a dash in the name, the dist-info metadata uses underscores in the name. Ensure the metadata loads. """ - pkg_name = self.pkg_with_dashes(self.site_dir) - assert version(pkg_name) == '1.0' - - @staticmethod - def pkg_with_mixed_case(site_dir): - """ - Create minimal metadata for a package with mixed case - in the name. - """ - contents = { - 'CherryPy.dist-info': { - 'METADATA': 'VERSION: 1.0\n', - }, - } - fixtures.build_files(contents, site_dir) - return 'CherryPy' + fixtures.build_files(self.make_pkg('my_pkg'), self.site_dir) + assert version('my-pkg') == '1.0' def test_dist_name_found_as_any_case(self): """ Ensure the metadata loads when queried with any case. """ - pkg_name = self.pkg_with_mixed_case(self.site_dir) + pkg_name = 'CherryPy' + fixtures.build_files(self.make_pkg(pkg_name), self.site_dir) assert version(pkg_name) == '1.0' assert version(pkg_name.lower()) == '1.0' assert version(pkg_name.upper()) == '1.0' From a3ad5f708054e1a86a97a086f8ec01c34549eed6 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 11:56:47 -0400 Subject: [PATCH 21/22] Extract '_unique' for identifying unique distributions. --- importlib_metadata/__init__.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index b1db5a6e..29ce1175 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -1015,6 +1015,15 @@ def version(distribution_name): return distribution(distribution_name).version +_unique = functools.partial( + unique_everseen, + key=operator.attrgetter('_normalized_name'), +) +""" +Wrapper for ``distributions`` to return unique distributions by name. +""" + + def entry_points(**params) -> Union[EntryPoints, SelectableGroups]: """Return EntryPoint objects for all installed packages. @@ -1032,10 +1041,8 @@ def entry_points(**params) -> Union[EntryPoints, SelectableGroups]: :return: EntryPoints or SelectableGroups for all installed packages. """ - 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()) + dist.entry_points for dist in _unique(distributions()) ) return SelectableGroups.load(eps).select(**params) From da980921eaf63bdaf5b0242356a85ba815cb930d Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 21 May 2022 12:15:34 -0400 Subject: [PATCH 22/22] Add test for _unique. --- tests/test_main.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_main.py b/tests/test_main.py index c88ce35a..215662dd 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -13,6 +13,7 @@ EntryPoint, MetadataPathFinder, PackageNotFoundError, + _unique, distributions, entry_points, metadata, @@ -105,6 +106,21 @@ def test_dist_name_found_as_any_case(self): assert version(pkg_name.lower()) == '1.0' assert version(pkg_name.upper()) == '1.0' + def test_unique_distributions(self): + """ + Two distributions varying only by non-normalized name on + the file system should resolve as the same. + """ + fixtures.build_files(self.make_pkg('abc'), self.site_dir) + before = list(_unique(distributions())) + + alt_site_dir = self.fixtures.enter_context(fixtures.tempdir()) + self.fixtures.enter_context(self.add_sys_path(alt_site_dir)) + fixtures.build_files(self.make_pkg('ABC'), alt_site_dir) + after = list(_unique(distributions())) + + assert len(after) == len(before) + class NonASCIITests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase): @staticmethod