1
|
|
|
""" |
2
|
|
|
PRIVATE MODULE: do not import (from) it directly. |
3
|
|
|
|
4
|
|
|
This module contains functionality for supporting the compatibility with |
5
|
|
|
multiple Python versions. |
6
|
|
|
""" |
7
|
|
|
import sys |
8
|
|
|
from typing import ( |
9
|
|
|
get_type_hints as get_type_hints_, |
10
|
|
|
Type, |
11
|
|
|
Callable, |
12
|
|
|
Dict, |
13
|
|
|
Tuple, |
14
|
|
|
Optional) |
15
|
|
|
|
16
|
|
|
|
17
|
|
|
def get_naked_class(cls: type) -> type: |
18
|
|
|
""" |
19
|
|
|
Return the given type without generics. For example, ``List[int]`` will |
20
|
|
|
result in ``List``. |
21
|
|
|
:param cls: the type that should be stripped off its generic type. |
22
|
|
|
:return: a type without generics. |
23
|
|
|
""" |
24
|
|
|
# Python3.5: typing classes have __extra__ |
25
|
|
|
# Python3.6: typing classes have __extra__ |
26
|
|
|
# Python3.7: typing classes have __origin__ |
27
|
|
|
# Return the non-generic class (e.g. dict) of a generic type (e.g. Dict). |
28
|
|
|
attr = '__origin__' |
29
|
|
|
if sys.version_info[1] in (5, 6): |
30
|
|
|
attr = '__extra__' |
31
|
|
|
return getattr(cls, attr, cls) |
32
|
|
|
|
33
|
|
|
|
34
|
|
|
def get_type_hints(func: callable) -> Dict[str, type]: |
35
|
|
|
""" |
36
|
|
|
Return the type hints of the parameters of the given callable. |
37
|
|
|
:param func: the callable of which the type hints are to be returned. |
38
|
|
|
:return: a dict with parameter names and their types. |
39
|
|
|
""" |
40
|
|
|
# Python3.5: get_type_hints raises on classes without explicit constructor |
41
|
|
|
try: |
42
|
|
|
result = get_type_hints_(func) |
43
|
|
|
except AttributeError: |
44
|
|
|
result = {} |
45
|
|
|
return result |
46
|
|
|
|
47
|
|
|
|
48
|
|
|
def get_args_and_return_type( |
49
|
|
|
hint: Type[Callable]) -> Tuple[Optional[Tuple[type]], Optional[type]]: |
50
|
|
|
""" |
51
|
|
|
Get the argument types and the return type of a callable type hint |
52
|
|
|
(e.g. ``Callable[[int], str]). |
53
|
|
|
|
54
|
|
|
Example: |
55
|
|
|
``` |
56
|
|
|
arg_types, return_type = get_args_and_return_type(Callable[[int], str]) |
57
|
|
|
# args_types is (int, ) |
58
|
|
|
# return_type is str |
59
|
|
|
``` |
60
|
|
|
|
61
|
|
|
Example for when ``hint`` has no generics: |
62
|
|
|
``` |
63
|
|
|
arg_types, return_type = get_args_and_return_type(Callable) |
64
|
|
|
# args_types is None |
65
|
|
|
# return_type is None |
66
|
|
|
``` |
67
|
|
|
:param hint: the callable type hint. |
68
|
|
|
:return: a tuple of the argument types (as a tuple) and the return type. |
69
|
|
|
""" |
70
|
|
|
if hint in (callable, Callable): |
71
|
|
|
arg_types = None |
72
|
|
|
return_type = None |
73
|
|
|
elif hasattr(hint, '__result__'): |
74
|
|
|
arg_types = hint.__args__ |
75
|
|
|
return_type = hint.__result__ |
76
|
|
|
else: |
77
|
|
|
arg_types = hint.__args__[0:-1] |
78
|
|
|
return_type = hint.__args__[-1] |
79
|
|
|
return arg_types, return_type |
80
|
|
|
|