Skip to content

Commit aa0f816

Browse files
committed
feat: UV venv support.
Signed-off-by: Mateusz Chrominski <mateusz.chrominski@intel.com>
1 parent d461ab6 commit aa0f816

File tree

3 files changed

+145
-36
lines changed

3 files changed

+145
-36
lines changed

mfd_code_quality/code_standard/checks.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,21 @@ def _get_available_code_standard_module() -> str:
5858
:raises Exception: When no code standard module is available
5959
"""
6060
code_standard_modules = ["ruff", "flake8"]
61-
pip_list = run((sys.executable, "-m", "pip", "list"), capture_output=True, text=True, cwd=get_root_dir())
62-
for code_standard_module in code_standard_modules:
63-
if f"{code_standard_module} " in pip_list.stdout:
64-
logger.info(f"{code_standard_module.capitalize()} will be used for code standard check.")
65-
return code_standard_module
61+
commands = [("uv", "pip", "list"), (sys.executable, "-m", "pip", "list")]
62+
for cmd in commands:
63+
try:
64+
pip_list = run(cmd, capture_output=True, text=True, cwd=get_root_dir())
65+
except Exception as e: # noqa
66+
logger.debug(f"Error occurred while running {cmd}:\n{e}")
67+
continue
68+
69+
if pip_list.returncode != 0:
70+
continue
71+
72+
for code_standard_module in code_standard_modules:
73+
if f"{code_standard_module} " in pip_list.stdout:
74+
logger.info(f"{code_standard_module.capitalize()} will be used for code standard check.")
75+
return code_standard_module
6676

6777
raise Exception("No code standard module is available! [flake8 or ruff]")
6878

tests/unit/test_mfd_code_quality/test_code_standard/test_checks.py

Lines changed: 124 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,75 +3,169 @@
33
from textwrap import dedent
44

55
import logging
6+
import sys
7+
68
import pytest
79

8-
from mfd_code_quality.code_standard.checks import _get_available_code_standard_module, _test_ruff_check, run_checks
10+
from mfd_code_quality.code_standard.checks import (
11+
_get_available_code_standard_module,
12+
_run_code_standard_tests,
13+
_test_ruff_check,
14+
)
915

1016

1117
class TestChecks:
1218
def test_get_available_code_standard_module_flake8(self, mocker):
13-
output = dedent(
14-
"""\
15-
flake8 7.1.1
16-
flake8-annotations 3.0.1
17-
flake8-black 0.2.4
18-
"""
19+
"""flake8 is chosen when ruff is not present but flake8 is."""
20+
# First command (uv pip list) returns no ruff / flake8
21+
mocker.patch(
22+
"mfd_code_quality.code_standard.checks.run",
23+
side_effect=[
24+
mocker.Mock(stdout="", returncode=0),
25+
mocker.Mock(
26+
stdout=dedent(
27+
"""\
28+
flake8 7.1.1
29+
flake8-annotations 3.0.1
30+
flake8-black 0.2.4
31+
"""
32+
),
33+
returncode=0,
34+
),
35+
],
1936
)
20-
mocker.patch("mfd_code_quality.code_standard.checks.run", return_value=mocker.Mock(stdout=output))
2137
mocker.patch("mfd_code_quality.code_standard.checks.get_root_dir", return_value="/path/to/root")
38+
2239
assert _get_available_code_standard_module() == "flake8"
2340

24-
def test_get_available_code_standard_module_ruff(self, mocker):
41+
def test_get_available_code_standard_module_ruff_preferred(self, mocker):
42+
"""Ruff is preferred when both ruff and flake8 are installed."""
2543
output = dedent(
2644
"""\
2745
ruff 0.6.4
46+
flake8 7.1.1
2847
flake8-annotations 3.0.1
2948
flake8-black 0.2.4
3049
"""
3150
)
32-
mocker.patch("mfd_code_quality.code_standard.checks.run", return_value=mocker.Mock(stdout=output))
51+
mocker.patch(
52+
"mfd_code_quality.code_standard.checks.run",
53+
return_value=mocker.Mock(stdout=output, returncode=0),
54+
)
3355
mocker.patch("mfd_code_quality.code_standard.checks.get_root_dir", return_value="/path/to/root")
56+
3457
assert _get_available_code_standard_module() == "ruff"
3558

3659
def test_get_available_code_standard_module_none(self, mocker):
37-
mocker.patch("mfd_code_quality.code_standard.checks.run", return_value=mocker.Mock(stdout=""))
60+
mocker.patch(
61+
"mfd_code_quality.code_standard.checks.run",
62+
return_value=mocker.Mock(stdout="", returncode=0),
63+
)
3864
mocker.patch("mfd_code_quality.code_standard.checks.get_root_dir", return_value="/path/to/root")
3965
with pytest.raises(Exception) as excinfo:
4066
_get_available_code_standard_module()
4167
assert "No code standard module is available! [flake8 or ruff]" in str(excinfo.value)
4268

4369
def test__test_ruff_check_call(self, mocker, caplog):
4470
caplog.set_level(logging.INFO)
45-
mocker.patch("mfd_code_quality.code_standard.checks.run", return_value=mocker.Mock(returncode=1))
71+
mocker.patch(
72+
"mfd_code_quality.code_standard.checks.run",
73+
return_value=mocker.Mock(returncode=1, stdout=""),
74+
)
4675
mocker.patch("mfd_code_quality.code_standard.checks.get_root_dir", return_value="/path/to/root")
4776
_test_ruff_check()
4877
assert "Checking 'ruff check'..." in caplog.text
4978

50-
def test_run_checks_failure(self, mocker, caplog):
51-
output = dedent(
52-
"""\
53-
ruff 0.6.4
54-
"""
55-
)
56-
mocker.patch("mfd_code_quality.code_standard.checks.run", return_value=mocker.Mock(stdout=output))
57-
mocker.patch("mfd_code_quality.code_standard.checks.get_root_dir", return_value="/path/to/root")
58-
mocker.patch("mfd_code_quality.code_standard.checks.set_cwd")
59-
mocker.patch("mfd_code_quality.code_standard.checks.sys.exit", return_value=mocker.Mock())
79+
def test_run_code_standard_tests_failure_logs_and_returns_false(self, mocker, caplog):
80+
"""When ruff checks fail, helper returns False and logs failure message."""
6081
caplog.set_level(logging.INFO)
61-
run_checks(with_configs=False)
82+
mocker.patch("mfd_code_quality.code_standard.checks.set_up_logging")
83+
mocker.patch("mfd_code_quality.code_standard.checks.set_cwd")
84+
mocker.patch(
85+
"mfd_code_quality.code_standard.checks._get_available_code_standard_module",
86+
return_value="ruff",
87+
)
88+
mocker.patch(
89+
"mfd_code_quality.code_standard.checks._test_ruff_format",
90+
return_value=False,
91+
)
92+
mocker.patch(
93+
"mfd_code_quality.code_standard.checks._test_ruff_check",
94+
return_value=False,
95+
)
96+
delete_mock = mocker.patch("mfd_code_quality.code_standard.checks.delete_config_files")
97+
create_mock = mocker.patch("mfd_code_quality.code_standard.checks.create_config_files")
98+
99+
result = _run_code_standard_tests(with_configs=False)
100+
101+
assert result is False
62102
assert "Code standard check FAILED." in caplog.text
103+
# with_configs=False -> no config files should be touched
104+
create_mock.assert_not_called()
105+
delete_mock.assert_not_called()
63106

64-
def test_run_checks_with_configs(self, mocker):
65-
mocker.patch("mfd_code_quality.code_standard.checks.sys.exit", return_value=mocker.Mock())
66-
create_mock = mocker.patch("mfd_code_quality.code_standard.checks.create_config_files")
67-
delete_mock = mocker.patch("mfd_code_quality.code_standard.checks.delete_config_files")
107+
def test_run_code_standard_tests_with_configs_calls_create_and_delete(self, mocker, caplog):
108+
"""With configs enabled and ruff selected, config files are created and deleted in finally block."""
109+
caplog.set_level(logging.INFO)
110+
mocker.patch("mfd_code_quality.code_standard.checks.set_up_logging")
68111
mocker.patch("mfd_code_quality.code_standard.checks.set_cwd")
69112
mocker.patch(
70113
"mfd_code_quality.code_standard.checks._get_available_code_standard_module",
71114
return_value="ruff",
72115
)
73-
mocker.patch("mfd_code_quality.code_standard.checks._test_ruff_format", return_value=True)
74-
mocker.patch("mfd_code_quality.code_standard.checks._test_ruff_check", return_value=True)
75-
run_checks()
116+
mocker.patch(
117+
"mfd_code_quality.code_standard.checks._test_ruff_format",
118+
return_value=True,
119+
)
120+
mocker.patch(
121+
"mfd_code_quality.code_standard.checks._test_ruff_check",
122+
return_value=True,
123+
)
124+
create_mock = mocker.patch("mfd_code_quality.code_standard.checks.create_config_files")
125+
delete_mock = mocker.patch("mfd_code_quality.code_standard.checks.delete_config_files")
126+
127+
result = _run_code_standard_tests(with_configs=True)
128+
129+
assert result is True
76130
create_mock.assert_called_once()
77131
delete_mock.assert_called_once()
132+
133+
def test_run_checks_exits_with_correct_code(self, mocker):
134+
"""High-level run_checks exits with 0/1 depending on helper result."""
135+
from mfd_code_quality.code_standard import checks
136+
137+
mocker.patch.object(checks, "_run_code_standard_tests", return_value=True)
138+
exit_mock = mocker.patch.object(sys, "exit")
139+
140+
checks.run_checks(with_configs=True)
141+
142+
exit_mock.assert_called_once_with(0)
143+
144+
# Now simulate failure
145+
exit_mock.reset_mock()
146+
mocker.patch.object(checks, "_run_code_standard_tests", return_value=False)
147+
148+
checks.run_checks(with_configs=False)
149+
150+
exit_mock.assert_called_once_with(1)
151+
152+
def test_get_available_code_standard_module_uv_raises_then_fallback(self, mocker):
153+
"""If the first command raises (e.g. uv missing), fallback command is used."""
154+
mocker.patch(
155+
"mfd_code_quality.code_standard.checks.run",
156+
side_effect=[
157+
FileNotFoundError(), # simulates missing 'uv'
158+
mocker.Mock(
159+
stdout=dedent(
160+
"""\
161+
ruff 0.6.4
162+
flake8 7.1.1
163+
"""
164+
),
165+
returncode=0,
166+
),
167+
],
168+
)
169+
mocker.patch("mfd_code_quality.code_standard.checks.get_root_dir", return_value="/path/to/root")
170+
171+
assert _get_available_code_standard_module() == "ruff"

tests/unit/test_mfd_code_quality/test_mfd_code_quality.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@ def test_run_all_checks_with_flake8(mock_dependencies):
7171
)
7272

7373

74-
def test_log_help_info_logs_commands(caplog):
74+
def test_log_help_info_logs_commands(caplog, mocker):
75+
"""log_help_info should log available commands without parsing real CLI args."""
7576
caplog.set_level("INFO")
77+
# Prevent argparse in set_up_logging/get_parsed_args from seeing pytest/IDE args.
78+
mocker.patch("mfd_code_quality.utils.get_parsed_args", return_value=mocker.Mock(verbose=False))
79+
7680
log_help_info()
81+
7782
assert "Available commands:" in caplog.text

0 commit comments

Comments
 (0)