judgevet.testing._conformance_async

Status: draft.

judgevet.testing._conformance_async

Reusable pytest conformance tests for an AsyncSystemOnePort provider.

BaseAsyncProviderConformance applies the nine rules of the synchronous kit to an asynchronous provider:

  • test_port_shape: system_one is callable with the port's positional and keyword arguments.
  • test_typed_answers_pass_policy: system_one returns an awaitable, and awaiting it gives a SystemOneResponse whose answers pass judgevet.policy.evaluate_policy.
  • test_failure_raises_provider_error: awaiting the failing port raises a ProviderError subclass.
  • test_scope_entry_yields_usable_port, test_scope_exit_runs_once and test_scope_propagates_body_exception: the factory keeps the async_provider_scope lifecycle rules.
  • test_media_refused_without_media_support: a port from the factory without every media method callable exposes no partial media surface, and async_judge_with_images refuses it with ProviderCapabilityError.
  • test_media_port_refuses_undeclared_media: async_judge_with_images refuses media outside the declared capabilities before any media dispatch.
  • test_media_port_judges_declared_media: system_one_media returns an awaitable, and one declared kit image returns answers that pass evaluate_policy.

Source: https://github.com/Alberto-Codes/judgevet/issues/251. Source: https://github.com/Alberto-Codes/judgevet/issues/252.

Each rule is an ordinary synchronous test method that drives its coroutine with anyio.run. The kit adds no pytest plugin, because AnyIO's pytest plugin and pytest-asyncio interfere when both are installed. Source: https://anyio.readthedocs.io/en/stable/testing.html. Source: https://github.com/agronholm/anyio/issues/328. Source: https://github.com/Alberto-Codes/judgevet/issues/246.

The kit's fixtures are synchronous. pytest-asyncio's auto mode runs a synchronous test that requests an asynchronous fixture, and its strict mode refuses one. Source: https://github.com/pytest-dev/pytest-asyncio/issues/1570.

The kit imports anyio directly, so the conformance extra declares it beside pytest. Source: https://github.com/Alberto-Codes/judgevet/issues/253#issuecomment-5904100904.

Examples:

from contextlib import nullcontext

import pytest

from judgevet.providers import ProviderTransportError
from judgevet.testing import AsyncFakeSystemOnePort
from judgevet.testing.conformance import (
    VALID_ANSWERS,
    BaseAsyncProviderConformance,
)


class TestAsyncFakeProvider(BaseAsyncProviderConformance):
    @pytest.fixture
    def provider_factory(self):
        return lambda: nullcontext(AsyncFakeSystemOnePort(answers=VALID_ANSWERS))

    @pytest.fixture
    def failing_port(self):
        return AsyncFakeSystemOnePort(error=ProviderTransportError("offline"))
See Also

BaseAsyncProviderConformance

Conformance rules an AsyncSystemOnePort provider inherits in its tests.

Name the subclass Test... so pytest collects it. Override the fixtures below as pytest fixtures on the subclass. Each rule enters one async with provider_factory() scope inside its own anyio.run call. The scope rules enter it through async_provider_scope and record each context the factory constructs.

Attributes:

Name Type Description
provider_factory fixture

Required. A zero-argument callable that returns an async context manager yielding a working port.

failing_port fixture

Required. A port configured so that every awaited system_one call fails.

provider_model fixture

The model label the kit passes. The default is CONFORMANCE_MODEL.

media_port fixture

Optional. An AsyncMediaSystemOnePort that both media-port rules check. The default is None, and then a media-capable port from provider_factory is used.

Examples:

class TestMyAsyncProvider(BaseAsyncProviderConformance):
    pass

failing_port()

Fail until the provider supplies a port configured to fail.

Raises:

Type Description
Exception

Always.

media_port()

Supply no dedicated media port, so the kit checks the factory's port.

provider_factory()

Fail until the provider supplies its factory.

Raises:

Type Description
Exception

Always.

provider_model()

Supply the kit's default model label.

Returns:

Type Description
str

The model label.

test_failure_raises_provider_error(failing_port, provider_model)

Rule 3: an awaited failed judgment raises a ProviderError subclass.

Parameters:

Name Type Description Default
failing_port AsyncSystemOnePort

The port configured to fail.

required
provider_model str

The selected model.

required

test_media_port_judges_declared_media(provider_factory, media_port, provider_model)

Rule 6: declared media reaches the port and returns typed answers.

A system_one_media that returns a value that is not awaitable fails this rule. The rule skips when the declaration admits no kit image.

Parameters:

Name Type Description Default
provider_factory AsyncProviderFactory

The provider's factory, used without a media port.

required
media_port AsyncMediaSystemOnePort | None

The dedicated media port, or None.

required
provider_model str

The selected model.

required

test_media_port_refuses_undeclared_media(provider_factory, media_port, provider_model)

Rule 5: media outside the declared capabilities is refused first.

Parameters:

Name Type Description Default
provider_factory AsyncProviderFactory

The provider's factory, used without a media port.

required
media_port AsyncMediaSystemOnePort | None

The dedicated media port, or None.

required
provider_model str

The selected model.

required

test_media_refused_without_media_support(provider_factory, provider_model)

Rule 5: a text-only port exposes no partial media surface.

A media-capable port from the factory skips this rule, and test_media_port_refuses_undeclared_media checks it instead.

Parameters:

Name Type Description Default
provider_factory AsyncProviderFactory

The provider's factory.

required
provider_model str

The selected model.

required

test_port_shape(provider_factory, provider_model)

Rule 1: system_one is callable as the port declares it.

Parameters:

Name Type Description Default
provider_factory AsyncProviderFactory

The provider's factory.

required
provider_model str

The selected model.

required

test_scope_entry_yields_usable_port(provider_factory, provider_model)

Rule 4: scope entry validates the port and yields one that answers.

Parameters:

Name Type Description Default
provider_factory AsyncProviderFactory

The provider's factory.

required
provider_model str

The selected model.

required

test_scope_exit_runs_once(provider_factory)

Rule 4: each scope gets its own context, and each exits exactly once.

Parameters:

Name Type Description Default
provider_factory AsyncProviderFactory

The provider's factory.

required

test_scope_propagates_body_exception(provider_factory)

Rule 4: a body exception reaches the caller and exits the scope once.

The kit also enters one context directly, as AsyncProviderFactory callers may, and requires that its exit does not suppress the error.

Parameters:

Name Type Description Default
provider_factory AsyncProviderFactory

The provider's factory.

required

test_typed_answers_pass_policy(provider_factory, provider_model)

Rule 2: awaited typed answers per question kind pass the evaluator.

A system_one that returns a value that is not awaitable fails this rule. A failure message also names every answer whose type does not match its question kind.

Parameters:

Name Type Description Default
provider_factory AsyncProviderFactory

The provider's factory.

required
provider_model str

The selected model.

required