1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
import typing
def check_command_type(value: typing.Any, typeinfo: typing.Any) -> bool:
"""
Check if the provided value is an instance of typeinfo. Returns True if the
types match, False otherwise. This function supports only those types
required for command return values.
"""
typename = str(typeinfo)
if typename.startswith("typing.Sequence"):
try:
T = typeinfo.__args__[0] # type: ignore
except AttributeError:
# Python 3.5.0
T = typeinfo.__parameters__[0] # type: ignore
if not isinstance(value, (tuple, list)):
return False
for v in value:
if not check_command_type(v, T):
return False
elif typename.startswith("typing.Union"):
try:
types = typeinfo.__args__ # type: ignore
except AttributeError:
# Python 3.5.x
types = typeinfo.__union_params__ # type: ignore
for T in types:
checks = [check_command_type(value, T) for T in types]
if not any(checks):
return False
elif value is None and typeinfo is None:
return True
elif not isinstance(value, typeinfo):
return False
return True
def check_option_type(name: str, value: typing.Any, typeinfo: typing.Any) -> None:
"""
Check if the provided value is an instance of typeinfo and raises a
TypeError otherwise. This function supports only those types required for
options.
"""
e = TypeError("Expected {} for {}, but got {}.".format(
typeinfo,
name,
type(value)
))
typename = str(typeinfo)
if typename.startswith("typing.Union"):
try:
types = typeinfo.__args__ # type: ignore
except AttributeError:
# Python 3.5.x
types = typeinfo.__union_params__ # type: ignore
for T in types:
try:
check_option_type(name, value, T)
except TypeError:
pass
else:
return
raise e
elif typename.startswith("typing.Tuple"):
try:
types = typeinfo.__args__ # type: ignore
except AttributeError:
# Python 3.5.x
types = typeinfo.__tuple_params__ # type: ignore
if not isinstance(value, (tuple, list)):
raise e
if len(types) != len(value):
raise e
for i, (x, T) in enumerate(zip(value, types)):
check_option_type("{}[{}]".format(name, i), x, T)
return
elif typename.startswith("typing.Sequence"):
try:
T = typeinfo.__args__[0] # type: ignore
except AttributeError:
# Python 3.5.0
T = typeinfo.__parameters__[0] # type: ignore
if not isinstance(value, (tuple, list)):
raise e
for v in value:
check_option_type(name, v, T)
elif typename.startswith("typing.IO"):
if hasattr(value, "read"):
return
else:
raise e
elif typename.startswith("typing.Any"):
return
elif not isinstance(value, typeinfo):
raise e
def typespec_to_str(typespec: typing.Any) -> str:
if typespec in (str, int, bool):
t = typespec.__name__
elif typespec == typing.Optional[str]:
t = 'optional str'
elif typespec == typing.Sequence[str]:
t = 'sequence of str'
else:
raise NotImplementedError
return t
|