Coverage for src / mafw / devtools / cli / dependencies / oldest.py: 99%
55 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-06-28 13:34 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-06-28 13:34 +0000
1# Copyright 2026 European Union
2# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
3# SPDX-License-Identifier: EUPL-1.2
4"""Oldest-dependency verification commands."""
6from __future__ import annotations
8import shlex
9from typing import Final
11import click
13from mafw.devtools.dependencies.compile import (
14 ensure_mafw_project_root,
15 python_versions_between,
16)
17from mafw.devtools.dependencies.verify import (
18 get_expected_lower_bounds,
19 verify_lowest_resolution,
20)
21from mafw.tools.click_extensions import AbbreviateGroup, DeprecatedOption
22from mafw.tools.shell_tools import run as cmd
24DEFAULT_TEST_FILES: Final[list[str]] = [
25 'tests/test_full_integration.py',
26]
27"""List of test files executed by default during dependency verification."""
30@click.group(
31 context_settings={'help_option_names': ['-h', '--help']},
32 help='Placeholder commands for the oldest dependency stack.',
33 cls=AbbreviateGroup,
34)
35def oldest() -> None:
36 """Group for oldest-dependency commands."""
39@oldest.command(
40 name='check',
41 context_settings={'help_option_names': ['-h', '--help']},
42 help='Verify compatibility with oldest supported dependencies.',
43)
44@click.option(
45 '--min-python-ver',
46 default='3.11',
47 show_default=True,
48 type=click.STRING,
49 help='The oldest version of python to be used for the dependencies verification, constrain it to >=3.11',
50)
51@click.option(
52 '--max-python-ver',
53 default='3.14',
54 show_default=True,
55 type=click.STRING,
56 help='The newest version of python to be used for the dependencies verification',
57)
58@click.option(
59 '--full-unittest',
60 is_flag=True,
61 default=False,
62 show_default=True,
63 help='Perform the test over the whole test suite.',
64)
65@click.option(
66 '--preserve-envs',
67 'preserve_envs',
68 is_flag=True,
69 default=False,
70 show_default=True,
71 help='Preserve created hatch environments after the check is completed.',
72)
73@click.option(
74 '--remove-envs/--no-remove-envs',
75 'remove_envs',
76 default=True,
77 show_default=True,
78 cls=DeprecatedOption,
79 deprecated_message=(
80 '--remove-envs/--no-remove-envs is deprecated and will be removed in MAFw 3.0.0. Use --preserve-envs instead.'
81 ),
82 help='Remove or preserve environments after check.',
83)
84def check(
85 min_python_ver: str,
86 max_python_ver: str,
87 full_unittest: bool,
88 preserve_envs: bool,
89 remove_envs: bool,
90) -> None:
91 """Verify MAFw compatibility against the oldest supported dependency stack."""
92 # --- Conflict detection and resolution between --preserve-envs and --remove-envs ---
93 ctx = click.get_current_context()
94 preserve_source = ctx.get_parameter_source('preserve_envs')
95 remove_source = ctx.get_parameter_source('remove_envs')
97 if (
98 preserve_source == click.core.ParameterSource.COMMANDLINE
99 and remove_source == click.core.ParameterSource.COMMANDLINE
100 and remove_envs
101 ):
102 raise click.UsageError('--preserve-envs and --remove-envs are mutually exclusive.')
104 if preserve_source == click.core.ParameterSource.COMMANDLINE:
105 effective_preserve = True
106 elif remove_source == click.core.ParameterSource.COMMANDLINE:
107 effective_preserve = not remove_envs
108 else:
109 effective_preserve = False
111 supported_python_versions = ensure_mafw_project_root()
112 expected_bounds = get_expected_lower_bounds()
113 lowest_resolution = {'UV_RESOLUTION': 'lowest-direct'}
115 for python_version in python_versions_between(min_python_ver, max_python_ver, supported_python_versions):
116 # remove existing test envs
117 cmd_line = shlex.split(f'hatch env remove hatch-test.py{python_version}')
118 cmd(cmd_line)
120 # create test env with lowest-direct resolution
121 cmd_line = shlex.split(f'hatch env create hatch-test.py{python_version}')
122 cmd(cmd_line, env=lowest_resolution)
124 # verify that the freshly created environment has the right lowest resolution
125 verify_lowest_resolution('hatch-test', python_version, expected_bounds)
127 # run the test suite full or reduced
128 files_to_be_tested = []
129 if not full_unittest: 129 ↛ 131line 129 didn't jump to line 131 because the condition on line 129 was always true
130 files_to_be_tested = DEFAULT_TEST_FILES
131 cmd_line = shlex.split(f'hatch test -py {python_version}')
132 cmd(cmd_line + files_to_be_tested)
134 # remove existing typing env
135 cmd_line = shlex.split(f'hatch env remove types.py{python_version}')
136 cmd(cmd_line)
138 # create static typing env with lowest direct resolution
139 cmd_line = shlex.split(f'hatch env create types.py{python_version}')
140 cmd(cmd_line, env=lowest_resolution)
142 # verify that the freshly created environment has the right lowest resolution
143 verify_lowest_resolution('types', python_version, expected_bounds)
145 # run static typing
146 cmd_line = shlex.split(f'hatch run types.py{python_version}:check --python-version {python_version}')
147 cmd(cmd_line)
149 if not effective_preserve:
150 # remove environments
151 envs = ['hatch-test.py', 'types.py']
152 for env in envs:
153 cmd_line = shlex.split(f'hatch env remove {env}{python_version}')
154 cmd(cmd_line)