Look for the well-known project URL keys

According to the official specification:
https://packaging.python.org/en/latest/specifications/well-known-project-urls/
project URLs' labels can be normalized and then searched for the
matches.
Attempt to find "homepage" and "source" first, and only return other
project URL values if these are not found.
This commit is contained in:
Karolina Surma
2025-01-24 17:02:08 +01:00
parent 833c8e7f8f
commit 30d5e96947
9 changed files with 36 additions and 17 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ import tomli_w
from pyp2spec.license_processor import check_compliance, resolve_license_expression
from pyp2spec.utils import Pyp2specError, normalize_name, get_extras, get_summary_or_placeholder
from pyp2spec.utils import prepend_name_with_python, archive_name
from pyp2spec.utils import is_archful, get_first_url_or_placeholder
from pyp2spec.utils import is_archful, resolve_url
from pyp2spec.utils import warn, caution, inform, yay
from pyp2spec.pypi_loaders import load_from_pypi, load_core_metadata_from_pypi, CoreMetadataNotFoundError
@@ -28,7 +28,7 @@ def prepare_package_info(data):
"pypi_name": normalize_name(data.get("name")),
"pypi_version": data.get("version"),
"summary": get_summary_or_placeholder(data.get("summary")),
"url": get_first_url_or_placeholder(project_urls),
"url": resolve_url(project_urls),
"extras": get_extras(data.get("requires_dist", [])),
"license_files_present": bool(data.get("license_files")),
"license": resolve_license_expression(data),
+24 -5
View File
@@ -3,6 +3,7 @@ This module contains common functions and classes imported in multiple other mod
"""
import re
import string
from functools import partial
import click
@@ -152,13 +153,31 @@ def is_archful(archive_urls):
return False
def get_first_url_or_placeholder(urls):
def _normalize_url_label(label: str) -> str:
"""
Copied verbatim from
https://packaging.python.org/en/latest/specifications/well-known-project-urls/#label-normalization
"""
chars_to_remove = string.punctuation + string.whitespace
removal_map = str.maketrans("", "", chars_to_remove)
return label.translate(removal_map).lower()
def resolve_url(urls):
"""
Project urls are an optional field and come in a form of a dict, e.g.:
{"homepage": "https://mypackagehomepage.com"}.
There may be multiple urls defined and keys are arbitrary.
As there's no way to programmatically determine "the best" url for the
spec file, return the first existing url from the dict.
Try to return url for normalized "homepage", then "source" keys.
Otherwise return the first value from the dictionary or "..." if the dict is empty.
"""
return list(urls.values())[0] if urls else "..."
normalized_urls = {_normalize_url_label(k): v for k, v in urls.items()}
print(normalized_urls)
return (
normalized_urls.get("homepage")
or normalized_urls.get("source")
or normalized_urls.get("sourcecode")
or normalized_urls.get("github")
or normalized_urls.get("repository")
or next(iter(normalized_urls.values()), "...")
)
+1 -1
View File
@@ -7,7 +7,7 @@ Summary: Composable command line interface toolkit
# Check if the automatically generated License and its spelling is correct for Fedora
# https://docs.fedoraproject.org/en-US/packaging-guidelines/LicensingGuidelines/
License: BSD-3-Clause
URL: https://palletsprojects.com/donate
URL: https://github.com/pallets/click/
Source: %{pypi_source click}
BuildArch: noarch
+1 -1
View File
@@ -7,7 +7,7 @@ Summary: Fundamental package for array computing in Python
# Check if the automatically generated License and its spelling is correct for Fedora
# https://docs.fedoraproject.org/en-US/packaging-guidelines/LicensingGuidelines/
License: BSD-3-Clause
URL: https://github.com/numpy/numpy/issues
URL: https://github.com/numpy/numpy
Source: %{pypi_source numpy}
BuildRequires: python3-devel
+1 -1
View File
@@ -6,7 +6,7 @@ Summary: Python documentation generator
# No license information obtained, it's up to the packager to fill it in
License: ...
URL: https://www.sphinx-doc.org/en/master/changes.html
URL: https://www.sphinx-doc.org/
Source: %{pypi_source sphinx}
BuildArch: noarch
@@ -2,7 +2,7 @@ summary = "Python documentation generator"
pypi_version = "8.1.3"
pypi_name = "sphinx"
python_name = "python-sphinx"
url = "https://www.sphinx-doc.org/en/master/changes.html"
url = "https://www.sphinx-doc.org/"
source = "PyPI"
extras = [
"docs",
+1 -1
View File
@@ -3,7 +3,7 @@ license = "BSD-3-Clause"
pypi_name = "click"
pypi_version = "8.1.7"
python_name = "python-click"
url = "https://palletsprojects.com/donate"
url = "https://github.com/pallets/click/"
source = "PyPI"
extras = []
archful = false
+1 -1
View File
@@ -4,7 +4,7 @@ pypi_version = "1.25.2"
license = "BSD-3-Clause"
pypi_name = "numpy"
python_name = "python-numpy"
url = "https://github.com/numpy/numpy/issues"
url = "https://github.com/numpy/numpy"
source = "PyPI"
automode = true
extras = []
+4 -4
View File
@@ -3,7 +3,7 @@ import pytest
from pyp2spec.utils import filter_license_classifiers, prepend_name_with_python
from pyp2spec.utils import normalize_name, get_extras, is_archful
from pyp2spec.utils import normalize_as_wheel_name, archive_name
from pyp2spec.utils import get_first_url_or_placeholder, SdistNotFoundError
from pyp2spec.utils import resolve_url, SdistNotFoundError
def test_license_classifier_read_correctly():
@@ -161,7 +161,7 @@ def test_archive_name_empty_list():
def test_project_urls_valid_single():
urls = {"homepage": "https://example.com"}
assert get_first_url_or_placeholder(urls) == "https://example.com"
assert resolve_url(urls) == "https://example.com"
def test_project_urls_valid_multiple():
@@ -169,8 +169,8 @@ def test_project_urls_valid_multiple():
"homepage": "https://example.com",
"documentation": "https://docs.example.com",
}
assert get_first_url_or_placeholder(urls) == "https://example.com"
assert resolve_url(urls) == "https://example.com"
def test_project_urls_empty():
assert get_first_url_or_placeholder({}) == "..."
assert resolve_url({}) == "..."