Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion importlib_metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,21 @@ def version(distribution_name: str) -> str:
"""


def _unique_valid(dists: Iterable[Distribution]) -> Iterable[Distribution]:
"""
Return unique distributions, preferring valid metadata for duplicates.
"""
has_metadata = ExceptionTrap(MetadataNotFound).passes(operator.attrgetter('metadata'))
unique: dict[str, Distribution] = {}
for dist in dists:
name = dist._normalized_name
if name not in unique:
unique[name] = dist
elif not has_metadata(unique[name]) and has_metadata(dist):
unique[name] = dist
return unique.values()


def entry_points(**params) -> EntryPoints:
"""Return EntryPoint objects for all installed packages.

Expand All @@ -1131,7 +1146,7 @@ def entry_points(**params) -> EntryPoints:
:return: EntryPoints for all installed packages.
"""
eps = itertools.chain.from_iterable(
dist.entry_points for dist in _unique(distributions())
dist.entry_points for dist in _unique_valid(distributions())
)
return EntryPoints(eps).select(**params)

Expand Down
33 changes: 33 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import pickle
import re
import unittest
from unittest import mock

import pyfakefs.fake_filesystem_unittest as ffs
from test.support import os_helper
Expand Down Expand Up @@ -168,6 +169,38 @@ def test_missing_metadata(self):
with self.assertRaises(MetadataNotFound):
metadata('foo')

def test_entry_points_prefer_valid_distribution(self):
"""
Entry points should be exposed from the valid distribution when an
empty dist-info directory for the same name is discovered first.

Ref python/importlib_metadata#534.
"""
fixtures.build_files(self.make_pkg('foo-0.9', files={}), self.site_dir)
fixtures.build_files(
self.make_pkg(
'foo-1.0',
files={
"METADATA": """
Name: foo
Version: 1.0
""",
"entry_points.txt": """
[entries]
main = mod:main
""",
},
),
self.site_dir,
)
dists = [
Distribution.at(self.site_dir / 'foo-0.9.dist-info'),
Distribution.at(self.site_dir / 'foo-1.0.dist-info'),
]
with mock.patch.object(importlib_metadata, 'distributions', return_value=dists):
entries = importlib_metadata.entry_points(group='entries')
assert entries['main'].value == 'mod:main'


class NonASCIITests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
@staticmethod
Expand Down