mirror of
https://github.com/danieldemus/pyp2spec.git
synced 2026-07-27 21:00:37 +02:00
Determine if package is archful by parsing the wheel name
Packages on PyPI publish wheels which contain an abi tag informing whether a package contains extensions compiled for a specific architecture or not. pyp2conf reads this information and saves it in the config file. conf2spec automatically adds `gcc` to the generated specfile in case package is archful.
This commit is contained in:
committed by
Karolina Surma
parent
ba868ae3ce
commit
f6e4b0b4ba
@@ -90,6 +90,7 @@ Configuration data is stored in a TOML file.
|
||||
| source | %{pypi_source} macro with optional arguments (tarball URL can be used instead) | string |
|
||||
| description | long package description | multiline string |
|
||||
| extras | extra subpackages names | list of strings |
|
||||
| archful | package contains compiled extensions, implies not using `BuildArch: noarch` and adding `BuildRequires: gcc` | bool
|
||||
|
||||
|
||||
### Optional fields
|
||||
@@ -106,7 +107,6 @@ Configuration data is stored in a TOML file.
|
||||
| binary_files | list binary files from the package | list |
|
||||
| license_files | list license files from the package | list |
|
||||
| doc_files | list doc files from the package | list |
|
||||
| archful | package contains compiled extensions | bool |
|
||||
|
||||
|
||||
### Example config file generated by pyp2spec
|
||||
@@ -123,6 +123,7 @@ url = "https://github.com/bachya/aionotion"
|
||||
source = "%{pypi_source aionotion}"
|
||||
archive_name = "aionotion"
|
||||
extras = []
|
||||
archful = false
|
||||
```
|
||||
|
||||
### Spec file generated using the example config
|
||||
|
||||
@@ -16,6 +16,9 @@ from pyp2spec.utils import Pyp2specError
|
||||
|
||||
|
||||
TEMPLATE_FILENAME = "template.spec"
|
||||
ADDITIONAL_BUILD_REQUIRES_ARCHFUL = ["gcc"]
|
||||
ADDITIONAL_BUILD_REQUIRES_NOARCH = []
|
||||
|
||||
|
||||
class ConfigError(Pyp2specError):
|
||||
"""Raised when a config value has got a wrong type"""
|
||||
@@ -107,6 +110,16 @@ def generate_unwanted_tests(config):
|
||||
return formatted_unwanteds
|
||||
|
||||
|
||||
def list_additional_build_requires(config):
|
||||
"""Returns a list of additionally defined BuildRequires,
|
||||
|
||||
The list differs for packages that are or aren't archful.
|
||||
"""
|
||||
if config.get_bool("archful"):
|
||||
return ADDITIONAL_BUILD_REQUIRES_ARCHFUL
|
||||
return ADDITIONAL_BUILD_REQUIRES_NOARCH
|
||||
|
||||
|
||||
def wrap_description(config):
|
||||
"""Wrap description line to 79 characters at most.
|
||||
|
||||
@@ -127,6 +140,7 @@ def fill_in_template(config):
|
||||
spec_template = Template(f.read())
|
||||
|
||||
result = spec_template.render(
|
||||
additional_build_requires=list_additional_build_requires(config),
|
||||
archful=config.get_bool("archful"),
|
||||
archive_name=config.get_string("archive_name"),
|
||||
binary_files=config.get_list("binary_files"),
|
||||
|
||||
@@ -204,6 +204,32 @@ class PypiPackage:
|
||||
except (KeyError, TypeError):
|
||||
return self.package_data["info"]["package_url"]
|
||||
|
||||
def is_archful(self):
|
||||
"""Determine if package is archful by checking the wheel filenames.
|
||||
|
||||
Wheel name consists of defined fields, one of them being an abi tag.
|
||||
Example abi tags:
|
||||
- click-0.2-py2.py3-none-any.whl -> "none"
|
||||
- cryptography-2.2-cp34-abi3-manylinux1_x86_64.whl -> "abi3"
|
||||
If the value is "none", wheel was not built for a specific architecture,
|
||||
probably containing pure Python modules.
|
||||
Other values indicate build for an architechture, which can mean
|
||||
the presence of compiled extensions.
|
||||
Packages can publish multiple wheels, the pure-Python alongside the compiled ones.
|
||||
For our purposes, if we find at least one wheel with an abi tag different that "none",
|
||||
we consider the package archful.
|
||||
The compiled extensions bring optimizations and in Fedora,
|
||||
it is generally encouraged to bring in the optional features of the packages.
|
||||
"""
|
||||
|
||||
for entry in self.package_data["urls"]:
|
||||
if entry["packagetype"] == "bdist_wheel":
|
||||
abi_tag = entry["filename"].split("-")[-2]
|
||||
if abi_tag != "none":
|
||||
return True
|
||||
# all of the found wheel names had 'none' as abi_tag
|
||||
return False
|
||||
|
||||
def find_and_save_sdist_filename(self):
|
||||
"""Save the given's package version sdist name for further processing.
|
||||
|
||||
@@ -348,6 +374,8 @@ def create_config_contents(
|
||||
click.secho("Package is set to --archful", fg="magenta")
|
||||
click.secho("You may need to specify manual_build_requires in the config file", fg="magenta")
|
||||
contents["archful"] = archful
|
||||
else:
|
||||
contents["archful"] = pkg.is_archful()
|
||||
|
||||
contents["description"] = description
|
||||
contents["summary"] = summary
|
||||
|
||||
@@ -12,7 +12,9 @@ Source: {{source}}
|
||||
BuildArch: noarch
|
||||
{%- endif %}
|
||||
BuildRequires: python3-devel
|
||||
|
||||
{% for br in additional_build_requires -%}
|
||||
BuildRequires: {{br}}
|
||||
{% endfor %}
|
||||
|
||||
# Fill in the actual package description to submit package to Fedora
|
||||
%global _description %{expand:
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
Name: python-numpy
|
||||
Version: 1.25.2
|
||||
Release: %autorelease
|
||||
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://www.numpy.org
|
||||
Source: %{pypi_source numpy}
|
||||
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: gcc
|
||||
|
||||
|
||||
# Fill in the actual package description to submit package to Fedora
|
||||
%global _description %{expand:
|
||||
This is package 'numpy' generated automatically by pyp2spec.}
|
||||
|
||||
%description %_description
|
||||
|
||||
%package -n python3-numpy
|
||||
Summary: %{summary}
|
||||
|
||||
%description -n python3-numpy %_description
|
||||
|
||||
|
||||
%prep
|
||||
%autosetup -p1 -n numpy-%{version}
|
||||
|
||||
|
||||
%generate_buildrequires
|
||||
%pyproject_buildrequires
|
||||
|
||||
|
||||
%build
|
||||
%pyproject_wheel
|
||||
|
||||
|
||||
%install
|
||||
%pyproject_install
|
||||
# For official Fedora packages, including files with '*' +auto is not allowed
|
||||
# Replace it with a list of relevant Python modules/globs and list extra files in %%files
|
||||
%pyproject_save_files '*' +auto
|
||||
|
||||
|
||||
%check
|
||||
%pyproject_check_import
|
||||
|
||||
|
||||
%files -n python3-numpy -f %{pyproject_files}
|
||||
|
||||
|
||||
%changelog
|
||||
%autochangelog
|
||||
File diff suppressed because one or more lines are too long
@@ -121,6 +121,7 @@ def test_archful_flag_is_loaded(config_dir, conf, expected):
|
||||
"default_python-click.conf",
|
||||
"customized_markdown-it-py.conf",
|
||||
"customized_python-sphinx.conf",
|
||||
"default_python-numpy.conf"
|
||||
]
|
||||
)
|
||||
def test_default_generated_specfile(file_regression, config_dir, conf):
|
||||
|
||||
@@ -12,3 +12,4 @@ A asyncio-friendly library for Notion Home Monitoring devices.
|
||||
'''
|
||||
test_top_level = true
|
||||
extras = []
|
||||
archful = false
|
||||
|
||||
@@ -9,3 +9,4 @@ url = "https://github.com/bachya/aionotion"
|
||||
source = "%{pypi_source aionotion}"
|
||||
archive_name = "aionotion"
|
||||
extras = []
|
||||
archful = false
|
||||
|
||||
@@ -9,3 +9,4 @@ url = "https://palletsprojects.com/p/click/"
|
||||
source = "%{pypi_source click}"
|
||||
archive_name = "click"
|
||||
extras = []
|
||||
archful = false
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
archful = true
|
||||
description = "This is package 'numpy' generated automatically by pyp2spec."
|
||||
summary = "Fundamental package for array computing in Python"
|
||||
version = "1.25.2"
|
||||
pypi_version = "%{version}"
|
||||
license = "BSD-3-Clause"
|
||||
pypi_name = "numpy"
|
||||
python_name = "python-numpy"
|
||||
url = "https://www.numpy.org"
|
||||
source = "%{pypi_source numpy}"
|
||||
archive_name = "numpy"
|
||||
+82
-6
@@ -61,17 +61,16 @@ def test_config_with_customization_is_valid(betamax_session):
|
||||
|
||||
|
||||
def test_archful_package(betamax_session):
|
||||
"""Generate config for tornado which is archful"""
|
||||
package = "tornado"
|
||||
"""Generate config for numpy which is archful"""
|
||||
package = "numpy"
|
||||
config = create_config_contents(
|
||||
package=package,
|
||||
top_level=True,
|
||||
license="Apache 2.0",
|
||||
archful=True,
|
||||
license="fake-string",
|
||||
version="1.25.2",
|
||||
session=betamax_session,
|
||||
)
|
||||
|
||||
with open(f"tests/test_configs/customized_{package}.conf", "rb") as config_file:
|
||||
with open(f"tests/test_configs/default_python-{package}.conf", "rb") as config_file:
|
||||
loaded_contents = tomllib.load(config_file)
|
||||
|
||||
assert config["archful"] == loaded_contents["archful"]
|
||||
@@ -271,3 +270,80 @@ def test_extras_detected_correctly():
|
||||
}
|
||||
pkg = PypiPackage("_", version="0", package_metadata=fake_pkg_data)
|
||||
assert pkg.extras() == ["dev", "docs", "lint", "test"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("wheel_name", "archful"), [
|
||||
("sampleproject-3.0.0-py3-none-any.whl", False),
|
||||
("numpy-1.26.0-cp39-cp39-win_amd64.whl", True),
|
||||
("numpy-1.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", True),
|
||||
("numpy-1.26.0-cp39-cp39-musllinux_1_1_x86_64.whl", True),
|
||||
]
|
||||
)
|
||||
def test_archfulness_is_detected(wheel_name, archful):
|
||||
fake_pkg_data = {
|
||||
"urls": [
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"filename": wheel_name,
|
||||
}
|
||||
]
|
||||
}
|
||||
pkg = PypiPackage("_", version="0", package_metadata=fake_pkg_data)
|
||||
assert pkg.is_archful() is archful
|
||||
|
||||
|
||||
def test_archfulness_is_detected_from_multiple_urls_1():
|
||||
fake_pkg_data = {
|
||||
"urls": [
|
||||
{
|
||||
"packagetype": "sdist",
|
||||
"filename": "sampleproject-3.0.0.tar.gz",
|
||||
},
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"filename": "sampleproject-3.0.0-py3-none-any.whl",
|
||||
},
|
||||
]
|
||||
}
|
||||
pkg = PypiPackage("_", version="0", package_metadata=fake_pkg_data)
|
||||
assert not pkg.is_archful()
|
||||
|
||||
|
||||
def test_archfulness_is_detected_from_multiple_urls_2():
|
||||
fake_pkg_data = {
|
||||
"urls": [
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"filename": "sampleproject-3.0.0-py3-none-any.whl",
|
||||
},
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"filename": "sampleproject-3.0.0-cp312-abi3-manylinux1_x86_64.whl",
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
pkg = PypiPackage("_", version="0", package_metadata=fake_pkg_data)
|
||||
assert pkg.is_archful()
|
||||
|
||||
|
||||
def test_archfulness_is_detected_from_multiple_urls_3():
|
||||
fake_pkg_data = {
|
||||
"urls": [
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"filename": "sampleproject-3.0.0-cp312-abi3-manylinux1_x86_64.whl",
|
||||
},
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"filename": "sampleproject-3.0.0-cp39-cp39-win_amd64.whl",
|
||||
},
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"filename": "sampleproject-3.0.0-py3-none-any.whl",
|
||||
},
|
||||
]
|
||||
}
|
||||
pkg = PypiPackage("_", version="0", package_metadata=fake_pkg_data)
|
||||
assert pkg.is_archful()
|
||||
|
||||
Reference in New Issue
Block a user