pythonpytestpython-typingfixtures

How can request.param be annotated in indirect parametrization?


In the Indirect parametrization example I want to type hint request.param indicating a specific type, a str for example.

The problem is since the argument to fixt must be the request fixture there seems to be no way to indicate what type the parameters passed through the "optional param attribute" should be (quoting the documentation).

What are the alternatives? Perhaps documenting the type hint in the fixt docstring, or in the test_indirect docstring?

@pytest.fixture
def fixt(request):
    return request.param * 3

@pytest.mark.parametrize("fixt", ["a", "b"], indirect=True)
def test_indirect(fixt):
    assert len(fixt) == 3

Solution

  • As of now (version 6.2), pytest doesn't provide any type hint for the param attribute. If you need to just type param regardless of the rest of FixtureRequest fields and methods, you can inline your own impl stub:

    from typing import TYPE_CHECKING
    
    
    if TYPE_CHECKING:
        class FixtureRequest:
            param: str
    else:
        from typing import Any
        FixtureRequest = Any
    
    
    @pytest.fixture
    def fixt(request: FixtureRequest) -> str:
        return request.param * 3
    

    If you want to extend existing typing of FixtureRequest, the stubbing gets somewhat more complex:

    from typing import TYPE_CHECKING
    
    
    if TYPE_CHECKING:
        from pytest import FixtureRequest as __FixtureRequest
        class FixtureRequest(__FixtureRequest):
            param: str
    else:
        from pytest import FixtureRequest
    
    
    @pytest.fixture
    def fixt(request: FixtureRequest) -> str:
        return request.param * 3
    

    Ideally, pytest would allow generic param types in FixtureRequest, e.g.

    P = TypeVar("P")  # generic param type
    
    class FixtureRequest(Generic[P]):
        def __init__(self, param: P, ...):
            ...
    

    You would then just do

    from pytest import FixtureRequest
    
    @pytest.fixture
    def fixt(request: FixtureRequest[str]) -> str:
        return request.param * 3
    

    Not sure, however, whether this typing is agreeable with the current pytest's codebase - I guess it was omitted for a reason...