Skip to content

Commit 43d9d18

Browse files
committed
Extract class for fast path searching
1 parent c3550f1 commit 43d9d18

File tree

1 file changed

+32
-17
lines changed

1 file changed

+32
-17
lines changed

importlib_metadata/__init__.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,32 @@ def find_distributions(self, context=Context()):
386386
"""
387387

388388

389+
class FastPath:
390+
"""
391+
Micro-optimized class for searching a path for
392+
children.
393+
"""
394+
395+
def __init__(self, root):
396+
self.root = root
397+
398+
def children(self):
399+
try:
400+
children = os.listdir(self.root or '.')
401+
path_type = pathlib.Path
402+
except Exception:
403+
try:
404+
with zipfile.ZipFile(self.root) as zf:
405+
children = [os.path.split(child)[0]
406+
for child in zf.namelist()]
407+
path_type = zipp.Path
408+
except Exception:
409+
children = []
410+
path_type = None
411+
412+
return children, path_type
413+
414+
389415
@install
390416
class MetadataPathFinder(NullFinder, DistributionFinder):
391417
"""A degenerate finder for distribution packages on the file system.
@@ -410,42 +436,31 @@ def find_distributions(self, context=DistributionFinder.Context()):
410436
def _search_paths(cls, name, paths):
411437
"""Find metadata directories in paths heuristically."""
412438
return itertools.chain.from_iterable(
413-
cls._search_path(path, name) for path in paths)
439+
cls._search_path(path, name)
440+
for path in map(FastPath, paths)
441+
)
414442

415443
@classmethod
416444
def _search_path(cls, root, name):
417-
# This function is microoptimized by avoiding the use of regexes and
418-
# using strs rather than Path objects.
419-
root = root or '.'
420-
try:
421-
children = os.listdir(root)
422-
path_type = pathlib.Path
423-
except Exception:
424-
try:
425-
with zipfile.ZipFile(root) as zf:
426-
children = [os.path.split(child)[0]
427-
for child in zf.namelist()]
428-
path_type = zipp.Path
429-
except Exception:
430-
return
431445
if name is not None:
432446
normalized = name.lower().replace('-', '_')
433447
prefix = normalized + '-'
434448
else:
435449
normalized = prefix = ''
436450
suffixes = ('.dist-info', '.egg-info')
437451
exact_matches = [normalized + suffix for suffix in suffixes]
438-
root_n_low = os.path.split(root)[1].lower()
452+
root_n_low = os.path.split(root.root)[1].lower()
439453
root_is_egg = (
440454
root_n_low == normalized + '.egg'
441455
or root_n_low.startswith(prefix) and root_n_low.endswith('.egg'))
456+
children, path_type = root.children()
442457
for child in children:
443458
n_low = child.lower()
444459
if (n_low in exact_matches
445460
or n_low.startswith(prefix) and n_low.endswith(suffixes)
446461
# legacy case:
447462
or root_is_egg and n_low == 'egg-info'):
448-
yield path_type(root, child)
463+
yield path_type(root.root, child)
449464

450465

451466
class PathDistribution(Distribution):

0 commit comments

Comments
 (0)