Skip to content

bpo-46414: Add typing.reveal_type #30646

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 NewType
Expand All @@ -35,7 +36,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 @@ -5108,6 +5109,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
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def _idfunc(_, x):
'overload',
'ParamSpecArgs',
'ParamSpecKwargs',
'reveal_type',
'runtime_checkable',
'Text',
'TYPE_CHECKING',
Expand Down Expand Up @@ -2667,3 +2668,23 @@ class re(metaclass=_DeprecatedType):

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


def reveal_type(obj: T, /) -> T:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we use type hints in typing.py? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is merged, we will :). I don't see any reason not to, especially in cases like this where the type is simple and helps document the behavior.

Copy link
Member

@AlexWaygood AlexWaygood Jan 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are type annotations in a few lines of typing.py:

def read(self, n: int = -1) -> AnyStr:

It's just about the only module in the stdlib in which I've spotted any type annotations other than importlib :)

"""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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :func:`typing.reveal_type`. Patch by Jelle Zijlstra.