From 69ec928e5959b17f0d6489d06a0e36d2759b6ba2 Mon Sep 17 00:00:00 2001 From: kokotatan Date: Sat, 3 Oct 2026 20:20:32 +0900 Subject: [PATCH 1/2] Preserve recent multiple-use metadata fields in JSON Assisted-by: OpenAI Codex --- importlib_metadata/_adapters.py | 5 ++++- newsfragments/+json-multiple-use.bugfix.rst | 1 + tests/test_api.py | 23 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 newsfragments/+json-multiple-use.bugfix.rst diff --git a/importlib_metadata/_adapters.py b/importlib_metadata/_adapters.py index 0bc23000..3c5a7db9 100644 --- a/importlib_metadata/_adapters.py +++ b/importlib_metadata/_adapters.py @@ -59,6 +59,9 @@ class Message(email.message.Message): FoldedCase, [ 'Classifier', + 'Import-Name', + 'Import-Namespace', + 'License-File', 'Obsoletes-Dist', 'Platform', 'Project-URL', @@ -72,7 +75,7 @@ class Message(email.message.Message): ) ) """ - Keys that may be indicated multiple times per PEP 566. + Keys that may be indicated multiple times in Core Metadata. """ def __new__(cls, orig: email.message.Message): diff --git a/newsfragments/+json-multiple-use.bugfix.rst b/newsfragments/+json-multiple-use.bugfix.rst new file mode 100644 index 00000000..cad1ea4a --- /dev/null +++ b/newsfragments/+json-multiple-use.bugfix.rst @@ -0,0 +1 @@ +Return ``License-File``, ``Import-Name``, and ``Import-Namespace`` as lists in JSON-compatible metadata, including when only one value is present, and retain all repeated values as required by PEP 566. diff --git a/tests/test_api.py b/tests/test_api.py index 1468e0a9..23b117af 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -281,6 +281,29 @@ def test_as_json_odd_case(self): assert len(md['requires_dist']) == 2 assert md['keywords'] == ['SAMPLE', 'PACKAGE'] + @fixtures.parameterize( + dict(key='License-File', values=['LICENSE', 'NOTICE']), + dict(key='Import-Name', values=['example', '_example ; private']), + dict(key='Import-Namespace', values=['example', 'another']), + dict(key='Import-Name', values=['']), + ) + def test_as_json_recent_multiple_use_fields(self, key, values): + for count in range(1, len(values) + 1): + with self.subTest(count=count): + selected = values[:count] + headers = '\n'.join( + f'{key if index == 0 else key.upper()}: {value}' + for index, value in enumerate(selected) + ) + content = ( + 'Metadata-Version: 2.5\nName: distinfo-pkg\nVersion: 1.0.0\n' + + headers + ) + path = self.site_dir / 'distinfo_pkg-1.0.0.dist-info' / 'METADATA' + path.write_text(content, encoding='utf-8') + md = metadata('distinfo-pkg').json + assert md[key.lower().replace('-', '_')] == selected + class LegacyDots(fixtures.DistInfoPkgWithDotLegacy, unittest.TestCase): def test_name_normalization(self): From a21b33ee4359e6df2888bdc52c2c09d9c5d06829 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 7 Nov 2026 14:15:58 -0500 Subject: [PATCH 2/2] Remove the regression test for the added multiple-use keys. That multiple-use keys become lists is already covered by the 'keywords' and 'requires_dist' assertions in the as_json tests, so the new keys need no test of their own. Its name would also have gone stale as soon as it was committed. Co-Authored-By: Claude Opus 5 --- tests/test_api.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 7c5b146e..2d660b3d 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -311,29 +311,6 @@ def test_as_json_odd_case(self): assert len(md['requires_dist']) == 2 assert md['keywords'] == ['SAMPLE', 'PACKAGE'] - @fixtures.parameterize( - dict(key='License-File', values=['LICENSE', 'NOTICE']), - dict(key='Import-Name', values=['example', '_example ; private']), - dict(key='Import-Namespace', values=['example', 'another']), - dict(key='Import-Name', values=['']), - ) - def test_as_json_recent_multiple_use_fields(self, key, values): - for count in range(1, len(values) + 1): - with self.subTest(count=count): - selected = values[:count] - headers = '\n'.join( - f'{key if index == 0 else key.upper()}: {value}' - for index, value in enumerate(selected) - ) - content = ( - 'Metadata-Version: 2.5\nName: distinfo-pkg\nVersion: 1.0.0\n' - + headers - ) - path = self.site_dir / 'distinfo_pkg-1.0.0.dist-info' / 'METADATA' - path.write_text(content, encoding='utf-8') - md = metadata('distinfo-pkg').json - assert md[key.lower().replace('-', '_')] == selected - class LegacyDots(fixtures.DistInfoPkgWithDotLegacy, unittest.TestCase): def test_name_normalization(self):