许可示例和用户场景

PEP 639 规定了声明项目许可证、许可证文件路径以及其他法律要求信息的方式。本文档旨在提供清晰的指导,说明如何从遗留的许可证声明方式迁移到标准化的方式。在尝试应用新指南之前,请确保您首选的构建后端支持PEP 639

许可示例

基本示例

Setuptools 项目本身,截至版本 75.6.0,在其自己的项目源元数据中没有使用 License 字段。此外,它不再像以前那样明确指定 license_file/license_files,因为 Setuptools 依赖于其自动包含符合常见模式的许可证相关文件,例如它使用的 LICENSE 文件。

它在其 pyproject.toml 中包含了以下许可证相关元数据

[project]
classifiers = [
    "License :: OSI Approved :: MIT License"
]

迁移到 PEP 639 最简单的方法是使用这个

[project]
license = "MIT"

或者,如果项目使用 setup.cfg,则在其 [metadata] 表中

[metadata]
license = MIT

分发包的输出核心元数据将是

License-Expression: MIT
License-File: LICENSE

LICENSE 文件将存储在 sdist 的 /setuptools-VERSION/LICENSE 和 wheel 的 /setuptools-VERSION.dist-info/licenses/LICENSE 中,并在安装时从那里解包到站点目录(例如 site-packages/);/ 是相应存档的根目录,{VERSION} 是核心元数据中 Setuptools 版本的版本号。

高级示例

假设 Setuptools 包含在 setuptools/_vendor/pkg_resources/_vendor/ 目录中售卖的第三方项目的许可证;具体来说

packaging==21.2
pyparsing==2.2.1
ordered-set==3.1.1
more_itertools==8.8.0

这些项目的许可表达式为

packaging: Apache-2.0 OR BSD-2-Clause
pyparsing: MIT
ordered-set: MIT
more_itertools: MIT

一个涵盖 Setuptools 本身及其供应商依赖项的全面许可证表达式将包含这些元数据,将所有许可证表达式组合在一起。这样的表达式可能是

MIT AND (Apache-2.0 OR BSD-2-Clause)

此外,根据许可证的要求,必须在包中包含相关许可证文件。假设 LICENSE 文件包含 MIT 许可证文本以及 Setuptools、pyparsingmore_itertoolsordered-set 使用的版权;并且 setuptools/_vendor/packaging/ 目录中的 LICENSE* 文件包含 Apache 2.0 和 2-clause BSD 许可证文本,以及 Packaging 版权声明和许可证选择通知

具体来说,我们假设许可证文件位于项目源树中的以下路径(相对于项目根目录和 pyproject.toml

LICENSE
setuptools/_vendor/packaging/LICENSE
setuptools/_vendor/packaging/LICENSE.APACHE
setuptools/_vendor/packaging/LICENSE.BSD

综上所述,我们的 pyproject.toml 将是

[project]
license = "MIT AND (Apache-2.0 OR BSD-2-Clause)"
license-files = [
    "LICENSE*",
    "setuptools/_vendor/LICENSE*",
]

或者,许可证文件也可以明确指定(路径将被解释为 glob 模式)

[project]
license = "MIT AND (Apache-2.0 OR BSD-2-Clause)"
license-files = [
    "LICENSE",
    "setuptools/_vendor/LICENSE",
    "setuptools/_vendor/LICENSE.APACHE",
    "setuptools/_vendor/LICENSE.BSD",
]

如果我们的项目使用 setup.cfg,我们可以这样定义:

[metadata]
license = MIT AND (Apache-2.0 OR BSD-2-Clause)
license_files =
    LICENSE
    setuptools/_vendor/packaging/LICENSE
    setuptools/_vendor/packaging/LICENSE.APACHE
    setuptools/_vendor/packaging/LICENSE.BSD

无论采用哪种方法,分发中的输出核心元数据将是

License-Expression: MIT AND (Apache-2.0 OR BSD-2-Clause)
License-File: LICENSE
License-File: setuptools/_vendor/packaging/LICENSE
License-File: setuptools/_vendor/packaging/LICENSE.APACHE
License-File: setuptools/_vendor/packaging/LICENSE.BSD

在生成的 sdist 中,以 / 作为存档的根目录,{VERSION} 作为核心元数据中指定的 Setuptools 发布版本,许可证文件将位于以下路径:

/setuptools-{VERSION}/LICENSE
/setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE
/setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE.APACHE
/setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE.BSD

在构建的 wheel 中,以 / 作为存档的根目录,{VERSION} 如前所述,许可证文件将存储在

/setuptools-{VERSION}.dist-info/licenses/LICENSE
/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE
/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.APACHE
/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.BSD

最后,在已安装的项目中,以 site-packages/ 作为站点目录,{VERSION} 如前所述,许可证文件将安装到

site-packages/setuptools-{VERSION}.dist-info/licenses/LICENSE
site-packages/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE
site-packages/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.APACHE
site-packages/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.BSD

表达式示例

其他有效的 License-Expression 值示例

License-Expression: MIT
License-Expression: BSD-3-Clause
License-Expression: MIT AND (Apache-2.0 OR BSD-2-Clause)
License-Expression: MIT OR GPL-2.0-or-later OR (FSFUL AND BSD-2-Clause)
License-Expression: GPL-3.0-only WITH Classpath-Exception-2.0 OR BSD-3-Clause
License-Expression: LicenseRef-Public-Domain OR CC0-1.0 OR Unlicense
License-Expression: LicenseRef-Proprietary
License-Expression: LicenseRef-Custom-License

用户场景

以下从用户角度涵盖了常见的用例范围,并为每个用例提供了指导。请注意,以下内容不应被视为法律建议,如果读者不确定其具体情况,应咨询其管辖范围内的持牌法律执业人员。

我有一个不会分发的私有包

如果您的包不在公司、组织或家庭之外公开共享,通常情况下,严格来说没有必要包含正式许可证,因此您不一定需要在此处做任何额外的事情。

但是,最好在您的包配置中包含 LicenseRef-Proprietary 作为许可证表达式,和/或在您项目根目录下的 LICENSE.txt 文件中包含版权声明和任何法律声明,这些文件将由打包工具自动包含。

我想在特定许可证下分发我的项目

要使用特定许可证,只需将其文本粘贴到您的仓库根目录下的 LICENSE.txt 文件中(如果您的文件中没有以 LICENSECOPYING 开头的文件),并在您的 pyproject.toml 中(如果您的打包工具支持)或在其配置文件中 [project] 下添加 license = "LICENSE-ID"。您可以在 ChooseALicenseSPDX 等网站上找到 LICENSE-ID 和可复制的许可证文本。

许多流行的代码托管服务、项目模板和打包工具可以为您添加许可证文件,将来也可能支持此表达式。

我维护一个已经获得许可的现有包

如果您的项目已经有许可证文件和元数据,您只需进行一些调整即可利用新功能。

在您的项目配置文件中,在 licensepyproject.toml 中的 [project] 表)下输入您的许可证表达式,或者使用您的打包工具的等效方式,并确保删除任何旧的 license 表子键或 License :: 分类器。您现有的 license 值可能已经有效(例如 MITApache-2.0 OR BSD-2-Clause 等);否则,请查阅 SPDX 许可证列表,以找到与您项目使用的许可证匹配的标识符。

确保在 pyproject.toml[project] 下或您的工具配置文件中列出您的许可证文件在 license-files 下。

请参阅基本示例,了解如何实际应用此功能的一个简单但完整的真实世界演示。另请参阅 PEP 639 作者提供的关于如何将许可证分类器转换为许可证表达式的最佳努力指导:将许可证分类器映射到 SPDX 标识符。打包工具可能支持自动转换遗留许可证元数据;请查阅您的工具文档以获取更多信息。

我的包包含其他许可证下的代码

如果您的项目包含来自受不同许可证保护的其他代码,例如供应商依赖项或从其他开源软件复制的文件,您可以构建一个许可证表达式来描述所涉及的许可证及其之间的关系。

简而言之,License-1 AND License-2 意味着两个许可证都适用于您的项目或其部分(例如,您包含了一个在另一个许可证下的文件),而 License-1 OR License-2 意味着用户可以根据自己的选择使用其中一个许可证(例如,您希望允许用户选择多个许可证)。您可以使用括号 (()) 进行分组,以形成涵盖最复杂情况的表达式。

在您的项目配置文件中,在 licensepyproject.toml[project] 表)下输入您的许可证表达式,或者使用您的打包工具的等效方式,并确保删除任何旧的 license 表子键或 License :: 分类器。

此外,请确保将所有许可证的完整许可证文本作为文件添加到您的项目仓库中的某个位置。在 pyproject.toml[project] 下(如果您的工具支持)或您的工具配置文件中,列出每个文件的相对路径或 glob 模式,并在 license-files 下。

例如,如果您的项目是 MIT 许可的,但包含了一个供应商依赖项(例如 packaging),该依赖项是 Apache 2.0 或 2-clause BSD 许可的,那么您的许可证表达式将是 MIT AND (Apache-2.0 OR BSD-2-Clause)。您的仓库根目录中可能有一个 LICENSE.txt,并且在 _vendor/ 子目录中有一个 LICENSE-APACHE.txtLICENSE-BSD.txt,因此要包含所有这些文件,您可以将 ["LICENSE.txt", "_vendor/packaging/LICENSE*"] 指定为 glob 模式,或将 ["LICENSE.txt", "_vendor/LICENSE-APACHE.txt", "_vendor/LICENSE-BSD.txt"] 指定为文字文件路径。

请参阅一个完整的高级示例,了解如何在真实的复杂项目中端到端应用此功能,其中包含许多技术细节,并查阅教程以获取更多使用 SPDX 标识符和表达式的帮助和示例。