Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate SPDX license expressions #217

Merged
merged 5 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Download = "https://pypi.org/project/validate-pyproject/#files"

[project.optional-dependencies]
all = [
"packaging>=20.4",
"packaging>=24.2",
"tomli>=1.2.1; python_version<'3.11'",
"trove-classifiers>=2021.10.20",
]
Expand Down
26 changes: 22 additions & 4 deletions src/validate_pyproject/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,25 @@ def int(value: builtins.int) -> bool:
return -(2**63) <= value < 2**63


def SPDX(value: str) -> bool:
"""Should validate eventually"""
# TODO: validate conditional to the presence of (the right version) of packaging
return True
try:
henryiii marked this conversation as resolved.
Show resolved Hide resolved
from packaging import licenses as _licenses

def SPDX(value: str) -> bool:
"""See :ref:`PyPA's License-Expression specification
<pypa:core-metadata-license-expression>` (added in :pep:`639`).
"""
try:
_licenses.canonicalize_license_expression(value)
return True
except _licenses.InvalidLicenseExpression:
return False

except ImportError: # pragma: no cover
_logger.warning(
"Could not find an up-to-date installation of `packaging`. "
"License expressions might not be validated. "
"To enforce validation, please install `packaging>=24.2`."
)

def SPDX(value: str) -> bool:
return True
File renamed without changes.
1 change: 1 addition & 0 deletions tests/invalid-examples/simple/pep639.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`project.license` must be valid exactly by one definition (0 matches found)
5 changes: 5 additions & 0 deletions tests/invalid-examples/simple/pep639.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[project]
name = "example"
version = "1.2.3"
license = "Apache Software License" # should be "Apache-2.0"
license-files = ["licenses/LICENSE"]
48 changes: 48 additions & 0 deletions tests/test_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,54 @@ def test_invalid_module_name_relaxed(example):
assert formats.python_module_name_relaxed(example) is False


@pytest.mark.parametrize(
"example",
[
"MIT",
"Bsd-3-clause",
"mit and (apache-2.0 or bsd-2-clause)",
"MIT OR GPL-2.0-or-later OR (FSFUL AND BSD-2-Clause)",
"GPL-3.0-only WITH Classpath-exception-2.0 OR BSD-3-Clause",
"LicenseRef-Special-License OR CC0-1.0 OR Unlicense",
"LicenseRef-Public-Domain",
"licenseref-proprietary",
"LicenseRef-Beerware-4.2",
"(LicenseRef-Special-License OR LicenseRef-OtherLicense) OR Unlicense",
],
)
def test_valid_pep639_license_expression(example):
assert formats.SPDX(example) is True


@pytest.mark.parametrize(
"example",
[
"",
"Use-it-after-midnight",
"LicenseRef-License with spaces",
"LicenseRef-License_with_underscores",
"or",
"and",
"with",
"mit or",
"mit and",
"mit with",
"or mit",
"and mit",
"with mit",
"(mit",
"mit)",
"mit or or apache-2.0",
# Missing an operator before `(`.
"mit or apache-2.0 (bsd-3-clause and MPL-2.0)",
# "2-BSD-Clause is not a valid license.
"Apache-2.0 OR 2-BSD-Clause",
],
)
def test_invalid_pep639_license_expression(example):
assert formats.SPDX(example) is False


class TestClassifiers:
"""The ``_TroveClassifier`` class and ``_download_classifiers`` are part of the
private API and therefore need to be tested.
Expand Down