You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Poetry打包如何包含不在项目子路径下的Python包/模块

问题背景

单代码仓库存放2个Python项目,二者依赖同一个共享工具包,目标是将两个项目分别打包为.tar.gz格式的软件分发包。此前通过setuptools配合setup.py实现该需求,但操作流程繁琐,希望改用Poetry完成两个项目的独立依赖管理与打包工作。

现有目录结构

repo
    project1/ 
        __init__.py
        main_module.py
        pyproject.toml
    project2/ 
        __init__.py
        main_module.py
        pyproject.toml
    util/
        __init__.py
        util_module.py

已尝试操作与报错

为实现Poetry构建project1时将上级目录的util包纳入打包范围,修改了project1目录下的pyproject.toml配置:

[tool.poetry]
name = "project1"
version = "0.1.0"
description = ""
authors = [""]
packages = [
    { include = "../util/*.py" }
]

[tool.poetry.dependencies]
python = "^3.9"

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

执行poetry build命令时抛出如下错误:

Building project1 (0.1.0)
  - Building sdist

  ValueError

  'C:\\repo\\util\\__init__.py' is not in the subpath of 'C:\\repo\\project1' OR one path is relative and the other is absolute.

  at ~\.pyenv\pyenv-win\versions\3.9.6\lib\pathlib.py:929 in relative_to
       925│         n = len(to_abs_parts)
       926│         cf = self._flavour.casefold_parts
       927│         if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
       928│         formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
    →  929│             raise ValueError("{!r} is not in the subpath of {!r}"
       930│                     " OR one path is relative and the other is absolute."
       931│                              .format(str(self), str(formatted)))
       932│         return self._from_parsed_parts('', root if n == 1 else '',
       933│                                        abs_parts[n:])
核心疑问
  • Poetry是否原生支持该使用场景?
  • 如果支持,遗漏了哪些配置项?
  • 如果不支持,有哪些可行方案可实现两个项目独立打包,且两个分发包中都包含共享的util包。

解答

Poetry 原生不支持直接将pyproject.toml所在目录(即项目根目录)之外的文件纳入打包范围。你遇到的报错是Poetry的默认路径校验逻辑导致的:执行构建时,Poetry的构建上下文被严格限制在当前项目目录内,上级目录的文件不在可打包的路径范围内,无论怎么修改include规则都无法绕过该校验。

以下是两种可落地的实现方案:

方案1:将共享util包配置为独立本地依赖(推荐)

这是最符合Python打包规范、长期维护成本最低的方案:

  • 进入util目录,执行poetry init按照引导生成util包自己的pyproject.toml,将util配置为独立的Poetry包,比如命名为common-util
  • 分别在project1、project2的pyproject.toml中添加util的本地路径依赖,替换原有错误的packages配置:
[tool.poetry]
name = "project1"
version = "0.1.0"
description = ""
authors = [""]
# 不需要额外配置include规则,Poetry默认会打包当前项目目录下的代码包

[tool.poetry.dependencies]
python = "^3.9"
common-util = { path = "../util" }

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
  • 分别在两个项目目录下执行poetry build,Poetry会自动将util包的代码一并打包到最终的分发包中,不需要额外操作。如果后续需要将项目发布到公共或私有PyPI源,只需要将util包也发布到对应源,把本地路径依赖替换为版本号依赖即可,业务代码不需要任何修改。

方案2:构建前临时复制共享包(临时适配方案)

如果不想拆分util为独立包,可以通过构建脚本临时复制文件的方式实现,不需要调整现有业务代码结构:

  • 修改project1的pyproject.toml的packages配置,去掉跨上级目录的include规则,改为包含当前目录下的util包:
packages = [
    { include = "project1" },
    { include = "util" }
]
  • 编写简单的构建脚本,在构建前将util目录复制到当前项目目录,构建完成后删除临时文件即可。以Linux/macOS的shell脚本为例:
#!/bin/bash
# 进入project1目录
cd project1
# 临时复制util包到当前构建目录
cp -r ../util ./util
# 执行打包
poetry build
# 清理临时文件
rm -rf ./util
  • project2的构建脚本逻辑完全一致,只需要把路径替换为project2的目录即可。Windows环境可以编写对应的bat/PowerShell脚本实现相同逻辑。该方案的缺点是需要额外维护构建脚本,跨平台使用时需要做适配。

内容的提问来源于stack exchange,提问作者urig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 23:46:03