Skip to content

Commit 6a39aee

Browse files
jaracoclaude
andcommitted
Prefer valid distributions when collecting entry points.
Where an unclean upgrade leaves an empty metadata directory beside the valid one, `_unique` kept whichever the file system happened to list first, so the entry points of the valid distribution could go missing entirely. Closes #534. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 99afbc2 commit 6a39aee

3 files changed

Lines changed: 41 additions & 1 deletion

File tree

‎importlib_metadata/__init__.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,8 @@ def entry_points(**params) -> EntryPoints:
12011201
:return: EntryPoints for all installed packages.
12021202
"""
12031203
eps = itertools.chain.from_iterable(
1204-
dist.entry_points for dist in _unique(distributions())
1204+
dist.entry_points
1205+
for dist in _unique(Distribution._prefer_valid(distributions()))
12051206
)
12061207
return EntryPoints(eps).select(**params)
12071208

‎newsfragments/534.bugfix.rst‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
``entry_points()`` now prefers distributions whose metadata is readable, so
2+
an empty metadata directory left behind by an unclean upgrade no longer
3+
shadows the valid one of the same name and suppresses its entry points.
4+
Invalid distributions are deferred to the end of the enumeration rather than
5+
dropped.

‎tests/test_main.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,40 @@ def test_valid_dists_preferred(self):
160160
dist = Distribution.from_name('foo')
161161
assert dist.version == "1.0"
162162

163+
def test_invalid_dists_deferred(self):
164+
"""
165+
Preferring the valid dists defers the invalid ones to the end
166+
rather than dropping them.
167+
"""
168+
fixtures.build_files(self.make_pkg('foo-4.0', files={}), self.site_dir)
169+
fixtures.build_files(self.make_pkg('foo-4.1'), self.site_dir)
170+
dists = list(Distribution._prefer_valid(Distribution.discover(name='foo')))
171+
assert len(dists) == 2
172+
assert dists[0].version == "1.0"
173+
174+
def test_entry_points_from_valid_dist(self):
175+
"""
176+
Entry points come from the valid dist even when an invalid one
177+
of the same name is discovered first.
178+
179+
Ref python/importlib_metadata#534.
180+
"""
181+
# as in test_valid_dists_preferred, bracket the valid dist so that
182+
# on most file systems it is never naturally first.
183+
fixtures.build_files(self.make_pkg('foo-4.0', files={}), self.site_dir)
184+
fixtures.build_files(
185+
self.make_pkg(
186+
'foo-4.1',
187+
files={
188+
'METADATA': "VERSION: 1.0",
189+
'entry_points.txt': '[shadowed]\nep = foo:main\n',
190+
},
191+
),
192+
self.site_dir,
193+
)
194+
fixtures.build_files(self.make_pkg('foo-4.2', files={}), self.site_dir)
195+
assert entry_points(group='shadowed').names == {'ep'}
196+
163197
def test_missing_metadata(self):
164198
"""
165199
Dists with a missing metadata file should raise ``MetadataNotFound``.

0 commit comments

Comments
 (0)