From dddb29ffccae1fcbe1b568abbb60de2e29df90d5 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 11 Oct 2024 01:30:35 -0400 Subject: [PATCH] feat: support PEP 753 Signed-off-by: Henry Schreiner --- pyproject.toml | 6 ++++++ pyproject_metadata/__init__.py | 11 ++++++++--- pyproject_metadata/constants.py | 4 ++-- tests/test_standard_metadata.py | 33 +++++++++++++++++++++------------ 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2b659a8..3bab582 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,12 @@ homepage = "https://github.com/pypa/pyproject-metadata" [tool.flit.sdist] include = ["LICENSE", "tests/**", "docs/**", ".gitignore"] +[tool.uv] +dev-dependencies = ["pyproject-metadata[test]"] +environments = [ + "python_version >= '3.10'", +] + [tool.pytest.ini_options] minversion = "6.0" diff --git a/pyproject_metadata/__init__.py b/pyproject_metadata/__init__.py index 39ae6e4..a624468 100644 --- a/pyproject_metadata/__init__.py +++ b/pyproject_metadata/__init__.py @@ -481,6 +481,7 @@ def validate(self, *, warn: bool = True) -> None: # noqa: C901 - License classifiers deprecated for metadata_version >= 2.4 (warning) - ``license`` is an SPDX license expression if metadata_version >= 2.4 - ``license_files`` is supported only for metadata_version >= 2.4 + - ``project_url`` can't contain keys over 32 characters """ errors = ErrorCollector(collect_errors=self.all_errors) @@ -544,6 +545,11 @@ def validate(self, *, warn: bool = True) -> None: # noqa: C901 msg = "{key} is supported only when emitting metadata version >= 2.4" errors.config_error(msg, key="project.license-files") + for name in self.urls: + if len(name) > 32: + msg = "{key} names cannot be more than 32 characters long" + errors.config_error(msg, key="project.urls", got=name) + errors.finalize("Metadata validation failed") def _write_metadata( # noqa: C901 @@ -565,8 +571,7 @@ def _write_metadata( # noqa: C901 if self.description: smart_message["Summary"] = self.description smart_message["Keywords"] = ",".join(self.keywords) or None - if "homepage" in self.urls: - smart_message["Home-page"] = self.urls["homepage"] + # skip 'Home-page' # skip 'Download-URL' smart_message["Author"] = _name_list(self.authors) smart_message["Author-Email"] = _email_list(self.authors) @@ -588,7 +593,7 @@ def _write_metadata( # noqa: C901 # skip 'Obsoletes-Dist' # skip 'Requires-External' for name, url in self.urls.items(): - smart_message["Project-URL"] = f"{name.capitalize()}, {url}" + smart_message["Project-URL"] = f"{name}, {url}" if self.requires_python: smart_message["Requires-Python"] = str(self.requires_python) for dep in self.dependencies: diff --git a/pyproject_metadata/constants.py b/pyproject_metadata/constants.py index afa1185..56cb743 100644 --- a/pyproject_metadata/constants.py +++ b/pyproject_metadata/constants.py @@ -58,9 +58,9 @@ def __dir__() -> list[str]: "classifier", "description", "description-content-type", - "download-url", # Not specified via pyproject standards + "download-url", # Not specified via pyproject standards, deprecated by PEP 753 "dynamic", # Can't be in dynamic - "home-page", # Not specified via pyproject standards + "home-page", # Not specified via pyproject standards, deprecated by PEP 753 "keywords", "license", "license-expression", diff --git a/tests/test_standard_metadata.py b/tests/test_standard_metadata.py index 0c21cdd..32eb8e3 100644 --- a/tests/test_standard_metadata.py +++ b/tests/test_standard_metadata.py @@ -590,9 +590,9 @@ def all_errors(request: pytest.FixtureRequest, monkeypatch: pytest.MonkeyPatch) name = "test" version = "0.1.0" [project.urls] - documentation = true + Documentation = true """, - 'Field "project.urls.documentation" has an invalid type, expecting a string (got bool)', + 'Field "project.urls.Documentation" has an invalid type, expecting a string (got bool)', id="Invalid urls documentation type", ), pytest.param( @@ -606,6 +606,17 @@ def all_errors(request: pytest.FixtureRequest, monkeypatch: pytest.MonkeyPatch) 'Field "project.urls.repository" has an invalid type, expecting a string (got bool)', id="Invalid urls repository type", ), + pytest.param( + """ + [project] + name = "test" + version = "0.1.0" + [project.urls] + "I am really really too long for this place" = "url" + """, + '"project.urls" names cannot be more than 32 characters long (got \'I am really really too long for this place\')', + id="URL name too long", + ), pytest.param( """ [project] @@ -1097,17 +1108,16 @@ def test_as_json(monkeypatch: pytest.MonkeyPatch) -> None: ], "description": "some readme 👋\n", "description_content_type": "text/markdown", - "home_page": "example.com", "keywords": ["trampolim", "is", "interesting"], "license": "some license text", "maintainer_email": "Other Example ", "metadata_version": "2.1", "name": "full_metadata", "project_url": [ - "Homepage, example.com", - "Documentation, readthedocs.org", - "Repository, github.com/some/repo", - "Changelog, github.com/some/repo/blob/master/CHANGELOG.rst", + "homepage, example.com", + "documentation, readthedocs.org", + "repository, github.com/some/repo", + "changelog, github.com/some/repo/blob/master/CHANGELOG.rst", ], "provides_extra": ["test"], "requires_dist": [ @@ -1138,17 +1148,16 @@ def test_as_rfc822(monkeypatch: pytest.MonkeyPatch) -> None: ("Version", "3.2.1"), ("Summary", "A package with all the metadata :)"), ("Keywords", "trampolim,is,interesting"), - ("Home-page", "example.com"), ("Author", "Example!"), ("Author-Email", "Unknown "), ("Maintainer-Email", "Other Example "), ("License", "some license text"), ("Classifier", "Development Status :: 4 - Beta"), ("Classifier", "Programming Language :: Python"), - ("Project-URL", "Homepage, example.com"), - ("Project-URL", "Documentation, readthedocs.org"), - ("Project-URL", "Repository, github.com/some/repo"), - ("Project-URL", "Changelog, github.com/some/repo/blob/master/CHANGELOG.rst"), + ("Project-URL", "homepage, example.com"), + ("Project-URL", "documentation, readthedocs.org"), + ("Project-URL", "repository, github.com/some/repo"), + ("Project-URL", "changelog, github.com/some/repo/blob/master/CHANGELOG.rst"), ("Requires-Python", ">=3.8"), ("Requires-Dist", "dependency1"), ("Requires-Dist", "dependency2>1.0.0"),