8

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.

sorin
  • 161,544
  • 178
  • 535
  • 806
Rene Oschmann
  • 676
  • 4
  • 16
  • 2
    `from _pytest.config import Config` is the way to go since `Config` is not exported by `pytest` ATM for some reasons. Feel free to [open a new issue](https://github.com/pytest-dev/pytest/issues/new?template=2_feature_request.md), though. For `request` typing, check out [my other recent answer](https://stackoverflow.com/a/65342113/2650249) and the related [issue #8073](https://github.com/pytest-dev/pytest/issues/8073). – hoefling Dec 29 '20 at 12:19
  • Thanks, if you put that as answer, I will accept it. Opened https://github.com/pytest-dev/pytest/issues/8202 – Rene Oschmann Dec 29 '20 at 15:01

1 Answers1

4

Importing 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.

Custom type stubs

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.

hoefling
  • 59,418
  • 12
  • 147
  • 194