已安装可编辑模式Python包,为何无法导入?
问题:可编辑模式安装的Python包无法导入
我通过克隆仓库,用pip install -e .的可编辑模式安装了一个Python包,但在对应的虚拟环境里,脚本无法导入这个包(导入报错)。
操作步骤
- 创建并激活虚拟环境:
venv .venv - 克隆仓库:
git clone https://github.com/rm-hull/luma.lcd.git - 可编辑模式安装包:
python -m pip install -e ./luma.lcd - 在根目录创建
test.py,尝试导入luma.lcd
导入luma.lcd时失败,但它的非可编辑依赖luma.core能正常导入。
目录结构
. ├── luma.lcd │ ├── luma │ │ └── lcd │ │ └── (…) │ └── luma.lcd.egg-info ├── test.py └── .venv └── lib └── python3.11 └── site-packages └── luma └── core ├── __editable___luma_lcd_2_11_0_finder.py └── __editable__.luma_lcd-2.11.0.pth
可编辑模式finder文件内容
__editable___luma_lcd_2_11_0_finder.py内容如下:
from __future__ import annotations import sys from importlib.machinery import ModuleSpec, PathFinder from importlib.machinery import all_suffixes as module_suffixes from importlib.util import spec_from_file_location from itertools import chain from pathlib import Path MAPPING: dict[str, str] = {'luma': '/home/user/luma/luma.lcd/luma'} NAMESPACES: dict[str, list[str]] = {'luma': ['/home/user/luma/luma.lcd/luma']} PATH_PLACEHOLDER = '__editable__.luma_lcd-2.11.0.finder' + ".__path_hook__" class _EditableFinder: # MetaPathFinder @classmethod def find_spec(cls, fullname: str, path=None, target=None) -> ModuleSpec | None: # type: ignore # Top-level packages and modules (we know these exist in the FS) if fullname in MAPPING: pkg_path = MAPPING[fullname] return cls._find_spec(fullname, Path(pkg_path)) # Handle immediate children modules (required for namespaces to work) # To avoid problems with case sensitivity in the file system we delegate # to the importlib.machinery implementation. parent, _, child = fullname.rpartition(".") if parent and parent in MAPPING: return PathFinder.find_spec(fullname, path=[MAPPING[parent]]) # Other levels of nesting should be handled automatically by importlib # using the parent path. return None @classmethod def _find_spec(cls, fullname: str, candidate_path: Path) -> ModuleSpec | None: 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(): return spec_from_file_location(fullname, candidate) return None class _EditableNamespaceFinder: # PathEntryFinder @classmethod def _path_hook(cls, path) -> type[_EditableNamespaceFinder]: if path == PATH_PLACEHOLDER: return cls raise ImportError @classmethod def _paths(cls, fullname: str) -> list[str]: paths = NAMESPACES[fullname] if not paths and fullname in MAPPING: paths = [MAPPING[fullname]] # Always add placeholder, for 2 reasons: # 1. __path__ cannot be empty for the spec to be considered namespace. # 2. In the case of nested namespaces, we need to force # import machinery to query _EditableNamespaceFinder again. return [*paths, PATH_PLACEHOLDER] @classmethod def find_spec(cls, fullname: str, target=None) -> ModuleSpec | None: # type: ignore if fullname in NAMESPACES: spec = ModuleSpec(fullname, None, is_package=True) spec.submodule_search_locations = cls._paths(fullname) return spec return None @classmethod def find_module(cls, _fullname) -> None: return None def install(): if not any(finder == _EditableFinder for finder in sys.meta_path): sys.meta_path.append(_EditableFinder) if not NAMESPACES: return if not any(hook == _EditableNamespaceFinder._path_hook for hook in sys.path_hooks): # PathEntryFinder is needed to create NamespaceSpec without private APIS sys.path_hooks.append(_EditableNamespaceFinder._path_hook) if PATH_PLACEHOLDER not in sys.path: sys.path.append(PATH_PLACEHOLDER) # Used just to trigger the path hook
sys.path输出
['', '/usr/lib/python311.zip', '/usr/lib/python3.11', '/usr/lib/python3.11/lib-dynload', '/home/user/luma/.venv/lib/python3.11/site-packages', '__editable__.luma_lcd-2.11.0.finder.__path_hook__']
排查与解决
- 确认命名空间包结构:
luma/lcd目录下必须存在__init__.py文件(即使是空文件),否则Python无法识别它为合法子包。检查克隆仓库里的luma.lcd/luma/lcd目录是否有该文件。 - 测试导入逻辑:修改
test.py的导入代码为:
或者先查看命名空间路径再导入:from luma import lcdimport luma print(luma.__path__) # 验证是否包含仓库内的luma目录 from luma import lcd - 升级pip并重装:旧版pip对命名空间包的可编辑支持存在缺陷,执行以下命令:
python -m pip install --upgrade pip pip install -e ./luma.lcd --force-reinstall - 临时添加路径验证:在
test.py开头添加仓库路径,验证是否能正常导入:
若成功导入,说明可编辑安装的finder未正常生效,重装后可解决。import sys sys.path.insert(0, '/home/user/luma/luma.lcd') import luma.lcd - 确认虚拟环境激活:运行
test.py前,确保已激活.venv:# Linux/macOS source .venv/bin/activate # Windows .venv\Scripts\activate python test.py
内容的提问来源于stack exchange,提问作者Cutter
相关产品推荐
相关产品推荐

