Coverage for /home/tbone/.local/share/hatch/env/virtual/importnb-aVRh-lqt/test-legacy.interactive/lib/python3.9/site-packages/importnb/finder.py: 98%

1# coding: utf-8

2"""# `sys.path_hook` modifiers

3

4 Many 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"""

6

7 import inspect

8 import sys

9 from importlib.machinery import ModuleSpec

10 from pathlib import Path

11

12 from importlib._bootstrap_external import FileFinder

13

14

15 class FileModuleSpec(ModuleSpec):

16 def __init__(self, *args, **kwargs):

17 super().__init__(*args, **kwargs)

18 self._set_fileattr = True

19

20

21 class 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

33

34

35 def 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("_", "?")

40

41

42 def 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

49

50

51 class FuzzyFinder(FileFinder):

52 """Adds the ability to open file names with special characters using underscores."""

53

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

62

63 if "." in fullname:

64 original, fullname = fullname.rsplit(".", 1)

65 else:

66 original, fullname = "", original

67

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

88

89

90 def 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

99

100

101 def 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