Skip to content

Commit c65d836

Browse files
committed
enforce a non-None parent in build_function
We also remove `add_local_node` to avoid redundancy. Instead we do the attachment to the parent scope in the constructor of `FunctionDef`. We append a node to the body of the frame when it is also the parent. If it's not a parent, then the node should belong to the "body" of the parent if it existed. An example is a definition within an "if", where the parent is the If node, but the frame is the whole module. it's a part of the campaign to get rid of non-module roots
1 parent b4ac0e2 commit c65d836

File tree

3 files changed

+20
-13
lines changed

3 files changed

+20
-13
lines changed

astroid/nodes/scoped_nodes/scoped_nodes.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,13 @@ def function_to_method(n, klass):
178178
return n
179179

180180

181+
def _attach_to_parent(node: NodeNG, name: str, parent: NodeNG):
182+
frame = parent.frame()
183+
frame.set_local(name, node)
184+
if frame is parent:
185+
frame._append_node(node)
186+
187+
181188
class Module(LocalsDictNodeNG):
182189
"""Class representing an :class:`ast.Module` node.
183190
@@ -1167,8 +1174,7 @@ def __init__(
11671174
parent=parent,
11681175
)
11691176
if parent and not isinstance(parent, Unknown):
1170-
frame = parent.frame()
1171-
frame.set_local(name, self)
1177+
_attach_to_parent(self, name, parent)
11721178

11731179
def postinit(
11741180
self,

astroid/raw_building.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ def build_class(
129129

130130
def build_function(
131131
name: str,
132+
parent: nodes.NodeNG,
132133
args: list[str] | None = None,
133134
posonlyargs: list[str] | None = None,
134135
defaults: list[Any] | None = None,
@@ -142,7 +143,7 @@ def build_function(
142143
name,
143144
lineno=0,
144145
col_offset=0,
145-
parent=node_classes.Unknown(),
146+
parent=parent,
146147
end_col_offset=0,
147148
end_lineno=0,
148149
)
@@ -312,8 +313,9 @@ def object_build_function(
312313
kwonly_defaults,
313314
) = _get_args_info_from_callable(member)
314315

315-
func = build_function(
316+
build_function(
316317
getattr(member, "__name__", None) or localname,
318+
node,
317319
args,
318320
posonlyargs,
319321
defaults,
@@ -322,8 +324,6 @@ def object_build_function(
322324
kwonlydefaults=kwonly_defaults,
323325
)
324326

325-
node.add_local_node(func, localname)
326-
327327

328328
def object_build_datadescriptor(
329329
node: nodes.Module | nodes.ClassDef, member: type, name: str
@@ -340,9 +340,8 @@ def object_build_methoddescriptor(
340340
"""create astroid for a living method descriptor object"""
341341
# FIXME get arguments ?
342342
func = build_function(
343-
getattr(member, "__name__", None) or localname, doc=member.__doc__
343+
getattr(member, "__name__", None) or localname, node, doc=member.__doc__
344344
)
345-
node.add_local_node(func, localname)
346345
_add_dunder_class(func, member)
347346

348347

tests/test_raw_building.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
build_module,
3434
)
3535

36+
DUMMY_MOD = build_module("DUMMY")
37+
3638

3739
class RawBuildingTC(unittest.TestCase):
3840
def test_attach_dummy_node(self) -> None:
@@ -53,28 +55,28 @@ def test_build_class(self) -> None:
5355
self.assertEqual(node.doc_node, None)
5456

5557
def test_build_function(self) -> None:
56-
node = build_function("MyFunction")
58+
node = build_function("MyFunction", DUMMY_MOD)
5759
self.assertEqual(node.name, "MyFunction")
5860
self.assertEqual(node.doc_node, None)
5961

6062
def test_build_function_args(self) -> None:
6163
args = ["myArgs1", "myArgs2"]
62-
node = build_function("MyFunction", args)
64+
node = build_function("MyFunction", DUMMY_MOD, args)
6365
self.assertEqual("myArgs1", node.args.args[0].name)
6466
self.assertEqual("myArgs2", node.args.args[1].name)
6567
self.assertEqual(2, len(node.args.args))
6668

6769
def test_build_function_defaults(self) -> None:
6870
defaults = ["defaults1", "defaults2"]
69-
node = build_function(name="MyFunction", args=None, defaults=defaults)
71+
node = build_function("MyFunction", DUMMY_MOD, args=None, defaults=defaults)
7072
self.assertEqual(2, len(node.args.defaults))
7173

7274
def test_build_function_posonlyargs(self) -> None:
73-
node = build_function(name="MyFunction", posonlyargs=["a", "b"])
75+
node = build_function("MyFunction", DUMMY_MOD, posonlyargs=["a", "b"])
7476
self.assertEqual(2, len(node.args.posonlyargs))
7577

7678
def test_build_function_kwonlyargs(self) -> None:
77-
node = build_function(name="MyFunction", kwonlyargs=["a", "b"])
79+
node = build_function("MyFunction", DUMMY_MOD, kwonlyargs=["a", "b"])
7880
assert len(node.args.kwonlyargs) == 2
7981
assert node.args.kwonlyargs[0].name == "a"
8082
assert node.args.kwonlyargs[1].name == "b"

0 commit comments

Comments
 (0)