1 """A shim module for deprecated imports 2 """ 3 # Copyright (c) IPython Development Team. 4 # Distributed under the terms of the Modified BSD License. 5 6 import importlib.abc 7 import importlib.util 8 import sys 9 import types 10 from importlib import import_module 11 12 from .importstring import import_item 13 14 15 class ShimWarning(Warning): 16 """A warning to show when a module has moved, and a shim is in its place.""" 17 18 19 class ShimImporter(importlib.abc.MetaPathFinder): 20 """Import hook for a shim. 21 22 This ensures that submodule imports return the real target module, 23 not a clone that will confuse `is` and `isinstance` checks. 24 """ 25 def __init__(self, src, mirror): 26 self.src = src 27 self.mirror = mirror 28 29 def _mirror_name(self, fullname): 30 """get the name of the mirrored module""" 31 32 return self.mirror + fullname[len(self.src) :] 33 34 def find_spec(self, fullname, path, target=None): 35 if fullname.startswith(self.src + "."): 36 mirror_name = self._mirror_name(fullname) 37 return importlib.util.find_spec(mirror_name) 38 39 40 class ShimModule(types.ModuleType): 41 42 def __init__(self, *args, **kwargs): 43 self._mirror = kwargs.pop("mirror") 44 src = kwargs.pop("src", None) 45 if src: 46 kwargs['name'] = src.rsplit('.', 1)[-1] 47 super(ShimModule, self).__init__(*args, **kwargs) 48 # add import hook for descendent modules 49 if src: 50 sys.meta_path.append( 51 ShimImporter(src=src, mirror=self._mirror) 52 ) 53 54 @property 55 def __path__(self): 56 return [] 57 58 @property 59 def __spec__(self): 60 """Don't produce __spec__ until requested""" 61 return import_module(self._mirror).__spec__ 62 63 def __dir__(self): 64 return dir(import_module(self._mirror)) 65 66 @property 67 def __all__(self): 68 """Ensure __all__ is always defined""" 69 mod = import_module(self._mirror) 70 try: 71 return mod.__all__ 72 except AttributeError: 73 return [name for name in dir(mod) if not name.startswith('_')] 74 75 def __getattr__(self, key): 76 # Use the equivalent of import_item(name), see below 77 name = "%s.%s" % (self._mirror, key) 78 try: 79 return import_item(name) 80 except ImportError as e: 81 raise AttributeError(key) from e 82 83 def __repr__(self): 84 # repr on a module can be called during error handling; make sure 85 # it does not fail, even if the import fails 86 try: 87 return self.__getattr__("__repr__")() 88 except AttributeError: 89 return f"<ShimModule for {self._mirror!r}>" 90