From bc156c44600a3d5433cdb1b1ebe2e85f934db706 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 17 Jul 2019 18:16:16 +0200 Subject: [PATCH] Generate run-time requirements for tests --- macros.pyproject | 6 ++++-- pyproject-rpm-macros.spec | 2 ++ pyproject_buildrequires.py | 31 ++++++++++++++++++++++++------- test_pyproject_buildrequires.py | 3 +++ testcases.yaml | 26 +++++++++++++++++++++++++- tests/python-entrypoints.spec | 3 ++- tests/python-pytest.spec | 2 +- 7 files changed, 61 insertions(+), 12 deletions(-) diff --git a/macros.pyproject b/macros.pyproject index 6679b8e..9ddd652 100644 --- a/macros.pyproject +++ b/macros.pyproject @@ -17,12 +17,14 @@ if [ -d %{buildroot}%{python3_sitearch} ]; then fi } -%pyproject_buildrequires() %{expand:\\\ +%pyproject_buildrequires(r) %{expand:\\\ echo 'python3-devel' echo 'python3dist(packaging)' echo 'python3dist(pip) >= 19' echo 'python3dist(pytoml)' +# setuptools assumes no pre-existing dist-info +rm -rfv *.dist-info/ if [ -f %{__python3} ]; then - %{__python3} -I %{_rpmconfigdir}/redhat/pyproject_buildrequires.py %{?*} + %{__python3} -I %{_rpmconfigdir}/redhat/pyproject_buildrequires.py %{?**} fi } diff --git a/pyproject-rpm-macros.spec b/pyproject-rpm-macros.spec index 09433cb..fd2b805 100644 --- a/pyproject-rpm-macros.spec +++ b/pyproject-rpm-macros.spec @@ -34,6 +34,8 @@ BuildRequires: python3dist(pyyaml) BuildRequires: python3dist(packaging) BuildRequires: python3dist(pytoml) BuildRequires: python3dist(pip) +BuildRequires: python3dist(setuptools) +BuildRequires: python3dist(wheel) %endif diff --git a/pyproject_buildrequires.py b/pyproject_buildrequires.py index 45155c3..d4e3879 100644 --- a/pyproject_buildrequires.py +++ b/pyproject_buildrequires.py @@ -8,6 +8,7 @@ from io import StringIO import subprocess import pathlib import re +import email.parser print_err = functools.partial(print, file=sys.stderr) @@ -83,7 +84,6 @@ class Requirements: key=lambda s: (s.operator, s.version), ): version = canonicalize_version(specifier.version) - print_err(version) if not VERSION_RE.fullmatch(str(specifier.version)): raise ValueError( f'Unknown character in version: {specifier.version}. ' @@ -154,6 +154,22 @@ def generate_build_requirements(backend, requirements): requirements.extend(new_reqs, source='get_requires_for_build_wheel') +def generate_run_requirements(backend, requirements): + prepare_metadata = getattr(backend, "prepare_metadata_for_build_wheel", None) + if not prepare_metadata: + raise ValueError( + 'build backend cannot provide build metadata ' + + '(incl. runtime requirements) before buld' + ) + with hook_call(): + dir_basename = prepare_metadata('.') + with open(dir_basename + '/METADATA') as f: + message = email.parser.Parser().parse(f, headersonly=True) + for key in 'Requires', 'Requires-Dist': + requires = message.get_all(key, ()) + requirements.extend(requires, source=f'wheel metadata: {key}') + + def python3dist(name, op=None, version=None): if op is None: if version is not None: @@ -163,12 +179,14 @@ def python3dist(name, op=None, version=None): return f'python3dist({name}) {op} {version}' -def generate_requires(freeze_output): +def generate_requires(freeze_output, *, include_runtime=False, toxenv=None): requirements = Requirements(freeze_output) try: backend = get_backend(requirements) generate_build_requirements(backend, requirements) + if include_runtime: + generate_run_requirements(backend, requirements) except EndPass: return @@ -178,11 +196,11 @@ def main(argv): description='Generate BuildRequires for a Python project.' ) parser.add_argument( - '--runtime', action='store_true', + '-r', '--runtime', action='store_true', help='Generate run-time requirements (not implemented)', ) parser.add_argument( - '--toxenv', metavar='TOXENVS', + '-t', '--toxenv', metavar='TOXENVS', help='generate test tequirements from tox environment ' + '(not implemented; implies --runtime)', ) @@ -190,8 +208,7 @@ def main(argv): args = parser.parse_args(argv) if args.toxenv: args.runtime = True - if args.runtime: - print_err('--runtime is not implemented') + print_err('--toxenv is not implemented') exit(1) freeze_output = subprocess.run( @@ -202,7 +219,7 @@ def main(argv): ).stdout try: - generate_requires(freeze_output) + generate_requires(freeze_output, include_runtime=args.runtime) except Exception as e: # Log the traceback explicitly (it's useful debug info) traceback.print_exc() diff --git a/test_pyproject_buildrequires.py b/test_pyproject_buildrequires.py index edc17c5..225d1c3 100644 --- a/test_pyproject_buildrequires.py +++ b/test_pyproject_buildrequires.py @@ -28,10 +28,13 @@ def test_data(case_name, capsys, tmp_path, monkeypatch): try: generate_requires( case['freeze_output'], + include_runtime=case.get('include_runtime', False), ) except SystemExit as e: assert e.code == case['result'] except Exception as e: + if 'except' not in case: + raise assert type(e).__name__ == case['except'] else: assert 0 == case['result'] diff --git a/testcases.yaml b/testcases.yaml index 6b6d5fc..8291074 100644 --- a/testcases.yaml +++ b/testcases.yaml @@ -99,7 +99,7 @@ Build system dependencies in pyproject.toml: python3dist(wheel) result: 0 -Default build system, dependencies in setup.py: +Default build system, build dependencies in setup.py: freeze_output: | setuptools==50 wheel==1 @@ -109,6 +109,7 @@ Default build system, dependencies in setup.py: name='test', version='0.1', setup_requires=['foo', 'bar!=2'], + install_requires=['inst'], ) expected: | python3dist(setuptools) >= 40.8 @@ -117,3 +118,26 @@ Default build system, dependencies in setup.py: python3dist(foo) (python3dist(bar) < 2 or python3dist(bar) > 2.0) result: 0 + +Default build system, run dependencies in setup.py: + freeze_output: | + setuptools==50 + wheel==1 + pyyaml==1 + include_runtime: true + setup.py: | + from setuptools import setup + setup( + name='test', + version='0.1', + setup_requires=['pyyaml'], # nb. setuptools will try to install this + install_requires=['inst > 1', 'inst2 < 3'], + ) + expected: | + python3dist(setuptools) >= 40.8 + python3dist(wheel) + python3dist(wheel) + python3dist(pyyaml) + python3dist(inst) > 1 + python3dist(inst2) < 3 + result: 0 diff --git a/tests/python-entrypoints.spec b/tests/python-entrypoints.spec index ff52bb7..e99a433 100644 --- a/tests/python-entrypoints.spec +++ b/tests/python-entrypoints.spec @@ -27,7 +27,8 @@ Discover and load entry points from installed packages. %generate_buildrequires -%pyproject_buildrequires +rm -rfv *.dist-info/ +%pyproject_buildrequires -r %build diff --git a/tests/python-pytest.spec b/tests/python-pytest.spec index beb9b8e..e427ccf 100644 --- a/tests/python-pytest.spec +++ b/tests/python-pytest.spec @@ -27,7 +27,7 @@ py.test provides simple, yet powerful testing for Python. %generate_buildrequires -%pyproject_buildrequires +%pyproject_buildrequires -r %build