Skip to content

Commit

Permalink
Add the license presence assertion (closes: #49)
Browse files Browse the repository at this point in the history
If "License-File" is present in Metadata file, we can safely add the
`-l` flag to %pyproject_save_files. The flag asserts that at least
one license file is marked as %license in the %files section
when there are none specified manually.
Not all build backends expose the field yet, which was oficially added
to Core Metadata 2.4 with PEP 639.
  • Loading branch information
befeleme committed Oct 11, 2024
1 parent bf70f16 commit 5d7b64f
Show file tree
Hide file tree
Showing 21 changed files with 111 additions and 59 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ Configuration data is stored in a TOML file.
| archful | package contains compiled extensions, implies not using `BuildArch: noarch` and adding `BuildRequires: gcc` | bool |
| python_alt_version | specific Python version to create the spec file for, e.g. 3.9, 3.10, 3.12 | string |
| automode | create buildable spec files that don't have to fully comply with Fedora Guidelines; useful for automatic build environments | bool |
| license_files_present | `License-File` field was detected in the package metadata | bool |


### Example config file generated by pyp2spec
Expand All @@ -139,6 +140,7 @@ archive_name = "aionotion"
extras = []
archful = false
automode = false
license_files_present = false
```

### Spec file generated using the example config
Expand Down
1 change: 1 addition & 0 deletions pyp2spec/conf2spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def fill_in_template(config):
extras=",".join(config.get_list("extras")),
license=license,
license_notice=license_notice,
mandate_license=config.get_bool("license_files_present"),
name=config.get_string("pypi_name"),
python_name=config.get_string("python_name"),
pypi_version=config.get_string("pypi_version"),
Expand Down
22 changes: 21 additions & 1 deletion pyp2spec/pyp2conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from functools import wraps
import email.parser
import re
import sys

Expand Down Expand Up @@ -44,14 +45,15 @@ class PypiPackage:
This is only relevant for testing.
"""

def __init__(self, package_name, *, version=None, package_metadata=None, session=None):
def __init__(self, package_name, *, version=None, package_metadata=None, metadata_from_file=None, session=None):
self.package_name = package_name
self._session = session or requests.Session()
self.version = version or self._get_version_from_package_metadata()
# package_metadata - custom dictionary with package metadata - used for testing
# in the typical app run it's not set,
# meaning we jump to the other sources package metadata data (eg. PyPI)
self.package_data = package_metadata or self._get_package_version_metadata()
self.metadata_from_file = metadata_from_file or self.parse_metadata()
self.sdist_filename = None

@property
Expand Down Expand Up @@ -87,6 +89,20 @@ def _get_package_version_metadata(self):
error_str = f"Package `{self.package_name}` or version `{self.version}` was not found on PyPI"
return self._get_from_url(pkg_index, error_str)

def _get_metadata_file(self):
for entry in self.package_data["urls"]:
if entry["packagetype"] == "bdist_wheel":
response = self._session.get(entry["url"] + ".metadata")
if not response.ok:
click.secho("The metadata file could not be located", fg="red")
response.text = None
return response.text

def parse_metadata(self):
metadata = self._get_metadata_file()
parser = email.parser.Parser()
return parser.parsestr(metadata)

def python_name(self, *, python_alt_version=None):
"""Create a component name for the specfile.
Expand Down Expand Up @@ -328,6 +344,9 @@ def extras(self):
extras.add(found.group(1))
return sorted(extras)

def are_license_files_included(self):
return True if self.metadata_from_file.get_all("License-File") else False


def get_description(package):
"""Return a default package description."""
Expand Down Expand Up @@ -404,6 +423,7 @@ def create_config_contents(
contents["source"] = pkg.source()
contents["archive_name"] = pkg.archive_name()
contents["extras"] = pkg.extras()
contents["license_files_present"] = pkg.are_license_files_included()

return contents

Expand Down
2 changes: 1 addition & 1 deletion pyp2spec/template.spec
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Summary: %{summary}
%pyproject_save_files '*' +auto
{%- else -%}
# Add top-level Python module names here as arguments, you can use globs
%pyproject_save_files ...
%pyproject_save_files{% if mandate_license %} -l{% endif %} ...
{%- endif %}


Expand Down
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import email.parser
import json

import betamax
Expand All @@ -17,3 +18,9 @@
def fake_fedora_licenses():
with open("tests/fedora_license_data.json", "r", encoding="utf-8") as f:
return json.load(f)


@pytest.fixture(scope="session")
def fake_metadata_from_file():
# Return an object with fake metadata
return email.parser.Parser().parsestr("Name: foo")
4 changes: 2 additions & 2 deletions tests/expected_specfiles/python-click.spec
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Name: python-click
Version: 7.1.2
Version: 8.1.7
Release: %autorelease
# Fill in the actual package summary to submit package to Fedora
Summary: Composable command line interface toolkit
Expand Down Expand Up @@ -41,7 +41,7 @@ Summary: %{summary}
%install
%pyproject_install
# Add top-level Python module names here as arguments, you can use globs
%pyproject_save_files ...
%pyproject_save_files -l ...


%check
Expand Down
2 changes: 1 addition & 1 deletion tests/expected_specfiles/python3.9-pello.spec
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ This is package 'Pello' generated automatically by pyp2spec.}
%install
%pyproject_install
# Add top-level Python module names here as arguments, you can use globs
%pyproject_save_files ...
%pyproject_save_files -l ...


%check
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

This file was deleted.

Loading

0 comments on commit 5d7b64f

Please sign in to comment.