如何通过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

