pytest
pytest copied to clipboard
Add dedicated page about using types with pytest
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.
This would be good. I’m on a project trying to use fixture types and it’s not obvious how to get those types.
Hi, it is my first time make contribution. Can this be assigned to me please? Thank you.
Sure, thank you for wanting to contribute to pytest !
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.
@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.