Python项目安装时用data_files递归添加数据文件夹报错求助
data_files抛出异常的问题 看起来你遇到的问题大概率是data_files的路径配置不符合预期,或者这个方式本身就不适合你想要的「把数据文件夹和包一起安装」的需求。咱们一步步来理清楚:
先修正代码里的小笔误
你在调用gen_data_files时写了两次'mydata2',应该是gen_data_files('mydata1', 'mydata2')吧?这可能是手滑,但先提一下避免后续混淆。
为什么你的data_files配置会导致安装异常?
data_files的设计初衷是用来安装系统级或全局路径的文件(比如把配置文件放到/etc,文档放到/usr/share/doc)。你的gen_data_files函数返回的元组里,第一个元素是os.walk得到的相对路径(比如mydata1/subdir),这会让setuptools尝试把文件安装到Python的系统前缀目录(比如sys.prefix/mydata1/subdir)——这个路径要么没有写入权限,要么根本不是你想要的「和代码包同目录」的位置。
另外,os.walk返回的路径在不同操作系统下格式有差异,也会进一步导致安装时的路径解析错误。
推荐解决方案:改用package_data(更适合项目内数据文件)
如果你希望把mydata1和mydata2作为包的一部分,和代码一起安装到包的目录下,package_data才是正确的选择,步骤如下:
- 确保你的根包目录下有
__init__.py(哪怕是空文件),让Python识别它为合法包。 - 修改
setup.py,去掉data_files配置,改用package_data:
from setuptools import setup, find_packages setup( # ... 其他配置(比如name、version等) ... packages=find_packages(), # 自动发现你的项目包 package_data={ # 这里的''表示根包,若根包有具体名称可替换成对应名称 '': ['mydata1/**/*', 'mydata2/**/*'], }, # 确保非文本/二进制数据文件也能被正确包含 include_package_data=True, )
这里的**/*是递归匹配文件夹下所有文件的通配符,需要setuptools 40.0及以上版本支持。
- (可选)编写
MANIFEST.in文件,确保源码包sdist能包含这些数据文件:
recursive-include mydata1 * recursive-include mydata2 *
若坚持要用data_files(不推荐)
如果一定要用data_files,需要明确指定安装的目标路径(比如和包同目录),修改后的gen_data_files函数如下:
import os from setuptools import setup def gen_data_files(package_name, *dirs): results = [] # 目标安装路径为包目录下的对应文件夹 base_install_path = os.path.join(package_name) for datadir in dirs: for p, subdirs, files in os.walk(datadir): install_path = os.path.join(base_install_path, p) file_list = [os.path.join(p, f) for f in files] results.append((install_path, file_list)) return results setup( # ... 其他配置 ... data_files=gen_data_files('your_package_name', 'mydata1', 'mydata2'), )
记得把your_package_name替换成你实际的根包名称,这样文件会安装到包的目录下,避免权限或路径问题。
总结
优先选择package_data+MANIFEST.in的组合,这是Python项目管理内部数据文件的标准方式,能避免大部分安装路径相关的异常。
内容的提问来源于stack exchange,提问作者aviit

