pypa / hatch

Modern, extensible Python project management
https://hatch.pypa.io/latest/
MIT License
6.1k stars 309 forks source link

Hatch is not PEP 639 compliant by incorrectly rejecting valid custom SPDX license identifiers #1708

Open Edward-Knight opened 2 months ago

Edward-Knight commented 2 months ago

Hatch currently rejects licenses in the form LicenseRef-[idstring].


Quoting from PEP 639:

This PEP adopts the SPDX license expression syntax as documented in the SPDX specification, either Version 2.2 or a later compatible version.

A license expression can use the following license identifiers:

  • Any SPDX-listed license short-form identifiers that are published in the SPDX License List, version 3.17 or any later compatible version. Note that the SPDX working group never removes any license identifiers; instead, they may choose to mark an identifier as “deprecated”.
  • The custom LicenseRef-[idstring] string(s), where [idstring] is a unique string containing letters, numbers, . and/or -, to identify licenses that are not included in the SPDX license list. The custom identifiers must follow the SPDX specification, clause 10.1 of the given specification version.

Examples of valid SPDX expressions:

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-Proprietary

Examples of invalid SPDX expressions:

Use-it-after-midnight
Apache-2.0 OR 2-BSD-Clause
LicenseRef-License with spaces
LicenseRef-License_with_underscores

Error can be reproduced by running:

pip install hatch==1.12.0
hatch new license-test
cd license-test
examples=("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-Proprietary")
for example in "${examples[@]}"; do echo "${example}"; sed -i "s/license = \".*\"/license = \"${example}\"/g" pyproject.toml; hatch build > /dev/null; done

Which produces the output:

MIT
dist/license_test-0.0.1.tar.gz
dist/license_test-0.0.1-py3-none-any.whl
BSD-3-Clause
dist/license_test-0.0.1.tar.gz
dist/license_test-0.0.1-py3-none-any.whl
MIT AND (Apache-2.0 OR BSD-2-Clause)
dist/license_test-0.0.1.tar.gz
dist/license_test-0.0.1-py3-none-any.whl
MIT OR GPL-2.0-or-later OR (FSFUL AND BSD-2-Clause)
dist/license_test-0.0.1.tar.gz
dist/license_test-0.0.1-py3-none-any.whl
GPL-3.0-only WITH Classpath-Exception-2.0 OR BSD-3-Clause
dist/license_test-0.0.1.tar.gz
dist/license_test-0.0.1-py3-none-any.whl
LicenseRef-Special-License OR CC0-1.0 OR Unlicense
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File ".../site-packages/hatchling/__main__.py", line 6, in <module>
    sys.exit(hatchling())
             ^^^^^^^^^^^
  File ".../site-packages/hatchling/cli/__init__.py", line 26, in hatchling
    command(**kwargs)
  File ".../site-packages/hatchling/cli/build/__init__.py", line 82, in build_impl
    for artifact in builder.build(
  File ".../site-packages/hatchling/builders/plugin/interface.py", line 90, in build
    self.metadata.validate_fields()
  File ".../site-packages/hatchling/metadata/core.py", line 266, in validate_fields
    self.core.validate_fields()
  File ".../site-packages/hatchling/metadata/core.py", line 1376, in validate_fields
    getattr(self, attribute)
  File ".../site-packages/hatchling/metadata/core.py", line 683, in license
    raise ValueError(message) from None
ValueError: Error parsing field `project.license` - unknown license: licenseref-special-license
LicenseRef-Proprietary
dist/license_test-0.0.1.tar.gz
dist/license_test-0.0.1-py3-none-any.whl

Other notes: