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

如何通过pyproject.toml将含编译二进制文件的目录纳入Python Wheel

问题描述

我想创建一个包含单个Python模块(script.py)和编译后C++二进制文件目录的Python Wheel包,项目结构如下:

root/
│
├── bin/
│   ├── binary1
│   ├── binary2
│   ├── binary3
│   └── binary4
├── script.py
├── pyproject.toml
├── MANIFEST.in
├── README.md

当前pyproject.toml配置:

[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
py-modules = ["script"]

[project]
name = "script-test"
description = "Lorem ipsum"
readme = "README.md"
license = { file = "LICENSE" }
authors = [
  { name = "", email = "your.email@example.com" },
]
requires-python = ">=3.7"
dynamic = ["version"]
classifiers = [
  "Programming Language :: Python :: 3",
  "License :: OSI Approved :: GNU Affero General Public License v3",
  "Natural Language :: English",
  "Intended Audience :: Science/Research",
  "Topic :: Scientific/Engineering :: Bio-Informatics",
  "Operating System :: MacOS",
  "Operating System :: POSIX :: Linux"
]

[tool.setuptools.dynamic]
version = {attr = "script.__version__"}

[tool.setuptools.package-data]
"*" = ["bin/*"]

[project.scripts]
script = "script:main"

MANIFEST.in内容:

include README.md
include LICENSE
recursive-include bin *

执行python -m build后,成功生成wheel文件(script_test-0.0.4-py3-none-any.whl)和源码包,但bin目录未被纳入wheel,却正确包含在源码包(script_test-0.0.4.tar.gz)中。

构建输出片段:

* Building wheel...
/private/var/folders/1k/dnrtvbx9445dpk1shw82v9fw0000gn/T/build-env-jgwgjjff/lib/python3.12/site-packages/setuptools/config/expand.py:126: SetuptoolsWarning: File '/private/var/folders/1k/dnrtvbx9445dpk1shw82v9fw0000gn/T/build-via-sdist-l75sfsez/script_test-0.0.4/LICENSE' cannot be found
  for path in _filter_existing_files(_filepaths)
running bdist_wheel
running build
running build_py
creating build/lib
copying script.py -> build/lib
running egg_info
writing script_test.egg-info/PKG-INFO
writing dependency_links to script_test.egg-info/dependency_links.txt
writing entry points to script_test.egg-info/entry_points.txt
writing top-level names to script_test.egg-info/top_level.txt
reading manifest file 'script_test.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: no files found matching 'LICENSE'
writing manifest file 'script_test.egg-info/SOURCES.txt'
installing to build/bdist.macosx-10.13-universal2/wheel
running install
running install_lib
creating build/bdist.macosx-10.13-universal2/wheel
copying build/lib/script.py -> build/bdist.macosx-10.13-universal2/wheel/.
running install_egg_info
Copying script_test.egg-info to build/bdist.macosx-10.13-universal2/wheel/./script_test-0.0.4-py3.12.egg-info
running install_scripts
creating build/bdist.macosx-10.13-universal2/wheel/script_test-0.0.4.dist-info/WHEEL
creating '/Users/andrzej/Desktop/vclust_env/vclust_test/dist/.tmp-8zpx71kj/script_test-0.0.4-py3-none-any.whl' and adding 'build/bdist.macosx-10.13-universal2/wheel' to it
adding 'script.py'
adding 'script_test-0.0.4.dist-info/METADATA'
adding 'script_test-0.0.4.dist-info/WHEEL'
adding 'script_test-0.0.4.dist-info/entry_points.txt'
adding 'script_test-0.0.4.dist-info/top_level.txt'
adding 'script_test-0.0.4.dist-info/RECORD'
removing build/bdist.macosx-10.13-universal2/wheel
Successfully built script_test-0.0.4.tar.gz and script_test-0.0.4-py3-none-any.whl

需求:让bin目录成为wheel的一部分,与script.py处于同一层级,二进制文件随包安装到Python的site-packages目录中。

解决方案

问题出在package-data的配置逻辑——当使用py-modules指定单个模块而非完整包结构时,package-data无法正确识别并包含根目录下的bin文件夹。需要调整配置,改用data-files来显式声明要包含的非Python文件:

  • 修改pyproject.toml,移除原有的[tool.setuptools.package-data]段,添加[tool.setuptools.data-files]配置:

    [tool.setuptools.data-files]
    "" = ["bin/*"]
    

    这里的""表示将bin目录下的所有文件安装到与script.py相同的层级(即site-packages根目录)。

  • 确保MANIFEST.in保持不变,它负责将bin目录包含进源码包,而data-files则负责将其纳入wheel包。

  • 重新执行构建命令:

    python -m build
    

修改后的完整pyproject.toml示例:

[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
py-modules = ["script"]

[project]
name = "script-test"
description = "Lorem ipsum"
readme = "README.md"
license = { file = "LICENSE" }
authors = [
  { name = "", email = "your.email@example.com" },
]
requires-python = ">=3.7"
dynamic = ["version"]
classifiers = [
  "Programming Language :: Python :: 3",
  "License :: OSI Approved :: GNU Affero General Public License v3",
  "Natural Language :: English",
  "Intended Audience :: Science/Research",
  "Topic :: Scientific/Engineering :: Bio-Informatics",
  "Operating System :: MacOS",
  "Operating System :: POSIX :: Linux"
]

[tool.setuptools.dynamic]
version = {attr = "script.__version__"}

[tool.setuptools.data-files]
"" = ["bin/*"]

[project.scripts]
script = "script:main"

验证:构建完成后,解压wheel文件查看,bin目录会和script.py一起出现在根层级,安装后也会被放置到site-packages目录下。

另外,构建输出中的LICENSE警告是因为项目根目录下缺少LICENSE文件,添加该文件即可消除警告。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 06:55:55