Skip to content

Commit 12e33bb

Browse files
committed
Extract Lookup class out of directory lookup behavior. Separate it from mtime caching behavior.
1 parent f787075 commit 12e33bb

File tree

1 file changed

+44
-36
lines changed

1 file changed

+44
-36
lines changed

importlib_metadata/__init__.py

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import functools
1313
import itertools
1414
import posixpath
15+
import contextlib
1516
import collections.abc
1617

1718
from ._compat import (
@@ -602,13 +603,10 @@ class FastPath:
602603

603604
@functools.lru_cache() # type: ignore
604605
def __new__(cls, root):
605-
self = object().__new__(cls)
606+
return super().__new__(cls)
607+
608+
def __init__(self, root):
606609
self.root = str(root)
607-
self.base = os.path.basename(self.root).lower()
608-
self.last_mtime = -1
609-
self.infos = {}
610-
self.eggs = {}
611-
return self
612610

613611
def joinpath(self, child):
614612
return pathlib.Path(self.root, child)
@@ -624,47 +622,54 @@ def zip_children(self):
624622
zip_path = zipp.Path(self.root)
625623
names = zip_path.root.namelist()
626624
self.joinpath = zip_path.joinpath
625+
627626
return dict.fromkeys(child.split(posixpath.sep, 1)[0] for child in names)
628627

629-
def update_cache(self):
630-
root = self.root or "."
631-
try:
632-
mtime = os.stat(root).st_mtime
633-
except OSError:
634-
self.infos.clear()
635-
self.eggs.clear()
636-
self.last_mtime = -1
637-
return
638-
if mtime == self.last_mtime:
639-
return
640-
self.infos.clear()
641-
self.eggs.clear()
642-
base_is_egg = self.base.endswith(".egg")
643-
for child in self.children():
628+
def search(self, name):
629+
return self.lookup(self.mtime).search(name)
630+
631+
@property
632+
def mtime(self):
633+
with contextlib.suppress(OSError):
634+
return os.stat(self.root).st_mtime
635+
FastPath.lookup.cache_clear()
636+
637+
@functools.lru_cache()
638+
def lookup(self, mtime):
639+
return Lookup(self)
640+
641+
642+
class Lookup:
643+
def __init__(self, path: FastPath):
644+
base = os.path.basename(path.root).lower()
645+
base_is_egg = base.endswith(".egg")
646+
self.infos = collections.defaultdict(list)
647+
self.eggs = collections.defaultdict(list)
648+
649+
for child in path.children():
644650
low = child.lower()
645651
if low.endswith((".dist-info", ".egg-info")):
646652
# rpartition is faster than splitext and suitable for this purpose.
647653
name = low.rpartition(".")[0].partition("-")[0]
648654
normalized = Prepared.normalize(name)
649-
self.infos.setdefault(normalized, []).append(child)
655+
self.infos[normalized].append(path.joinpath(child))
650656
elif base_is_egg and low == "egg-info":
651-
name = self.base.rpartition(".")[0].partition("-")[0]
657+
name = base.rpartition(".")[0].partition("-")[0]
652658
legacy_normalized = Prepared.legacy_normalize(name)
653-
self.eggs.setdefault(legacy_normalized, []).append(child)
654-
self.last_mtime = mtime
659+
self.eggs[legacy_normalized].append(path.joinpath(child))
655660

656661
def search(self, prepared):
657-
self.update_cache()
658-
if prepared.name:
659-
infos = self.infos.get(prepared.normalized, [])
660-
yield from map(self.joinpath, infos)
661-
eggs = self.eggs.get(prepared.legacy_normalized, [])
662-
yield from map(self.joinpath, eggs)
663-
else:
664-
for infos in self.infos.values():
665-
yield from map(self.joinpath, infos)
666-
for eggs in self.eggs.values():
667-
yield from map(self.joinpath, eggs)
662+
infos = (
663+
self.infos[prepared.normalized]
664+
if prepared
665+
else itertools.chain.from_iterable(self.infos.values())
666+
)
667+
eggs = (
668+
self.eggs[prepared.legacy_normalized]
669+
if prepared
670+
else itertools.chain.from_iterable(self.eggs.values())
671+
)
672+
return itertools.chain(infos, eggs)
668673

669674

670675
class Prepared:
@@ -697,6 +702,9 @@ def legacy_normalize(name):
697702
"""
698703
return name.lower().replace('-', '_')
699704

705+
def __bool__(self):
706+
return bool(self.name)
707+
700708

701709
@install
702710
class MetadataPathFinder(NullFinder, DistributionFinder):

0 commit comments

Comments
 (0)