我如何使setup.py包含一个不是代码一部分的文件?(具体来说,它是一个许可证文件,但也可以是其他任何东西。)
我希望能够控制文件的位置。在原始源文件夹中,文件位于包的根目录中。(即与最顶层的__init__.py在同一层。)我希望它在安装包时保持在那里,而不管操作系统是什么。我怎么做呢?
我如何使setup.py包含一个不是代码一部分的文件?(具体来说,它是一个许可证文件,但也可以是其他任何东西。)
我希望能够控制文件的位置。在原始源文件夹中,文件位于包的根目录中。(即与最顶层的__init__.py在同一层。)我希望它在安装包时保持在那里,而不管操作系统是什么。我怎么做呢?
当前回答
步骤1:创建MANIFEST。和setup.py在同一个文件夹里
步骤2:在MANIFEST.in中包含要添加的文件的相对路径
include README.rst
include docs/*.txt
include funniest/data.json
步骤3:在setup()函数中设置include_package_data=True,将这些文件复制到site-package
参考资料在这里。
其他回答
对于要包含在安装中的非python文件,它们必须位于已安装包目录中的一个目录中。如果您在MANIFEST中指定包目录之外的非python文件。中,它们将包含在您的发行版中,但不会被安装。在包目录之外安装任意文件的“文档化”方式并不可靠(现在每个人都注意到了)。
The above answer from Julian Mann copies the files to your package directory in the build directory, so it does work, but not if you are installing in editable/develop mode (pip install -e or python setup.py develop). Based on this answer to a related question (and Julian's answer), below is an example that copies files to your installed package location either way after all the other install/develop tasks are done. The assumption here is that files file1 and file2 in your root-level data directory will be copied to your installed package directory (my_package), and that they will be accessible from python modules in your package using os.path.join(os.path.dirname(__file__), 'file1'), etc.
记得也要做清单。在上面描述的东西中,以便这些文件也包含在您的发行版中。为什么setuptools会在你的发行版中包含文件,然后默默地不安装它们,这超出了我的理解范围。尽管在包目录之外安装它们可能更可疑。
import os
from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install
from shutil import copyfile
HERE = os.path.abspath(os.path.dirname(__file__))
NAME = 'my_package'
def copy_files (target_path):
source_path = os.path.join(HERE, 'data')
for fn in ["file1", "file2"]:
copyfile(os.path.join(source_path, fn), os.path.join(target_path,fn))
class PostDevelopCommand(develop):
"""Post-installation for development mode."""
def run(self):
develop.run(self)
copy_files (os.path.abspath(NAME))
class PostInstallCommand(install):
"""Post-installation for installation mode."""
def run(self):
install.run(self)
copy_files (os.path.abspath(os.path.join(self.install_lib, NAME)))
setup(
name=NAME,
cmdclass={
'develop': PostDevelopCommand,
'install': PostInstallCommand,
},
version='0.1.0',
packages=[NAME],
include_package_data=True,
setup_requires=['setuptools_scm'],
)
这里有一个对我有用的更简单的答案。
首先,根据上面Python Dev的注释,setuptools是不需要的:
package_data is also available to pure distutils setup scripts
since 2.3. – Éric Araujo
这很好,因为在包中添加setuptools要求意味着您也必须安装它。简而言之:
from distutils.core import setup
setup(
# ...snip...
packages = ['pkgname'],
package_data = {'pkgname': ['license.txt']},
)
我找到了一个解决办法:我将我的lgpl2.1 .1_license.txt重命名为lgpl2.1 .1_license.txt.py,并在文本周围加上一些三引号。现在我不需要使用data_files选项,也不需要指定任何绝对路径。我知道把它变成Python模块很难看,但我认为它没有指定绝对路径难看。
没有一个答案对我有用,因为我的文件在顶层,在包之外。我使用了自定义构建命令。
import os
import setuptools
from setuptools.command.build_py import build_py
from shutil import copyfile
HERE = os.path.abspath(os.path.dirname(__file__))
NAME = "thepackage"
class BuildCommand(build_py):
def run(self):
build_py.run(self)
if not self.dry_run:
target_dir = os.path.join(self.build_lib, NAME)
for fn in ["VERSION", "LICENSE.txt"]:
copyfile(os.path.join(HERE, fn), os.path.join(target_dir,fn))
setuptools.setup(
name=NAME,
cmdclass={"build_py": BuildCommand},
description=DESCRIPTION,
...
)
现在是2019年,以下是行之有效的方法 尽管这里和那里的建议,我在互联网上发现的是使用setuptools_scm,作为选项传递给setuptools.setup。这将包括VCS中版本化的任何数据文件,无论是git还是其他任何文件,到wheel包中,并将从git存储库中进行“pip install”以将这些文件带进来。
因此,我只是在“setup.py”的设置调用中添加了这两行。无需额外安装或导入:
setup_requires=['setuptools_scm'],
include_package_data=True,
No need to manually list package_data, or in a MANIFEST.in file - if it is versioned, it is included in the package. The docs on "setuptools_scm" put emphasis on creating a version number from the commit position, and disregard the really important part of adding the data files. (I can't care less if my intermediate wheel file is named "*0.2.2.dev45+g3495a1f" or will use the hardcoded version number "0.3.0dev0" I've typed in - but leaving crucial files for the program to work behind is somewhat important)