如何从嵌套Git子模块安装独立Python包(不修改子模块)
问题描述
项目结构
project-dir ├── pyproject.toml ├── bin │ └── app.py ├── main_pkg │ └── __init__.py ├── setup.py └── tools (git子模块) ├── setup.py ├── a_pkg │ └── __init__.py ├── b_pkg │ └── __init__.py └── c_pkg └── __init__.py
需求
将main_pkg、a_pkg、b_pkg、c_pkg直接安装到.venv/lib/python3.10/site-packages/根目录,同时安装子模块tools的依赖,且不能修改git子模块(无写入权限)。
当前pyproject.toml配置
[build-system] build-backend = 'setuptools.build_meta' requires = ['setuptools >= 63.0.0'] [project] name = "main_pkg" version = "3.8.1a" requires-python = ">3.10.1" dependencies = [ "aiohttp >= 3.7.4", "aiohttp_cors", "aiosql", "jsonschema", "requests", "sentry-sdk" ] [project.optional-dependencies] test = [ "coverage", "hypothesis", "pytest" ] dev = [ "psycopg2-binary >= 2.9.5", "sqlalchemy >= 1.4.43", "black", "flake8", "Flake8-pyproject", "isort", "pre-commit", "python-dotenv", "vermin", ] [project.scripts] main = "bin.app:start" [tool.setuptools] include-package-data = true package-dir = {main_pkg="main_pkg", a_pkg="tools/a_pkg", b_pkg="tools/b_pkg", c_pkg="tools/c_pkg"} [tool.setuptools.packages.find] where = [".", "tools"] include = ["main", "a_pkg", "b_pkg", "c_pkg"]
问题现象
执行安装后,整个tools目录被完整安装到site-packages,还包含冗余的build目录:
.venv/lib/python3.10/site_packages/ ├── main_pkg │ └── __init__.py ├── tools ├── setup.py ├── build │ └── lib/* ├── a_pkg │ └── __init__.py ├── b_pkg │ └── __init__.py └── c_pkg └── __init__.py
期望的安装结构
.venv/lib/python3.10/site_packages/ ├── main_pkg │ └── __init__.py ├── a_pkg │ └── __init__.py ├── b_pkg │ └── __init__.py └── c_pkg └── __init__.py
尝试调整[tool.setuptools.packages.find]导致安装混乱,使用package-dir显式声明后目标包未被安装,询问遗漏的配置。
解决方案
1. 修正后的pyproject.toml配置
核心问题是package-dir与自动包发现的配置冲突,且未排除tools目录本身被打包。以下是正确配置:
[build-system] build-backend = 'setuptools.build_meta' requires = ['setuptools >= 63.0.0'] [project] name = "main_pkg" version = "3.8.1a" requires-python = ">3.10.1" dependencies = [ "aiohttp >= 3.7.4", "aiohttp_cors", "aiosql", "jsonschema", "requests", "sentry-sdk", # 手动添加tools子模块setup.py中的依赖(因无权限修改子模块,需硬编码) # 示例:假设tools/setup.py的依赖是"requests>=2.25.0",请替换为实际内容 ] [project.optional-dependencies] test = [ "coverage", "hypothesis", "pytest" ] dev = [ "psycopg2-binary >= 2.9.5", "sqlalchemy >= 1.4.43", "black", "flake8", "Flake8-pyproject", "isort", "pre-commit", "python-dotenv", "vermin", ] [project.scripts] main = "bin.app:start" [tool.setuptools] include-package-data = true # 根包目录映射为当前项目根,同时指定子模块内包的路径 package-dir = {"" = ".", "a_pkg" = "tools/a_pkg", "b_pkg" = "tools/b_pkg", "c_pkg" = "tools/c_pkg"} # 明确列出要安装的包,避免自动发现误识别tools目录 packages = ["main_pkg", "a_pkg", "b_pkg", "c_pkg"] # 排除tools目录下所有文件,防止被打包到site-packages exclude-package-data = {"" = ["tools/*"]}
2. 配置说明
package-dir:"" = "."定义项目根为默认包路径,再单独映射子模块内的包,确保setuptools能准确定位源码。packages:直接指定要安装的包名,替代自动发现机制,避免把tools目录(含setup.py)误识别为一个包。exclude-package-data:完全排除tools目录的文件,阻止其被打包到site-packages。- 子模块依赖处理:因无法修改子模块的setup.py,需手动将
tools/setup.py中install_requires的内容复制到主项目的dependencies列表,确保子模块依赖被安装。
3. 安装命令
执行可编辑安装或常规安装即可:
# 可编辑安装(方便开发) pip install -e . # 常规安装 pip install .
内容的提问来源于stack exchange,提问作者crowgers
相关产品推荐
相关产品推荐

