构建Python包:如何仅将指定文件/文件夹纳入源码分发包而非wheel?
好问题!这两个场景在Python打包里确实挺常见的,我来一步步给你拆解解决方案:
一、通用方法:将文件/文件夹仅纳入源码分发包(sdist)而非wheel
Python打包中,sdist(源码包)和wheel(二进制包)的文件包含逻辑是分开控制的,我们可以利用这一点实现“仅进sdist”的需求,主要有两种方式:
1. 使用MANIFEST.in配置(传统且兼容广泛)
MANIFEST.in是专门控制sdist包含文件的配置文件,而wheel的文件则由setup.py/setup.cfg/pyproject.toml里的包数据规则控制。
步骤:
- 项目根目录创建
MANIFEST.in文件,添加你要纳入sdist的文件/文件夹规则:# 比如要包含vendor/pipenv下所有内容 recursive-include vendor/pipenv * - 然后确保这些文件不被wheel包含:
- 如果你用
include_package_data = True(自动包含版本控制追踪的文件),需要在setup.cfg里添加排除规则:[options] include_package_data = True [options.exclude_package_data] * = vendor/pipenv/* - 如果你手动用
package_data指定wheel要包含的文件,只要不把vendor/pipenv加进去,它自然不会出现在wheel里。
- 如果你用
2. 使用pyproject.toml配置(现代推荐,适用于setuptools>=61.0.0)
如果你已经在使用pyproject.toml管理构建配置,可以直接在里面分别控制sdist和wheel的文件:
# 先指定构建后端(必须是setuptools) [build-system] requires = ["setuptools>=61.0.0", "wheel"] build-backend = "setuptools.build_meta" # 控制sdist要包含的文件 [tool.setuptools.sdist] include = ["vendor/pipenv/**/*"] # 控制wheel要排除的文件(或只指定要包含的) [tool.setuptools.exclude-package-data] * = ["vendor/pipenv/**/*"]
二、针对你的pipenv依赖场景的具体实现
你的需求是vendor/pipenv要在setup.py执行前运行,所以必须随源码包分发,但不能进入wheel(避免冗余安装),结合上面的方法,具体步骤如下:
1. 配置文件设置
用上面两种方式中的任意一种,确保vendor/pipenv被纳入sdist但排除在wheel外。比如用MANIFEST.in + setup.cfg的组合。
2. 修改setup.py加载本地pipenv
在setup.py的最开头,把vendor目录加入Python的路径,这样就能直接导入里面的pipenv代码了:
import sys from pathlib import Path # 将项目根目录下的vendor文件夹加入Python路径 sys.path.insert(0, str(Path(__file__).parent / "vendor")) # 现在可以导入pipenv的模块来解析install_requires了 from pipenv.some_module import parse_install_requires # 解析依赖列表 install_requires = parse_install_requires() # 正常编写setup逻辑 from setuptools import setup setup( name="your_package_name", version="0.1.0", install_requires=install_requires, # 其他配置项... )
3. 验证效果
运行以下命令生成包,然后检查内容:
# 生成sdist和wheel python -m build
- 解压生成的
.tar.gz源码包,确认vendor/pipenv存在; - 用
unzip或查看wheel工具(比如wheel unpack)检查生成的.whl文件,确认vendor/pipenv不在其中。
内容的提问来源于stack exchange,提问作者Stephan Fitzpatrick




