如何在setup.py脚本中包含许可文件?

时间:2012-04-02 14:00:42

标签: python setuptools

我用C ++编写了一个Python扩展模块。 我打算用setuptools分发模块。 将有32位和64位Windows的二进制发行版(使用setup.py bdist_egg构建)和类似UNIX的平台的源代码发行版(使用setup.py sdist构建)。

我打算根据BSD许可证授权该模块。 在我的源代码树中,文件LICENSE.txt与setup.py一起位于顶层文件夹中。 我应该如何将它包含在安装包中?

我尝试了以下setup.py脚本:

from setuptools import setup, Extension
from glob import glob

setup(
    name = 'Foo',
    version = '0.1.0',
    ext_modules = [Extension('Foo', glob('Source/*.cpp'))],
    package_data = {'': ['LICENSE.txt']}
)

它不起作用,许可证文件不包含在安装包中。 也许是因为setup.py文件没有定义任何包, 只有一个扩展模块。

我该如何解决这个问题?

7 个答案:

答案 0 :(得分:14)

使用data_files

setup(
    name = "Foo",
    version = "0.1.0",
    ext_modules = [Extension("Foo", glob("Source/*.cpp"))],
    data_files = [("", ["LICENSE.txt"])]
)

两个评论:

  1. 无需直接向您的产品发送许可证,您可以使用distutils中的license metadata来指定此项。

  2. 请勿在代码中使用混合的单引号和双引号:)

答案 1 :(得分:4)

写一个setup.cfg文件并在其中指定:

[metadata]
license_file = LICENSE.txt

为了使其工作,似乎需要安装车轮。那就是:

pip install wheel

然后,当通过pip install <path>安装软件包时,将包含LICENSE文件。

答案 2 :(得分:4)

setuptools 42.0.0 开始,您可以使用 license_files 键指定要包含在分发中的许可文件列表。

请注意,由于 implementation details,您实际上不需要将此密钥放入 setup.cfg 文件中(如 documentationanother answer 建议的那样)。您可以简单地将其作为参数提供给 setup() 函数:

from setuptools import setup

setup(
    ...
    license_files = ('LICENSE.txt',),
    ...
)

另请注意,虽然这些文件将包含在二进制(wheel)和源代码发行版中,但它们不会与来自 {{3} 的包一起安装 } 如果用户没有安装 wheel 包,则分发源代码!
为了确保许可证文件将与您的软件包一起安装,您需要对安装脚本进行一些额外的修改:

from setuptools import setup
from setuptools.command.egg_info import egg_info


class egg_info_ex(egg_info):
    """Includes license file into `.egg-info` folder."""

    def run(self):
        # don't duplicate license into `.egg-info` when building a distribution
        if not self.distribution.have_run.get('install', True):
            # `install` command is in progress, copy license
            self.mkpath(self.egg_info)
            self.copy_file('LICENSE.txt', self.egg_info)

        egg_info.run(self)


setup(
    ...
    license_files = ('LICENSE.txt',),
    cmdclass = {'egg_info': egg_info_ex},
    ...
)

如果您的项目是 setup.py-style 并且您认为它将由 PEP 517 兼容的前端(例如 pip>=19)安装,则将从您的源强制构建一个轮子,并且许可证文件将是自动安装到 .dist-info 文件夹中。

答案 3 :(得分:2)

使用METADATA.in文件,许可证可以自动包含在源包和轮子中:

METADATA.in String str=null; int rng=(int)(Math.random()*NumberOfTheLinesInYourFile);//generate a random number for(int i =0; i<rng;i++){ str=strReader.readLine();//pick the line at rng variable; } System.out.println(srt);

点击此处查看示例: https://github.com/node40/smsh

答案 4 :(得分:1)

新的setuptools(40.x)允许将包括许可证在内的元数据存储在setup.cfg's "metadata" section中。如果您使用旧的setuptools,则可以使用setup()中名为“ license”的自变量来提供许可证:

def read_text(file_name: str):
    return open(os.path.join(base_path, file_name)).read()


setup(
    name = 'Foo',
    version = '0.1.0',
    ext_modules = [Extension('Foo', glob('Source/*.cpp'))],
    # package_data = {'': ['LICENSE.txt']}
    license=read_text("LICENSE.txt")
)

答案 5 :(得分:-1)

例如:

setup(
    ...
    license="ZPL",
    classifiers=[
        ...
        'License :: OSI Approved :: Zope Public License',
        ...
        ],
     ...)

另外,您可以将许可文本插入'long_description':

setup(
    ...
    long_description="Package description. \nLicense Text",
    ...)

答案 6 :(得分:-1)

您必须将LICENSE.txt文件移动到项目的程序包目录中。它不能位于顶层。 Python目录得到部署,而不是部署工件。如果创建python软件包,则该软件包实际上包含许多子软件包。每个子包都必须包含与部署相关的所有文件。

请勿使用data_files,因为它实际上会将文件作为单独的软件包分发。 (我听说package_files有用,但是我还没有看到一个可行的例子来做到这一点。)