semanal_namedtuple.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. """Semantic analysis of named tuple definitions.
  2. This is conceptually part of mypy.semanal.
  3. """
  4. from __future__ import annotations
  5. from contextlib import contextmanager
  6. from typing import Final, Iterator, List, Mapping, cast
  7. from mypy.exprtotype import TypeTranslationError, expr_to_unanalyzed_type
  8. from mypy.nodes import (
  9. ARG_NAMED_OPT,
  10. ARG_OPT,
  11. ARG_POS,
  12. MDEF,
  13. Argument,
  14. AssignmentStmt,
  15. Block,
  16. CallExpr,
  17. ClassDef,
  18. Context,
  19. Decorator,
  20. EllipsisExpr,
  21. Expression,
  22. ExpressionStmt,
  23. FuncBase,
  24. FuncDef,
  25. ListExpr,
  26. NamedTupleExpr,
  27. NameExpr,
  28. PassStmt,
  29. RefExpr,
  30. Statement,
  31. StrExpr,
  32. SymbolTable,
  33. SymbolTableNode,
  34. TempNode,
  35. TupleExpr,
  36. TypeInfo,
  37. TypeVarExpr,
  38. Var,
  39. is_StrExpr_list,
  40. )
  41. from mypy.options import Options
  42. from mypy.semanal_shared import (
  43. PRIORITY_FALLBACKS,
  44. SemanticAnalyzerInterface,
  45. calculate_tuple_fallback,
  46. has_placeholder,
  47. set_callable_name,
  48. )
  49. from mypy.types import (
  50. TYPED_NAMEDTUPLE_NAMES,
  51. AnyType,
  52. CallableType,
  53. LiteralType,
  54. TupleType,
  55. Type,
  56. TypeOfAny,
  57. TypeType,
  58. TypeVarLikeType,
  59. TypeVarType,
  60. UnboundType,
  61. has_type_vars,
  62. )
  63. from mypy.util import get_unique_redefinition_name
  64. # Matches "_prohibited" in typing.py, but adds __annotations__, which works at runtime but can't
  65. # easily be supported in a static checker.
  66. NAMEDTUPLE_PROHIBITED_NAMES: Final = (
  67. "__new__",
  68. "__init__",
  69. "__slots__",
  70. "__getnewargs__",
  71. "_fields",
  72. "_field_defaults",
  73. "_field_types",
  74. "_make",
  75. "_replace",
  76. "_asdict",
  77. "_source",
  78. "__annotations__",
  79. )
  80. NAMEDTUP_CLASS_ERROR: Final = (
  81. "Invalid statement in NamedTuple definition; " 'expected "field_name: field_type [= default]"'
  82. )
  83. SELF_TVAR_NAME: Final = "_NT"
  84. class NamedTupleAnalyzer:
  85. def __init__(self, options: Options, api: SemanticAnalyzerInterface) -> None:
  86. self.options = options
  87. self.api = api
  88. def analyze_namedtuple_classdef(
  89. self, defn: ClassDef, is_stub_file: bool, is_func_scope: bool
  90. ) -> tuple[bool, TypeInfo | None]:
  91. """Analyze if given class definition can be a named tuple definition.
  92. Return a tuple where first item indicates whether this can possibly be a named tuple,
  93. and the second item is the corresponding TypeInfo (may be None if not ready and should be
  94. deferred).
  95. """
  96. for base_expr in defn.base_type_exprs:
  97. if isinstance(base_expr, RefExpr):
  98. self.api.accept(base_expr)
  99. if base_expr.fullname in TYPED_NAMEDTUPLE_NAMES:
  100. result = self.check_namedtuple_classdef(defn, is_stub_file)
  101. if result is None:
  102. # This is a valid named tuple, but some types are incomplete.
  103. return True, None
  104. items, types, default_items, statements = result
  105. if is_func_scope and "@" not in defn.name:
  106. defn.name += "@" + str(defn.line)
  107. existing_info = None
  108. if isinstance(defn.analyzed, NamedTupleExpr):
  109. existing_info = defn.analyzed.info
  110. info = self.build_namedtuple_typeinfo(
  111. defn.name, items, types, default_items, defn.line, existing_info
  112. )
  113. defn.analyzed = NamedTupleExpr(info, is_typed=True)
  114. defn.analyzed.line = defn.line
  115. defn.analyzed.column = defn.column
  116. defn.defs.body = statements
  117. # All done: this is a valid named tuple with all types known.
  118. return True, info
  119. # This can't be a valid named tuple.
  120. return False, None
  121. def check_namedtuple_classdef(
  122. self, defn: ClassDef, is_stub_file: bool
  123. ) -> tuple[list[str], list[Type], dict[str, Expression], list[Statement]] | None:
  124. """Parse and validate fields in named tuple class definition.
  125. Return a four tuple:
  126. * field names
  127. * field types
  128. * field default values
  129. * valid statements
  130. or None, if any of the types are not ready.
  131. """
  132. if self.options.python_version < (3, 6) and not is_stub_file:
  133. self.fail("NamedTuple class syntax is only supported in Python 3.6", defn)
  134. return [], [], {}, []
  135. if len(defn.base_type_exprs) > 1:
  136. self.fail("NamedTuple should be a single base", defn)
  137. items: list[str] = []
  138. types: list[Type] = []
  139. default_items: dict[str, Expression] = {}
  140. statements: list[Statement] = []
  141. for stmt in defn.defs.body:
  142. statements.append(stmt)
  143. if not isinstance(stmt, AssignmentStmt):
  144. # Still allow pass or ... (for empty namedtuples).
  145. if isinstance(stmt, PassStmt) or (
  146. isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, EllipsisExpr)
  147. ):
  148. continue
  149. # Also allow methods, including decorated ones.
  150. if isinstance(stmt, (Decorator, FuncBase)):
  151. continue
  152. # And docstrings.
  153. if isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, StrExpr):
  154. continue
  155. statements.pop()
  156. defn.removed_statements.append(stmt)
  157. self.fail(NAMEDTUP_CLASS_ERROR, stmt)
  158. elif len(stmt.lvalues) > 1 or not isinstance(stmt.lvalues[0], NameExpr):
  159. # An assignment, but an invalid one.
  160. statements.pop()
  161. defn.removed_statements.append(stmt)
  162. self.fail(NAMEDTUP_CLASS_ERROR, stmt)
  163. else:
  164. # Append name and type in this case...
  165. name = stmt.lvalues[0].name
  166. items.append(name)
  167. if stmt.type is None:
  168. types.append(AnyType(TypeOfAny.unannotated))
  169. else:
  170. # We never allow recursive types at function scope. Although it is
  171. # possible to support this for named tuples, it is still tricky, and
  172. # it would be inconsistent with type aliases.
  173. analyzed = self.api.anal_type(
  174. stmt.type,
  175. allow_placeholder=not self.options.disable_recursive_aliases
  176. and not self.api.is_func_scope(),
  177. prohibit_self_type="NamedTuple item type",
  178. )
  179. if analyzed is None:
  180. # Something is incomplete. We need to defer this named tuple.
  181. return None
  182. types.append(analyzed)
  183. # ...despite possible minor failures that allow further analyzis.
  184. if name.startswith("_"):
  185. self.fail(
  186. f"NamedTuple field name cannot start with an underscore: {name}", stmt
  187. )
  188. if stmt.type is None or hasattr(stmt, "new_syntax") and not stmt.new_syntax:
  189. self.fail(NAMEDTUP_CLASS_ERROR, stmt)
  190. elif isinstance(stmt.rvalue, TempNode):
  191. # x: int assigns rvalue to TempNode(AnyType())
  192. if default_items:
  193. self.fail(
  194. "Non-default NamedTuple fields cannot follow default fields", stmt
  195. )
  196. else:
  197. default_items[name] = stmt.rvalue
  198. return items, types, default_items, statements
  199. def check_namedtuple(
  200. self, node: Expression, var_name: str | None, is_func_scope: bool
  201. ) -> tuple[str | None, TypeInfo | None, list[TypeVarLikeType]]:
  202. """Check if a call defines a namedtuple.
  203. The optional var_name argument is the name of the variable to
  204. which this is assigned, if any.
  205. Return a tuple of two items:
  206. * Internal name of the named tuple (e.g. the name passed as an argument to namedtuple)
  207. or None if it is not a valid named tuple
  208. * Corresponding TypeInfo, or None if not ready.
  209. If the definition is invalid but looks like a namedtuple,
  210. report errors but return (some) TypeInfo.
  211. """
  212. if not isinstance(node, CallExpr):
  213. return None, None, []
  214. call = node
  215. callee = call.callee
  216. if not isinstance(callee, RefExpr):
  217. return None, None, []
  218. fullname = callee.fullname
  219. if fullname == "collections.namedtuple":
  220. is_typed = False
  221. elif fullname in TYPED_NAMEDTUPLE_NAMES:
  222. is_typed = True
  223. else:
  224. return None, None, []
  225. result = self.parse_namedtuple_args(call, fullname)
  226. if result:
  227. items, types, defaults, typename, tvar_defs, ok = result
  228. else:
  229. # Error. Construct dummy return value.
  230. if var_name:
  231. name = var_name
  232. if is_func_scope:
  233. name += "@" + str(call.line)
  234. else:
  235. name = var_name = "namedtuple@" + str(call.line)
  236. info = self.build_namedtuple_typeinfo(name, [], [], {}, node.line, None)
  237. self.store_namedtuple_info(info, var_name, call, is_typed)
  238. if name != var_name or is_func_scope:
  239. # NOTE: we skip local namespaces since they are not serialized.
  240. self.api.add_symbol_skip_local(name, info)
  241. return var_name, info, []
  242. if not ok:
  243. # This is a valid named tuple but some types are not ready.
  244. return typename, None, []
  245. # We use the variable name as the class name if it exists. If
  246. # it doesn't, we use the name passed as an argument. We prefer
  247. # the variable name because it should be unique inside a
  248. # module, and so we don't need to disambiguate it with a line
  249. # number.
  250. if var_name:
  251. name = var_name
  252. else:
  253. name = typename
  254. if var_name is None or is_func_scope:
  255. # There are two special cases where need to give it a unique name derived
  256. # from the line number:
  257. # * This is a base class expression, since it often matches the class name:
  258. # class NT(NamedTuple('NT', [...])):
  259. # ...
  260. # * This is a local (function or method level) named tuple, since
  261. # two methods of a class can define a named tuple with the same name,
  262. # and they will be stored in the same namespace (see below).
  263. name += "@" + str(call.line)
  264. if defaults:
  265. default_items = {
  266. arg_name: default for arg_name, default in zip(items[-len(defaults) :], defaults)
  267. }
  268. else:
  269. default_items = {}
  270. existing_info = None
  271. if isinstance(node.analyzed, NamedTupleExpr):
  272. existing_info = node.analyzed.info
  273. info = self.build_namedtuple_typeinfo(
  274. name, items, types, default_items, node.line, existing_info
  275. )
  276. # If var_name is not None (i.e. this is not a base class expression), we always
  277. # store the generated TypeInfo under var_name in the current scope, so that
  278. # other definitions can use it.
  279. if var_name:
  280. self.store_namedtuple_info(info, var_name, call, is_typed)
  281. else:
  282. call.analyzed = NamedTupleExpr(info, is_typed=is_typed)
  283. call.analyzed.set_line(call)
  284. # There are three cases where we need to store the generated TypeInfo
  285. # second time (for the purpose of serialization):
  286. # * If there is a name mismatch like One = NamedTuple('Other', [...])
  287. # we also store the info under name 'Other@lineno', this is needed
  288. # because classes are (de)serialized using their actual fullname, not
  289. # the name of l.h.s.
  290. # * If this is a method level named tuple. It can leak from the method
  291. # via assignment to self attribute and therefore needs to be serialized
  292. # (local namespaces are not serialized).
  293. # * If it is a base class expression. It was not stored above, since
  294. # there is no var_name (but it still needs to be serialized
  295. # since it is in MRO of some class).
  296. if name != var_name or is_func_scope:
  297. # NOTE: we skip local namespaces since they are not serialized.
  298. self.api.add_symbol_skip_local(name, info)
  299. return typename, info, tvar_defs
  300. def store_namedtuple_info(
  301. self, info: TypeInfo, name: str, call: CallExpr, is_typed: bool
  302. ) -> None:
  303. self.api.add_symbol(name, info, call)
  304. call.analyzed = NamedTupleExpr(info, is_typed=is_typed)
  305. call.analyzed.set_line(call)
  306. def parse_namedtuple_args(
  307. self, call: CallExpr, fullname: str
  308. ) -> None | (tuple[list[str], list[Type], list[Expression], str, list[TypeVarLikeType], bool]):
  309. """Parse a namedtuple() call into data needed to construct a type.
  310. Returns a 6-tuple:
  311. - List of argument names
  312. - List of argument types
  313. - List of default values
  314. - First argument of namedtuple
  315. - All typevars found in the field definition
  316. - Whether all types are ready.
  317. Return None if the definition didn't typecheck.
  318. """
  319. type_name = "NamedTuple" if fullname in TYPED_NAMEDTUPLE_NAMES else "namedtuple"
  320. # TODO: Share code with check_argument_count in checkexpr.py?
  321. args = call.args
  322. if len(args) < 2:
  323. self.fail(f'Too few arguments for "{type_name}()"', call)
  324. return None
  325. defaults: list[Expression] = []
  326. if len(args) > 2:
  327. # Typed namedtuple doesn't support additional arguments.
  328. if fullname in TYPED_NAMEDTUPLE_NAMES:
  329. self.fail('Too many arguments for "NamedTuple()"', call)
  330. return None
  331. for i, arg_name in enumerate(call.arg_names[2:], 2):
  332. if arg_name == "defaults":
  333. arg = args[i]
  334. # We don't care what the values are, as long as the argument is an iterable
  335. # and we can count how many defaults there are.
  336. if isinstance(arg, (ListExpr, TupleExpr)):
  337. defaults = list(arg.items)
  338. else:
  339. self.fail(
  340. "List or tuple literal expected as the defaults argument to "
  341. "{}()".format(type_name),
  342. arg,
  343. )
  344. break
  345. if call.arg_kinds[:2] != [ARG_POS, ARG_POS]:
  346. self.fail(f'Unexpected arguments to "{type_name}()"', call)
  347. return None
  348. if not isinstance(args[0], StrExpr):
  349. self.fail(f'"{type_name}()" expects a string literal as the first argument', call)
  350. return None
  351. typename = args[0].value
  352. types: list[Type] = []
  353. tvar_defs = []
  354. if not isinstance(args[1], (ListExpr, TupleExpr)):
  355. if fullname == "collections.namedtuple" and isinstance(args[1], StrExpr):
  356. str_expr = args[1]
  357. items = str_expr.value.replace(",", " ").split()
  358. else:
  359. self.fail(
  360. 'List or tuple literal expected as the second argument to "{}()"'.format(
  361. type_name
  362. ),
  363. call,
  364. )
  365. return None
  366. else:
  367. listexpr = args[1]
  368. if fullname == "collections.namedtuple":
  369. # The fields argument contains just names, with implicit Any types.
  370. if not is_StrExpr_list(listexpr.items):
  371. self.fail('String literal expected as "namedtuple()" item', call)
  372. return None
  373. items = [item.value for item in listexpr.items]
  374. else:
  375. type_exprs = [
  376. t.items[1]
  377. for t in listexpr.items
  378. if isinstance(t, TupleExpr) and len(t.items) == 2
  379. ]
  380. tvar_defs = self.api.get_and_bind_all_tvars(type_exprs)
  381. # The fields argument contains (name, type) tuples.
  382. result = self.parse_namedtuple_fields_with_types(listexpr.items, call)
  383. if result is None:
  384. # One of the types is not ready, defer.
  385. return None
  386. items, types, _, ok = result
  387. if not ok:
  388. return [], [], [], typename, [], False
  389. if not types:
  390. types = [AnyType(TypeOfAny.unannotated) for _ in items]
  391. underscore = [item for item in items if item.startswith("_")]
  392. if underscore:
  393. self.fail(
  394. f'"{type_name}()" field names cannot start with an underscore: '
  395. + ", ".join(underscore),
  396. call,
  397. )
  398. if len(defaults) > len(items):
  399. self.fail(f'Too many defaults given in call to "{type_name}()"', call)
  400. defaults = defaults[: len(items)]
  401. return items, types, defaults, typename, tvar_defs, True
  402. def parse_namedtuple_fields_with_types(
  403. self, nodes: list[Expression], context: Context
  404. ) -> tuple[list[str], list[Type], list[Expression], bool] | None:
  405. """Parse typed named tuple fields.
  406. Return (names, types, defaults, whether types are all ready), or None if error occurred.
  407. """
  408. items: list[str] = []
  409. types: list[Type] = []
  410. for item in nodes:
  411. if isinstance(item, TupleExpr):
  412. if len(item.items) != 2:
  413. self.fail('Invalid "NamedTuple()" field definition', item)
  414. return None
  415. name, type_node = item.items
  416. if isinstance(name, StrExpr):
  417. items.append(name.value)
  418. else:
  419. self.fail('Invalid "NamedTuple()" field name', item)
  420. return None
  421. try:
  422. type = expr_to_unanalyzed_type(type_node, self.options, self.api.is_stub_file)
  423. except TypeTranslationError:
  424. self.fail("Invalid field type", type_node)
  425. return None
  426. # We never allow recursive types at function scope.
  427. analyzed = self.api.anal_type(
  428. type,
  429. allow_placeholder=not self.options.disable_recursive_aliases
  430. and not self.api.is_func_scope(),
  431. prohibit_self_type="NamedTuple item type",
  432. )
  433. # Workaround #4987 and avoid introducing a bogus UnboundType
  434. if isinstance(analyzed, UnboundType):
  435. analyzed = AnyType(TypeOfAny.from_error)
  436. # These should be all known, otherwise we would defer in visit_assignment_stmt().
  437. if analyzed is None:
  438. return [], [], [], False
  439. types.append(analyzed)
  440. else:
  441. self.fail('Tuple expected as "NamedTuple()" field', item)
  442. return None
  443. return items, types, [], True
  444. def build_namedtuple_typeinfo(
  445. self,
  446. name: str,
  447. items: list[str],
  448. types: list[Type],
  449. default_items: Mapping[str, Expression],
  450. line: int,
  451. existing_info: TypeInfo | None,
  452. ) -> TypeInfo:
  453. strtype = self.api.named_type("builtins.str")
  454. implicit_any = AnyType(TypeOfAny.special_form)
  455. basetuple_type = self.api.named_type("builtins.tuple", [implicit_any])
  456. dictype = self.api.named_type("builtins.dict", [strtype, implicit_any])
  457. # Actual signature should return OrderedDict[str, Union[types]]
  458. ordereddictype = self.api.named_type("builtins.dict", [strtype, implicit_any])
  459. fallback = self.api.named_type("builtins.tuple", [implicit_any])
  460. # Note: actual signature should accept an invariant version of Iterable[UnionType[types]].
  461. # but it can't be expressed. 'new' and 'len' should be callable types.
  462. iterable_type = self.api.named_type_or_none("typing.Iterable", [implicit_any])
  463. function_type = self.api.named_type("builtins.function")
  464. literals: list[Type] = [LiteralType(item, strtype) for item in items]
  465. match_args_type = TupleType(literals, basetuple_type)
  466. info = existing_info or self.api.basic_new_typeinfo(name, fallback, line)
  467. info.is_named_tuple = True
  468. tuple_base = TupleType(types, fallback)
  469. if info.special_alias and has_placeholder(info.special_alias.target):
  470. self.api.process_placeholder(
  471. None, "NamedTuple item", info, force_progress=tuple_base != info.tuple_type
  472. )
  473. info.update_tuple_type(tuple_base)
  474. info.line = line
  475. # For use by mypyc.
  476. info.metadata["namedtuple"] = {"fields": items.copy()}
  477. # We can't calculate the complete fallback type until after semantic
  478. # analysis, since otherwise base classes might be incomplete. Postpone a
  479. # callback function that patches the fallback.
  480. if not has_placeholder(tuple_base) and not has_type_vars(tuple_base):
  481. self.api.schedule_patch(
  482. PRIORITY_FALLBACKS, lambda: calculate_tuple_fallback(tuple_base)
  483. )
  484. def add_field(
  485. var: Var, is_initialized_in_class: bool = False, is_property: bool = False
  486. ) -> None:
  487. var.info = info
  488. var.is_initialized_in_class = is_initialized_in_class
  489. var.is_property = is_property
  490. var._fullname = f"{info.fullname}.{var.name}"
  491. info.names[var.name] = SymbolTableNode(MDEF, var)
  492. fields = [Var(item, typ) for item, typ in zip(items, types)]
  493. for var in fields:
  494. add_field(var, is_property=True)
  495. # We can't share Vars between fields and method arguments, since they
  496. # have different full names (the latter are normally used as local variables
  497. # in functions, so their full names are set to short names when generated methods
  498. # are analyzed).
  499. vars = [Var(item, typ) for item, typ in zip(items, types)]
  500. tuple_of_strings = TupleType([strtype for _ in items], basetuple_type)
  501. add_field(Var("_fields", tuple_of_strings), is_initialized_in_class=True)
  502. add_field(Var("_field_types", dictype), is_initialized_in_class=True)
  503. add_field(Var("_field_defaults", dictype), is_initialized_in_class=True)
  504. add_field(Var("_source", strtype), is_initialized_in_class=True)
  505. add_field(Var("__annotations__", ordereddictype), is_initialized_in_class=True)
  506. add_field(Var("__doc__", strtype), is_initialized_in_class=True)
  507. if self.options.python_version >= (3, 10):
  508. add_field(Var("__match_args__", match_args_type), is_initialized_in_class=True)
  509. assert info.tuple_type is not None # Set by update_tuple_type() above.
  510. tvd = TypeVarType(
  511. name=SELF_TVAR_NAME,
  512. fullname=info.fullname + "." + SELF_TVAR_NAME,
  513. id=self.api.tvar_scope.new_unique_func_id(),
  514. values=[],
  515. upper_bound=info.tuple_type,
  516. default=AnyType(TypeOfAny.from_omitted_generics),
  517. )
  518. selftype = tvd
  519. def add_method(
  520. funcname: str,
  521. ret: Type,
  522. args: list[Argument],
  523. is_classmethod: bool = False,
  524. is_new: bool = False,
  525. ) -> None:
  526. if is_classmethod or is_new:
  527. first = [Argument(Var("_cls"), TypeType.make_normalized(selftype), None, ARG_POS)]
  528. else:
  529. first = [Argument(Var("_self"), selftype, None, ARG_POS)]
  530. args = first + args
  531. types = [arg.type_annotation for arg in args]
  532. items = [arg.variable.name for arg in args]
  533. arg_kinds = [arg.kind for arg in args]
  534. assert None not in types
  535. signature = CallableType(cast(List[Type], types), arg_kinds, items, ret, function_type)
  536. signature.variables = [tvd]
  537. func = FuncDef(funcname, args, Block([]))
  538. func.info = info
  539. func.is_class = is_classmethod
  540. func.type = set_callable_name(signature, func)
  541. func._fullname = info.fullname + "." + funcname
  542. func.line = line
  543. if is_classmethod:
  544. v = Var(funcname, func.type)
  545. v.is_classmethod = True
  546. v.info = info
  547. v._fullname = func._fullname
  548. func.is_decorated = True
  549. dec = Decorator(func, [NameExpr("classmethod")], v)
  550. dec.line = line
  551. sym = SymbolTableNode(MDEF, dec)
  552. else:
  553. sym = SymbolTableNode(MDEF, func)
  554. sym.plugin_generated = True
  555. info.names[funcname] = sym
  556. add_method(
  557. "_replace",
  558. ret=selftype,
  559. args=[Argument(var, var.type, EllipsisExpr(), ARG_NAMED_OPT) for var in vars],
  560. )
  561. def make_init_arg(var: Var) -> Argument:
  562. default = default_items.get(var.name, None)
  563. kind = ARG_POS if default is None else ARG_OPT
  564. return Argument(var, var.type, default, kind)
  565. add_method("__new__", ret=selftype, args=[make_init_arg(var) for var in vars], is_new=True)
  566. add_method("_asdict", args=[], ret=ordereddictype)
  567. add_method(
  568. "_make",
  569. ret=selftype,
  570. is_classmethod=True,
  571. args=[Argument(Var("iterable", iterable_type), iterable_type, None, ARG_POS)],
  572. )
  573. self_tvar_expr = TypeVarExpr(
  574. SELF_TVAR_NAME,
  575. info.fullname + "." + SELF_TVAR_NAME,
  576. [],
  577. info.tuple_type,
  578. AnyType(TypeOfAny.from_omitted_generics),
  579. )
  580. info.names[SELF_TVAR_NAME] = SymbolTableNode(MDEF, self_tvar_expr)
  581. return info
  582. @contextmanager
  583. def save_namedtuple_body(self, named_tuple_info: TypeInfo) -> Iterator[None]:
  584. """Preserve the generated body of class-based named tuple and then restore it.
  585. Temporarily clear the names dict so we don't get errors about duplicate names
  586. that were already set in build_namedtuple_typeinfo (we already added the tuple
  587. field names while generating the TypeInfo, and actual duplicates are
  588. already reported).
  589. """
  590. nt_names = named_tuple_info.names
  591. named_tuple_info.names = SymbolTable()
  592. yield
  593. # Make sure we didn't use illegal names, then reset the names in the typeinfo.
  594. for prohibited in NAMEDTUPLE_PROHIBITED_NAMES:
  595. if prohibited in named_tuple_info.names:
  596. if nt_names.get(prohibited) is named_tuple_info.names[prohibited]:
  597. continue
  598. ctx = named_tuple_info.names[prohibited].node
  599. assert ctx is not None
  600. self.fail(f'Cannot overwrite NamedTuple attribute "{prohibited}"', ctx)
  601. # Restore the names in the original symbol table. This ensures that the symbol
  602. # table contains the field objects created by build_namedtuple_typeinfo. Exclude
  603. # __doc__, which can legally be overwritten by the class.
  604. for key, value in nt_names.items():
  605. if key in named_tuple_info.names:
  606. if key == "__doc__":
  607. continue
  608. sym = named_tuple_info.names[key]
  609. if isinstance(sym.node, (FuncBase, Decorator)) and not sym.plugin_generated:
  610. # Keep user-defined methods as is.
  611. continue
  612. # Keep existing (user-provided) definitions under mangled names, so they
  613. # get semantically analyzed.
  614. r_key = get_unique_redefinition_name(key, named_tuple_info.names)
  615. named_tuple_info.names[r_key] = sym
  616. named_tuple_info.names[key] = value
  617. # Helpers
  618. def fail(self, msg: str, ctx: Context) -> None:
  619. self.api.fail(msg, ctx)