diff options
author | Ivan Levkivskyi <levkivskyi@gmail.com> | 2019-05-30 23:10:07 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-30 23:10:07 (GMT) |
commit | 4c23aff065fb28aba789a211937a2af974842110 (patch) | |
tree | f6f2757eb59d315e2835f7dcf8b2f1b7f18506ea /Lib/typing.py | |
parent | 2a58b0636d1f620f8a85a2e4c030cc10551936a5 (diff) | |
download | cpython-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.py | 42 |
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. |