Skip to content

Commit

Permalink
bpo-46414: Add typing.reveal_type (#30646)
Browse files Browse the repository at this point in the history
Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
  • Loading branch information
JelleZijlstra and sobolevn committed Feb 2, 2022
1 parent b128896 commit abcc3d7
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 1 deletion.
31 changes: 31 additions & 0 deletions Doc/library/typing.rst
Expand Up @@ -1932,6 +1932,37 @@ Functions and decorators
runtime we intentionally don't check anything (we want this
to be as fast as possible).

.. function:: reveal_type(obj)

Reveal the inferred static type of an expression.

When a static type checker encounters a call to this function,
it emits a diagnostic with the type of the argument. For example::

x: int = 1
reveal_type(x) # Revealed type is "builtins.int"

This can be useful when you want to debug how your type checker
handles a particular piece of code.

The function returns its argument unchanged, which allows using
it within an expression::

x = reveal_type(1) # Revealed type is "builtins.int"

Most type checkers support ``reveal_type()`` anywhere, even if the
name is not imported from ``typing``. Importing the name from
``typing`` allows your code to run without runtime errors and
communicates intent more clearly.

At runtime, this function prints the runtime type of its argument to stderr
and returns it unchanged::

x = reveal_type(1) # prints "Runtime type is int"
print(x) # prints "1"

.. versionadded:: 3.11

.. decorator:: overload

The ``@overload`` decorator allows describing functions and methods
Expand Down
11 changes: 10 additions & 1 deletion Lib/test/test_typing.py
Expand Up @@ -20,6 +20,7 @@
from typing import get_type_hints
from typing import get_origin, get_args
from typing import is_typeddict
from typing import reveal_type
from typing import no_type_check, no_type_check_decorator
from typing import Type
from typing import NamedTuple, TypedDict
Expand All @@ -34,7 +35,7 @@
import weakref
import types

from test.support import import_helper
from test.support import import_helper, captured_stderr
from test import mod_generics_cache
from test import _typed_dict_helper

Expand Down Expand Up @@ -5289,6 +5290,14 @@ def bar(self):
self.assertIn('baz', dir(Foo[int]))


class RevealTypeTests(BaseTestCase):
def test_reveal_type(self):
obj = object()
with captured_stderr() as stderr:
self.assertIs(obj, reveal_type(obj))
self.assertEqual(stderr.getvalue(), "Runtime type is 'object'\n")


class AllTests(BaseTestCase):
"""Tests for __all__."""

Expand Down
21 changes: 21 additions & 0 deletions Lib/typing.py
Expand Up @@ -130,6 +130,7 @@ def _idfunc(_, x):
'overload',
'ParamSpecArgs',
'ParamSpecKwargs',
'reveal_type',
'runtime_checkable',
'Text',
'TYPE_CHECKING',
Expand Down Expand Up @@ -2675,3 +2676,23 @@ class re(metaclass=_DeprecatedType):

re.__name__ = __name__ + '.re'
sys.modules[re.__name__] = re


def reveal_type(obj: T, /) -> T:
"""Reveal the inferred type of a variable.
When a static type checker encounters a call to ``reveal_type()``,
it will emit the inferred type of the argument::
x: int = 1
reveal_type(x)
Running a static type checker (e.g., ``mypy``) on this example
will produce output similar to 'Revealed type is "builtins.int"'.
At runtime, the function prints the runtime type of the
argument and returns it unchanged.
"""
print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr)
return obj
@@ -0,0 +1 @@
Add :func:`typing.reveal_type`. Patch by Jelle Zijlstra.

0 comments on commit abcc3d7

Please sign in to comment.