8000 Merge branch 'maint/3.8.x' · python/importlib_metadata@61fcac1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 61fcac1

Browse files
committed
Merge branch 'maint/3.8.x'
2 parents 703a29b + d84930c commit 61fcac1

File tree

3 files changed

+43
-5
lines changed

3 files changed

+43
-5
lines changed

importlib_metadata/__init__.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
import contextlib
1616
import collections
1717

18+
from ._collections import freezable_defaultdict
1819
from ._compat import (
1920
NullFinder,
21+
Protocol,
2022
PyPy_repr,
2123
install,
22-
Protocol,
2324
)
24-
2525
from ._functools import method_cache
2626
from ._itertools import unique_everseen
2727

@@ -710,8 +710,8 @@ class Lookup:
710710
def __init__(self, path: FastPath):
711711
base = os.path.basename(path.root).lower()
712712
base_is_egg = base.endswith(".egg")
713-
self.infos = collections.defaultdict(list)
714-
self.eggs = collections.defaultdict(list)
713+
self.infos = freezable_defaultdict(list)
714+
self.eggs = freezable_defaultdict(list)
715715

716716
for child in path.children():
717717
low = child.lower()
@@ -725,6 +725,9 @@ def __init__(self, path: FastPath):
725725
legacy_normalized = Prepared.legacy_normalize(name)
726726
self.eggs[legacy_normalized].append(path.joinpath(child))
727727

728+
self.infos.freeze()
729+
self.eggs.freeze()
730+
728731
def search(self, prepared):
729732
infos = (
730733
self.infos[prepared.normalized]
@@ -736,7 +739,7 @@ def search(self, prepared):
736739
if prepared
737740
else itertools.chain.from_iterable(self.eggs.values())
738741
)
739-
return list(itertools.chain(infos, eggs))
742+
return itertools.chain(infos, eggs)
740743

741744

742745
class Prepared:

importlib_metadata/_collections.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import collections
2+
3+
4+
class freezable_defaultdict(collections.defaultdict):
5+
"""
6+
Mix-in to freeze a defaultdict.
7+
8+
>>> dd = freezable_defaultdict(list)
9+
>>> dd[0].append('1')
10+
>>> dd.freeze()
11+
>>> dd[1]
12+
[]
13+
>>> len(dd)
14+
1
15+
"""
16+
17+
def __missing__(self, key):
18+
return getattr(self, '_frozen', super().__missing__)(key)
19+
20+
def freeze(self):
21+
self._frozen = lambda key: self.default_factory()

tests/test_integration.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Distribution,
88
MetadataPathFinder,
99
_compat,
10+
distributions,
1011
version,
1112
)
1213

@@ -59,3 +60,16 @@ def test_search_dist_dirs(self):
5960
"""
6061
res = MetadataPathFinder._search_paths('any-name', [])
6162
assert list(res) == []
63+
64+
def test_interleaved_discovery(self):
65+
"""
66+
When the search is cached, it is
67+
possible for searches to be interleaved, so make sure
68+
those use-cases are safe.
69+
70+
Ref #293
71+
"""
72+
dists = distributions()
73+
next(dists)
74+
version('importlib_metadata')
75+
next(dists)

0 commit comments

Comments
 (0)
0