Licensing examples and user scenarios¶
PEP 639 has specified the way to declare a project’s license and paths to license files and other legally required information. This document aims to provide clear guidance how to migrate from the legacy to the standardized way of declaring licenses.
Licensing Examples¶
Basic example¶
The Setuptools project itself, as of version 75.6.0,
does not use the License
field in its own project source metadata.
Further, it no longer explicitly specifies license_file
/license_files
as it did previously, since Setuptools relies on its own automatic
inclusion of license-related files matching common patterns,
such as the LICENSE
file it uses.
It includes the following license-related metadata in its
pyproject.toml
:
[project]
classifiers = [
"License :: OSI Approved :: MIT License"
]
The simplest migration to PEP 639 would consist of using this instead:
[project]
license = "MIT"
Or, if the project used setup.cfg
, in its [metadata]
table:
[metadata]
license = MIT
The output Core Metadata for the distribution packages would then be:
License-Expression: MIT
License-File: LICENSE
The LICENSE
file would be stored at /setuptools-VERSION/LICENSE
in the sdist and /setuptools-VERSION.dist-info/licenses/LICENSE
in the wheel, and unpacked from there into the site directory (e.g.
site-packages/
) on installation; /
is the root of the respective archive
and {VERSION}
the version of the Setuptools release in the Core Metadata.
Advanced example¶
Suppose Setuptools were to include the licenses of the third-party projects
that are vendored in the setuptools/_vendor/
and pkg_resources/_vendor/
directories; specifically:
packaging==21.2
pyparsing==2.2.1
ordered-set==3.1.1
more_itertools==8.8.0
The license expressions for these projects are:
packaging: Apache-2.0 OR BSD-2-Clause
pyparsing: MIT
ordered-set: MIT
more_itertools: MIT
A comprehensive license expression covering both Setuptools proper and its vendored dependencies would contain these metadata, combining all the license expressions into one. Such an expression might be:
MIT AND (Apache-2.0 OR BSD-2-Clause)
In addition, per the requirements of the licenses, the relevant license files
must be included in the package. Suppose the LICENSE
file contains the text
of the MIT license and the copyrights used by Setuptools, pyparsing
,
more_itertools
and ordered-set
; and the LICENSE*
files in the
setuptools/_vendor/packaging/
directory contain the Apache 2.0 and
2-clause BSD license text, and the Packaging copyright statement and
license choice notice.
Specifically, we assume the license files are located at the following
paths in the project source tree (relative to the project root and
pyproject.toml
):
LICENSE
setuptools/_vendor/packaging/LICENSE
setuptools/_vendor/packaging/LICENSE.APACHE
setuptools/_vendor/packaging/LICENSE.BSD
Putting it all together, our pyproject.toml
would be:
[project]
license = "MIT AND (Apache-2.0 OR BSD-2-Clause)"
license-files = [
"LICENSE*",
"setuptools/_vendor/LICENSE*",
]
Or alternatively, the license files can be specified explicitly (paths will be interpreted as glob patterns):
[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",
]
If our project used setup.cfg
, we could define this in :
[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
With either approach, the output Core Metadata in the distribution would be:
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
In the resulting sdist, with /
as the root of the archive and {VERSION}
the version of the Setuptools release specified in the Core Metadata,
the license files would be located at the paths:
/setuptools-{VERSION}/LICENSE
/setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE
/setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE.APACHE
/setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE.BSD
In the built wheel, with /
being the root of the archive and
{VERSION}
as the previous, the license files would be stored at:
/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
Finally, in the installed project, with site-packages/
being the site dir
and {VERSION}
as the previous, the license files would be installed to:
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
Expression examples¶
Some additional examples of valid License-Expression
values:
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
User Scenarios¶
The following covers the range of common use cases from a user perspective, providing guidance for each. Do note that the following should not be considered legal advice, and readers should consult a licensed legal practitioner in their jurisdiction if they are unsure about the specifics for their situation.
I have a private package that won’t be distributed¶
If your package isn’t shared publicly, i.e. outside your company, organization or household, it usually isn’t strictly necessary to include a formal license, so you wouldn’t necessarily have to do anything extra here.
However, it is still a good idea to include LicenseRef-Proprietary
as a license expression in your package configuration, and/or a
copyright statement and any legal notices in a LICENSE.txt
file
in the root of your project directory, which will be automatically
included by packaging tools.
I want to distribute my project under a specific license¶
To use a particular license, simply paste its text into a LICENSE.txt
file at the root of your repo, if you don’t have it in a file starting with
LICENSE
or COPYING
already, and add
license = "LICENSE-ID"
under [project]
in your
pyproject.toml
if your packaging tool supports it, or else in its
config file. You can find the LICENSE-ID
and copyable license text on sites like
ChooseALicense or SPDX.
Many popular code hosts, project templates and packaging tools can add the license file for you, and may support the expression as well in the future.
I maintain an existing package that’s already licensed¶
If you already have license files and metadata in your project, you should only need to make a couple of tweaks to take advantage of the new functionality.
In your project config file, enter your license expression under
license
([project]
table in pyproject.toml
),
or the equivalent for your packaging tool,
and make sure to remove any legacy license
table subkeys or
License ::
classifiers. Your existing license
value may already
be valid as one (e.g. MIT
, Apache-2.0 OR BSD-2-Clause
, etc);
otherwise, check the SPDX license list for the identifier
that matches the license used in your project.
Make sure to list your license files under license-files
under [project]
in pyproject.toml
or else in your tool’s configuration file.
See the Basic example for a simple but complete real-world demo of how this works in practice. See also the best-effort guidance on how to translate license classifiers into license expression provided by the PEP 639 authors: Mapping License Classifiers to SPDX Identifiers. Packaging tools may support automatically converting legacy licensing metadata; check your tool’s documentation for more information.
My package includes other code under different licenses¶
If your project includes code from others covered by different licenses, such as vendored dependencies or files copied from other open source software, you can construct a license expression to describe the licenses involved and the relationship between them.
In short, License-1 AND License-2
mean that both licenses apply
to your project, or parts of it (for example, you included a file
under another license), and License-1 OR License-2
means that
either of the licenses can be used, at the user’s option (for example,
you want to allow users a choice of multiple licenses). You can use
parenthesis (()
) for grouping to form expressions that cover even the most
complex situations.
In your project config file, enter your license expression under
license
([project]
table of pyproject.toml
),
or the equivalent for your packaging tool,
and make sure to remove any legacy license
table subkeys
or License ::
classifiers.
Also, make sure you add the full license text of all the licenses as files
somewhere in your project repository. List the
relative path or glob patterns to each of them under license-files
under [project]
in pyproject.toml
(if your tool supports it), or else in your tool’s configuration file.
As an example, if your project was licensed MIT but incorporated
a vendored dependency (say, packaging
) that was licensed under
either Apache 2.0 or the 2-clause BSD, your license expression would
be MIT AND (Apache-2.0 OR BSD-2-Clause)
. You might have a
LICENSE.txt
in your repo root, and a LICENSE-APACHE.txt
and
LICENSE-BSD.txt
in the _vendor/
subdirectory, so to include
all of them, you’d specify ["LICENSE.txt", "_vendor/packaging/LICENSE*"]
as glob patterns, or
["LICENSE.txt", "_vendor/LICENSE-APACHE.txt", "_vendor/LICENSE-BSD.txt"]
as literal file paths.
See a fully worked out Advanced example for an end-to-end application of this to a real-world complex project, with many technical details, and consult a tutorial for more help and examples using SPDX identifiers and expressions.