I am trying to specify mypy type hints for the pytest native fixtures I am using in my test project e.g.:
import pytest
def pytest_configure(config):
# Do something useful here
The config
fixture returns a _pytest.config.Config
object. If I try to model this naively:
import pytest
def pytest_configure(config: Config) -> None:
# Do something useful here
I receive a mypy error:
conftest.py:3: error: Name 'Config' is not defined [name-defined]
I could do from _pytest.config import Config
, but this doesn't seem to be a good way, because _pytest is private.
Another option would be to ignore the type with # type: ignore
. If this is the recommended way I would of course do this, but I wonder if there is a better option.
I have the same issues in with any kind of pytest native fixtures I use, e.g. request
which is used for parameterized fixtures. This would be a _pytest.fixtures.FixtureRequest
.
from _pytest.config
Since pytest
doesn't currently export Config
(as of 6.2), the only way for typing is to use from _pytest.config import Config
. This is how I also type config
, as can be seen e.g. in this question of mine:
from _pytest.config import Config
def pytest_configure(config: Config) -> None:
...
You can track the typing progress in this pytest
issue: #7469.
You can also introduce a small custom type stub that hides the reexport. It's questionable whether it will be useful here, only worth to mention for an alternative solution. If you create a file _typeshed/pytest.pyi
with the following contents:
from typing import Any
from _pytest.config import Config as Config
def __getattr__(name: str) -> Any: ... # incomplete
and make it accessible to mypy
in mypy.ini
:
[mypy]
mypy_path = _typeshed
Now you can import from pytest import Config
at least in type checking mode - the runtime import will still fail. So the imports would look like
from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
from pytest import Config
else:
Config = Any
def pytest_configure(config: Config) -> None:
pass
The only benefit of that solution is that the private import is now hidden; I'd still go with the private import though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With