16

As the title says. I am using the caplog fixture that comes with pytest. I am using mypy for my type checking, and would like to know what the correct type hint for caplog is.

For example:

def test_validate_regs(caplog: Any) -> None:
    validate_regs(df, logger)
    assert caplog.text == "", "No logs should have been made."

In this example, I have it set to Any, but I am wondering if there is a more specific type hint I can use.

I've tried reading the docs on caplog, as well as searching the pytest code in github to see what the caplog fixture returns, but couldn't find anything more than the following. But using a str type just gave me an error, saying that str type doesn't have the attribute text, which makes sense.

When I print the type of caplog I get _pytest.logging.LogCaptureFixture although I'm not sure how I'd import this from _pytest and make use of it.

Jamie
  • 1,530
  • 1
  • 19
  • 35
  • 2
    `print(type(caplog))` could be helpful. – Klaus D. Jul 29 '21 at 13:17
  • @KlausD. I forgot to mention that i tried that and got `_pytest.logging.LogCaptureFixture` although I'm not sure how I should/could import this from `_pytest`. – Jamie Jul 29 '21 at 14:22

2 Answers2

23

as of pytest 6.2.0 you should use pytest.LogCaptureFixture

prior to that you needed to import a private name which is not recommended (we frequently change the internals inside the _pytest namespace without notice and with no promises of forward or backward compatibility)


disclaimer: I'm a pytest core dev

anthony sottile
  • 61,815
  • 15
  • 148
  • 207
1

This answer is for users that are not or cannot update yet to pytest 6+
If you are on pytest 6+ and above, see this more updated answer.


For pytest <6.x, you can use _pytest.logging.LogCaptureFixture.

from _pytest.logging import LogCaptureFixture

def test_logs(caplog: LogCaptureFixture) -> None:
    ...

The type hint does work with MyPy:

from _pytest.logging import LogCaptureFixture

def test_logs(caplog: LogCaptureFixture) -> None:
    caplog.at_level(logging.ERROR)
    caplog.at_level('10')
$ mypy test.py
/path/to/test.py:18: error: Argument 1 to "at_level" of "LogCaptureFixture" has incompatible type "str"; expected "int"
Found 3 errors in 2 files (checked 1 source file)

The type hint works with Intellisense as well:

caplog with type hint

(The above Intellisense popup matches the API doc for get_records).

Be warned though that the _ in _pytest suggests that it's not a "public" API (as mentioned in this answer). Adding typing to fixtures started with this Github issue: Support for static typing:

I would also add that if you import from _pytest we do not guarantee stability. It's OK as long as you are willing to adapt if/when it breaks. We are working on a stable solution for this for pytest 6.1: #7469.

Which leads to this Github issue: Typing and public API:

pytest's "official" public API is exported by the pytest package, and everything else is defined in the _pytest package.

...and that "everything else" includes the LogCaptureFixture type hint (as can be seen from that issue's TODO list). There was a lot of discussions on how to make it "official":

How do we want to officialy declare something as public API?

I think there should be three criteria:

  • It is exported in pytest.
  • It doesn't have a _ or __ prefix.
  • It is documented in the reference.
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135