我如何使setup.py包含一个不是代码一部分的文件?(具体来说,它是一个许可证文件,但也可以是其他任何东西。)

我希望能够控制文件的位置。在原始源文件夹中,文件位于包的根目录中。(即与最顶层的__init__.py在同一层。)我希望它在安装包时保持在那里,而不管操作系统是什么。我怎么做呢?


当前回答

我只是想跟进我在Centos 6上的Python 2.7中发现的一些东西。如上所述,添加package_data或data_files对我不起作用。我加了一份清单。IN中有我想要的文件,这些文件将非python文件放入tarball中,但没有通过RPM将它们安装到目标机器上。

最后,我能够使用setup/setuptools中的“选项”将文件导入到我的解决方案中。选项文件允许您从setup.py修改规范文件的各个部分。如下。

from setuptools import setup


setup(
    name='theProjectName',
    version='1',
    packages=['thePackage'],
    url='',
    license='',
    author='me',
    author_email='me@email.com',
    description='',
    options={'bdist_rpm': {'install_script': 'filewithinstallcommands'}},
)

file - MANIFEST.in:

include license.txt

文件 - 文件与安装命令:

mkdir -p $RPM_BUILD_ROOT/pathtoinstall/
#this line installs your python files
python setup.py install -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES
#install license.txt into /pathtoinstall folder
install -m 700 license.txt $RPM_BUILD_ROOT/pathtoinstall/
echo /pathtoinstall/license.txt >> INSTALLED_FILES

其他回答

最好的方法可能是使用setuptools package_data指令。这确实意味着使用setuptools(或distribute)而不是distutils,但这是一个非常无缝的“升级”。

下面是一个完整的(但未经测试的)例子:

from setuptools import setup, find_packages

setup(
    name='your_project_name',
    version='0.1',
    description='A description.',
    packages=find_packages(exclude=['ez_setup', 'tests', 'tests.*']),
    package_data={'': ['license.txt']},
    include_package_data=True,
    install_requires=[],
)

注意这里的关键行:

package_data={'': ['license.txt']},
include_package_data=True,

Package_data是包名(空=所有包)到模式列表(可以包括glob)的字典。例如,如果你只想在你的包中指定文件,你也可以这样做:

package_data={'yourpackage': ['*.txt', 'path/to/resources/*.txt']}

这里的解决方案肯定不是用.py扩展名重命名非py文件。

更多信息请看Ian Bicking的演讲。

更新:另一个[更好的]方法

如果你只是想控制源分发(sdist)的内容,并且在包之外有文件(例如顶级目录),另一种工作得很好的方法是添加一个MANIFEST。在文件中。有关此文件的格式,请参阅Python文档。

写完这篇文章后,我发现使用MANIFEST。In通常是一种不那么令人沮丧的方法,可以确保您的源发行版(tar.gz)有您需要的文件。

例如,如果你想包含顶层的requirements.txt,递归地包含顶层的"data"目录:

include requirements.txt
recursive-include data *

然而,为了在安装时将这些文件复制到site-packages内的包的文件夹中,您需要向setup()函数提供include_package_data=True。有关更多信息,请参见添加非代码文件。

这在2020年有效!

正如其他人所说,创造“显化”。在“setup.py所在的位置”。

接下来在manifest中包含/排除所有必要的东西。这里要注意语法。 例如:假设我们有模板文件夹要包含在源包中。

在manifest文件中这样做:

recursive-include template *

确保像上面那样在文件/dirs的dir-name和pattern之间留有空格。 不要像我们在gitignore那样做

recursive-include template/* [this won't work]

其他选项是使用include。有很多选择。看看他们的Manifest.in文件

最后重要的一步是,在setup.py中包含这个参数,然后就可以开始了!

   setup(
    ...
    include_package_data=True,
    ......
)

希望有帮助!编码快乐!

现在是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)

步骤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

参考资料在这里。

没有一个答案对我有用,因为我的文件在顶层,在包之外。我使用了自定义构建命令。

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,
    ...
)