uv workspace 依赖能解析,运行仍找不到本地包
workspace 依赖能解析,不代表成员已打包安装。检查成员构建系统、package 设置、同步参数,以及目标解释器实际导入位置。
workspace 中的本地依赖已经写进配置,解析也能完成,运行却报 ModuleNotFoundError。先查这个成员是否作为包安装到实际项目环境:让 uv 找到源码项目,与让 Python 能导入其中的模块,是两个步骤。
这类问题曾出现在 uv 0.4.28 的 workspace 配置中,缺少构建系统的成员没有按预期安装。当前 uv 的打包和同步规则仍值得核对,但不能把历史项目的配置缺失说成所有新建项目的默认行为。
区分 distribution 名称和 import 名称
例如依赖元数据名是 example-core,代码可能写 import example_core。两者并非必须完全相同;应该查看项目真正的包目录和后端配置,不能把连字符直接照搬进 import。
在原来的 workspace 环境中确认解释器与模块查找结果。下面只演示诊断入口,模块名需替换;--no-sync 用来观察现有环境,避免诊断同时改变安装状态:
uv run --no-sync python -c "import sys, importlib.util; print(sys.executable); print(importlib.util.find_spec('example_core'))"
uv pip show example-core
核对两条命令实际选择的环境。元数据存在而模块找不到时,还要查构建产物包含什么;模块能在源码目录找到,也不能单独证明包已经安装。若失败进程使用了其他解释器,先处理 安装与运行解释器不一致。
看成员自己的 build-system,而不只看根项目
检查 root 的 workspace members、依赖声明和 workspace = true 对应关系,再打开被依赖成员自己的 pyproject.toml。根项目可解析它,不等于成员声明了正确的打包方式。
uv 通过构建系统和 tool.uv.package 判断项目是否应打包安装。对需要按项目打包的成员,配置适合真实目录布局的后端;[build-system] 中的依赖和 build-backend 应与项目已有后端一致,而不是随便复制另一个工程的配置。
如果是 src/example_core/ 布局,后端必须把该目录中的实际包纳入构建。多个顶层目录、单文件模块与 namespace package 又有不同发现规则。增加 [build-system] 后构建成功,却仍打包了错误目录,也不会让目标 import 自动恢复。
tool.uv.package = true 可以强制构建安装项目;没有声明后端时会采用 setuptools 的 legacy 后端,并不保证它适合任意布局。package = false 则会阻止作为项目安装,即使已有构建系统也要核对。显式本地路径安装、uv pip 和普通外部依赖还有 legacy 构建规则,不能概括成“任何缺 build-system 的包都不能安装”。
当前默认 uv init 会创建打包项目,--no-package 则用于未打包项目。旧仓库迁移后的状态应逐个检查,不能用今天的新建默认值倒推旧文件已经完整。
同步成功还要检查安装选择
保存原配置和锁文件后,修正已经确认的打包配置,再按项目原入口同步。uv 通常将项目和其他 workspace 成员作为 editable 包安装;开发源码改动可随安装映射被读取,但包范围和安装方式改变后仍需重新同步验证。
检查真正执行的命令是否用了 --no-install-project、--no-install-workspace、--no-install-package 或只安装特定依赖组的选择。这些参数可以让依赖解析和项目安装出现不同结果,不要把“同步没报错”当作目标包一定存在的证明。
若发布时采用 --no-editable,还应检查正式安装是否包含所需模块和资源。editable 状态下碰巧能读到源码文件,不表示 wheel 也带有它。
验收使用失败应用同一解释器、原入口和测试流程,确认导入位置属于正确成员,依赖能正常使用;需要从其他工作目录运行的业务,再单独测试这一条件。不要默认把改变工作目录或追加 PYTHONPATH 作为打包缺失的修复。需要回退时恢复配置和锁文件,并按原流程重新同步,保存已有环境证据后再处置环境,不批量删除其他 workspace 数据。


