38
38
from astroid .util import Uninferable
39
39
40
40
TYPING_NAMEDTUPLE_BASENAMES = {"NamedTuple" , "typing.NamedTuple" }
41
- TYPING_TYPEVARS = {"TypeVar" , "NewType" }
42
- TYPING_TYPEVARS_QUALIFIED = {"typing.TypeVar" , "typing.NewType" }
43
41
TYPING_TYPE_TEMPLATE = """
44
42
class Meta(type):
45
43
def __getitem__(self, item):
@@ -52,6 +50,11 @@ def __args__(self):
52
50
class {0}(metaclass=Meta):
53
51
pass
54
52
"""
53
+ # PEP484 suggests NewType is equivalent to this for typing purposes
54
+ TYPING_NEWTYPE_TEMPLATE = """
55
+ class {derived}({base}):
56
+ pass
57
+ """
55
58
TYPING_MEMBERS = set (getattr (typing , "__all__" , []))
56
59
57
60
TYPING_ALIAS = frozenset (
@@ -106,23 +109,32 @@ def __class_getitem__(cls, item):
106
109
"""
107
110
108
111
109
- def looks_like_typing_typevar_or_newtype (node ):
112
+ def looks_like_typing_typevar (node ):
113
+ func = node .func
114
+ if isinstance (func , Attribute ):
115
+ return func .attrname == "TypeVar"
116
+ if isinstance (func , Name ):
117
+ return func .name == "TypeVar"
118
+ return False
119
+
120
+
121
+ def looks_like_typing_newtype (node ):
110
122
func = node .func
111
123
if isinstance (func , Attribute ):
112
- return func .attrname in TYPING_TYPEVARS
124
+ return func .attrname == "NewType"
113
125
if isinstance (func , Name ):
114
- return func .name in TYPING_TYPEVARS
126
+ return func .name == "NewType"
115
127
return False
116
128
117
129
118
- def infer_typing_typevar_or_newtype (node , context_itton = None ):
130
+ def infer_typing_typevar (node , context_itton = None ):
119
131
"""Infer a typing.TypeVar(...) or typing.NewType(...) call"""
120
132
try :
121
133
func = next (node .func .infer (context = context_itton ))
122
134
except (InferenceError , StopIteration ) as exc :
123
135
raise UseInferenceDefault from exc
124
136
125
- if func .qname () not in TYPING_TYPEVARS_QUALIFIED :
137
+ if func .qname () != "typing.TypeVar" :
126
138
raise UseInferenceDefault
127
139
if not node .args :
128
140
raise UseInferenceDefault
@@ -132,6 +144,24 @@ def infer_typing_typevar_or_newtype(node, context_itton=None):
132
144
return node .infer (context = context_itton )
133
145
134
146
147
+ def infer_typing_newtype (node , context_itton = None ):
148
+ """Infer a typing.TypeVar(...) or typing.NewType(...) call"""
149
+ try :
150
+ func = next (node .func .infer (context = context_itton ))
151
+ except (InferenceError , StopIteration ) as exc :
152
+ raise UseInferenceDefault from exc
153
+
154
+ if func .qname () != "typing.NewType" :
155
+ raise UseInferenceDefault
156
+ if not node .args :
157
+ raise UseInferenceDefault
158
+
159
+ derived = node .args [0 ].as_string ().strip ("'" )
160
+ base = node .args [1 ].as_string ().strip ("'" )
161
+ node = extract_node (TYPING_NEWTYPE_TEMPLATE .format (derived = derived , base = base ))
162
+ return node .infer (context = context_itton )
163
+
164
+
135
165
def _looks_like_typing_subscript (node ):
136
166
"""Try to figure out if a Subscript node *might* be a typing-related subscript"""
137
167
if isinstance (node , Name ):
@@ -409,8 +439,13 @@ def infer_typing_cast(
409
439
410
440
AstroidManager ().register_transform (
411
441
Call ,
412
- inference_tip (infer_typing_typevar_or_newtype ),
413
- looks_like_typing_typevar_or_newtype ,
442
+ inference_tip (infer_typing_typevar ),
443
+ looks_like_typing_typevar ,
444
+ )
445
+ AstroidManager ().register_transform (
446
+ Call ,
447
+ inference_tip (infer_typing_newtype ),
448
+ looks_like_typing_newtype ,
414
449
)
415
450
AstroidManager ().register_transform (
416
451
Subscript , inference_tip (infer_typing_attr ), _looks_like_typing_subscript
0 commit comments