Coverage for /home/tbone/.local/share/hatch/env/virtual/importnb-aVRh-lqt/test.stdlib/lib/python3.9/site-packages/importnb/finder.py: 98%
57 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-03 09:31 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-03 09:31 -0700
1# coding: utf-8
2"""# `sys.path_hook` modifiers
4Many suggestions for importing notebooks use `sys.meta_paths`, but `importnb` relies on the `sys.path_hooks` to load any notebook in the path. `PathHooksContext` is a base class for the `importnb.Notebook` `SourceFileLoader`.
5"""
7import inspect
8import sys
9from importlib.machinery import ModuleSpec
10from pathlib import Path
12from importlib._bootstrap_external import FileFinder
15class FileModuleSpec(ModuleSpec):
16 def __init__(self, *args, **kwargs):
17 super().__init__(*args, **kwargs)
18 self._set_fileattr = True
21class FuzzySpec(FileModuleSpec):
22 def __init__(
23 self, name, loader, *, alias=None, origin=None, loader_state=None, is_package=None
24 ):
25 super().__init__(
26 name,
27 loader,
28 origin=origin,
29 loader_state=loader_state,
30 is_package=is_package,
31 )
32 self.alias = alias
35def fuzzy_query(str):
36 new = ""
37 for chr in str:
38 new += (not new.endswith("__") or chr != "_") and chr or ""
39 return new.replace("__", "*").replace("_", "?")
42def fuzzy_file_search(path, fullname):
43 results = []
44 id, details = get_loader_details()
45 for ext in sum((list(object[1]) for object in details), []):
46 results.extend(Path(path).glob(fullname + ext))
47 "_" in fullname and results.extend(Path(path).glob(fuzzy_query(fullname) + ext))
48 return results
51class FuzzyFinder(FileFinder):
52 """Adds the ability to open file names with special characters using underscores."""
54 def find_spec(self, fullname, target=None):
55 """Try to finder the spec and if it cannot be found, use the underscore starring syntax
56 to identify potential matches.
57 """
58 spec = super().find_spec(fullname, target=target)
59 raw = fullname
60 if spec is None:
61 original = fullname
63 if "." in fullname:
64 original, fullname = fullname.rsplit(".", 1)
65 else:
66 original, fullname = "", original
68 if "_" in fullname:
69 # find any files using the fuzzy convention
70 files = fuzzy_file_search(self.path, fullname)
71 if files:
72 # sort and create of a path of the chosen file
73 file = sorted(files, key=lambda x: x.stat().st_mtime, reverse=True)[0]
74 name = file.stem
75 if original:
76 name = ".".join((original, name))
77 name = (original + "." + file.stem).lstrip(".")
78 spec = super().find_spec(name, target=target)
79 spec = spec and FuzzySpec(
80 spec.name,
81 spec.loader,
82 origin=spec.origin,
83 loader_state=spec.loader_state,
84 alias=raw,
85 is_package=bool(spec.submodule_search_locations),
86 )
87 return spec
90def get_loader_details():
91 for id, path_hook in enumerate(sys.path_hooks):
92 try:
93 return (
94 id,
95 list(inspect.getclosurevars(path_hook).nonlocals["loader_details"]),
96 )
97 except:
98 continue
101def get_loader_index(ext):
102 path_id, details = get_loader_details()
103 for i, (loader, exts) in enumerate(details):
104 if ext in exts:
105 return path_id, i, details