From 3290cc3dbf2afa9d640540cbc9844dccbc10484e Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 31 Jul 2025 06:09:36 +0800 Subject: [PATCH 1/4] Add API to retrieve project metadata from an installed package. --- pyroma/projectdata.py | 10 ++++++++++ pyroma/tests.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/pyroma/projectdata.py b/pyroma/projectdata.py index e5859f4..149e50a 100644 --- a/pyroma/projectdata.py +++ b/pyroma/projectdata.py @@ -4,6 +4,7 @@ import os import pathlib import re +from importlib.metadata import metadata from setuptools.config.setupcfg import read_configuration from distutils.errors import DistutilsFileError @@ -47,6 +48,10 @@ def build_metadata(path, isolated=None): # metadata from PyPI, we just couldn't get the additional build data. return {"_wheel_build_failed": True} + return normalize_metadata(metadata) + + +def normalize_metadata(metadata): # As far as I can tell, we can't trust that the builders normalize the keys, # so we do it here. Definitely most builders do not lower case them, which # Core Metadata Specs recommend. @@ -72,6 +77,11 @@ def build_metadata(path, isolated=None): return data +def installed_metadata(name): + """Retrieve the metadata for an package that is installed in the environment.""" + return normalize_metadata(metadata(name)) + + def get_build_data(path, isolated=None): metadata = build_metadata(path, isolated=isolated) # Check if there is a pyproject_toml diff --git a/pyroma/tests.py b/pyroma/tests.py index 6705c37..d1b9fb8 100644 --- a/pyroma/tests.py +++ b/pyroma/tests.py @@ -334,6 +334,40 @@ def test_complete(self): del data["_path"] # This changes, so I just ignore it self.assertEqual(data, COMPLETE) + def test_installed(self): + # pyroma must be installed in the test environment. + data = projectdata.installed_metadata("pyroma") + + # Verify some key metadata + self.assertEqual(data["name"], "pyroma") + self.assertEqual(data["summary"], "Test your project's packaging friendliness") + self.assertEqual(data["classifier"], [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + ]) + self.assertEqual(data["keywords"], "pypi,quality,testing") + self.assertEqual(data["author"], "Lennart Regebro") + self.assertEqual(data["author-email"], "regebro@gmail.com") + self.assertEqual(data["home-page"], "https://github.com/regebro/pyroma") + self.assertEqual(data["license"], "MIT") + self.assertEqual(data["license-file"], "LICENSE.txt") + self.assertEqual(data["project-url"], "Source Code, https://github.com/regebro/pyroma") + self.assertEqual(data["provides-extra"], "test") + self.assertEqual(data["requires-python"], "3.9") + class DistroDataTest(unittest.TestCase): maxDiff = None From ee97f7687ada92400bbd92507c159a49f96a313f Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 1 Aug 2025 05:53:34 +0800 Subject: [PATCH 2/4] Rename some variables to avoid naming collisions. --- pyroma/projectdata.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pyroma/projectdata.py b/pyroma/projectdata.py index 149e50a..5c710ac 100644 --- a/pyroma/projectdata.py +++ b/pyroma/projectdata.py @@ -40,7 +40,7 @@ def wheel_metadata(path, isolated=None): def build_metadata(path, isolated=None): try: - metadata = wheel_metadata(path, isolated) + data = wheel_metadata(path, isolated) except build.BuildBackendException: # The backend failed spectacularily. This happens with old packages, # when we can't build a wheel. It's not always a fatal error. F ex, if @@ -48,16 +48,16 @@ def build_metadata(path, isolated=None): # metadata from PyPI, we just couldn't get the additional build data. return {"_wheel_build_failed": True} - return normalize_metadata(metadata) + return normalize_metadata(data) -def normalize_metadata(metadata): +def normalize_metadata(data): # As far as I can tell, we can't trust that the builders normalize the keys, # so we do it here. Definitely most builders do not lower case them, which # Core Metadata Specs recommend. - data = {} - for key in set(metadata.keys()): - value = metadata.get_all(key) + normalized = {} + for key in set(data.keys()): + value = data.get_all(key) key = normalize(key) if len(value) == 1: @@ -66,15 +66,15 @@ def normalize_metadata(metadata): # XXX This is also old behavior that may not hjappen any more. continue - data[key] = value + normalized[key] = value - if "description" not in data.keys(): + if "description" not in normalized.keys(): # XXX I *think* having the description as a payload doesn't happen anymore, but I haven't checked. # Having the description as a payload tends to add two newlines, we clean that up here: - description = metadata.get_payload().strip() + description = data.get_payload().strip() if description: - data["description"] = description + "\n" - return data + normalized["description"] = description + "\n" + return normalized def installed_metadata(name): From db31701b191408953cbf26bffdd872ec7a8efdf5 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 1 Aug 2025 05:53:45 +0800 Subject: [PATCH 3/4] Correct a test case. --- pyroma/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyroma/tests.py b/pyroma/tests.py index d1b9fb8..e8689c4 100644 --- a/pyroma/tests.py +++ b/pyroma/tests.py @@ -366,7 +366,7 @@ def test_installed(self): self.assertEqual(data["license-file"], "LICENSE.txt") self.assertEqual(data["project-url"], "Source Code, https://github.com/regebro/pyroma") self.assertEqual(data["provides-extra"], "test") - self.assertEqual(data["requires-python"], "3.9") + self.assertEqual(data["requires-python"], ">=3.9") class DistroDataTest(unittest.TestCase): From fab80f4677001aec829792ab86b0eedbb0212635 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 1 Aug 2025 05:57:05 +0800 Subject: [PATCH 4/4] Correct linting failures. --- pyroma/tests.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/pyroma/tests.py b/pyroma/tests.py index e8689c4..5380613 100644 --- a/pyroma/tests.py +++ b/pyroma/tests.py @@ -341,23 +341,26 @@ def test_installed(self): # Verify some key metadata self.assertEqual(data["name"], "pyroma") self.assertEqual(data["summary"], "Test your project's packaging friendliness") - self.assertEqual(data["classifier"], [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - ]) + self.assertEqual( + data["classifier"], + [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + ], + ) self.assertEqual(data["keywords"], "pypi,quality,testing") self.assertEqual(data["author"], "Lennart Regebro") self.assertEqual(data["author-email"], "regebro@gmail.com")