附录:Python 及其他项目中的许可证文档
摘要
有多种用于或推荐的许可证文档方式。本文档包含了对 Python 和其他语言中许可证文档的全面调查结果。
调查的主要结论,指导了 PEP 639 的建议,如下所示
Python 中的许可证文档
核心元数据
有两个重叠的核心元数据字段用于记录许可证:许可证 Classifier
字符串,以 License ::
为前缀,以及 License
字段 作为自由文本。
核心元数据 License
字段文档目前为
License
=======
.. versionadded:: 1.0
Text indicating the license covering the distribution where the license
is not a selection from the "License" Trove classifiers. See
:ref:`"Classifier" <metadata-classifier>` below.
This field may also be used to specify a
particular version of a license which is named via the ``Classifier``
field, or to indicate a variation or exception to such a license.
Examples::
License: This software may only be obtained by sending the
author a postcard, and then the user promises not
to redistribute it.
License: GPL version 3, excluding DRM provisions
即使有两个字段,有时也很难传达除简单许可之外的任何内容。例如,一些分类器缺乏精确性(没有版本的 GPL),并且当列出多个许可证分类器时,不清楚是否必须应用这两个许可证,或者用户可以在它们之间进行选择。此外,可用的许可证分类器列表相当有限且过时。
Setuptools 和 Wheel
除了许可证代码或限定符之外,许可证文本文件在构建的包中被隐式或显式地记录和包含,这也是另一个可能造成混淆的来源
- 在 Setuptools 和 Wheel 项目中,如果许可证文件与许多常见许可证文件名模式之一匹配(
LICEN[CS]E*
、COPYING*
、NOTICE*
和AUTHORS*
),则会自动将其添加到发行版中(在源发行版/sdist 中的源位置,以及构建的 wheel 的.dist-info
目录中)。或者,包作者可以指定要包含在构建的 wheel 中的许可证文件路径列表,方法是在项目的setup.cfg
文件的[metadata]
部分的license_files
键下指定,或作为setuptools.setup()
函数的参数。目前,遵循 Wheel 项目的领导,Setuptools 将收集到的许可证文件展平到元数据目录中,覆盖同名的文件,并将许可证文件直接转储到顶级.dist-info
目录中,但有一个 希望解决这两个问题,这取决于 PEP 639 是否被接受。 - 这两个工具还支持一个较旧的、单一的
license_file
参数,该参数允许仅指定一个要添加到发行版的许可证文件,该参数已弃用一段时间,但仍然 有一些用途。 - 在发布 PEP 639 的早期草案后,Setuptools 添加了对
License-File
的支持,该字段在发行版元数据中进行了描述,如本规范所述。这允许其他使用结果元数据的工具明确地找到给定包的许可证文件。
PyPA 打包指南和示例项目
PyPA 的 打包初学者教程 及其更全面的 打包指南 都指出,每个包都包含许可证文件非常重要。它们将 PyPA 官方示例项目中的 LICENSE.txt
作为示例,该文件在 setup.cfg
文件中的 license_files
键下 明确列出,遵循 PEP 639 正式指定的现有实践。
打包初学者教程和 示例项目 都只使用分类器来声明包的许可证,并且不包含或提及 License
字段。完整的 打包指南 确实提到了此字段,但指出作者应该使用许可证分类器,除非项目使用非标准许可证(指南不鼓励这样做)。
Python 源代码文件
注意:PEP 639 不在记录源代码中的许可证范围内。
除了使用注释和/或 SPDX-License-Identifier
约定之外,许可证有时还使用 Python 代码文件中的“dunder”模块级常量(通常命名为 __license__
)进行记录 有时。
此约定虽然可能有些过时,但被内置的 help()
函数和标准的 pydoc
模块识别。dunder 变量将显示在模块的 help()
DATA 部分中。
其他项目中的许可证文档
Linux 发行版包
注意:在大多数情况下,最常见许可证的文本在共享文档目录(例如 /usr/share/doc
)中全局包含。
- Debian 使用 机器可读版权文件 记录包许可证。它定义了自己的许可证表达式语法和常用许可证的标识符列表,这两者都与 SPDX 密切相关。
- Fedora 包 指定如何包含 许可证文本,并使用 许可证字段,该字段必须填写来自广泛的 “良好许可证” 列表的适当的简短许可证标识符。Fedora 使用 SPDX 许可证表达式语法。
- OpenSUSE 包 使用带有 SPDX 许可证 ID 的 SPDX 许可证表达式和 其他许可证标识符列表。
- Gentoo ebuild 使用
LICENSE
变量。此字段在 GLEP-0023 和 Gentoo 开发手册 中指定。Gentoo 还定义了允许的许可证列表和许可证表达式语法,该语法与 SPDX 差异很大。 - FreeBSD 包 Makefile 提供了
LICENSE
和LICENSE_FILE
字段,其中包含自定义许可证符号列表。对于非标准许可证,FreeBSD 建议使用LICENSE=UNKNOWN
并添加LICENSE_NAME
和LICENSE_TEXT
字段,以及复杂的LICENSE_PERMS
来限定许可证权限和LICENSE_GROUPS
来记录许可证分组。LICENSE_COMB
允许记录多个许可证以及它们如何一起应用,从而形成自定义许可证表达式语法。FreeBSD 还建议在源代码文件中使用SPDX-License-Identifier
。 - Arch Linux PKGBUILD 定义了自己的 许可证标识符。如果未定义许可证,可以使用值
'unknown'
。 - OpenWRT ipk 包 使用
PKG_LICENSE
和PKG_LICENSE_FILES
变量,并建议使用 SPDX 许可证标识符。 - NixOS 使用 SPDX 标识符 及其许可证字段中的一些额外许可证 ID。
- GNU Guix(基于 NixOS)具有单个许可证字段,使用其自己的 许可证符号列表 并指定如何使用一个许可证或 它们的列表。
- Alpine Linux 包 建议在许可证字段中使用 SPDX 标识符。
语言和应用程序包
- 在 Java 中,Maven POM 定义了一个
licenses
XML 标签,其中包含许可证列表,每个许可证都有名称、URL、注释和“分发”类型。这不是强制性的,并且每个字段的内容未指定。 - JavaScript NPM package.json 使用单个许可证字段,其中包含 SPDX 许可证表达式,或者如果未指定任何许可证,则使用
UNLICENSED
ID。可以使用SEE LICENSE IN <filename>
在单个license
字段中引用许可证文件作为替代。 - Rubygems gemspec 指定单个或许可证字符串列表。列表中多个许可证之间的关系未指定。他们建议使用 SPDX 许可证标识符。
- CPAN Perl 模块 使用单个 license 字段,该字段可以是单个字符串或字符串列表。列表中许可证之间的关系未指定。除了以下通用标识符外,还提供了一系列自定义许可证标识符:
open_source
、restricted
、unrestricted
、unknown
。 - Rust Cargo 指定在
license
字段中使用 SPDX 许可证表达式 (v2.1)。它还支持使用斜杠分隔的 SPDX 许可证标识符的替代表达式语法,并且还有一个license_file
字段。 crates.io 包注册表 要求在上传包时设置license
或license_file
字段。 - PHP composer.json 使用
license
字段,该字段包含 SPDX 许可证 ID 或proprietary
。license
字段可以是单个字符串,类似于 SPDX 许可证表达式语法,使用and
和or
关键字;或者如果有多个(析取)许可证选择,则为字符串列表。 - NuGet 包 以前仅使用简单的许可证 URL,但现在指定使用 SPDX 许可证表达式和/或包中许可证文件的路径。NuGet.org 存储库声明它们仅接受“开源计划或自由软件基金会批准”的许可证表达式。
- Go 语言模块
go.mod
没有为除依赖项之外的任何元数据提供规定。许可证信息留给代码作者和其他社区包管理器来记录。 - Dart/Flutter 规范 建议使用单个
LICENSE
文件,该文件应包含所有许可证文本,每个文本之间用 80 个连字符分隔的行分隔。 - JavaScript Bower
license
字段可以是单个字符串或字符串列表,使用 SPDX 许可证标识符或指向许可证文件的路径/URL。 - Cocoapods podspec
license
字段可以是单个字符串,也可以是包含type
、file
和text
键的映射。除非提供了LICENSE
/LICENCE
文件,否则此字段是必需的。 - Haskell Cabal 从 2.2 版开始接受 SPDX 许可证表达式。使用的 SPDX 许可证列表的版本是 Cabal 版本的函数。规范还提供了传统(SPDX 之前)和 SPDX 许可证标识符之间的映射。Cabal 还指定了一个
license-file(s)
字段,该字段列出要与包一起安装的许可证文件。 - Erlang/Elixir mix/hex 包 将
licenses
字段指定为许可证字符串的必需列表,并建议使用 SPDX 许可证标识符。 - D 语言 dub 包 定义了自己的许可证标识符列表和许可证表达式语法,类似于 SPDX 标准。
- R 包 DESCRIPTION 定义了自己的复杂许可证表达式语法和许可证标识符列表。R 有一种独特的方式来支持其许可证表达式语法中的许可证版本说明符(例如
LGPL (>= 2.0, < 3)
)。
其他生态系统
SPDX-License-Identifier
标头 是一种简单的约定,用于记录文件内的许可证。- 自由软件基金会 (FSF) 推广使用 SPDX 许可证标识符,以提高 GPL 和其他版本化的自由软件许可证的清晰度。
- 欧洲自由软件基金会 (FSFE) REUSE 项目 推广使用
SPDX-License-Identifier
。 - Linux 内核 使用
SPDX-License-Identifier
和 FSFE REUSE 约定的部分内容来记录其许可证。 - U-Boot 带头在代码中使用
SPDX-License-Identifier
,现在遵循 Linux 的方法。 - Apache 软件基金会的项目使用 RDF DOAP,其中单个 license 字段指向 SPDX 许可证标识符。
- Eclipse 基金会 推广使用
SPDX-license-Identifiers
。 - ClearlyDefined 项目 推广使用 SPDX 许可证标识符和表达式,以提高许可证的清晰度。
- Android 开源项目 使用
MODULE_LICENSE_XXX
空标签文件,其中XXX
是许可证代码,例如BSD
、APACHE
、GPL
等。它还使用NOTICE
文件,其中包含许可证和通知文本。