安装时复制配置文件



我正在尝试打包我的Python项目,该项目带有一个配置点文件,我希望在安装时将其复制到用户的主目录中。打包快速指南说,这可以使用data_files参数来完成setuptools.setup。所以这就是我所拥有的:

data_files = [(os.path.expanduser("~"), [".my_config"])]

如果我使用python setup.py install,这似乎可以正常工作,但是当我将我的包上传到 PyPI 并pip install运行时,不会复制点文件。

FWIW,我已经将点文件放在MANIFEST.in中,并尝试将package_data参数包含在setup.这些步骤似乎都没有区别。如果我pip install并在site-packages目录中四处寻找,则只有源文件在这里。

我怎样才能实现我想要的?

这是我曾经遇到过的问题。它的根源是,当你构建一个轮文件时,data_files中指定的所有绝对路径都将相对化到目标site-packages目录,在 github 上看到这个问题。这会影响pip install执行的安装,因为它会用任何源码包(.tar.gz.tar.bz2.zip)构建一个轮子,并安装得到的轮子:

$ pip install spam-0.1.tar.gz 
Processing ./spam-0.1.tar.gz
Building wheels for collected packages: spam
Running setup.py bdist_wheel for spam ... done
Stored in directory: /Users/hoefling/Library/Caches/pip/wheels/d0/95/be/bc79f1d589d90d67139481a3e706bcc54578fdbf891aef75c0
Successfully built spam
Installing collected packages: spam
Successfully installed spam-0.1

检查已安装的文件会产生:

$ pip show -f spam
Name: spam
Version: 0.1
...
Location: /Users/hoefling/.virtualenvs/stackoverflow/lib/python3.6/site-packages
Requires: 
Files:
Users/hoefling/.my_config
spam-0.1.dist-info/DESCRIPTION.rst
spam-0.1.dist-info/INSTALLER
spam-0.1.dist-info/METADATA
spam-0.1.dist-info/RECORD
spam-0.1.dist-info/WHEEL
spam-0.1.dist-info/metadata.json
spam-0.1.dist-info/top_level.txt

请注意,绝对路径相对于Location目录。在示例中,.my_config将放在/Users/hoefling/.virtualenvs/stackoverflow/lib/python3.6/site-packages/Users/hoefling/.my_config下。

它变得更好,因为这些构建的轮子缓存在你的磁盘上,所以下次你重新安装软件包并且构建的轮子仍然存在于pip的缓存中时,它将用于安装,你甚至不会在终端日志中看到任何关于构建轮子的提及。

没有真正的解决方案可以避免这种情况。我发现的最体面的解决方法是在安装时禁止"二进制"包,以强制在安装时执行包的setup.py

$ pip install spam-0.1.tar.gz --no-binary=spam
Processing ./spam-0.1.tar.gz
Skipping bdist_wheel for spam, due to binaries being disabled for it.
Installing collected packages: spam
Running setup.py install for spam ... done
Successfully installed spam-0.1

文件现在已正确放置:

$ pip show -f spam
Name: spam
Version: 0.1
...
Location: /Users/hoefling/.virtualenvs/stackoverflow/lib/python3.6/site-packages
Requires: 
Files:
../../../../../.my_config
spam-0.1-py3.6.egg-info/PKG-INFO
spam-0.1-py3.6.egg-info/SOURCES.txt
spam-0.1-py3.6.egg-info/dependency_links.txt
spam-0.1-py3.6.egg-info/top_level.txt

不幸的是,必须单独通知用户使用额外密钥调用pip install(通过自述文件、网页常见问题解答或类似内容),因为不可能禁止在包元数据中构建轮子。

因此,我不再包含具有绝对路径的文件。相反,我将它们与site-packages目录中的 python 源代码一起安装。在python代码中,如有必要,我必须为存在检查和文件复制添加其他逻辑:

# program entrypoint
if __name__ == '__main__':
config = os.path.join(os.path.expanduser('~'), '.my_config')
if not os.path.exists(config):
shutil.copyfile('.my_config', config)
main.run()

除了@hoefling说的,我建议你根本不使用data_files!因为文件将复制到何处确实不可预测。您可以通过为目录提供类似'''/''/anything/you/want'之类的东西来测试这一点。

我建议您改用package_data,它只是在安装时复制分布式软件包根目录下的文件。然后,您可以在运行时将其复制到所需的任何位置。

有关package_data的更多信息,请参阅 Python 文档 https://docs.python.org/2/distutils/setupscript.html#installing-package-data