-
Notifications
You must be signed in to change notification settings - Fork 194
Expand file tree
/
Copy pathconftest.py
More file actions
70 lines (55 loc) · 2.44 KB
/
Copy pathconftest.py
File metadata and controls
70 lines (55 loc) · 2.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""Sybil-powered doctest for README.md.
Validates that Python code blocks in the project README remain importable
and syntactically valid after refactors.
This conftest lives at the project root so Sybil can discover README.md
relative to its path. It is picked up because pyproject.toml includes
"README.md" in testpaths.
"""
import pytest
from sybil import Sybil
from sybil.parsers.markdown.clear import ClearNamespaceParser
from sybil.parsers.markdown.codeblock import PythonCodeBlockParser
from sybil.parsers.markdown.skip import SkipParser
pytest_collect_file = Sybil(
parsers=[PythonCodeBlockParser(), SkipParser(), ClearNamespaceParser()],
path=".",
patterns=["README.md"],
excludes=["*/README.md"],
).pytest()
_EXPECTED_LINE_PARTS = 2
@pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(items: list[pytest.Item]) -> None:
"""Restore document order for README.md sybil items and pin them to one xdist worker.
Sybil's skip directive state is tracked per-document and depends on sequential, ordered
evaluation. Two pytest plugins break this:
- pytest-randomly reorders items, breaking the skip state machine.
- pytest-xdist distributes items across workers, so each worker sees
an unbalanced subset of skip:start/skip:end pairs.
This hook runs before pytest-randomly's shuffle (``tryfirst=True``) and uses
``pytest.mark.order(N)`` to pin each README item to its document position. pytest-order
(``trylast=True`` by default) then re-orders these items back into sequence after the random
shuffle.
It also marks them with a shared ``xdist_group`` so ``--dist=loadgroup`` sends them to a single
worker.
"""
readme_items = []
other_items = []
for item in items:
if "README.md" in item.nodeid:
readme_items.append(item)
else:
other_items.append(item)
# Sort README items by line number to restore document order
def readme_sort_key(item: pytest.Item) -> int:
parts = item.nodeid.split("line:")
if len(parts) == _EXPECTED_LINE_PARTS:
try:
return int(parts[1].split(",")[0])
except ValueError:
return 0
return 0
readme_items.sort(key=readme_sort_key)
for index, item in enumerate(readme_items):
item.add_marker(pytest.mark.order(index))
item.add_marker(pytest.mark.xdist_group("readme_sybil"))
items[:] = readme_items + other_items