附录:Python 及其他项目中的许可证文档
摘要
有多种方法被使用或推荐用于文档化许可证。本文档包含了对 Python 及其他语言中许可证文档进行全面调查的结果。
调查的关键要点(指导了 PEP 639 的建议)如下:
Python 中的许可证文档
核心元数据
有两个重叠的核心元数据字段用于文档化许可证:以 License :: 为前缀的许可证 Classifier 字符串 和作为自由文本的 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目录中)。或者,包作者可以通过项目setup.cfg中[metadata]部分的license_files键,或作为setuptools.setup()函数的参数,指定要包含在构建的 wheel 中的许可证文件路径列表。目前,遵循 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 许可证表达式,并带有 SPDX 许可证 ID 和 其他许可证标识符列表。
- 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)有一个单一的 License 字段,使用自己的 许可证符号列表,并指定了如何使用一个许可证或 它们的列表。
- Alpine Linux 包 推荐在许可证字段中使用 SPDX 标识符。
语言和应用程序包
- 在 Java 中,Maven POM 定义了一个
licensesXML 标签,其中包含一个许可证列表,每个许可证都有名称、URL、注释和“分发”类型。这不是强制性的,并且每个字段的内容都没有指定。 - JavaScript NPM package.json 使用单个许可证字段,该字段可以是 SPDX 许可证表达式,或者如果没有指定则为
UNLICENSEDID。可以通过在单个license字段中使用SEE LICENSE IN <filename>来作为替代引用许可证文件。 - Rubygems gemspec 指定单个或多个许可证字符串。列表中多个许可证之间的关系未指定。他们推荐使用 SPDX 许可证标识符。
- CPAN Perl 模块 使用单个许可证字段,该字段是单个或多个字符串。列表中许可证之间的关系未指定。有一个自定义许可证标识符列表,加上这些通用标识符:
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字段可以是单个字符串,其格式类似于带有and和or关键字的 SPDX 许可证表达式;或者,如果存在(析取的)许可证选择,则是一个字符串列表。 - 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 和其他版本化的自由软件许可证的清晰度,请参阅 GPL。
- 欧洲自由软件基金会 (FSFE) 的 REUSE 项目 提倡使用
SPDX-License-Identifier。 - Linux 内核 使用
SPDX-License-Identifier和 FSFE REUSE 约定的部分来文档化其许可证。 - U-Boot 带头在代码中使用
SPDX-License-Identifier,现在遵循 Linux 的方法。 - Apache 软件基金会项目使用 RDF DOAP,其中一个许可证字段指向 SPDX 许可证标识符。
- Eclipse 基金会 提倡使用
SPDX-license-Identifiers。 - ClearlyDefined 项目 提倡使用 SPDX 许可证标识符和表达式以提高许可证的清晰度。
- Android 开源项目 使用
MODULE_LICENSE_XXX空标签文件,其中XXX是一个许可证代码,例如BSD、APACHE、GPL等。它还使用一个NOTICE文件,其中包含许可证和通知文本。