From c4d1be72d6e6e4178032a94c60791edda142338a Mon Sep 17 00:00:00 2001 From: Artem Yurchenko Date: Tue, 10 Sep 2024 10:00:27 -0700 Subject: [PATCH] set proper parents for namedtuple's and enum's it's a part of the campaign to get rid of non-module roots --- astroid/brain/brain_namedtuple_enum.py | 47 +++++++++++++------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/astroid/brain/brain_namedtuple_enum.py b/astroid/brain/brain_namedtuple_enum.py index 72a07c118..91d64db87 100644 --- a/astroid/brain/brain_namedtuple_enum.py +++ b/astroid/brain/brain_namedtuple_enum.py @@ -74,7 +74,9 @@ def _extract_namedtuple_arg_or_keyword( # pylint: disable=inconsistent-return-s def infer_func_form( node: nodes.Call, - base_type: list[nodes.NodeNG], + base_type: nodes.NodeNG, + *, + parent: nodes.NodeNG, context: InferenceContext | None = None, enum: bool = False, ) -> tuple[nodes.ClassDef, str, list[str]]: @@ -147,15 +149,11 @@ def infer_func_form( col_offset=node.col_offset, end_lineno=node.end_lineno, end_col_offset=node.end_col_offset, - parent=nodes.Unknown(), + parent=parent, ) - # A typical ClassDef automatically adds its name to the parent scope, - # but doing so causes problems, so defer setting parent until after init - # see: https://github.com/pylint-dev/pylint/issues/5982 - class_node.parent = node.parent class_node.postinit( # set base class=tuple - bases=base_type, + bases=[base_type], body=[], decorators=None, ) @@ -195,25 +193,16 @@ def infer_named_tuple( node: nodes.Call, context: InferenceContext | None = None ) -> Iterator[nodes.ClassDef]: """Specific inference function for namedtuple Call node.""" - tuple_base_name: list[nodes.NodeNG] = [ - nodes.Name( - name="tuple", - parent=node.root(), - lineno=0, - col_offset=0, - end_lineno=None, - end_col_offset=None, - ) - ] + tuple_base: nodes.Name = _extract_single_node("tuple") class_node, name, attributes = infer_func_form( - node, tuple_base_name, context=context + node, tuple_base, parent=AstroidManager().adhoc_module, context=context ) + call_site = arguments.CallSite.from_call(node, context=context) - node = extract_node("import collections; collections.namedtuple") - try: - func = next(node.infer()) - except StopIteration as e: - raise InferenceError(node=node) from e + func = util.safe_infer( + _extract_single_node("import collections; collections.namedtuple") + ) + assert isinstance(func, nodes.NodeNG) try: rename = next( call_site.infer_argument(func, "rename", context or InferenceContext()) @@ -364,7 +353,17 @@ def value(self): __members__ = [''] """ ) - class_node = infer_func_form(node, [enum_meta], context=context, enum=True)[0] + + # FIXME arguably, the base here shouldn't be the EnumMeta class definition + # itself, but a reference (Name) to it. Otherwise, the invariant that all + # children of a node have that node as their parent is broken. + class_node = infer_func_form( + node, + enum_meta, + parent=AstroidManager().adhoc_module, + context=context, + enum=True, + )[0] return iter([class_node.instantiate_class()])