如何在Python源分发包中纳入构建时生成的外部数据文件
解决Python sdist包含构建生成文件但不污染源码树的问题
我太懂你这个需求了!想把构建时生成的文件(比如build/generated/data.txt)塞进source distribution,但又不想让这些文件出现在源码树里,生怕不小心提交到Git对吧?之前用data_files没用很正常——那玩意儿是管安装时文件路径的,和sdist打包完全不是一回事儿。给你几个实用的解决方案:
方案一:MANIFEST.in + 预生成脚本(最推荐)
sdist打包的核心是MANIFEST.in文件,它决定了哪些文件会被纳入源码包。结合预生成步骤就能完美解决你的问题:
- 写数据生成脚本:比如创建
generate_data.py,把生成的文件输出到build/generated目录(这个目录默认不会被Git追踪,刚好符合你的需求)。 - 在setup.py里先跑生成脚本:确保打包前文件已经存在,示例代码:
import os import sys from setuptools import setup # 先执行数据生成逻辑 sys.path.insert(0, os.path.dirname(__file__)) from generate_data import generate_all_data generate_all_data() # 调用你的生成函数 # 正常执行打包配置 setup( name="your-awesome-package", version="0.1.0", packages=["your_package"], include_package_data=True, # 其他参数... )
- 配置MANIFEST.in:告诉sdist要包含
build/generated下的文件:
# 包含generated目录下所有文件 include build/generated/**/* # 如果只想包含特定类型,比如txt文件: # include build/generated/*.txt
- 保护源码树:把
build/目录加到.gitignore里,彻底避免误提交:
build/ dist/ *.egg-info/
方案二:动态指定package_data(适合更灵活的场景)
如果需要更动态的文件选择(比如根据生成结果自动包含),可以在setup.py里直接收集生成的文件并添加到package_data:
import os import sys from setuptools import setup # 先执行生成脚本(同上) sys.path.insert(0, os.path.dirname(__file__)) from generate_data import generate_all_data generate_all_data() # 收集生成的文件 generated_dir = os.path.join("build", "generated") generated_files = [] for root, _, files in os.walk(generated_dir): for f in files: # 转换为相对路径 rel_path = os.path.relpath(os.path.join(root, f), os.path.dirname(__file__)) generated_files.append(rel_path) setup( name="your-awesome-package", # 其他参数... package_data={ # 空字符串表示所有包都包含这些文件,或者指定特定包名 "": generated_files, }, include_package_data=True, )
关键注意事项
- 一定要先生成文件再打包:不管用哪种方案,必须确保
sdist命令执行前,生成的文件已经存在。如果嫌手动麻烦,可以写个Makefile自动化:
sdist: python generate_data.py python setup.py sdist
- 别再用
data_files了:它的作用是指定安装时文件要放到系统的哪个位置(比如/usr/share),和sdist打包无关,这就是你之前尝试没用的原因。
内容的提问来源于stack exchange,提问作者Lior Cohen
相关产品推荐
相关产品推荐

