@@ -138,47 +138,48 @@ def check_namedtuple_classdef(self, defn: ClassDef, is_stub_file: bool
138138 def check_namedtuple (self ,
139139 node : Expression ,
140140 var_name : Optional [str ],
141- is_func_scope : bool ) -> Tuple [bool , Optional [TypeInfo ]]:
141+ is_func_scope : bool ) -> Tuple [Optional [ str ] , Optional [TypeInfo ]]:
142142 """Check if a call defines a namedtuple.
143143
144144 The optional var_name argument is the name of the variable to
145145 which this is assigned, if any.
146146
147147 Return a tuple of two items:
148- * Can it be a valid named tuple?
148+ * Internal name of the named tuple (e.g. the name passed as an argument to namedtuple)
149+ or None if it is not a valid named tuple
149150 * Corresponding TypeInfo, or None if not ready.
150151
151152 If the definition is invalid but looks like a namedtuple,
152153 report errors but return (some) TypeInfo.
153154 """
154155 if not isinstance (node , CallExpr ):
155- return False , None
156+ return None , None
156157 call = node
157158 callee = call .callee
158159 if not isinstance (callee , RefExpr ):
159- return False , None
160+ return None , None
160161 fullname = callee .fullname
161162 if fullname == 'collections.namedtuple' :
162163 is_typed = False
163164 elif fullname == 'typing.NamedTuple' :
164165 is_typed = True
165166 else :
166- return False , None
167+ return None , None
167168 result = self .parse_namedtuple_args (call , fullname )
168169 if result :
169- items , types , defaults , ok = result
170+ items , types , defaults , typename , ok = result
170171 else :
171- # This is a valid named tuple but some types are not ready.
172- return True , None
173- if not ok :
174172 # Error. Construct dummy return value.
175173 if var_name :
176174 name = var_name
177175 else :
178176 name = 'namedtuple@' + str (call .line )
179177 info = self .build_namedtuple_typeinfo (name , [], [], {}, node .line )
180178 self .store_namedtuple_info (info , name , call , is_typed )
181- return True , info
179+ return name , info
180+ if not ok :
181+ # This is a valid named tuple but some types are not ready.
182+ return typename , None
182183
183184 # We use the variable name as the class name if it exists. If
184185 # it doesn't, we use the name passed as an argument. We prefer
@@ -188,7 +189,7 @@ def check_namedtuple(self,
188189 if var_name :
189190 name = var_name
190191 else :
191- name = cast ( Union [ StrExpr , BytesExpr , UnicodeExpr ], call . args [ 0 ]). value
192+ name = typename
192193
193194 if var_name is None or is_func_scope :
194195 # There are two special cases where need to give it a unique name derived
@@ -228,7 +229,7 @@ def check_namedtuple(self,
228229 if name != var_name or is_func_scope :
229230 # NOTE: we skip local namespaces since they are not serialized.
230231 self .api .add_symbol_skip_local (name , info )
231- return True , info
232+ return typename , info
232233
233234 def store_namedtuple_info (self , info : TypeInfo , name : str ,
234235 call : CallExpr , is_typed : bool ) -> None :
@@ -237,26 +238,30 @@ def store_namedtuple_info(self, info: TypeInfo, name: str,
237238 call .analyzed .set_line (call .line , call .column )
238239
239240 def parse_namedtuple_args (self , call : CallExpr , fullname : str
240- ) -> Optional [Tuple [List [str ], List [Type ], List [Expression ], bool ]]:
241+ ) -> Optional [Tuple [List [str ], List [Type ], List [Expression ],
242+ str , bool ]]:
241243 """Parse a namedtuple() call into data needed to construct a type.
242244
243- Returns a 4 -tuple:
245+ Returns a 5 -tuple:
244246 - List of argument names
245247 - List of argument types
246- - Number of arguments that have a default value
247- - Whether the definition typechecked.
248+ - List of default values
249+ - First argument of namedtuple
250+ - Whether all types are ready.
248251
249- Return None if at least one of the types is not ready .
252+ Return None if the definition didn't typecheck .
250253 """
251254 # TODO: Share code with check_argument_count in checkexpr.py?
252255 args = call .args
253256 if len (args ) < 2 :
254- return self .fail_namedtuple_arg ("Too few arguments for namedtuple()" , call )
257+ self .fail ("Too few arguments for namedtuple()" , call )
258+ return None
255259 defaults = [] # type: List[Expression]
256260 if len (args ) > 2 :
257261 # Typed namedtuple doesn't support additional arguments.
258262 if fullname == 'typing.NamedTuple' :
259- return self .fail_namedtuple_arg ("Too many arguments for NamedTuple()" , call )
263+ self .fail ("Too many arguments for NamedTuple()" , call )
264+ return None
260265 for i , arg_name in enumerate (call .arg_names [2 :], 2 ):
261266 if arg_name == 'defaults' :
262267 arg = args [i ]
@@ -272,38 +277,42 @@ def parse_namedtuple_args(self, call: CallExpr, fullname: str
272277 )
273278 break
274279 if call .arg_kinds [:2 ] != [ARG_POS , ARG_POS ]:
275- return self .fail_namedtuple_arg ("Unexpected arguments to namedtuple()" , call )
280+ self .fail ("Unexpected arguments to namedtuple()" , call )
281+ return None
276282 if not isinstance (args [0 ], (StrExpr , BytesExpr , UnicodeExpr )):
277- return self .fail_namedtuple_arg (
283+ self .fail (
278284 "namedtuple() expects a string literal as the first argument" , call )
285+ return None
286+ typename = cast (Union [StrExpr , BytesExpr , UnicodeExpr ], call .args [0 ]).value
279287 types = [] # type: List[Type]
280- ok = True
281288 if not isinstance (args [1 ], (ListExpr , TupleExpr )):
282289 if (fullname == 'collections.namedtuple'
283290 and isinstance (args [1 ], (StrExpr , BytesExpr , UnicodeExpr ))):
284291 str_expr = args [1 ]
285292 items = str_expr .value .replace (',' , ' ' ).split ()
286293 else :
287- return self .fail_namedtuple_arg (
294+ self .fail (
288295 "List or tuple literal expected as the second argument to namedtuple()" , call )
296+ return None
289297 else :
290298 listexpr = args [1 ]
291299 if fullname == 'collections.namedtuple' :
292300 # The fields argument contains just names, with implicit Any types.
293301 if any (not isinstance (item , (StrExpr , BytesExpr , UnicodeExpr ))
294302 for item in listexpr .items ):
295- return self .fail_namedtuple_arg ("String literal expected as namedtuple() item" ,
296- call )
303+ self .fail ("String literal expected as namedtuple() item" , call )
304+ return None
297305 items = [cast (Union [StrExpr , BytesExpr , UnicodeExpr ], item ).value
298306 for item in listexpr .items ]
299307 else :
300308 # The fields argument contains (name, type) tuples.
301309 result = self .parse_namedtuple_fields_with_types (listexpr .items , call )
302- if result :
303- items , types , _ , ok = result
304- else :
310+ if result is None :
305311 # One of the types is not ready, defer.
306312 return None
313+ items , types , _ , ok = result
314+ if not ok :
315+ return [], [], [], typename , False
307316 if not types :
308317 types = [AnyType (TypeOfAny .unannotated ) for _ in items ]
309318 underscore = [item for item in items if item .startswith ('_' )]
@@ -313,50 +322,46 @@ def parse_namedtuple_args(self, call: CallExpr, fullname: str
313322 if len (defaults ) > len (items ):
314323 self .fail ("Too many defaults given in call to namedtuple()" , call )
315324 defaults = defaults [:len (items )]
316- return items , types , defaults , ok
325+ return items , types , defaults , typename , True
317326
318327 def parse_namedtuple_fields_with_types (self , nodes : List [Expression ], context : Context
319328 ) -> Optional [Tuple [List [str ], List [Type ],
320- List [Expression ],
321- bool ]]:
329+ List [Expression ], bool ]]:
322330 """Parse typed named tuple fields.
323331
324- Return (names, types, defaults, error occurred), or None if at least one of
325- the types is not ready.
332+ Return (names, types, defaults, whether types are all ready), or None if error occurred.
326333 """
327334 items = [] # type: List[str]
328335 types = [] # type: List[Type]
329336 for item in nodes :
330337 if isinstance (item , TupleExpr ):
331338 if len (item .items ) != 2 :
332- return self .fail_namedtuple_arg ("Invalid NamedTuple field definition" ,
333- item )
339+ self .fail ("Invalid NamedTuple field definition" , item )
340+ return None
334341 name , type_node = item .items
335342 if isinstance (name , (StrExpr , BytesExpr , UnicodeExpr )):
336343 items .append (name .value )
337344 else :
338- return self .fail_namedtuple_arg ("Invalid NamedTuple() field name" , item )
345+ self .fail ("Invalid NamedTuple() field name" , item )
346+ return None
339347 try :
340348 type = expr_to_unanalyzed_type (type_node )
341349 except TypeTranslationError :
342- return self .fail_namedtuple_arg ('Invalid field type' , type_node )
350+ self .fail ('Invalid field type' , type_node )
351+ return None
343352 analyzed = self .api .anal_type (type )
344353 # Workaround #4987 and avoid introducing a bogus UnboundType
345354 if isinstance (analyzed , UnboundType ):
346355 analyzed = AnyType (TypeOfAny .from_error )
347356 # These should be all known, otherwise we would defer in visit_assignment_stmt().
348357 if analyzed is None :
349- return None
358+ return [], [], [], False
350359 types .append (analyzed )
351360 else :
352- return self .fail_namedtuple_arg ("Tuple expected as NamedTuple() field" , item )
361+ self .fail ("Tuple expected as NamedTuple() field" , item )
362+ return None
353363 return items , types , [], True
354364
355- def fail_namedtuple_arg (self , message : str , context : Context
356- ) -> Tuple [List [str ], List [Type ], List [Expression ], bool ]:
357- self .fail (message , context )
358- return [], [], [], False
359-
360365 def build_namedtuple_typeinfo (self ,
361366 name : str ,
362367 items : List [str ],
0 commit comments