简体   繁体   English

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

[英]How to include license file in setup.py script?

I have written a Python extension module in C++.我用 C++ 编写了一个 Python 扩展模块。 I plan to distribute the module with setuptools.我计划使用 setuptools 分发模块。 There will be binary distributions for 32- and 64-bit Windows (built with setup.py bdist_egg ) and a source distribution for UNIX-like platforms (built with setup.py sdist ).将有 32 位和 64 位 Windows 的二进制分发版(使用setup.py bdist_egg )和类 UNIX 平台的源代码分发版(使用setup.py sdist构建)。

I plan to license the module under the BSD license.我计划在 BSD 许可证下授权该模块。 In my source tree, the file LICENSE.txt is in the top folder along with setup.py.在我的源代码树中,文件 LICENSE.txt 与 setup.py 一起位于顶部文件夹中。 How should I include it in the installation package?我应该如何将它包含在安装包中?

I tried the following setup.py script:我尝试了以下 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']}
)

It did not work, the license file is not included in the installation package.它不起作用,许可证文件不包含在安装包中。 Maybe because the setup.py file does not define any packages, only a single extension module.可能是因为 setup.py 文件没有定义任何包,只有一个扩展模块。

How do I fix this?我该如何解决?

Write a setup.cfg file and in there specify:编写一个setup.cfg文件并在其中指定:

[metadata]
license_files = LICENSE.txt

For this to work it seems like wheel is required to be installed.为此,似乎需要安装轮子。 That is:那是:

pip install wheel

If you have wheel already installed and it doesn't work, try to update it:如果您已经安装了wheel并且它不起作用,请尝试更新它:

pip install --upgrade wheel

Then when installing the package via pip install <path> the LICENSE file gets included.然后,当通过pip install <path>安装软件包时,将包含 LICENSE 文件。

Use data_files : 使用data_files

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

Two remarks: 两个评论:

  1. There is no direct need to ship a license with your product, you can use the license metadata in distutils to specify this. 无需直接向您的产品发送许可证,您可以使用distutils中的许可证元数据来指定此项。

  2. Don't use mixed single-quote and double-quotes in your code :) 不要在代码中使用混合的单引号和双引号:)

Since setuptools 42.0.0 you can use the license_files key to specify a list of license files to be included into a distribution.setuptools 42.0.0 开始,您可以使用license_files键来指定要包含在分发中的许可证文件列表。 Since version 56.0.0 it supports pattern matching and defaults to ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*') .从 56.0.0 版开始,它支持模式匹配,默认为('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*')

Note that due to implementation details there's actually no need to put this key into setup.cfg file (as another answer suggests).请注意,由于实现细节,实际上不需要将此密钥放入setup.cfg文件中(正如另一个答案所暗示的那样)。 You could supply it as an argument to setup() function instead:您可以将其作为参数提供给setup()函数:
(documentation was unclear on this at the time of writing) (在撰写本文时文档尚不清楚)

from setuptools import setup

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

Also note that while these files will be included in both binary (wheel) and source distributions, they won't be installed with your package from setup.py -style source distribution if the user doesn't have a wheel package installed!另请注意,虽然这些文件将包含在二进制(wheel)和源代码分发中,但如果用户没有安装wheel包,它们将不会与您的setup.py风格的源代码分发包一起安装!
To ensure the license files will be installed along with your package you need to make some additional modifications to your setup script:为确保许可证文件将与您的软件包一起安装,您需要对安装脚本进行一些额外的修改:

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

If your project is a pyproject.toml -style project and you think it will be installed by PEP 517-compatible frontend (eg pip>=19 ), a wheel will be forcibly built from your sources and the license files will be installed into .dist-info folder automatically.如果您的项目是pyproject.toml风格的项目,并且您认为它将由 PEP 517 兼容的前端(例如pip>=19 )安装,则会从您的源代码强制构建一个轮子,并且许可证文件将安装到.dist-info文件夹自动。

Since version 61.0.0 you could specify project metadata and other configuration options in pyproject.toml file instead.从 61.0.0 版本开始,您可以改为pyproject.toml文件中指定项目元数据和其他配置选项

Using a METADATA.in file, the license can be included both the source package and wheels automatically:使用 METADATA.in 文件,许可证可以自动包含在源包和轮子中:

METADATA.in include README.md include COPYING METADATA.in include README.md include COPYING

Check out an example here: https://github.com/node40/smsh在此处查看示例: https ://github.com/node40/smsh

New setuptools (40.x) allows metadata, including license, to be stored in the setup.cfg's "metadata" section .新的 setuptools (40.x) 允许将元数据(包括许可证)存储在setup.cfg 的“元数据”部分中。 If you use older setuptools you could provide license using the "license" named argument in your setup():如果您使用较旧的 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")
)

You have to move the LICENSE.txt file into the package directory for your project.您必须将 LICENSE.txt 文件移动到项目的包目录中。 It cannot reside the top level.它不能驻留在顶层。 Python directories get deployed, not the deployment artifact.部署 Python 目录,而不是部署工件。 If you create a python package, that package actually contains a number of subpackages.如果您创建一个 python 包,该包实际上包含许多子包。 Each subpackage must contain ALL the files relevant to deployment.每个子包必须包含与部署相关的所有文件。

Do not use data_files as it will actually distribute the files as a separate package.不要使用data_files ,因为它实际上会将文件作为单独的包分发。 (I've heard package_files works, but I have yet to see a working example to do this). (我听说package_files有效,但我还没有看到一个可行的例子来做到这一点)。

For example:例如:

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

additionally you can insert your licence text into 'long_description':此外,您可以将许可证文本插入“long_description”:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM