| | """A shim module for deprecated imports |
| | """ |
| | |
| | |
| |
|
| | import importlib.abc |
| | import importlib.util |
| | import sys |
| | import types |
| | from importlib import import_module |
| |
|
| | from .importstring import import_item |
| |
|
| |
|
| | class ShimWarning(Warning): |
| | """A warning to show when a module has moved, and a shim is in its place.""" |
| |
|
| |
|
| | class ShimImporter(importlib.abc.MetaPathFinder): |
| | """Import hook for a shim. |
| | |
| | This ensures that submodule imports return the real target module, |
| | not a clone that will confuse `is` and `isinstance` checks. |
| | """ |
| | def __init__(self, src, mirror): |
| | self.src = src |
| | self.mirror = mirror |
| |
|
| | def _mirror_name(self, fullname): |
| | """get the name of the mirrored module""" |
| |
|
| | return self.mirror + fullname[len(self.src) :] |
| |
|
| | def find_spec(self, fullname, path, target=None): |
| | if fullname.startswith(self.src + "."): |
| | mirror_name = self._mirror_name(fullname) |
| | return importlib.util.find_spec(mirror_name) |
| |
|
| |
|
| | class ShimModule(types.ModuleType): |
| |
|
| | def __init__(self, *args, **kwargs): |
| | self._mirror = kwargs.pop("mirror") |
| | src = kwargs.pop("src", None) |
| | if src: |
| | kwargs['name'] = src.rsplit('.', 1)[-1] |
| | super(ShimModule, self).__init__(*args, **kwargs) |
| | |
| | if src: |
| | sys.meta_path.append( |
| | ShimImporter(src=src, mirror=self._mirror) |
| | ) |
| | |
| | @property |
| | def __path__(self): |
| | return [] |
| | |
| | @property |
| | def __spec__(self): |
| | """Don't produce __spec__ until requested""" |
| | return import_module(self._mirror).__spec__ |
| | |
| | def __dir__(self): |
| | return dir(import_module(self._mirror)) |
| | |
| | @property |
| | def __all__(self): |
| | """Ensure __all__ is always defined""" |
| | mod = import_module(self._mirror) |
| | try: |
| | return mod.__all__ |
| | except AttributeError: |
| | return [name for name in dir(mod) if not name.startswith('_')] |
| |
|
| | def __getattr__(self, key): |
| | |
| | name = "%s.%s" % (self._mirror, key) |
| | try: |
| | return import_item(name) |
| | except ImportError as e: |
| | raise AttributeError(key) from e |
| |
|
| | def __repr__(self): |
| | |
| | |
| | try: |
| | return self.__getattr__("__repr__")() |
| | except AttributeError: |
| | return f"<ShimModule for {self._mirror!r}>" |
| |
|