diff options
| author | Anderson Bravalheri <andersonbravalheri@gmail.com> | 2022-04-09 15:02:02 +0100 |
|---|---|---|
| committer | Anderson Bravalheri <andersonbravalheri@gmail.com> | 2022-06-15 16:43:50 +0100 |
| commit | 1a531db35955b16ecd703deca9789c5de48e74be (patch) | |
| tree | 15bb227ca8b2b3b2812bf9dbb1a3d2fa5410a1ff /setuptools/command/editable_wheel.py | |
| parent | a27b96be9abb2dfb6c0cd4dbd658cdfccb70bce7 (diff) | |
| download | python-setuptools-git-1a531db35955b16ecd703deca9789c5de48e74be.tar.gz | |
Add template for MetaPathFinder that can be used in editable mode
Diffstat (limited to 'setuptools/command/editable_wheel.py')
| -rw-r--r-- | setuptools/command/editable_wheel.py | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index bbf6999f..06a4a5d4 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -223,3 +223,58 @@ class _NamespaceInstaller(namespaces.Installer): def _get_root(self): """Where the modules/packages should be loaded from.""" return repr(str(self.src_root)) + + +_FINDER_TEMPLATE = """ +class __EditableFinder: + MAPPING = {mapping!r} + NAMESPACES = {namespaces!r} + + @classmethod + def install(cls): + import sys + + if not any(finder == cls for finder in sys.meta_path): + sys.meta_path.append(cls) + + @classmethod + def find_spec(cls, fullname, path, target=None): + if fullname in cls.NAMESPACES: + return cls._namespace_spec(fullname) + + for pkg, pkg_path in reversed(cls.MAPPING.items()): + if fullname.startswith(pkg): + return cls._find_spec(fullname, pkg, pkg_path) + + return None + + @classmethod + def _namespace_spec(cls, name): + # Since `cls` is appended to the path, this will only trigger + # when no other package is installed in the same namespace + from importlib.machinery import ModuleSpec + + # PEP 451 mentions setting loader to None for namespaces: + return ModuleSpec(name, None, is_package=True) + + @classmethod + def _find_spec(cls, fullname, parent, parent_path): + from importlib.machinery import all_suffixes as module_suffixes + from importlib.util import spec_from_file_location + from itertools import chain + + rest = fullname.replace(parent, "").strip(".").split(".") + candidate_path = Path(parent_path, *rest) + + init = candidate_path / "__init__.py" + candidates = (candidate_path.with_suffix(x) for x in module_suffixes()) + for candidate in chain([init], candidates): + if candidate.exists(): + spec = spec_from_file_location(fullname, candidate) + return spec + + return None + + +__EditableFinder.install() +""" |
