1"""Abstract base classes related to import.""" 2from . import _bootstrap 3from . import _bootstrap_external 4from . import machinery 5try: 6 import _frozen_importlib 7except ImportError as exc: 8 if exc.name != '_frozen_importlib': 9 raise 10 _frozen_importlib = None 11try: 12 import _frozen_importlib_external 13except ImportError as exc: 14 _frozen_importlib_external = _bootstrap_external 15import abc 16import warnings 17 18 19def _register(abstract_cls, *classes): 20 for cls in classes: 21 abstract_cls.register(cls) 22 if _frozen_importlib is not None: 23 try: 24 frozen_cls = getattr(_frozen_importlib, cls.__name__) 25 except AttributeError: 26 frozen_cls = getattr(_frozen_importlib_external, cls.__name__) 27 abstract_cls.register(frozen_cls) 28 29 30class Finder(metaclass=abc.ABCMeta): 31 32 """Legacy abstract base class for import finders. 33 34 It may be subclassed for compatibility with legacy third party 35 reimplementations of the import system. Otherwise, finder 36 implementations should derive from the more specific MetaPathFinder 37 or PathEntryFinder ABCs. 38 39 Deprecated since Python 3.3 40 """ 41 42 @abc.abstractmethod 43 def find_module(self, fullname, path=None): 44 """An abstract method that should find a module. 45 The fullname is a str and the optional path is a str or None. 46 Returns a Loader object or None. 47 """ 48 49 50class MetaPathFinder(Finder): 51 52 """Abstract base class for import finders on sys.meta_path.""" 53 54 # We don't define find_spec() here since that would break 55 # hasattr checks we do to support backward compatibility. 56 57 def find_module(self, fullname, path): 58 """Return a loader for the module. 59 60 If no module is found, return None. The fullname is a str and 61 the path is a list of strings or None. 62 63 This method is deprecated since Python 3.4 in favor of 64 finder.find_spec(). If find_spec() exists then backwards-compatible 65 functionality is provided for this method. 66 67 """ 68 warnings.warn("MetaPathFinder.find_module() is deprecated since Python " 69 "3.4 in favor of MetaPathFinder.find_spec() " 70 "(available since 3.4)", 71 DeprecationWarning, 72 stacklevel=2) 73 if not hasattr(self, 'find_spec'): 74 return None 75 found = self.find_spec(fullname, path) 76 return found.loader if found is not None else None 77 78 def invalidate_caches(self): 79 """An optional method for clearing the finder's cache, if any. 80 This method is used by importlib.invalidate_caches(). 81 """ 82 83_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter, 84 machinery.PathFinder, machinery.WindowsRegistryFinder) 85 86 87class PathEntryFinder(Finder): 88 89 """Abstract base class for path entry finders used by PathFinder.""" 90 91 # We don't define find_spec() here since that would break 92 # hasattr checks we do to support backward compatibility. 93 94 def find_loader(self, fullname): 95 """Return (loader, namespace portion) for the path entry. 96 97 The fullname is a str. The namespace portion is a sequence of 98 path entries contributing to part of a namespace package. The 99 sequence may be empty. If loader is not None, the portion will 100 be ignored. 101 102 The portion will be discarded if another path entry finder 103 locates the module as a normal module or package. 104 105 This method is deprecated since Python 3.4 in favor of 106 finder.find_spec(). If find_spec() is provided than backwards-compatible 107 functionality is provided. 108 """ 109 warnings.warn("PathEntryFinder.find_loader() is deprecated since Python " 110 "3.4 in favor of PathEntryFinder.find_spec() " 111 "(available since 3.4)", 112 DeprecationWarning, 113 stacklevel=2) 114 if not hasattr(self, 'find_spec'): 115 return None, [] 116 found = self.find_spec(fullname) 117 if found is not None: 118 if not found.submodule_search_locations: 119 portions = [] 120 else: 121 portions = found.submodule_search_locations 122 return found.loader, portions 123 else: 124 return None, [] 125 126 find_module = _bootstrap_external._find_module_shim 127 128 def invalidate_caches(self): 129 """An optional method for clearing the finder's cache, if any. 130 This method is used by PathFinder.invalidate_caches(). 131 """ 132 133_register(PathEntryFinder, machinery.FileFinder) 134 135 136class Loader(metaclass=abc.ABCMeta): 137 138 """Abstract base class for import loaders.""" 139 140 def create_module(self, spec): 141 """Return a module to initialize and into which to load. 142 143 This method should raise ImportError if anything prevents it 144 from creating a new module. It may return None to indicate 145 that the spec should create the new module. 146 """ 147 # By default, defer to default semantics for the new module. 148 return None 149 150 # We don't define exec_module() here since that would break 151 # hasattr checks we do to support backward compatibility. 152 153 def load_module(self, fullname): 154 """Return the loaded module. 155 156 The module must be added to sys.modules and have import-related 157 attributes set properly. The fullname is a str. 158 159 ImportError is raised on failure. 160 161 This method is deprecated in favor of loader.exec_module(). If 162 exec_module() exists then it is used to provide a backwards-compatible 163 functionality for this method. 164 165 """ 166 if not hasattr(self, 'exec_module'): 167 raise ImportError 168 return _bootstrap._load_module_shim(self, fullname) 169 170 def module_repr(self, module): 171 """Return a module's repr. 172 173 Used by the module type when the method does not raise 174 NotImplementedError. 175 176 This method is deprecated. 177 178 """ 179 # The exception will cause ModuleType.__repr__ to ignore this method. 180 raise NotImplementedError 181 182 183class ResourceLoader(Loader): 184 185 """Abstract base class for loaders which can return data from their 186 back-end storage. 187 188 This ABC represents one of the optional protocols specified by PEP 302. 189 190 """ 191 192 @abc.abstractmethod 193 def get_data(self, path): 194 """Abstract method which when implemented should return the bytes for 195 the specified path. The path must be a str.""" 196 raise OSError 197 198 199class InspectLoader(Loader): 200 201 """Abstract base class for loaders which support inspection about the 202 modules they can load. 203 204 This ABC represents one of the optional protocols specified by PEP 302. 205 206 """ 207 208 def is_package(self, fullname): 209 """Optional method which when implemented should return whether the 210 module is a package. The fullname is a str. Returns a bool. 211 212 Raises ImportError if the module cannot be found. 213 """ 214 raise ImportError 215 216 def get_code(self, fullname): 217 """Method which returns the code object for the module. 218 219 The fullname is a str. Returns a types.CodeType if possible, else 220 returns None if a code object does not make sense 221 (e.g. built-in module). Raises ImportError if the module cannot be 222 found. 223 """ 224 source = self.get_source(fullname) 225 if source is None: 226 return None 227 return self.source_to_code(source) 228 229 @abc.abstractmethod 230 def get_source(self, fullname): 231 """Abstract method which should return the source code for the 232 module. The fullname is a str. Returns a str. 233 234 Raises ImportError if the module cannot be found. 235 """ 236 raise ImportError 237 238 @staticmethod 239 def source_to_code(data, path='<string>'): 240 """Compile 'data' into a code object. 241 242 The 'data' argument can be anything that compile() can handle. The'path' 243 argument should be where the data was retrieved (when applicable).""" 244 return compile(data, path, 'exec', dont_inherit=True) 245 246 exec_module = _bootstrap_external._LoaderBasics.exec_module 247 load_module = _bootstrap_external._LoaderBasics.load_module 248 249_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter) 250 251 252class ExecutionLoader(InspectLoader): 253 254 """Abstract base class for loaders that wish to support the execution of 255 modules as scripts. 256 257 This ABC represents one of the optional protocols specified in PEP 302. 258 259 """ 260 261 @abc.abstractmethod 262 def get_filename(self, fullname): 263 """Abstract method which should return the value that __file__ is to be 264 set to. 265 266 Raises ImportError if the module cannot be found. 267 """ 268 raise ImportError 269 270 def get_code(self, fullname): 271 """Method to return the code object for fullname. 272 273 Should return None if not applicable (e.g. built-in module). 274 Raise ImportError if the module cannot be found. 275 """ 276 source = self.get_source(fullname) 277 if source is None: 278 return None 279 try: 280 path = self.get_filename(fullname) 281 except ImportError: 282 return self.source_to_code(source) 283 else: 284 return self.source_to_code(source, path) 285 286_register(ExecutionLoader, machinery.ExtensionFileLoader) 287 288 289class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader): 290 291 """Abstract base class partially implementing the ResourceLoader and 292 ExecutionLoader ABCs.""" 293 294_register(FileLoader, machinery.SourceFileLoader, 295 machinery.SourcelessFileLoader) 296 297 298class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLoader): 299 300 """Abstract base class for loading source code (and optionally any 301 corresponding bytecode). 302 303 To support loading from source code, the abstractmethods inherited from 304 ResourceLoader and ExecutionLoader need to be implemented. To also support 305 loading from bytecode, the optional methods specified directly by this ABC 306 is required. 307 308 Inherited abstractmethods not implemented in this ABC: 309 310 * ResourceLoader.get_data 311 * ExecutionLoader.get_filename 312 313 """ 314 315 def path_mtime(self, path): 316 """Return the (int) modification time for the path (str).""" 317 if self.path_stats.__func__ is SourceLoader.path_stats: 318 raise OSError 319 return int(self.path_stats(path)['mtime']) 320 321 def path_stats(self, path): 322 """Return a metadata dict for the source pointed to by the path (str). 323 Possible keys: 324 - 'mtime' (mandatory) is the numeric timestamp of last source 325 code modification; 326 - 'size' (optional) is the size in bytes of the source code. 327 """ 328 if self.path_mtime.__func__ is SourceLoader.path_mtime: 329 raise OSError 330 return {'mtime': self.path_mtime(path)} 331 332 def set_data(self, path, data): 333 """Write the bytes to the path (if possible). 334 335 Accepts a str path and data as bytes. 336 337 Any needed intermediary directories are to be created. If for some 338 reason the file cannot be written because of permissions, fail 339 silently. 340 """ 341 342_register(SourceLoader, machinery.SourceFileLoader) 343 344 345class ResourceReader(metaclass=abc.ABCMeta): 346 347 """Abstract base class to provide resource-reading support. 348 349 Loaders that support resource reading are expected to implement 350 the ``get_resource_reader(fullname)`` method and have it either return None 351 or an object compatible with this ABC. 352 """ 353 354 @abc.abstractmethod 355 def open_resource(self, resource): 356 """Return an opened, file-like object for binary reading. 357 358 The 'resource' argument is expected to represent only a file name 359 and thus not contain any subdirectory components. 360 361 If the resource cannot be found, FileNotFoundError is raised. 362 """ 363 raise FileNotFoundError 364 365 @abc.abstractmethod 366 def resource_path(self, resource): 367 """Return the file system path to the specified resource. 368 369 The 'resource' argument is expected to represent only a file name 370 and thus not contain any subdirectory components. 371 372 If the resource does not exist on the file system, raise 373 FileNotFoundError. 374 """ 375 raise FileNotFoundError 376 377 @abc.abstractmethod 378 def is_resource(self, name): 379 """Return True if the named 'name' is consider a resource.""" 380 raise FileNotFoundError 381 382 @abc.abstractmethod 383 def contents(self): 384 """Return an iterable of strings over the contents of the package.""" 385 return [] 386 387 388_register(ResourceReader, machinery.SourceFileLoader) 389