Coverage for lintro / tools / implementations / pytest / pytest_option_validators.py: 64%
78 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Option validation functions for pytest tool.
3This module contains validation logic extracted from PytestTool.set_options()
4to improve maintainability and reduce file size.
5"""
7from lintro.tools.implementations.pytest.collection import (
8 get_parallel_workers_from_preset,
9)
12def validate_pytest_options(
13 verbose: bool | None = None,
14 tb: str | None = None,
15 maxfail: int | None = None,
16 no_header: bool | None = None,
17 disable_warnings: bool | None = None,
18 json_report: bool | None = None,
19 junitxml: str | None = None,
20 slow_test_threshold: float | None = None,
21 total_time_warning: float | None = None,
22 workers: str | None = None,
23 coverage_threshold: float | None = None,
24 auto_junitxml: bool | None = None,
25 detect_flaky: bool | None = None,
26 flaky_min_runs: int | None = None,
27 flaky_failure_rate: float | None = None,
28 html_report: str | None = None,
29 parallel_preset: str | None = None,
30 list_plugins: bool | None = None,
31 check_plugins: bool | None = None,
32 required_plugins: str | None = None,
33 coverage_html: str | None = None,
34 coverage_xml: str | None = None,
35 coverage_report: bool | None = None,
36 coverage_term_missing: bool | None = None,
37 collect_only: bool | None = None,
38 list_fixtures: bool | None = None,
39 fixture_info: str | None = None,
40 list_markers: bool | None = None,
41 parametrize_help: bool | None = None,
42 show_progress: bool | None = None,
43 timeout: int | None = None,
44 reruns: int | None = None,
45 reruns_delay: int | None = None,
46) -> None:
47 """Validate pytest-specific options.
49 Args:
50 verbose: Enable verbose output.
51 tb: Traceback format (short, long, auto, line, native).
52 maxfail: Stop after first N failures.
53 no_header: Disable header.
54 disable_warnings: Disable warnings.
55 json_report: Enable JSON report output.
56 junitxml: Path for JUnit XML output.
57 slow_test_threshold: Duration threshold in seconds for slow test warning
58 (default: 1.0).
59 total_time_warning: Total execution time threshold in seconds for warning
60 (default: 60.0).
61 workers: Number of parallel workers for pytest-xdist (auto, N, or None).
62 coverage_threshold: Minimum coverage percentage to require (0-100).
63 auto_junitxml: Auto-enable junitxml in CI environments (default: True).
64 detect_flaky: Enable flaky test detection (default: True).
65 flaky_min_runs: Minimum runs before detecting flaky tests (default: 3).
66 flaky_failure_rate: Minimum failure rate to consider flaky (default: 0.3).
67 html_report: Path for HTML report output (pytest-html plugin).
68 parallel_preset: Parallel execution preset (auto, small, medium, large).
69 list_plugins: List all installed pytest plugins.
70 check_plugins: Check if required plugins are installed.
71 required_plugins: Comma-separated list of required plugin names.
72 coverage_html: Path for HTML coverage report (requires pytest-cov).
73 coverage_xml: Path for XML coverage report (requires pytest-cov).
74 coverage_report: Generate both HTML and XML coverage reports.
75 coverage_term_missing: Show coverage report in terminal with missing lines.
76 collect_only: List tests without executing them.
77 list_fixtures: List all available fixtures.
78 fixture_info: Show detailed information about a specific fixture.
79 list_markers: List all available markers.
80 parametrize_help: Show help for parametrized tests.
81 show_progress: Show progress during test execution.
82 timeout: Timeout in seconds for individual tests (pytest-timeout plugin).
83 reruns: Number of times to retry failed tests (pytest-rerunfailures plugin).
84 reruns_delay: Delay in seconds between retries (pytest-rerunfailures plugin).
86 Raises:
87 ValueError: If an option value is invalid.
88 """
89 if verbose is not None and not isinstance(verbose, bool):
90 raise ValueError("verbose must be a boolean")
92 if tb is not None and tb not in ("short", "long", "auto", "line", "native"):
93 raise ValueError("tb must be one of: short, long, auto, line, native")
95 if maxfail is not None and (not isinstance(maxfail, int) or maxfail <= 0):
96 raise ValueError("maxfail must be a positive integer")
98 if no_header is not None and not isinstance(no_header, bool):
99 raise ValueError("no_header must be a boolean")
101 if disable_warnings is not None and not isinstance(disable_warnings, bool):
102 raise ValueError("disable_warnings must be a boolean")
104 if json_report is not None and not isinstance(json_report, bool):
105 raise ValueError("json_report must be a boolean")
107 if junitxml is not None and not isinstance(junitxml, str):
108 raise ValueError("junitxml must be a string")
110 if slow_test_threshold is not None and (
111 not isinstance(slow_test_threshold, (int, float)) or slow_test_threshold < 0
112 ):
113 raise ValueError("slow_test_threshold must be a non-negative number")
115 if total_time_warning is not None and (
116 not isinstance(total_time_warning, (int, float)) or total_time_warning < 0
117 ):
118 raise ValueError("total_time_warning must be a non-negative number")
120 if workers is not None and not isinstance(workers, (str, int)):
121 raise ValueError(
122 f"workers must be a string or integer (e.g., 'auto', '2', 4), "
123 f"got {type(workers).__name__}: {workers!r}",
124 )
126 if coverage_threshold is not None and not isinstance(
127 coverage_threshold,
128 (int, float),
129 ):
130 raise ValueError("coverage_threshold must be a number")
131 if coverage_threshold is not None and not (0 <= coverage_threshold <= 100):
132 raise ValueError("coverage_threshold must be between 0 and 100")
134 if auto_junitxml is not None and not isinstance(auto_junitxml, bool):
135 raise ValueError("auto_junitxml must be a boolean")
137 if detect_flaky is not None and not isinstance(detect_flaky, bool):
138 raise ValueError("detect_flaky must be a boolean")
140 if flaky_min_runs is not None and (
141 not isinstance(flaky_min_runs, int) or flaky_min_runs < 1
142 ):
143 raise ValueError("flaky_min_runs must be a positive integer")
145 if flaky_failure_rate is not None:
146 if not isinstance(flaky_failure_rate, (int, float)):
147 raise ValueError("flaky_failure_rate must be a number")
148 if not (0 <= flaky_failure_rate <= 1):
149 raise ValueError("flaky_failure_rate must be between 0 and 1")
151 if html_report is not None and not isinstance(html_report, str):
152 raise ValueError("html_report must be a string (path to HTML report)")
154 if parallel_preset is not None and not isinstance(parallel_preset, str):
155 raise ValueError("parallel_preset must be a string")
156 # Validate preset value
157 if parallel_preset is not None:
158 try:
159 get_parallel_workers_from_preset(parallel_preset)
160 except ValueError as e:
161 raise ValueError(f"Invalid parallel_preset: {e}") from e
163 # Validate plugin options
164 if list_plugins is not None and not isinstance(list_plugins, bool):
165 raise ValueError("list_plugins must be a boolean")
167 if check_plugins is not None and not isinstance(check_plugins, bool):
168 raise ValueError("check_plugins must be a boolean")
170 if required_plugins is not None and not isinstance(required_plugins, str):
171 raise ValueError("required_plugins must be a string")
173 # Validate coverage options
174 if coverage_html is not None and not isinstance(coverage_html, str):
175 raise ValueError("coverage_html must be a string")
177 if coverage_xml is not None and not isinstance(coverage_xml, str):
178 raise ValueError("coverage_xml must be a string")
180 if coverage_report is not None and not isinstance(coverage_report, bool):
181 raise ValueError("coverage_report must be a boolean")
183 if coverage_term_missing is not None and not isinstance(
184 coverage_term_missing,
185 bool,
186 ):
187 raise ValueError("coverage_term_missing must be a boolean")
189 # Validate discovery and inspection options
190 if collect_only is not None and not isinstance(collect_only, bool):
191 raise ValueError("collect_only must be a boolean")
193 if list_fixtures is not None and not isinstance(list_fixtures, bool):
194 raise ValueError("list_fixtures must be a boolean")
196 if fixture_info is not None and not isinstance(fixture_info, str):
197 raise ValueError("fixture_info must be a string")
199 if list_markers is not None and not isinstance(list_markers, bool):
200 raise ValueError("list_markers must be a boolean")
202 if parametrize_help is not None and not isinstance(parametrize_help, bool):
203 raise ValueError("parametrize_help must be a boolean")
205 if show_progress is not None and not isinstance(show_progress, bool):
206 raise ValueError("show_progress must be a boolean")
208 # Validate plugin-specific options
209 if timeout is not None and (not isinstance(timeout, int) or timeout <= 0):
210 raise ValueError("timeout must be a positive integer (seconds)")
212 if reruns is not None and (not isinstance(reruns, int) or reruns < 0):
213 raise ValueError("reruns must be a non-negative integer")
215 if reruns_delay is not None and (
216 not isinstance(reruns_delay, int) or reruns_delay < 0
217 ):
218 raise ValueError("reruns_delay must be a non-negative integer (seconds)")