Optional tests are markers. Use the syntax in https://docs.pytest.org/en/stable/mark.html#registering-marks.
(config: "Config")
| 50 | |
| 51 | |
| 52 | def pytest_configure(config: "Config") -> None: |
| 53 | """Optional tests are markers. |
| 54 | |
| 55 | Use the syntax in https://docs.pytest.org/en/stable/mark.html#registering-marks. |
| 56 | """ |
| 57 | # Extract the configured optional-tests from pytest's ini config in a |
| 58 | # version-agnostic way. Depending on pytest version, the value can be a |
| 59 | # string, a list of strings, or a ConfigValue wrapper (with a `.value` attr). |
| 60 | raw_ot_ini: Any = config.inicfg.get("optional-tests") |
| 61 | ot_ini_lines: list[str] = [] |
| 62 | if raw_ot_ini: |
| 63 | value = getattr(raw_ot_ini, "value", raw_ot_ini) |
| 64 | if isinstance(value, str): |
| 65 | ot_ini_lines = value.strip().split("\n") |
| 66 | elif isinstance(value, list): |
| 67 | # Best-effort coercion to strings; pytest inis are textual. |
| 68 | ot_ini_lines = [str(v) for v in value] |
| 69 | else: |
| 70 | # Fallback: ignore unexpected shapes (non-iterable, etc.). |
| 71 | ot_ini_lines = [] |
| 72 | |
| 73 | ot_markers: set[str] = set() |
| 74 | ot_run: set[str] = set() |
| 75 | marker_re = re.compile(r"^\s*(?P<no>no_)?(?P<marker>\w+)(:\s*(?P<description>.*))?") |
| 76 | # Iterate over configured markers discovered above. |
| 77 | for ot in ot_ini_lines: |
| 78 | m = marker_re.match(ot) |
| 79 | if not m: |
| 80 | raise ValueError(f"{ot!r} doesn't match pytest marker syntax") |
| 81 | |
| 82 | marker = (m.group("no") or "") + m.group("marker") |
| 83 | description = m.group("description") |
| 84 | config.addinivalue_line("markers", f"{marker}: {description}") |
| 85 | config.addinivalue_line( |
| 86 | "markers", f"{no(marker)}: run when `{marker}` not passed" |
| 87 | ) |
| 88 | ot_markers.add(marker) |
| 89 | |
| 90 | # collect requested optional tests |
| 91 | passed_args = config.getoption("run_optional") |
| 92 | if passed_args: |
| 93 | ot_run.update(itertools.chain.from_iterable(a.split(",") for a in passed_args)) |
| 94 | ot_run |= {no(excluded) for excluded in ot_markers - ot_run} |
| 95 | ot_markers |= {no(m) for m in ot_markers} |
| 96 | |
| 97 | log.info("optional tests to run: %s", ot_run) |
| 98 | unknown_tests = ot_run - ot_markers |
| 99 | if unknown_tests: |
| 100 | raise ValueError(f"Unknown optional tests wanted: {unknown_tests!r}") |
| 101 | |
| 102 | store = config._store |
| 103 | store[ALL_POSSIBLE_OPTIONAL_MARKERS] = frozenset(ot_markers) |
| 104 | store[ENABLED_OPTIONAL_MARKERS] = frozenset(ot_run) |
| 105 | |
| 106 | |
| 107 | def pytest_collection_modifyitems(config: "Config", items: "list[Node]") -> None: |