Skip to content

Commit

Permalink
ensure that all nodes have a Module as their eventual root
Browse files Browse the repository at this point in the history
that involved several changes

- creating an "adhoc" module, specifically for nodes that are not
   based in the real syntactic tree, but created "ad-hoc". See
   "__astroid_adhoc" and 'AstroidManager().adhoc_module'.

- eliminating all "Unknown" nodes as parents. They are not
   'Module's. Most of the time, it is sufficient to either specify the
   actual parent in the constructor or the adhoc module from above.

- fixing construction of in-place properties (`bar =
   property(getter)`). They just create a nameless object, not the one
   with the name of the getter. Thus, the name was changed to
   "<property>". Furthermore, the definition of that property is not
   attached to any scope, as it's again nameless.

- using "tuple" ClassDef for a base of 'namedtuple' instead of a
   Name. We're already doing it for "enum"s, and I don't know how to
   ensure that the Name actually refers to the actual tuple, and not
   something shadowing it in the scope. Removed the test that asserted
   that the base is a Name and not a ClassDef. If it is actually
   useful, it should be checked and reworked comprehensively across
   all nodes (cf. Enum).

- appending 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. See FunctionDef.__init__.

- fixing inference of the "special" attributes of Instances. Before
   these changes, the FunctionDef attributes wouldn't get wrapped into
   a BoundMethod. This was facilitated by extracting the logic of
   inferring attributes into 'FunctionDef._infer_attrs' and reusing it
   in BaseInstance.

  This issue wasn't visible before, because the special attributes
   were simply not found due not being attached to the parent (the
   instance). Which in turn was caused by not providing the actual
   parent in the constructor.

- enforcing a non-None parent in various builders in raw_building.py

- fixing tests to accomodate for changes

attach classes to their parent; fix bugs uncovered by this

1. some '__doc__' fields of standard library
   symbols (e.g. WrapperDescriptorType.__doc__) don't return a string,
   they return a 'getset_descriptor'. Thus, an attempt to print "as
   string" fails. The solution is to check that __doc__ is an instance
   of str.

2. A "temporary_class" was attached to a function node, when it
   shouldn't have been. The solution is to reattach it to the adhoc
   module.
  • Loading branch information
temyurchenko committed Sep 11, 2024
1 parent b0e0a44 commit 69aea20
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 11 deletions.
3 changes: 1 addition & 2 deletions astroid/nodes/scoped_nodes/scoped_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2067,7 +2067,7 @@ def _infer_type_call(self, caller, context):
col_offset=0,
end_lineno=0,
end_col_offset=0,
parent=Unknown(),
parent=caller.parent,
)

# Get the bases of the class.
Expand Down Expand Up @@ -2101,7 +2101,6 @@ def _infer_type_call(self, caller, context):
if isinstance(attr, node_classes.Const) and isinstance(attr.value, str):
result.locals[attr.value] = [value]

result.parent = caller.parent
return result

def infer_call_result(
Expand Down
12 changes: 4 additions & 8 deletions astroid/raw_building.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,9 +626,8 @@ def _astroid_bootstrapping() -> None:
col_offset=0,
end_lineno=0,
end_col_offset=0,
parent=nodes.Unknown(),
parent=astroid_builtin,
)
_GeneratorType.parent = astroid_builtin
generator_doc_node = (
nodes.Const(value=types.GeneratorType.__doc__)
if types.GeneratorType.__doc__
Expand All @@ -650,9 +649,8 @@ def _astroid_bootstrapping() -> None:
col_offset=0,
end_lineno=0,
end_col_offset=0,
parent=nodes.Unknown(),
parent=astroid_builtin,
)
_AsyncGeneratorType.parent = astroid_builtin
async_generator_doc_node = (
nodes.Const(value=types.AsyncGeneratorType.__doc__)
if types.AsyncGeneratorType.__doc__
Expand All @@ -674,9 +672,8 @@ def _astroid_bootstrapping() -> None:
col_offset=0,
end_lineno=0,
end_col_offset=0,
parent=nodes.Unknown(),
parent=astroid_builtin,
)
_UnionTypeType.parent = astroid_builtin
union_type_doc_node = (
nodes.Const(value=types.UnionType.__doc__)
if types.UnionType.__doc__
Expand Down Expand Up @@ -711,9 +708,8 @@ def _astroid_bootstrapping() -> None:
col_offset=0,
end_lineno=0,
end_col_offset=0,
parent=nodes.Unknown(),
parent=astroid_builtin,
)
klass.parent = astroid_builtin
doc = _type.__doc__ if isinstance(_type.__doc__, str) else None
klass.postinit(
bases=[],
Expand Down
5 changes: 4 additions & 1 deletion tests/test_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
ParentMissingError,
StatementMissing,
)
from astroid.manager import AstroidManager
from astroid.nodes.node_classes import (
AssignAttr,
AssignName,
Expand Down Expand Up @@ -1973,7 +1974,9 @@ def test_str_repr_no_warnings(node):
if name == "self":
continue

if "int" in param_type.annotation:
if name == "parent" and "NodeNG" in param_type.annotation:
args[name] = AstroidManager().adhoc_module
elif "int" in param_type.annotation:
args[name] = random.randint(0, 50)
elif (
"NodeNG" in param_type.annotation
Expand Down

0 comments on commit 69aea20

Please sign in to comment.