summaryrefslogtreecommitdiffstats
path: root/Lib/typing.py
diff options
context:
space:
mode:
authorKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>2021-04-27 14:31:04 (GMT)
committerGitHub <noreply@github.com>2021-04-27 14:31:04 (GMT)
commit05ab4b60ab3dae61ee75692b6624537d4f3fdf85 (patch)
treeca79d746064f5c352b712b5bc66d8c0322d51e84 /Lib/typing.py
parentd92513390a1a0da781bb08c284136f4d7abea36d (diff)
downloadcpython-05ab4b60ab3dae61ee75692b6624537d4f3fdf85.zip
cpython-05ab4b60ab3dae61ee75692b6624537d4f3fdf85.tar.gz
cpython-05ab4b60ab3dae61ee75692b6624537d4f3fdf85.tar.bz2
bpo-43766: Implement PEP 647 (User-Defined Type Guards) in typing.py (#25282)
Diffstat (limited to 'Lib/typing.py')
-rw-r--r--Lib/typing.py49
1 files changed, 49 insertions, 0 deletions
diff --git a/Lib/typing.py b/Lib/typing.py
index 762a98a..d409517 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -119,6 +119,7 @@ __all__ = [
'Text',
'TYPE_CHECKING',
'TypeAlias',
+ 'TypeGuard',
]
# The pseudo-submodules 're' and 'io' are part of the public
@@ -567,6 +568,54 @@ def Concatenate(self, parameters):
return _ConcatenateGenericAlias(self, parameters)
+@_SpecialForm
+def TypeGuard(self, parameters):
+ """Special typing form used to annotate the return type of a user-defined
+ type guard function. ``TypeGuard`` only accepts a single type argument.
+ At runtime, functions marked this way should return a boolean.
+
+ ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static
+ type checkers to determine a more precise type of an expression within a
+ program's code flow. Usually type narrowing is done by analyzing
+ conditional code flow and applying the narrowing to a block of code. The
+ conditional expression here is sometimes referred to as a "type guard".
+
+ Sometimes it would be convenient to use a user-defined boolean function
+ as a type guard. Such a function should use ``TypeGuard[...]`` as its
+ return type to alert static type checkers to this intention.
+
+ Using ``-> TypeGuard`` tells the static type checker that for a given
+ function:
+
+ 1. The return value is a boolean.
+ 2. If the return value is ``True``, the type of its argument
+ is the type inside ``TypeGuard``.
+
+ For example::
+
+ def is_str(val: Union[str, float]):
+ # "isinstance" type guard
+ if isinstance(val, str):
+ # Type of ``val`` is narrowed to ``str``
+ ...
+ else:
+ # Else, type of ``val`` is narrowed to ``float``.
+ ...
+
+ Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower
+ form of ``TypeA`` (it can even be a wider form) and this may lead to
+ type-unsafe results. The main reason is to allow for things like
+ narrowing ``List[object]`` to ``List[str]`` even though the latter is not
+ a subtype of the former, since ``List`` is invariant. The responsibility of
+ writing type-safe type guards is left to the user.
+
+ ``TypeGuard`` also works with type variables. For more information, see
+ PEP 647 (User-Defined Type Guards).
+ """
+ item = _type_check(parameters, f'{self} accepts only single type.')
+ return _GenericAlias(self, (item,))
+
+
class ForwardRef(_Final, _root=True):
"""Internal wrapper to hold a forward reference."""