Configuration

This plugin provides a typing_scenario_runner fixture that lets a test use a pytest_typing_runner.Scenario object to create a scenario to run a type checker against.

There are several objects involved in this that allow customisation and a few fixtures that provide the ability to inject these customized objects into different parts of the pytest run.

There are these relevant protocols:

There are a few pytest fixtures that can be overridden within any pytest scope to change what concrete implementations get used:

from pytest_typing_runner import protocols
import pytest


@pytest.fixture
def typing_runner_config(pytestconfig: pytest.Config) -> protocols.RunnerConfig:
    """
    Fixture to get a RunnerConfig with all the relevant settings from the pytest config

    Override this if you want a RunnerConfig that overrides the options provided
    by the command line
    """
from pytest_typing_runner import protocols, Scenario
import pytest


@pytest.fixture
def typing_scenario_maker() -> protocols.ScenarioMaker[Scenario]:
    """
    Fixture to override the specific Scenario class that should be used.
    """
from pytest_typing_runner import protocols, Scenario
import pytest


@pytest.fixture
def typing_scenario_runner_maker() -> protocols.ScenarioRunnerMaker[Scenario]:
    """
    Fixture to override what object may be used to drive the scenario

    Note that the default implementation of ``ScenarioRunner`` already satisfies
    the ``ScenarioRunnerMaker`` protocol, but ultimately that is what this fixture
    should return.

    It should also be typed in terms of what scenario class is active for that
    scope.

    Also note that pytest and this plugin does not provide any verification
    that the type annotations are correct and it's recommended to have
    protective assertions in complicated setups.
    """
import pytest
import pathlib


@pytest.fixture
def typing_scenario_root_dir(tmp_path: pathlib.Path) -> pathlib.Path:
    """
    This sets the root path for all the files in the scenario.

    This example shows the default
    """
    return tmp_path / "scenario_root"

Example

For example:

import typing

import pytest

from pytest_typing_runner import protocols, scenarios


def test_it_works(typing_scenario_runner: scenarios.ScenarioRunner[scenarios.Scenario]) -> None:
    assert isinstance(typing_scenario_runner, scenarios.ScenarioRunner)
    assert isinstance(typing_scenario_runner.scenario, scenarios.Scenario)


class TestOther:
    class MyScenario(scenarios.Scenario):
        info: int = 1

        def some_functionality(self) -> None:
            self.info = 2

    class MyScenarioRunner(scenarios.ScenarioRunner[MyScenario]):
        def prepare_scenario(self) -> None:
            self.scenario.some_functionality()

    if typing.TYPE_CHECKING:
        # Let our type checker tell us if we satisfy the maker protocols
        _MS: protocols.ScenarioMaker[MyScenario] = MyScenario.create
        _MSH: protocols.ScenarioRunnerMaker[MyScenario] = MyScenarioRunner.create

    @pytest.fixture
    def typing_scenario_maker(self) -> protocols.ScenarioMaker[MyScenario]:
        return self.MyScenario.create

    @pytest.fixture
    def typing_scenario_runner_maker(self) -> protocols.ScenarioRunnerMaker[MyScenario]:
        return self.MyScenarioRunner.create

    def test_it_works(self, typing_scenario_runner: MyScenarioRunner) -> None:
        assert isinstance(typing_scenario_runner, scenarios.ScenarioRunner)
        assert isinstance(typing_scenario_runner.scenario, self.MyScenario)

        assert typing_scenario_runner.scenario.info == 2