Skip to content

Commit 3f16ae1

Browse files
Change of implementation
The finder cache is now a mapping from (normalized) names to actual filesystem names. With some luck this fixes test failures on Linux and Windows.
1 parent c216e08 commit 3f16ae1

File tree

2 files changed

+28
-18
lines changed

2 files changed

+28
-18
lines changed

Lib/importlib/_bootstrap_external.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,8 +1591,8 @@ def __init__(self, path, *loader_details):
15911591
else:
15921592
self.path = _path_abspath(path)
15931593
self._path_mtime = -1
1594-
self._path_cache = set()
1595-
self._relaxed_path_cache = set()
1594+
self._path_cache = dict()
1595+
self._relaxed_path_cache = dict()
15961596
self._cache_is_normalized = False
15971597

15981598
def invalidate_caches(self):
@@ -1628,8 +1628,12 @@ def find_spec(self, fullname, target=None):
16281628
cache_module = tail_module
16291629
cache = self._path_cache
16301630
# Check if the module is the name of a directory (and thus a package).
1631-
if cache_module in cache:
1632-
base_path = _path_join(self.path, tail_module)
1631+
try:
1632+
cache_path = cache[cache_module]
1633+
except KeyError:
1634+
pass
1635+
else:
1636+
base_path = _path_join(self.path, cache_path)
16331637
for suffix, loader_class in self._loaders:
16341638
init_filename = '__init__' + suffix
16351639
full_path = _path_join(base_path, init_filename)
@@ -1641,15 +1645,21 @@ def find_spec(self, fullname, target=None):
16411645
is_namespace = _path_isdir(base_path)
16421646
# Check for a file w/ a proper suffix exists.
16431647
for suffix, loader_class in self._loaders:
1648+
# XXX: Why is ValueError caught here?
1649+
#try:
1650+
# full_path = _path_join(self.path, tail_module + suffix)
1651+
#except ValueError:
1652+
# return None
1653+
_bootstrap._verbose_message('trying {}{} in {}', cache_module, suffix, self.path, verbosity=2)
16441654
try:
1645-
full_path = _path_join(self.path, tail_module + suffix)
1646-
except ValueError:
1647-
return None
1648-
_bootstrap._verbose_message('trying {}', full_path, verbosity=2)
1649-
if cache_module + suffix in cache:
1655+
cache_path = cache[cache_module + suffix]
1656+
except KeyError:
1657+
pass
1658+
1659+
else:
1660+
full_path = _path_join(self.path, cache_path)
16501661
if _path_isfile(full_path):
1651-
return self._get_spec(loader_class, fullname, full_path,
1652-
None, target)
1662+
return self._get_spec(loader_class, fullname, full_path, None, target)
16531663
if is_namespace:
16541664
_bootstrap._verbose_message('possible namespace for {}', base_path)
16551665
spec = _bootstrap.ModuleSpec(fullname, None)
@@ -1669,24 +1679,24 @@ def _fill_cache(self):
16691679
# We store two cached versions, to handle runtime changes of the
16701680
# PYTHONCASEOK environment variable.
16711681
if not sys.platform.startswith('win'):
1672-
self._path_cache = set(contents)
1682+
self._path_cache = { p: p for p in contents }
16731683
else:
16741684
# Windows users can import modules with case-insensitive file
16751685
# suffixes (for legacy reasons). Make the suffix lowercase here
16761686
# so it's done once instead of for every import. This is safe as
16771687
# the specified suffixes to check against are always specified in a
16781688
# case-sensitive manner.
1679-
lower_suffix_contents = set()
1689+
lower_suffix_contents = dict()
16801690
for item in contents:
16811691
name, dot, suffix = item.partition('.')
16821692
if dot:
16831693
new_name = f'{name}.{suffix.lower()}'
16841694
else:
16851695
new_name = name
1686-
lower_suffix_contents.add(new_name)
1696+
lower_suffix_contents[new_name] = item
16871697
self._path_cache = lower_suffix_contents
16881698
if sys.platform.startswith(_CASE_INSENSITIVE_PLATFORMS):
1689-
self._relaxed_path_cache = {fn.lower() for fn in contents}
1699+
self._relaxed_path_cache = {fn.lower(): fn for fn in contents}
16901700

16911701
self._cache_is_normalized = False
16921702

@@ -1696,8 +1706,8 @@ def _normalize_cache(self):
16961706
"""
16971707
from unicodedata import normalize
16981708

1699-
self._path_cache = { normalize('NFKC', p) for p in self._path_cache }
1700-
self._relaxed_path_cache = { normalize('NFKC', p) for p in self._relaxed_path_cache }
1709+
self._path_cache = { normalize('NFKC', p): p for p in self._path_cache }
1710+
self._relaxed_path_cache = { normalize('NFKC', p): p for p in self._relaxed_path_cache }
17011711
self._cache_is_normalized = True
17021712

17031713

Lib/test/test_importlib/source/test_case_sensitivity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_insensitive(self):
5959
self.assertIsNotNone(sensitive)
6060
self.assertIn(self.name, sensitive.get_filename(self.name))
6161
self.assertIsNotNone(insensitive)
62-
self.assertIn(self.name, insensitive.get_filename(self.name))
62+
self.assertIn(self.name.lower(), insensitive.get_filename(self.name))
6363

6464

6565
class CaseSensitivityTestPEP451(CaseSensitivityTest):

0 commit comments

Comments
 (0)