Parse a namedtuple() call into data needed to construct a type. Returns a 6-tuple: - List of argument names - List of argument types - List of default values - First argument of namedtuple - All typevars found in the field definition - Whether
(
self, call: CallExpr, fullname: str
)
| 337 | call.analyzed.set_line(call) |
| 338 | |
| 339 | def parse_namedtuple_args( |
| 340 | self, call: CallExpr, fullname: str |
| 341 | ) -> None | (tuple[list[str], list[Type], list[Expression], str, list[TypeVarLikeType], bool]): |
| 342 | """Parse a namedtuple() call into data needed to construct a type. |
| 343 | |
| 344 | Returns a 6-tuple: |
| 345 | - List of argument names |
| 346 | - List of argument types |
| 347 | - List of default values |
| 348 | - First argument of namedtuple |
| 349 | - All typevars found in the field definition |
| 350 | - Whether all types are ready. |
| 351 | |
| 352 | Return None if the definition didn't typecheck. |
| 353 | """ |
| 354 | type_name = "NamedTuple" if fullname in TYPED_NAMEDTUPLE_NAMES else "namedtuple" |
| 355 | # TODO: Share code with check_argument_count in checkexpr.py? |
| 356 | args = call.args |
| 357 | if len(args) < 2: |
| 358 | self.fail(f'Too few arguments for "{type_name}()"', call) |
| 359 | return None |
| 360 | defaults: list[Expression] = [] |
| 361 | rename = False |
| 362 | if len(args) > 2: |
| 363 | # Typed namedtuple doesn't support additional arguments. |
| 364 | if fullname in TYPED_NAMEDTUPLE_NAMES: |
| 365 | self.fail('Too many arguments for "NamedTuple()"', call) |
| 366 | return None |
| 367 | for i, arg_name in enumerate(call.arg_names[2:], 2): |
| 368 | if arg_name == "defaults": |
| 369 | arg = args[i] |
| 370 | # We don't care what the values are, as long as the argument is an iterable |
| 371 | # and we can count how many defaults there are. |
| 372 | if isinstance(arg, (ListExpr, TupleExpr)): |
| 373 | defaults = list(arg.items) |
| 374 | else: |
| 375 | self.fail( |
| 376 | "List or tuple literal expected as the defaults argument to " |
| 377 | "{}()".format(type_name), |
| 378 | arg, |
| 379 | ) |
| 380 | elif arg_name == "rename": |
| 381 | arg = args[i] |
| 382 | if isinstance(arg, NameExpr) and arg.name in ("True", "False"): |
| 383 | rename = arg.name == "True" |
| 384 | else: |
| 385 | self.fail( |
| 386 | f'Boolean literal expected as the "rename" argument to {type_name}()', |
| 387 | arg, |
| 388 | code=ARG_TYPE, |
| 389 | ) |
| 390 | if call.arg_kinds[:2] != [ARG_POS, ARG_POS]: |
| 391 | self.fail(f'Unexpected arguments to "{type_name}()"', call) |
| 392 | return None |
| 393 | if not isinstance(args[0], StrExpr): |
| 394 | self.fail(f'"{type_name}()" expects a string literal as the first argument', call) |
| 395 | return None |
| 396 | typename = args[0].value |
no test coverage detected