Migrating to PEP 639 License Expressions¶
Starting with setuptools v77.0.0, the project.license field accepts an
SPDX license expression as defined in
PEP 639. The previous TOML-table forms (license = {text = "..."} and
license = {file = "..."}) are deprecated and will be removed in a future
version.
This guide helps you migrate your project’s license configuration.
Background¶
The project.license field in pyproject.toml historically accepted a
TOML table, either with a text key holding a license description or a
file key pointing at a license file:
# Old format (deprecated)
license = {text = "Apache-2.0"}
# or
license = {file = "LICENSE"}
Starting with setuptools v77.0.0, project.license is instead a string
containing an SPDX license expression, and the files themselves are declared
separately via project.license-files:
# New format (PEP 639)
license = "Apache-2.0"
license-files = ["LICENSE"]
The SPDX expression format is standardized and supports composing licenses
(for example "Apache-2.0 OR MIT" or
"GPL-3.0-only WITH Classpath-exception-2.0").
Migrating your configuration¶
Replace a {text = ...} license¶
If the text value was already a recognized license identifier, use it
directly as an SPDX expression:
# Before
license = {text = "MIT"}
# After
license = "MIT"
If the text was free-form prose rather than a license identifier, express
the license as an SPDX expression and ship the full text as a license file
(see below).
Replace a {file = ...} license¶
Point license at the SPDX expression and list the file under
license-files:
# Before
license = {file = "LICENSE"}
# After
license = "Apache-2.0"
license-files = ["LICENSE"]
license-files accepts glob patterns, so multiple files (for example a
project license plus third-party notices) can be included:
license-files = ["LICENSE*", "NOTICE"]
Replace license classifiers¶
The License :: ... trove classifiers are also deprecated in favor of SPDX
expressions. Drop them from classifiers and record the license in
license instead:
# Before
classifiers = ["License :: OSI Approved :: MIT License"]
# After
license = "MIT"
Requiring a compatible setuptools¶
SPDX expressions and the license-files field are understood by
setuptools v77.0.0 and later. This is a build-time requirement on
setuptools itself; it is independent of the Python versions your project
supports at runtime (requires-python).
Most build frontends (such as build and pip) build in an
isolated environment and install the latest setuptools by default, so simply
declaring the minimum in [build-system].requires is usually enough:
[build-system]
requires = ["setuptools>=77"]
build-backend = "setuptools.build_meta"
[project]
name = "my_package"
license = "Apache-2.0"
license-files = ["LICENSE"]
If you need to keep supporting builds with an older setuptools, retain the old TOML-table form (it continues to work, with a deprecation warning) until you can require setuptools v77+.
Common SPDX License Expressions¶
Here are some common SPDX expressions:
"MIT"– MIT License"Apache-2.0"– Apache License 2.0"BSD-3-Clause"– BSD 3-Clause License"GPL-3.0-only"– GNU General Public License v3.0 only"Apache-2.0 OR MIT"– Dual licensed (either applies)"Apache-2.0 AND MIT"– Both licenses apply
For the full list, see the SPDX License List.
Troubleshooting¶
SetuptoolsDeprecationWarning: `project.license` as a TOML table is deprecated
This warning appears when using the old {text = ...} or {file = ...}
form. Follow the migration steps above to move to an SPDX expression (and
license-files where needed).
Invalid SPDX expression
Ensure your expression uses valid SPDX identifiers. Common mistakes:
Using
"GPL-3"instead of"GPL-3.0-only"(or"GPL-3.0-or-later")Using
"BSD"instead of"BSD-3-Clause"Forgetting the quotes around the expression
References¶
PEP 639 – Improving License Clarity with Better Package Metadata