summaryrefslogtreecommitdiffstats
path: root/Lib/typing.py
diff options
context:
space:
mode:
authorIvan Levkivskyi <levkivskyi@gmail.com>2019-05-30 23:10:07 (GMT)
committerGitHub <noreply@github.com>2019-05-30 23:10:07 (GMT)
commit4c23aff065fb28aba789a211937a2af974842110 (patch)
treef6f2757eb59d315e2835f7dcf8b2f1b7f18506ea /Lib/typing.py
parent2a58b0636d1f620f8a85a2e4c030cc10551936a5 (diff)
downloadcpython-4c23aff065fb28aba789a211937a2af974842110.zip
cpython-4c23aff065fb28aba789a211937a2af974842110.tar.gz
cpython-4c23aff065fb28aba789a211937a2af974842110.tar.bz2
bpo-29262: Add get_origin() and get_args() introspection helpers to typing (GH-13685)
This is an old feature request that appears from time to time. After a year of experimenting with various introspection capabilities in `typing_inspect` on PyPI, I propose to add these two most commonly used functions: `get_origin()` and `get_args()`. These are essentially thin public wrappers around private APIs: `__origin__` and `__args__`. As discussed in the issue and on the typing tracker, exposing some public helpers instead of `__origin__` and `__args__` directly will give us more flexibility if we will decide to update the internal representation, while still maintaining backwards compatibility. The implementation is very simple an is essentially a copy from `typing_inspect` with one exception: `ClassVar` was special-cased in `typing_inspect`, but I think this special-casing doesn't really help and only makes things more complicated.
Diffstat (limited to 'Lib/typing.py')
-rw-r--r--Lib/typing.py42
1 files changed, 42 insertions, 0 deletions
diff --git a/Lib/typing.py b/Lib/typing.py
index 3b4e9df..16ccfad 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -99,6 +99,8 @@ __all__ = [
'AnyStr',
'cast',
'final',
+ 'get_args',
+ 'get_origin',
'get_type_hints',
'NewType',
'no_type_check',
@@ -1253,6 +1255,46 @@ def get_type_hints(obj, globalns=None, localns=None):
return hints
+def get_origin(tp):
+ """Get the unsubscripted version of a type.
+
+ This supports generic types, Callable, Tuple, Union, Literal, Final and ClassVar.
+ Return None for unsupported types. Examples::
+
+ get_origin(Literal[42]) is Literal
+ get_origin(int) is None
+ get_origin(ClassVar[int]) is ClassVar
+ get_origin(Generic) is Generic
+ get_origin(Generic[T]) is Generic
+ get_origin(Union[T, int]) is Union
+ get_origin(List[Tuple[T, T]][int]) == list
+ """
+ if isinstance(tp, _GenericAlias):
+ return tp.__origin__
+ if tp is Generic:
+ return Generic
+ return None
+
+
+def get_args(tp):
+ """Get type arguments with all substitutions performed.
+
+ For unions, basic simplifications used by Union constructor are performed.
+ Examples::
+ get_args(Dict[str, int]) == (str, int)
+ get_args(int) == ()
+ get_args(Union[int, Union[T, int], str][int]) == (int, str)
+ get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
+ get_args(Callable[[], T][int]) == ([], int)
+ """
+ if isinstance(tp, _GenericAlias):
+ res = tp.__args__
+ if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis:
+ res = (list(res[:-1]), res[-1])
+ return res
+ return ()
+
+
def no_type_check(arg):
"""Decorator to indicate that annotations are not type hints.