1"""Abstract base classes related to import.""" 2from . import _bootstrap_external 3from . import machinery 4try: 5 import _frozen_importlib 6except ImportError as exc: 7 if exc.name != '_frozen_importlib': 8 raise 9 _frozen_importlib = None 10try: 11 import _frozen_importlib_external 12except ImportError: 13 _frozen_importlib_external = _bootstrap_external 14from ._abc import Loader 15import abc 16import warnings 17 18from .resources import abc as _resources_abc 19 20 21__all__ = [ 22 'Loader', 'MetaPathFinder', 'PathEntryFinder', 23 'ResourceLoader', 'InspectLoader', 'ExecutionLoader', 24 'FileLoader', 'SourceLoader', 25] 26 27 28def __getattr__(name): 29 """ 30 For backwards compatibility, continue to make names 31 from _resources_abc available through this module. #93963 32 """ 33 if name in _resources_abc.__all__: 34 obj = getattr(_resources_abc, name) 35 warnings._deprecated(f"{__name__}.{name}", remove=(3, 14)) 36 globals()[name] = obj 37 return obj 38 raise AttributeError(f'module {__name__!r} has no attribute {name!r}') 39 40 41def _register(abstract_cls, *classes): 42 for cls in classes: 43 abstract_cls.register(cls) 44 if _frozen_importlib is not None: 45 try: 46 frozen_cls = getattr(_frozen_importlib, cls.__name__) 47 except AttributeError: 48 frozen_cls = getattr(_frozen_importlib_external, cls.__name__) 49 abstract_cls.register(frozen_cls) 50 51 52class MetaPathFinder(metaclass=abc.ABCMeta): 53 54 """Abstract base class for import finders on sys.meta_path.""" 55 56 # We don't define find_spec() here since that would break 57 # hasattr checks we do to support backward compatibility. 58 59 def invalidate_caches(self): 60 """An optional method for clearing the finder's cache, if any. 61 This method is used by importlib.invalidate_caches(). 62 """ 63 64_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter, 65 machinery.PathFinder, machinery.WindowsRegistryFinder) 66 67 68class PathEntryFinder(metaclass=abc.ABCMeta): 69 70 """Abstract base class for path entry finders used by PathFinder.""" 71 72 def invalidate_caches(self): 73 """An optional method for clearing the finder's cache, if any. 74 This method is used by PathFinder.invalidate_caches(). 75 """ 76 77_register(PathEntryFinder, machinery.FileFinder) 78 79 80class ResourceLoader(Loader): 81 82 """Abstract base class for loaders which can return data from their 83 back-end storage. 84 85 This ABC represents one of the optional protocols specified by PEP 302. 86 87 """ 88 89 @abc.abstractmethod 90 def get_data(self, path): 91 """Abstract method which when implemented should return the bytes for 92 the specified path. The path must be a str.""" 93 raise OSError 94 95 96class InspectLoader(Loader): 97 98 """Abstract base class for loaders which support inspection about the 99 modules they can load. 100 101 This ABC represents one of the optional protocols specified by PEP 302. 102 103 """ 104 105 def is_package(self, fullname): 106 """Optional method which when implemented should return whether the 107 module is a package. The fullname is a str. Returns a bool. 108 109 Raises ImportError if the module cannot be found. 110 """ 111 raise ImportError 112 113 def get_code(self, fullname): 114 """Method which returns the code object for the module. 115 116 The fullname is a str. Returns a types.CodeType if possible, else 117 returns None if a code object does not make sense 118 (e.g. built-in module). Raises ImportError if the module cannot be 119 found. 120 """ 121 source = self.get_source(fullname) 122 if source is None: 123 return None 124 return self.source_to_code(source) 125 126 @abc.abstractmethod 127 def get_source(self, fullname): 128 """Abstract method which should return the source code for the 129 module. The fullname is a str. Returns a str. 130 131 Raises ImportError if the module cannot be found. 132 """ 133 raise ImportError 134 135 @staticmethod 136 def source_to_code(data, path='<string>'): 137 """Compile 'data' into a code object. 138 139 The 'data' argument can be anything that compile() can handle. The'path' 140 argument should be where the data was retrieved (when applicable).""" 141 return compile(data, path, 'exec', dont_inherit=True) 142 143 exec_module = _bootstrap_external._LoaderBasics.exec_module 144 load_module = _bootstrap_external._LoaderBasics.load_module 145 146_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter, machinery.NamespaceLoader) 147 148 149class ExecutionLoader(InspectLoader): 150 151 """Abstract base class for loaders that wish to support the execution of 152 modules as scripts. 153 154 This ABC represents one of the optional protocols specified in PEP 302. 155 156 """ 157 158 @abc.abstractmethod 159 def get_filename(self, fullname): 160 """Abstract method which should return the value that __file__ is to be 161 set to. 162 163 Raises ImportError if the module cannot be found. 164 """ 165 raise ImportError 166 167 def get_code(self, fullname): 168 """Method to return the code object for fullname. 169 170 Should return None if not applicable (e.g. built-in module). 171 Raise ImportError if the module cannot be found. 172 """ 173 source = self.get_source(fullname) 174 if source is None: 175 return None 176 try: 177 path = self.get_filename(fullname) 178 except ImportError: 179 return self.source_to_code(source) 180 else: 181 return self.source_to_code(source, path) 182 183_register( 184 ExecutionLoader, 185 machinery.ExtensionFileLoader, 186 machinery.AppleFrameworkLoader, 187) 188 189 190class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader): 191 192 """Abstract base class partially implementing the ResourceLoader and 193 ExecutionLoader ABCs.""" 194 195_register(FileLoader, machinery.SourceFileLoader, 196 machinery.SourcelessFileLoader) 197 198 199class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLoader): 200 201 """Abstract base class for loading source code (and optionally any 202 corresponding bytecode). 203 204 To support loading from source code, the abstractmethods inherited from 205 ResourceLoader and ExecutionLoader need to be implemented. To also support 206 loading from bytecode, the optional methods specified directly by this ABC 207 is required. 208 209 Inherited abstractmethods not implemented in this ABC: 210 211 * ResourceLoader.get_data 212 * ExecutionLoader.get_filename 213 214 """ 215 216 def path_mtime(self, path): 217 """Return the (int) modification time for the path (str).""" 218 if self.path_stats.__func__ is SourceLoader.path_stats: 219 raise OSError 220 return int(self.path_stats(path)['mtime']) 221 222 def path_stats(self, path): 223 """Return a metadata dict for the source pointed to by the path (str). 224 Possible keys: 225 - 'mtime' (mandatory) is the numeric timestamp of last source 226 code modification; 227 - 'size' (optional) is the size in bytes of the source code. 228 """ 229 if self.path_mtime.__func__ is SourceLoader.path_mtime: 230 raise OSError 231 return {'mtime': self.path_mtime(path)} 232 233 def set_data(self, path, data): 234 """Write the bytes to the path (if possible). 235 236 Accepts a str path and data as bytes. 237 238 Any needed intermediary directories are to be created. If for some 239 reason the file cannot be written because of permissions, fail 240 silently. 241 """ 242 243_register(SourceLoader, machinery.SourceFileLoader) 244