• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

psf / black / 6533516336

16 Oct 2023 12:24PM UTC coverage: 96.49%. Remained the same
6533516336

push

github

web-flow
Migrate mypy config to pyproject.toml (#3936)

Co-authored-by: Charles Patel <charles.patel@apkudo.com>

2 of 3 new or added lines in 3 files covered. (66.67%)

6625 of 6866 relevant lines covered (96.49%)

3.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.71
/tests/optional.py
1
"""
2
Allows configuring optional test markers in config, see pyproject.toml.
3

4
Run optional tests with `pytest --run-optional=...`.
5

6
Mark tests to run only if an optional test ISN'T selected by prepending the mark with
7
"no_".
8

9
You can specify a "no_" prefix straight in config, in which case you can mark tests
10
to run when this tests ISN'T selected by omitting the "no_" prefix.
11

12
Specifying the name of the default behavior in `--run-optional=` is harmless.
13

14
Adapted from https://pypi.org/project/pytest-optional-tests/, (c) 2019 Reece Hart
15
"""
16

17
import itertools
4✔
18
import logging
4✔
19
import re
4✔
20
from functools import lru_cache
4✔
21
from typing import TYPE_CHECKING, FrozenSet, List, Set
4✔
22

23
import pytest
4✔
24

25
try:
4✔
26
    from pytest import StashKey
4✔
27
except ImportError:
×
28
    # pytest < 7
NEW
29
    from _pytest.store import StoreKey as StashKey  # type: ignore[import, no-redef]
×
30

31
log = logging.getLogger(__name__)
4✔
32

33

34
if TYPE_CHECKING:
4✔
35
    from _pytest.config import Config
×
36
    from _pytest.config.argparsing import Parser
×
37
    from _pytest.mark.structures import MarkDecorator
×
38
    from _pytest.nodes import Node
×
39

40

41
ALL_POSSIBLE_OPTIONAL_MARKERS = StashKey[FrozenSet[str]]()
4✔
42
ENABLED_OPTIONAL_MARKERS = StashKey[FrozenSet[str]]()
4✔
43

44

45
def pytest_addoption(parser: "Parser") -> None:
4✔
46
    group = parser.getgroup("collect")
4✔
47
    group.addoption(
4✔
48
        "--run-optional",
49
        action="append",
50
        dest="run_optional",
51
        default=None,
52
        help="Optional test markers to run; comma-separated",
53
    )
54
    parser.addini("optional-tests", "List of optional tests markers", "linelist")
4✔
55

56

57
def pytest_configure(config: "Config") -> None:
4✔
58
    """Optional tests are markers.
59

60
    Use the syntax in https://docs.pytest.org/en/stable/mark.html#registering-marks.
61
    """
62
    ot_ini = config.inicfg.get("optional-tests") or []
4✔
63
    ot_markers = set()
4✔
64
    ot_run: Set[str] = set()
4✔
65
    if isinstance(ot_ini, str):
4✔
66
        ot_ini = ot_ini.strip().split("\n")
×
67
    marker_re = re.compile(r"^\s*(?P<no>no_)?(?P<marker>\w+)(:\s*(?P<description>.*))?")
4✔
68
    for ot in ot_ini:
4✔
69
        m = marker_re.match(ot)
4✔
70
        if not m:
4✔
71
            raise ValueError(f"{ot!r} doesn't match pytest marker syntax")
×
72

73
        marker = (m.group("no") or "") + m.group("marker")
4✔
74
        description = m.group("description")
4✔
75
        config.addinivalue_line("markers", f"{marker}: {description}")
4✔
76
        config.addinivalue_line(
4✔
77
            "markers", f"{no(marker)}: run when `{marker}` not passed"
78
        )
79
        ot_markers.add(marker)
4✔
80

81
    # collect requested optional tests
82
    passed_args = config.getoption("run_optional")
4✔
83
    if passed_args:
4✔
84
        ot_run.update(itertools.chain.from_iterable(a.split(",") for a in passed_args))
4✔
85
    ot_run |= {no(excluded) for excluded in ot_markers - ot_run}
4✔
86
    ot_markers |= {no(m) for m in ot_markers}
4✔
87

88
    log.info("optional tests to run:", ot_run)
4✔
89
    unknown_tests = ot_run - ot_markers
4✔
90
    if unknown_tests:
4✔
91
        raise ValueError(f"Unknown optional tests wanted: {unknown_tests!r}")
×
92

93
    store = config._store
4✔
94
    store[ALL_POSSIBLE_OPTIONAL_MARKERS] = frozenset(ot_markers)
4✔
95
    store[ENABLED_OPTIONAL_MARKERS] = frozenset(ot_run)
4✔
96

97

98
def pytest_collection_modifyitems(config: "Config", items: "List[Node]") -> None:
4✔
99
    store = config._store
4✔
100
    all_possible_optional_markers = store[ALL_POSSIBLE_OPTIONAL_MARKERS]
4✔
101
    enabled_optional_markers = store[ENABLED_OPTIONAL_MARKERS]
4✔
102

103
    for item in items:
4✔
104
        all_markers_on_test = {m.name for m in item.iter_markers()}
4✔
105
        optional_markers_on_test = all_markers_on_test & all_possible_optional_markers
4✔
106
        if not optional_markers_on_test or (
4✔
107
            optional_markers_on_test & enabled_optional_markers
108
        ):
109
            continue
4✔
110
        log.info("skipping non-requested optional", item)
4✔
111
        item.add_marker(skip_mark(frozenset(optional_markers_on_test)))
4✔
112

113

114
@lru_cache()
4✔
115
def skip_mark(tests: FrozenSet[str]) -> "MarkDecorator":
4✔
116
    names = ", ".join(sorted(tests))
4✔
117
    return pytest.mark.skip(reason=f"Marked with disabled optional tests ({names})")
4✔
118

119

120
@lru_cache()
4✔
121
def no(name: str) -> str:
4✔
122
    if name.startswith("no_"):
4✔
123
        return name[len("no_") :]
4✔
124
    return "no_" + name
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc