Skip to content

Add support for PEP 639 change from 'License' to 'License-Expression' in importlib.metadata#234

Closed
bskinn wants to merge 2 commits into
raimon49:dev-5.5.0from
bskinn:metadata-license_expression
Closed

Add support for PEP 639 change from 'License' to 'License-Expression' in importlib.metadata#234
bskinn wants to merge 2 commits into
raimon49:dev-5.5.0from
bskinn:metadata-license_expression

Conversation

@bskinn

@bskinn bskinn commented Aug 3, 2025

Copy link
Copy Markdown

EDIT: Just scanned the PR list, like I should have before putting this together. This PR is an alternative to #213; it seems like this smaller fix may be sufficient? According to the metadata spec, License and License-Expression are mutually exclusive, and License-Expression is expressly declared as the replacement for License, so it should never be necessary to handle package metadata where both fields appear.


PEP 639 made some changes to the packaging metadata standard, including deprecating License in favor of License-Expression. This has led to pip-licenses failing to locate various packages' licenses for releases after those packages' build systems rolled over onto PEP 639-compliant tooling.

This PR adds a second lambda to the lookup for the "license" metadata key, pulling the "license-expression" metadata entry, so that metadata with either key/field can be properly processed.

Given that License-Expression is now the standard and License is deprecated, there might be semantic reasons to put the check for "license-expression" first; I figure that's your call.

Example environment:

$ pip list
Package            Version Editable project location
------------------ ------- ----------------------------
black              25.1.0
build              1.3.0
click              8.2.1
coverage           7.10.1
docutils           0.22
iniconfig          2.1.0
isort              6.0.1
mypy_extensions    1.1.0
packaging          25.0
pathspec           0.12.1
pip                25.2
pip-licenses       5.0.0   .../pip-licenses
pip-tools          7.5.0
platformdirs       4.3.8
pluggy             1.6.0
prettytable        3.16.0
pycodestyle        2.14.0
Pygments           2.19.2
pyproject_hooks    1.2.0
pytest             8.4.1
pytest-cov         6.2.1
pytest-pycodestyle 2.5.0
setuptools         80.9.0
tomli              2.2.1
tomli_w            1.2.0
wcwidth            0.2.13
wheel              0.45.1

Before the fix (my arrows added):

$ pip-licenses
 Name                Version  License
 Pygments            2.19.2   BSD License
 black               25.1.0   MIT License
 build               1.3.0    UNKNOWN          <<<<<
 click               8.2.1    UNKNOWN          <<<<<
 coverage            7.10.1   Apache-2.0
 docutils            0.22     BSD License; GNU General Public License (GPL); Public Domain
 iniconfig           2.1.0    MIT License
 isort               6.0.1    MIT License
 mypy_extensions     1.1.0    UNKNOWN          <<<<<
 packaging           25.0     Apache Software License; BSD License
 pathspec            0.12.1   Mozilla Public License 2.0 (MPL 2.0)
 pip-tools           7.5.0    BSD License
 platformdirs        4.3.8    MIT License
 pluggy              1.6.0    MIT License
 pycodestyle         2.14.0   MIT
 pyproject_hooks     1.2.0    MIT License
 pytest              8.4.1    MIT License
 pytest-cov          6.2.1    MIT
 pytest-pycodestyle  2.5.0    UNKNOWN          <<<<<
 tomli_w             1.2.0    MIT License

After the fix:

$ pip-licenses
 Name                Version  License
 Pygments            2.19.2   BSD License
 black               25.1.0   MIT License
 build               1.3.0    MIT              <<<<<
 click               8.2.1    BSD-3-Clause     <<<<<
 coverage            7.10.1   Apache-2.0
 docutils            0.22     BSD License; GNU General Public License (GPL); Public Domain
 iniconfig           2.1.0    MIT License
 isort               6.0.1    MIT License
 mypy_extensions     1.1.0    MIT              <<<<<
 packaging           25.0     Apache Software License; BSD License
 pathspec            0.12.1   Mozilla Public License 2.0 (MPL 2.0)
 pip-tools           7.5.0    BSD License
 platformdirs        4.3.8    MIT License
 pluggy              1.6.0    MIT License
 pycodestyle         2.14.0   MIT
 pyproject_hooks     1.2.0    MIT License
 pytest              8.4.1    MIT License
 pytest-cov          6.2.1    MIT
 pytest-pycodestyle  2.5.0    MIT              <<<<<
 tomli_w             1.2.0    MIT License

The test suite had some failing tests on master branch immediately after clone:

================================================================================= tests coverage ==================================================================================
________________________________________________________________ coverage: platform linux, python 3.12.11-final-0 _________________________________________________________________

Name             Stmts   Miss  Cover   Missing
----------------------------------------------
piplicenses.py     458      2    99%   211, 909
----------------------------------------------
TOTAL              458      2    99%
============================================================================= short test summary info =============================================================================
FAILED test_piplicenses.py::TestGetLicenses::test_from_all - AssertionError: 'Apache 2.0' not found in ['BSD', 'Apache-2.0', 'UNKNOWN', 'UNKNOWN', 'UNKNOWN', 'UNKNOWN', 'UNKNOWN', 'UNKNOWN', 'MIT', 'UNKNOWN', 'BSD-2-Clause', 'UNKNOWN',...
FAILED test_piplicenses.py::TestGetLicenses::test_with_normalized_packages - AssertionError: Lists differ: ['typing_extensions'] != []
FAILED test_piplicenses.py::TestGetLicenses::test_with_packages - AssertionError: Lists differ: ['py'] != []
FAILED test_piplicenses.py::test_allow_only - AssertionError: assert 'license MIT License not in allow-only licenses was found for package' in 'license MIT not in allow-only licenses was found for package pycodestyle:2.1...
FAILED test_piplicenses.py::test_allow_only_partial - AssertionError: assert 'license MIT License not in allow-only licenses was found for package' in 'license MIT not in allow-only licenses was found for package pycodestyle:2.1...
FAILED test_piplicenses.py::test_fail_on_partial_match - AssertionError: assert 'fail-on license MIT License was found for package' in 'fail-on license MIT was found for package pycodestyle:2.14.0\n'
============================================================== 6 failed, 66 passed, 1 skipped, 82 warnings in 7.34s ===============================================================

After the change of this PR, the test results and coverage are unchanged:

================================================================================= tests coverage ==================================================================================
________________________________________________________________ coverage: platform linux, python 3.12.11-final-0 _________________________________________________________________

Name             Stmts   Miss  Cover   Missing
----------------------------------------------
piplicenses.py     458      2    99%   214, 912
----------------------------------------------
TOTAL              458      2    99%
============================================================================= short test summary info =============================================================================
FAILED test_piplicenses.py::TestGetLicenses::test_from_all - AssertionError: 'Apache 2.0' not found in ['BSD', 'Apache-2.0', 'UNKNOWN', 'MIT', 'UNKNOWN', 'MIT', 'MIT', 'UNKNOWN', 'MIT', 'UNKNOWN', 'BSD-2-Clause', 'UNKNOWN', 'MIT', 'MIT...
FAILED test_piplicenses.py::TestGetLicenses::test_with_normalized_packages - AssertionError: Lists differ: ['typing_extensions'] != []
FAILED test_piplicenses.py::TestGetLicenses::test_with_packages - AssertionError: Lists differ: ['py'] != []
FAILED test_piplicenses.py::test_allow_only - AssertionError: assert 'license MIT License not in allow-only licenses was found for package' in 'license MIT not in allow-only licenses was found for package pycodestyle:2.1...
FAILED test_piplicenses.py::test_allow_only_partial - AssertionError: assert 'license MIT License not in allow-only licenses was found for package' in 'license MIT not in allow-only licenses was found for package pycodestyle:2.1...
FAILED test_piplicenses.py::test_fail_on_partial_match - AssertionError: assert 'fail-on license MIT License was found for package' in 'fail-on license MIT was found for package pycodestyle:2.14.0\n'
============================================================== 6 failed, 66 passed, 1 skipped, 82 warnings in 7.14s ===============================================================

The line numbers of the coverage misses are offset due to the lines I added in the PR.

bskinn added 2 commits August 3, 2025 00:22
Appears to be an interface change in importlib.metadata.

Appears to be PEP 639, in fact.
@reactive-firewall
reactive-firewall self-requested a review October 9, 2025 04:27
@reactive-firewall reactive-firewall added bug Something isn't working duplicate This issue or pull request already exists labels Oct 9, 2025
@reactive-firewall reactive-firewall self-assigned this Oct 13, 2025
@reactive-firewall
reactive-firewall changed the base branch from master to dev-5.5.0 October 13, 2025 00:11
reactive-firewall added a commit that referenced this pull request Oct 13, 2025
…into patch-partial-matching-refactor-231

* includes and supersedes #216
* includes and supersedes #217
* includes and supersedes #224
* supersedes #234

* patch-2:
  Replaced element check logic with built in set.discard method
  Fixed: KeyError caused due to the same element getting removed from a set twice

* fix-keyerror:
  Fix KeyError on double deletion

* update-requirements:
  Update pinned requirements again
  Add changelog entry
  Fix KeyError if license matches multiple allow-only licenses
  Fix test case
  Update pinned dev requirements

* Closes GHI #231 (and related issues with modifing sets within loops)
* Improved related testing slightly with extra test-cases

Resolves Conflicts in:
	piplicenses.py

Co-authored-by: Marc Mueller <cdce8p@users.noreply.github.com>
Co-authored-by: Anmol Deep <anmol-aidora@users.noreply.github.com>
Co-authored-by: Florian Wünsche <flontis@users.noreply.github.com>
@reactive-firewall reactive-firewall mentioned this pull request Oct 13, 2025
1 task
@reactive-firewall

Copy link
Copy Markdown
Collaborator

Closing as Superseded by PR #238

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working duplicate This issue or pull request already exists

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants