Add `skipon_spawn_backend` pytest marker
A reusable `@pytest.mark.skipon_spawn_backend( '<backend>' [, ...],
reason='...')` marker for backend-specific known-hang / -borked cases
— avoids scattering `@pytest.mark.skipif(lambda ...)` branches across
tests that misbehave under a particular `--spawn-backend`.
Deats,
- `pytest_configure()` registers the marker via
`addinivalue_line('markers', ...)`.
- New `pytest_collection_modifyitems()` hook walks
each collected item with `item.iter_markers(
name='skipon_spawn_backend')`, checks whether the
active `--spawn-backend` appears in `mark.args`, and
if so injects a concrete `pytest.mark.skip(
reason=...)`. `iter_markers()` makes the decorator
work at function, class, or module (`pytestmark =
[...]`) scope transparently.
- First matching mark wins; default reason is
`f'Borked on --spawn-backend={backend!r}'` if the
caller doesn't supply one.
Also, tighten type annotations on nearby `pytest`
integration points — `pytest_configure`, `debug_mode`,
`spawn_backend`, `tpt_protos`, `tpt_proto` — now taking
typed `pytest.Config` / `pytest.FixtureRequest` params.
(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
subint_forkserver_backend
parent
f3cea714bc
commit
3b26b59dad
|
|
@ -224,8 +224,10 @@ def pytest_addoption(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(
|
||||||
backend = config.option.spawn_backend
|
config: pytest.Config,
|
||||||
|
):
|
||||||
|
backend: str = config.option.spawn_backend
|
||||||
from tractor.spawn._spawn import try_set_start_method
|
from tractor.spawn._spawn import try_set_start_method
|
||||||
try:
|
try:
|
||||||
try_set_start_method(backend)
|
try_set_start_method(backend)
|
||||||
|
|
@ -241,10 +243,52 @@ def pytest_configure(config):
|
||||||
'markers',
|
'markers',
|
||||||
'no_tpt(proto_key): test will (likely) not behave with tpt backend'
|
'no_tpt(proto_key): test will (likely) not behave with tpt backend'
|
||||||
)
|
)
|
||||||
|
config.addinivalue_line(
|
||||||
|
'markers',
|
||||||
|
'skipon_spawn_backend(*start_methods, reason=None): '
|
||||||
|
'skip this test under any of the given `--spawn-backend` '
|
||||||
|
'values; useful for backend-specific known-hang / -borked '
|
||||||
|
'cases (e.g. the `subint` GIL-starvation class documented '
|
||||||
|
'in `ai/conc-anal/subint_sigint_starvation_issue.md`).'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_collection_modifyitems(
|
||||||
|
config: pytest.Config,
|
||||||
|
items: list[pytest.Function],
|
||||||
|
):
|
||||||
|
'''
|
||||||
|
Expand any `@pytest.mark.skipon_spawn_backend('<backend>'[,
|
||||||
|
...], reason='...')` markers into concrete
|
||||||
|
`pytest.mark.skip(reason=...)` calls for tests whose
|
||||||
|
backend-arg set contains the active `--spawn-backend`.
|
||||||
|
|
||||||
|
Uses `item.iter_markers(name=...)` which walks function +
|
||||||
|
class + module-level marks in the correct scope order (and
|
||||||
|
handles both the single-`MarkDecorator` and `list[Mark]`
|
||||||
|
forms of a module-level `pytestmark`) — so the same marker
|
||||||
|
works at any level a user puts it.
|
||||||
|
|
||||||
|
'''
|
||||||
|
backend: str = config.option.spawn_backend
|
||||||
|
default_reason: str = f'Borked on --spawn-backend={backend!r}'
|
||||||
|
for item in items:
|
||||||
|
for mark in item.iter_markers(name='skipon_spawn_backend'):
|
||||||
|
if backend in mark.args:
|
||||||
|
reason: str = mark.kwargs.get(
|
||||||
|
'reason',
|
||||||
|
default_reason,
|
||||||
|
)
|
||||||
|
item.add_marker(pytest.mark.skip(reason=reason))
|
||||||
|
# first matching mark wins; no value in stacking
|
||||||
|
# multiple `skip`s on the same item.
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def debug_mode(request) -> bool:
|
def debug_mode(
|
||||||
|
request: pytest.FixtureRequest,
|
||||||
|
) -> bool:
|
||||||
'''
|
'''
|
||||||
Flag state for whether `--tpdb` (for `tractor`-py-debugger)
|
Flag state for whether `--tpdb` (for `tractor`-py-debugger)
|
||||||
was passed to the test run.
|
was passed to the test run.
|
||||||
|
|
@ -258,12 +302,16 @@ def debug_mode(request) -> bool:
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def spawn_backend(request) -> str:
|
def spawn_backend(
|
||||||
|
request: pytest.FixtureRequest,
|
||||||
|
) -> str:
|
||||||
return request.config.option.spawn_backend
|
return request.config.option.spawn_backend
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def tpt_protos(request) -> list[str]:
|
def tpt_protos(
|
||||||
|
request: pytest.FixtureRequest,
|
||||||
|
) -> list[str]:
|
||||||
|
|
||||||
# allow quoting on CLI
|
# allow quoting on CLI
|
||||||
proto_keys: list[str] = [
|
proto_keys: list[str] = [
|
||||||
|
|
@ -291,7 +339,7 @@ def tpt_protos(request) -> list[str]:
|
||||||
autouse=True,
|
autouse=True,
|
||||||
)
|
)
|
||||||
def tpt_proto(
|
def tpt_proto(
|
||||||
request,
|
request: pytest.FixtureRequest,
|
||||||
tpt_protos: list[str],
|
tpt_protos: list[str],
|
||||||
) -> str:
|
) -> str:
|
||||||
proto_key: str = tpt_protos[0]
|
proto_key: str = tpt_protos[0]
|
||||||
|
|
@ -343,7 +391,6 @@ def pytest_generate_tests(
|
||||||
metafunc: pytest.Metafunc,
|
metafunc: pytest.Metafunc,
|
||||||
):
|
):
|
||||||
spawn_backend: str = metafunc.config.option.spawn_backend
|
spawn_backend: str = metafunc.config.option.spawn_backend
|
||||||
|
|
||||||
if not spawn_backend:
|
if not spawn_backend:
|
||||||
# XXX some weird windows bug with `pytest`?
|
# XXX some weird windows bug with `pytest`?
|
||||||
spawn_backend = 'trio'
|
spawn_backend = 'trio'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue