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

1# coding: utf-8 

2"""# `sys.path_hook` modifiers 

3 

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

6 

7import inspect 

8import sys 

9from importlib.machinery import ModuleSpec 

10from pathlib import Path 

11 

12from importlib._bootstrap_external import FileFinder 

13 

14 

15class FileModuleSpec(ModuleSpec): 

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

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

18 self._set_fileattr = True 

19 

20 

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 

33 

34 

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

40 

41 

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 

49 

50 

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

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 

99 

100 

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