Skip to content

Commit

Permalink
Normalize license expression
Browse files Browse the repository at this point in the history
  • Loading branch information
cdce8p committed Nov 25, 2024
1 parent 3ecc644 commit a3fe92a
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 4 deletions.
1 change: 1 addition & 0 deletions setuptools/config/_apply_pyprojecttoml.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def apply(dist: Distribution, config: dict, filename: StrPath) -> Distribution:
os.chdir(root_dir)
try:
dist._finalize_requires()
dist._finalize_license_expression()
dist._finalize_license_files()
finally:
os.chdir(current_directory)
Expand Down
20 changes: 20 additions & 0 deletions setuptools/dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from typing import TYPE_CHECKING, Any, Union

from more_itertools import partition, unique_everseen
from packaging.licenses import canonicalize_license_expression
from packaging.markers import InvalidMarker, Marker
from packaging.specifiers import InvalidSpecifier, SpecifierSet
from packaging.version import Version
Expand All @@ -26,6 +27,7 @@
from ._reqs import _StrOrIter
from .config import pyprojecttoml, setupcfg
from .discovery import ConfigDiscovery
from .errors import InvalidConfigError
from .monkey import get_unpatched
from .warnings import InformationOnly, SetuptoolsDeprecationWarning

Expand Down Expand Up @@ -398,6 +400,23 @@ def _normalize_requires(self):
k: list(map(str, _reqs.parse(v or []))) for k, v in extras_require.items()
}

def _finalize_license_expression(self) -> None:
"""Normalize license and license_expression."""
license_expr = self.metadata.license_expression
if license_expr:
normalized = canonicalize_license_expression(license_expr)
if license_expr != normalized:
InformationOnly.emit(f"Normalizing '{license_expr}' to '{normalized}'")
self.metadata.license_expression = normalized

for cl in self.metadata.get_classifiers():
if not cl.startswith("License :: "):
continue
raise InvalidConfigError(
"License classifier are deprecated in favor of the license expression. "
f"Remove the '{cl}' classifier."
)

def _finalize_license_files(self) -> None:
"""Compute names of all license files which should be included."""
license_files: list[str] | None = self.metadata.license_files
Expand Down Expand Up @@ -649,6 +668,7 @@ def parse_config_files(
pyprojecttoml.apply_configuration(self, filename, ignore_option_errors)

self._finalize_requires()
self._finalize_license_expression()
self._finalize_license_files()

def fetch_build_eggs(
Expand Down
23 changes: 19 additions & 4 deletions setuptools/tests/config/test_apply_pyprojecttoml.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from setuptools.config import expand, pyprojecttoml, setupcfg
from setuptools.config._apply_pyprojecttoml import _MissingDynamic, _some_attrgetter
from setuptools.dist import Distribution
from setuptools.errors import RemovedConfigError
from setuptools.errors import InvalidConfigError, RemovedConfigError

from .downloads import retrieve_file, urls_from_file

Expand Down Expand Up @@ -174,7 +174,10 @@ def main_tomatoes(): pass
{email = "[email protected]"},
{name = "Tzu-Ping Chung"}
]
license = "MIT"
license = "mit or apache-2.0" # should be normalized in metadata
classifiers = [
"Development Status :: 5 - Production/Stable",
]
"""


Expand Down Expand Up @@ -285,8 +288,8 @@ def test_utf8_maintainer_in_metadata( # issue-3663
pytest.param(
PEP639_LICENSE_EXPRESSION,
None,
'MIT',
'License-Expression: MIT',
'MIT OR Apache-2.0',
'License-Expression: MIT OR Apache-2.0',
id='license-expression',
),
),
Expand All @@ -313,6 +316,18 @@ def test_license_in_metadata(
assert content_str in content


def test_license_expression_with_bad_classifier(tmp_path):
text = PEP639_LICENSE_EXPRESSION.rsplit("\n", 2)[0]
pyproject = _pep621_example_project(
tmp_path,
"README",
f"{text}\n \"License :: OSI Approved :: MIT License\"\n]",
)
msg = "License classifier are deprecated.*'License :: OSI Approved :: MIT License'"
with pytest.raises(InvalidConfigError, match=msg):
pyprojecttoml.apply_configuration(makedist(tmp_path), pyproject)


class TestLicenseFiles:
def base_pyproject(self, tmp_path, additional_text):
pyproject = _pep621_example_project(tmp_path, "README")
Expand Down

0 comments on commit a3fe92a

Please sign in to comment.