judgevet.testing._conformance_async_scope
Status: draft.
judgevet.testing._conformance_async_scope
Observers and checks for the asynchronous provider scope rules.
AsyncScopeRecorder wraps an AsyncProviderFactory and records every async
context it constructs. The kit observes entry and exit itself instead of
trusting the provider. exit_problem and body_problem drive
async_provider_scope and describe a broken lifecycle. Each returns None when
the provider keeps the rule. The synchronous kit's ScopeRecorder does the same
for a ProviderFactory. None of these import pytest.
Source: https://github.com/Alberto-Codes/judgevet/issues/251.
Examples:
from contextlib import nullcontext
import anyio
from judgevet.providers import async_provider_scope
from judgevet.testing import AsyncFakeSystemOnePort
from judgevet.testing._conformance_async_scope import (
AsyncScopeRecorder,
body_problem,
exit_problem,
)
recorder = AsyncScopeRecorder(lambda: nullcontext(AsyncFakeSystemOnePort()))
async def enter_once():
async with async_provider_scope(factory=recorder) as port:
assert callable(port.system_one)
anyio.run(enter_once)
assert recorder.contexts[0].exits == [None]
factory = lambda: nullcontext(AsyncFakeSystemOnePort())
assert anyio.run(exit_problem, factory) is None
assert anyio.run(body_problem, factory) is None
See Also
- judgevet.testing._conformance_async: The rules that use these checks
- judgevet.testing._conformance_probes: The synchronous
ScopeRecorder - judgevet.providers:
async_provider_scopeandAsyncProviderFactory
AsyncRecordedContext
Bases: AbstractAsyncContextManager[AsyncSystemOnePort]
Delegate to one async provider context and record its entry and exit.
Attributes:
| Name | Type | Description |
|---|---|---|
inner |
AbstractAsyncContextManager[AsyncSystemOnePort]
|
The provider's async context. |
enters |
int
|
How many times entry ran. |
exits |
list[BaseException | None]
|
The exception each exit received, or None for a clean exit. |
Examples:
from contextlib import nullcontext
import anyio
from judgevet.testing import AsyncFakeSystemOnePort
recorded = AsyncRecordedContext(nullcontext(AsyncFakeSystemOnePort()))
async def enter():
async with recorded:
pass
anyio.run(enter)
assert (recorded.enters, recorded.exits) == (1, [None])
__aenter__()
async
Count the entry and enter the provider context.
Returns:
| Type | Description |
|---|---|
AsyncSystemOnePort
|
The port the provider context yields. |
__aexit__(exc_type, exc, traceback)
async
Record the exit and pass the provider's suppression answer through.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exc_type
|
type[BaseException] | None
|
The escaping exception type, or None. |
required |
exc
|
BaseException | None
|
The escaping exception, or None. |
required |
traceback
|
TracebackType | None
|
The escaping traceback, or None. |
required |
Returns:
| Type | Description |
|---|---|
bool | None
|
The provider context's own return value. |
__init__(inner)
Wrap one async provider context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inner
|
AbstractAsyncContextManager[AsyncSystemOnePort]
|
The async context the provider factory returned. |
required |
AsyncScopeRecorder
Wrap an async provider factory and record every context it constructs.
Attributes:
| Name | Type | Description |
|---|---|---|
factory |
AsyncProviderFactory
|
The provider's own factory. |
contexts |
list[AsyncRecordedContext]
|
One recorder per factory call. |
Examples:
from contextlib import nullcontext
from judgevet.testing import AsyncFakeSystemOnePort
recorder = AsyncScopeRecorder(lambda: nullcontext(AsyncFakeSystemOnePort()))
recorder()
assert len(recorder.contexts) == 1
__call__()
Construct one provider context and start recording it.
Returns:
| Type | Description |
|---|---|
AsyncRecordedContext
|
A recorder that delegates to the new provider context. |
__init__(factory)
Store the provider factory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factory
|
AsyncProviderFactory
|
The provider's own factory. |
required |
body_problem(factory)
async
Raise inside a scope and describe a lost, replaced or suppressed error.
The check also enters one context directly, as AsyncProviderFactory
callers may, and requires that its exit does not suppress the error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factory
|
AsyncProviderFactory
|
The provider's factory. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
A failure message, or None when the body exception reaches the caller |
str | None
|
unchanged and the scope exits once with it. |
exit_problem(factory)
async
Enter two scopes and describe a shared context or a wrong exit count.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factory
|
AsyncProviderFactory
|
The provider's factory. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
A failure message, or None when each scope has its own context that |
str | None
|
entered once and exited once cleanly. |