Use importlib_metadata rather than pip freeze
This commit is contained in:
parent
23901d999a
commit
d262d909f5
@ -24,7 +24,6 @@ fi
|
|||||||
%{-e:%{expand:%global toxenv %{-e*}}}
|
%{-e:%{expand:%global toxenv %{-e*}}}
|
||||||
echo 'python3-devel'
|
echo 'python3-devel'
|
||||||
echo 'python3dist(packaging)'
|
echo 'python3dist(packaging)'
|
||||||
echo 'python3dist(pip) >= 19'
|
|
||||||
echo 'python3dist(pytoml)'
|
echo 'python3dist(pytoml)'
|
||||||
# setuptools assumes no pre-existing dist-info
|
# setuptools assumes no pre-existing dist-info
|
||||||
rm -rfv *.dist-info/
|
rm -rfv *.dist-info/
|
||||||
|
@ -21,17 +21,28 @@ URL: https://src.fedoraproject.org/rpms/pyproject-rpm-macros
|
|||||||
|
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
|
|
||||||
# We keep them here for now to avoid one loop of %%generate_buildrequires
|
|
||||||
# And to allow the other macros without %%pyproject_buildrequires (e.g. on Fedora 30)
|
|
||||||
# But those are also always in the output of %%generate_buildrequires
|
|
||||||
# in order to be removable in the future
|
|
||||||
Requires: python3-pip >= 19
|
Requires: python3-pip >= 19
|
||||||
Requires: python3-devel
|
Requires: python3-devel
|
||||||
|
|
||||||
|
# We keep these here for now to avoid one loop of %%generate_buildrequires
|
||||||
|
# But those are also always in the output of %%generate_buildrequires
|
||||||
|
# in order to be removable in the future
|
||||||
|
Requires: python3dist(packaging)
|
||||||
|
Requires: python3dist(pytoml)
|
||||||
|
|
||||||
|
# This is not output from %%generate_buildrequires to work around:
|
||||||
|
# https://github.com/rpm-software-management/mock/issues/336
|
||||||
|
Requires: (python3dist(importlib-metadata) if python3 < 3.8)
|
||||||
|
|
||||||
%if %{with tests}
|
%if %{with tests}
|
||||||
BuildRequires: python3dist(pytest)
|
BuildRequires: python3dist(pytest)
|
||||||
BuildRequires: python3dist(pyyaml)
|
BuildRequires: python3dist(pyyaml)
|
||||||
BuildRequires: python3dist(packaging)
|
BuildRequires: python3dist(packaging)
|
||||||
|
%if 0%{fedora} < 32
|
||||||
|
# The %%if should not be needed, it works around:
|
||||||
|
# https://github.com/rpm-software-management/mock/issues/336
|
||||||
|
BuildRequires: (python3dist(importlib-metadata) if python3 < 3.8)
|
||||||
|
%endif
|
||||||
BuildRequires: python3dist(pytoml)
|
BuildRequires: python3dist(pytoml)
|
||||||
BuildRequires: python3dist(pip)
|
BuildRequires: python3dist(pip)
|
||||||
BuildRequires: python3dist(setuptools)
|
BuildRequires: python3dist(setuptools)
|
||||||
|
@ -26,7 +26,10 @@ try:
|
|||||||
from packaging.requirements import Requirement, InvalidRequirement
|
from packaging.requirements import Requirement, InvalidRequirement
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
from packaging.utils import canonicalize_name, canonicalize_version
|
from packaging.utils import canonicalize_name, canonicalize_version
|
||||||
import pip
|
try:
|
||||||
|
import importlib.metadata as importlib_metadata
|
||||||
|
except ImportError:
|
||||||
|
import importlib_metadata
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print_err('Import error:', e)
|
print_err('Import error:', e)
|
||||||
# already echoed by the %pyproject_buildrequires macro
|
# already echoed by the %pyproject_buildrequires macro
|
||||||
@ -44,14 +47,8 @@ def hook_call():
|
|||||||
|
|
||||||
class Requirements:
|
class Requirements:
|
||||||
"""Requirement printer"""
|
"""Requirement printer"""
|
||||||
def __init__(self, freeze_output, extras=''):
|
def __init__(self, get_installed_version, extras=''):
|
||||||
self.installed_packages = {}
|
self.get_installed_version = get_installed_version
|
||||||
for line in freeze_output.splitlines():
|
|
||||||
line = line.strip()
|
|
||||||
if line.startswith('#'):
|
|
||||||
continue
|
|
||||||
name, version = line.split('==')
|
|
||||||
self.installed_packages[name.strip()] = Version(version)
|
|
||||||
|
|
||||||
self.marker_env = {'extra': extras}
|
self.marker_env = {'extra': extras}
|
||||||
|
|
||||||
@ -77,7 +74,11 @@ class Requirements:
|
|||||||
print_err(f'Ignoring alien requirement:', requirement_str)
|
print_err(f'Ignoring alien requirement:', requirement_str)
|
||||||
return
|
return
|
||||||
|
|
||||||
installed = self.installed_packages.get(requirement.name)
|
try:
|
||||||
|
installed = self.get_installed_version(requirement.name)
|
||||||
|
except importlib_metadata.PackageNotFoundError:
|
||||||
|
print_err(f'Requirement not satisfied: {requirement_str}')
|
||||||
|
installed = None
|
||||||
if installed and installed in requirement.specifier:
|
if installed and installed in requirement.specifier:
|
||||||
print_err(f'Requirement satisfied: {requirement_str}')
|
print_err(f'Requirement satisfied: {requirement_str}')
|
||||||
print_err(f' (installed: {requirement.name} {installed})')
|
print_err(f' (installed: {requirement.name} {installed})')
|
||||||
@ -203,9 +204,14 @@ def python3dist(name, op=None, version=None):
|
|||||||
|
|
||||||
|
|
||||||
def generate_requires(
|
def generate_requires(
|
||||||
freeze_output, *, include_runtime=False, toxenv=None, extras='',
|
*, include_runtime=False, toxenv=None, extras='',
|
||||||
|
get_installed_version=importlib_metadata.version, # for dep injection
|
||||||
):
|
):
|
||||||
requirements = Requirements(freeze_output, extras=extras)
|
"""Generate the BuildRequires for the project in the current directory
|
||||||
|
|
||||||
|
This is the main Python entry point.
|
||||||
|
"""
|
||||||
|
requirements = Requirements(get_installed_version, extras=extras)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
backend = get_backend(requirements)
|
backend = get_backend(requirements)
|
||||||
@ -259,16 +265,8 @@ def main(argv):
|
|||||||
print_err('-x (--extras) are only useful with -r (--runtime)')
|
print_err('-x (--extras) are only useful with -r (--runtime)')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
freeze_output = subprocess.run(
|
|
||||||
[sys.executable, '-I', '-m', 'pip', 'freeze', '--all'],
|
|
||||||
encoding='utf-8',
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
check=True,
|
|
||||||
).stdout
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
generate_requires(
|
generate_requires(
|
||||||
freeze_output,
|
|
||||||
include_runtime=args.runtime,
|
include_runtime=args.runtime,
|
||||||
toxenv=args.toxenv,
|
toxenv=args.toxenv,
|
||||||
extras=args.extras,
|
extras=args.extras,
|
||||||
|
@ -6,6 +6,11 @@ import yaml
|
|||||||
|
|
||||||
from pyproject_buildrequires import generate_requires
|
from pyproject_buildrequires import generate_requires
|
||||||
|
|
||||||
|
try:
|
||||||
|
import importlib.metadata as importlib_metadata
|
||||||
|
except ImportError:
|
||||||
|
import importlib_metadata
|
||||||
|
|
||||||
testcases = {}
|
testcases = {}
|
||||||
with Path(__file__).parent.joinpath('testcases.yaml').open() as f:
|
with Path(__file__).parent.joinpath('testcases.yaml').open() as f:
|
||||||
testcases = yaml.safe_load(f)
|
testcases = yaml.safe_load(f)
|
||||||
@ -26,9 +31,17 @@ def test_data(case_name, capsys, tmp_path, monkeypatch):
|
|||||||
if filename in case:
|
if filename in case:
|
||||||
cwd.joinpath(filename).write_text(case[filename])
|
cwd.joinpath(filename).write_text(case[filename])
|
||||||
|
|
||||||
|
def get_installed_version(dist_name):
|
||||||
|
try:
|
||||||
|
return str(case['installed'][dist_name])
|
||||||
|
except (KeyError, TypeError):
|
||||||
|
raise importlib_metadata.PackageNotFoundError(
|
||||||
|
f'info not found for {dist_name}'
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
generate_requires(
|
generate_requires(
|
||||||
case['freeze_output'],
|
get_installed_version=get_installed_version,
|
||||||
include_runtime=case.get('include_runtime', False),
|
include_runtime=case.get('include_runtime', False),
|
||||||
extras=case.get('extras', ''),
|
extras=case.get('extras', ''),
|
||||||
toxenv=case.get('toxenv', None),
|
toxenv=case.get('toxenv', None),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
No pyproject.toml, nothing installed:
|
No pyproject.toml, nothing installed:
|
||||||
freeze_output: |
|
installed:
|
||||||
# empty
|
# empty
|
||||||
expected: |
|
expected: |
|
||||||
python3dist(setuptools) >= 40.8
|
python3dist(setuptools) >= 40.8
|
||||||
@ -7,7 +7,7 @@ No pyproject.toml, nothing installed:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Nothing installed yet:
|
Nothing installed yet:
|
||||||
freeze_output: |
|
installed:
|
||||||
# empty
|
# empty
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
# empty
|
# empty
|
||||||
@ -17,9 +17,9 @@ Nothing installed yet:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Insufficient version of setuptools:
|
Insufficient version of setuptools:
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==5
|
setuptools: 5
|
||||||
wheel==1
|
wheel: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
# empty
|
# empty
|
||||||
expected: |
|
expected: |
|
||||||
@ -28,9 +28,9 @@ Insufficient version of setuptools:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Empty pyproject.toml, empty setup.py:
|
Empty pyproject.toml, empty setup.py:
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
setup.py: |
|
setup.py: |
|
||||||
expected: |
|
expected: |
|
||||||
python3dist(setuptools) >= 40.8
|
python3dist(setuptools) >= 40.8
|
||||||
@ -39,9 +39,9 @@ Empty pyproject.toml, empty setup.py:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Default build system, empty setup.py:
|
Default build system, empty setup.py:
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
# empty
|
# empty
|
||||||
setup.py: |
|
setup.py: |
|
||||||
@ -52,24 +52,24 @@ Default build system, empty setup.py:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Erroring setup.py:
|
Erroring setup.py:
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
setup.py: |
|
setup.py: |
|
||||||
exit(77)
|
exit(77)
|
||||||
result: 77
|
result: 77
|
||||||
|
|
||||||
Bad character in version:
|
Bad character in version:
|
||||||
freeze_output: |
|
installed: {}
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["pkg == 0.$.^.*"]
|
requires = ["pkg == 0.$.^.*"]
|
||||||
except: ValueError
|
except: ValueError
|
||||||
|
|
||||||
Build system dependencies in pyproject.toml:
|
Build system dependencies in pyproject.toml:
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = [
|
requires = [
|
||||||
@ -100,9 +100,9 @@ Build system dependencies in pyproject.toml:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Default build system, build dependencies in setup.py:
|
Default build system, build dependencies in setup.py:
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
setup.py: |
|
setup.py: |
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
setup(
|
setup(
|
||||||
@ -120,10 +120,10 @@ Default build system, build dependencies in setup.py:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Default build system, run dependencies in setup.py:
|
Default build system, run dependencies in setup.py:
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
pyyaml==1
|
pyyaml: 1
|
||||||
include_runtime: true
|
include_runtime: true
|
||||||
setup.py: |
|
setup.py: |
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
@ -143,10 +143,10 @@ Default build system, run dependencies in setup.py:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Run dependencies with extras (not selected):
|
Run dependencies with extras (not selected):
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
pyyaml==1
|
pyyaml: 1
|
||||||
include_runtime: true
|
include_runtime: true
|
||||||
setup.py: &pytest_setup_py |
|
setup.py: &pytest_setup_py |
|
||||||
# slightly abriged copy of pytest's setup.py
|
# slightly abriged copy of pytest's setup.py
|
||||||
@ -200,10 +200,10 @@ Run dependencies with extras (not selected):
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Run dependencies with extras (selected):
|
Run dependencies with extras (selected):
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
pyyaml==1
|
pyyaml: 1
|
||||||
include_runtime: true
|
include_runtime: true
|
||||||
extras: testing
|
extras: testing
|
||||||
setup.py: *pytest_setup_py
|
setup.py: *pytest_setup_py
|
||||||
@ -227,10 +227,10 @@ Run dependencies with extras (selected):
|
|||||||
|
|
||||||
Run dependencies with multiple extras:
|
Run dependencies with multiple extras:
|
||||||
xfail: requirement.marker.evaluate seems to not support multiple extras
|
xfail: requirement.marker.evaluate seems to not support multiple extras
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
pyyaml==1
|
pyyaml: 1
|
||||||
include_runtime: true
|
include_runtime: true
|
||||||
extras: testing,more-testing, even-more-testing , cool-feature
|
extras: testing,more-testing, even-more-testing , cool-feature
|
||||||
setup.py: |
|
setup.py: |
|
||||||
@ -246,19 +246,18 @@ Run dependencies with multiple extras:
|
|||||||
expected: |
|
expected: |
|
||||||
python3dist(setuptools) >= 40.8
|
python3dist(setuptools) >= 40.8
|
||||||
python3dist(wheel)
|
python3dist(wheel)
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(dep1)
|
python3dist(dep1)
|
||||||
python3dist(dep2)
|
python3dist(dep2)
|
||||||
python3dist(dep3)
|
python3dist(dep3)
|
||||||
python3dist(dep4)
|
python3dist(dep4)
|
||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
Tox depndencies:
|
Tox dependencies:
|
||||||
freeze_output: |
|
installed:
|
||||||
setuptools==50
|
setuptools: 50
|
||||||
wheel==1
|
wheel: 1
|
||||||
tox==3.5.3
|
tox: 3.5.3
|
||||||
tox-current-env==0.0.2
|
tox-current-env: 0.0.2
|
||||||
toxenv: py3
|
toxenv: py3
|
||||||
setup.py: |
|
setup.py: |
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
Loading…
Reference in New Issue
Block a user