如何通过setuptools将顶层目录的非Python文件纳入包分发
嘿,我看你在Python打包时卡壳了——想把根目录下的.config.json随包分发,但试了好几种方法都没效果,甚至用data_files还报错了。我来帮你理清每个方法失效的原因,再给你靠谱的解决办法:
为什么之前的操作都没生效?
- MANIFEST.in 没起作用:默认情况下,setuptools不会主动读取MANIFEST.in的内容,除非你在
setup.py里加上include_package_data=True。而且MANIFEST.in主要管源码包(sdist)的文件列表,wheel包还需要额外配置配合才能生效。 - package_data 无效:这个配置是给包目录内部的数据文件用的,也就是说你的
.config.json得放在你的Python包文件夹里(比如my_package/.config.json),如果它在项目根目录,package_data={'': ['.config.json']}这种写法完全不适用——空字符串对应的是“根包”,但根目录不属于任何包结构。 - data_files 报错:你写的
data_files=[('', '.config.json')]犯了个小错误:data_files的第二个参数必须是文件路径的列表,不是单个字符串。setuptools把单个字符串当成目录解析了,所以才会弹出“can't copy '.': doesn't exist or not a regular file”的错误。正确写法应该是把文件放进列表:data_files=[('', ['.config.json'])]。不过说实话,data_files不太推荐用,因为它会把文件安装到系统site-packages的对应位置,很多时候不是你想要的结果。
正确的解决方案,分两种情况
情况1:.config.json 在你的Python包目录里
比如你的包叫my_package,文件路径是my_package/.config.json,那这么配置:
- 在
setup.py里指定package_data,别忘了加include_package_data=True:
from setuptools import setup setup( # 其他必填配置(name、version之类的) package_data={ 'my_package': ['.config.json'] # 替换成你的实际包名 }, include_package_data=True )
- 再补个
MANIFEST.in,确保源码包也能包含这个文件:
include my_package/.config.json
情况2:.config.json 在项目根目录(不属于任何包)
最稳妥的方式是MANIFEST.in + include_package_data=True组合:
- 根目录创建
MANIFEST.in,加一行:
include .config.json
- 在
setup.py里开启自动包含数据文件:
from setuptools import setup setup( # 其他必填配置 include_package_data=True )
这样不管是生成sdist源码包还是wheel二进制包,.config.json都会被正确打包进去。
更现代的姿势:用pyproject.toml配置(推荐)
如果你已经在用PEP 621的现代打包方式,直接在pyproject.toml里写配置就行,不用管MANIFEST.in和setup.py的额外设置:
[project] name = "your-package-name" version = "0.1.0" # 其他项目配置... # 如果文件在包内: [tool.setuptools.package-data] "your_package_name" = [".config.json"] # 如果文件在根目录: [tool.setuptools.data-files] "" = [".config.json"]
验证是否成功
打包完之后,用这两个命令检查包内有没有目标文件:
- 查wheel包:
unzip -l your-package-*.whl - 查sdist包:
tar -tf your-package-*.tar.gz
如果输出里能看到.config.json,就说明成功啦!
内容的提问来源于stack exchange,提问作者wvxvw
相关产品推荐
相关产品推荐

