Python Type Hints - How to Debug Types With reveal_type()

2021-05-14 Eye see what type you have there.

When working with type hints, it’s often useful to debug the types of variables. Type checkers allow you to do this with reveal_type() and reveal_locals().

For example, take this code:

items = [1, None]

We don’t need to add a hint to items since our type checker can infer its type. But we might not be sure what type has been inferred—is it list[int | None], the less useful list[object], or worst list[Any]? We can check by adding a call to reveal_type():

items = [1, None]
reveal_type(items)

Then when we run our type checker, in this case Mypy, it will log the type of items:

$ mypy example.py
example.py:2: note: Revealed type is 'builtins.list[Union[builtins.int, None]]'

Here Mypy wrote its “long-form spelling” of list[int | None] (in a future version it may use a shorter form).

Note that reveal_type() does not exist at runtime, so if we run our code with the call in place, Python crashes with a NameError:

$ python example.py
Traceback (most recent call last):
  File "/.../example.py", line 2, in <module>
    reveal_type(items)
NameError: name 'reveal_type' is not defined

So, we need to remove all calls to reveal_type() before running our code.

A good way to make sure you never accidentally commit a call to reveal_type() is to use flake8, perhaps under pre-commit. It will flag calls with the error F821 undefined name 'reveal_type'.

Also, reveal_locals()

Mypy also supports reveal_locals(), which does a reveal_type() for each local variable. This can save time when debugging several variables.

For example, if we take this code:

CONSTANT = 1


def example() -> None:
    first_item = 1
    items = [first_item, None]
    reveal_locals()

We can run Mypy and see:

$ mypy example.py
example.py:7: note: Revealed local types are:
example.py:7: note:     first_item: builtins.int
example.py:7: note:     items: builtins.list[Union[builtins.int, None]]

The local variables first_item and items have their types revealed, but the global variable CONSTANT does not.

Fin

—Adam


📙👉Speed Up Your Django Tests👈📙


Subscribe via RSS, Twitter, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: mypy, python