pytest icon indicating copy to clipboard operation
pytest copied to clipboard

Add dedicated page about using types with pytest

Open nicoddemus opened this issue 1 year ago • 1 comments

As follow up to https://github.com/pytest-dev/pytest/discussions/9947, add a dedicated page describing how to use types with pytest: how to type tests, fixtures, etc.

nicoddemus avatar Sep 25 '24 16:09 nicoddemus

This would be good. I’m on a project trying to use fixture types and it’s not obvious how to get those types.

okken avatar Sep 25 '24 16:09 okken

Hi, it is my first time make contribution. Can this be assigned to me please? Thank you.

mwychung avatar Nov 13 '24 16:11 mwychung

Sure, thank you for wanting to contribute to pytest !

Pierre-Sassoulas avatar Nov 13 '24 16:11 Pierre-Sassoulas

Heya, I've got a Q about typing fixtures that return callables, which might fit into the docs PR.

Given the example below, the typing should be Callable[[str], str] based on the internal function in the fixture.

@pytest.fixture
def hello_world_fixture() -> Callable[[str], str]:
    def _hello_world_func(input: str) -> str:
        """docstring"""
        return "hello " + input

    return _hello_world_func


def test_hello_world(hello_world_fixture: Callable[[str], str]):
    assert hello_world_fixture("world") == "hello world"

What's the recommended typing for fixtures returning more complex callables? Should it be typed as a Protocol, or should the implementation be using a class instance?

class HelloWorldProtocol(Protocol):
    def __call__(self, input: str) -> str:
        """call docstring"""
        ...


class HelloWorldFixture:
    """class docstring"""

    def __call__(self, input: str) -> str:
        """call docstring"""
        return "hello " + input

Aware this is more useful for typing plugins than regular fixture use in projects.

daria-shaw avatar Dec 01 '24 15:12 daria-shaw

@daara-s I don't think there's anything pytest specific there, the same applies to type annotating complex callables elsewhere.

The Python documentation agrees with your Protocol example and explains that in-depth. Personally that's also what I'd prefer, as it seems simpler than defining a callable class that doesn't do anything else.

For more complex fixtures, you might want to expose functionality via an utility class. This also has the benefit of usually being easier to understand for Python beginners over returning a nested function. Then I'd prefer having a more clear method name (say, start) rather than using __call__ though.

The-Compiler avatar Dec 01 '24 18:12 The-Compiler