Skip to content

Commit 155bc48

Browse files
committed
Merge branch 'maint/2.x'
2 parents 9aee90b + 83c7dd2 commit 155bc48

File tree

4 files changed

+65
-23
lines changed

4 files changed

+65
-23
lines changed

CHANGES.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
v3.1.1
2+
======
3+
4+
v2.1.1
5+
======
6+
7+
* #261: Restored compatibility for package discovery for
8+
metadata without version in the name and for legacy
9+
eggs.
10+
111
v3.1.0
212
======
313

importlib_metadata/__init__.py

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -448,47 +448,29 @@ def zip_children(self):
448448

449449
return dict.fromkeys(child.split(posixpath.sep, 1)[0] for child in names)
450450

451-
def is_egg(self, search):
452-
base = self.base
451+
def search(self, name):
453452
return (
454-
base == search.versionless_egg_name
455-
or base.startswith(search.prefix)
456-
and base.endswith('.egg')
453+
self.joinpath(child)
454+
for child in self.children()
455+
if name.matches(child, self.base)
457456
)
458457

459-
def search(self, name):
460-
for child in self.children():
461-
n_low = child.lower()
462-
if (
463-
n_low in name.exact_matches
464-
or n_low.replace('.', '_').startswith(name.prefix)
465-
and n_low.endswith(name.suffixes)
466-
# legacy case:
467-
or self.is_egg(name)
468-
and n_low == 'egg-info'
469-
):
470-
yield self.joinpath(child)
471-
472458

473459
class Prepared:
474460
"""
475461
A prepared search for metadata on a possibly-named package.
476462
"""
477463

478-
normalized = ''
479-
prefix = ''
464+
normalized = None
480465
suffixes = '.dist-info', '.egg-info'
481466
exact_matches = [''][:0]
482-
versionless_egg_name = ''
483467

484468
def __init__(self, name):
485469
self.name = name
486470
if name is None:
487471
return
488472
self.normalized = self.normalize(name)
489-
self.prefix = self.normalized + '-'
490473
self.exact_matches = [self.normalized + suffix for suffix in self.suffixes]
491-
self.versionless_egg_name = self.normalized + '.egg'
492474

493475
@staticmethod
494476
def normalize(name):
@@ -497,6 +479,37 @@ def normalize(name):
497479
"""
498480
return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_')
499481

482+
@staticmethod
483+
def legacy_normalize(name):
484+
"""
485+
Normalize the package name as found in the convention in
486+
older packaging tools versions and specs.
487+
"""
488+
return name.lower().replace('-', '_')
489+
490+
def matches(self, cand, base):
491+
low = cand.lower()
492+
pre, ext = os.path.splitext(low)
493+
name, sep, rest = pre.partition('-')
494+
return (
495+
low in self.exact_matches
496+
or ext in self.suffixes
497+
and (not self.normalized or name.replace('.', '_') == self.normalized)
498+
# legacy case:
499+
or self.is_egg(base)
500+
and low == 'egg-info'
501+
)
502+
503+
def is_egg(self, base):
504+
normalized = self.legacy_normalize(self.name or '')
505+
prefix = normalized + '-' if normalized else ''
506+
versionless_egg_name = normalized + '.egg' if self.name else ''
507+
return (
508+
base == versionless_egg_name
509+
or base.startswith(prefix)
510+
and base.endswith('.egg')
511+
)
512+
500513

501514
@install
502515
class MetadataPathFinder(NullFinder, DistributionFinder):

tests/fixtures.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ class DistInfoPkgWithDotLegacy(OnSysPath, SiteDir):
128128
Version: 1.0.0
129129
""",
130130
},
131+
"pkg.lot.egg-info": {
132+
"METADATA": """
133+
Name: pkg.lot
134+
Version: 1.0.0
135+
""",
136+
},
131137
}
132138

133139
def setUp(self):

tests/test_api.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ def test_name_normalization(self):
4545
with self.subTest(name):
4646
assert distribution(name).metadata['Name'] == 'pkg.dot'
4747

48+
def test_prefix_not_matched(self):
49+
prefixes = 'p', 'pkg', 'pkg.'
50+
for prefix in prefixes:
51+
with self.subTest(prefix):
52+
with self.assertRaises(PackageNotFoundError):
53+
distribution(prefix)
54+
4855
def test_for_top_level(self):
4956
self.assertEqual(
5057
distribution('egginfo-pkg').read_text('top_level.txt').strip(), 'mod'
@@ -160,6 +167,12 @@ def test_name_normalization(self):
160167
with self.subTest(name):
161168
assert distribution(name).metadata['Name'] == 'pkg.dot'
162169

170+
def test_name_normalization_versionless_egg_info(self):
171+
names = 'pkg.lot', 'pkg_lot', 'pkg-lot', 'pkg..lot', 'Pkg.Lot'
172+
for name in names:
173+
with self.subTest(name):
174+
assert distribution(name).metadata['Name'] == 'pkg.lot'
175+
163176

164177
class OffSysPathTests(fixtures.DistInfoPkgOffPath, unittest.TestCase):
165178
def test_find_distributions_specified_path(self):

0 commit comments

Comments
 (0)