Skip to content

Commit e7a8669

Browse files
authored
Fix another non module root (pylint-dev#2744)
* add parents to Unknowns in the objectmodel * restore the invariant of root * add xfailing "__eval__.get(1)" test * enforce the correct parent on Unknown nodes
1 parent 97aac52 commit e7a8669

File tree

7 files changed

+34
-19
lines changed

7 files changed

+34
-19
lines changed

astroid/interpreter/objectmodel.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,17 +228,17 @@ def attr___package__(self):
228228
@property
229229
def attr___spec__(self):
230230
# No handling for now.
231-
return node_classes.Unknown()
231+
return node_classes.Unknown(parent=self._instance)
232232

233233
@property
234234
def attr___loader__(self):
235235
# No handling for now.
236-
return node_classes.Unknown()
236+
return node_classes.Unknown(parent=self._instance)
237237

238238
@property
239239
def attr___cached__(self):
240240
# No handling for now.
241-
return node_classes.Unknown()
241+
return node_classes.Unknown(parent=self._instance)
242242

243243

244244
class FunctionModel(ObjectModel):
@@ -462,7 +462,7 @@ def test(self):
462462
# These are here just for completion.
463463
@property
464464
def attr___ne__(self):
465-
return node_classes.Unknown()
465+
return node_classes.Unknown(parent=self._instance)
466466

467467
attr___subclasshook__ = attr___ne__
468468
attr___str__ = attr___ne__
@@ -493,8 +493,8 @@ def __init__(self):
493493
super().__init__()
494494

495495
@property
496-
def attr___annotations__(self) -> node_classes.Unkown:
497-
return node_classes.Unknown()
496+
def attr___annotations__(self) -> node_classes.Unknown:
497+
return node_classes.Unknown(parent=self._instance)
498498

499499
@property
500500
def attr___module__(self):

astroid/nodes/node_classes.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4963,9 +4963,9 @@ class Unknown(_base_nodes.AssignTypeNode):
49634963

49644964
def __init__(
49654965
self,
4966+
parent: NodeNG,
49664967
lineno: None = None,
49674968
col_offset: None = None,
4968-
parent: None = None,
49694969
*,
49704970
end_lineno: None = None,
49714971
end_col_offset: None = None,
@@ -4986,6 +4986,9 @@ def _infer(self, context: InferenceContext | None = None, **kwargs):
49864986
yield util.Uninferable
49874987

49884988

4989+
UNATTACHED_UNKNOWN = Unknown(parent=SYNTHETIC_ROOT)
4990+
4991+
49894992
class EvaluatedObject(NodeNG):
49904993
"""Contains an object that has already been inferred
49914994

astroid/nodes/node_ng.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,13 +309,13 @@ def scope(self) -> nodes.LocalsDictNodeNG:
309309
raise ParentMissingError(target=self)
310310
return self.parent.scope()
311311

312-
def root(self) -> nodes.Module | nodes.Unknown:
312+
def root(self) -> nodes.Module:
313313
"""Return the root node of the syntax tree.
314314
315315
:returns: The root node.
316316
"""
317317
if not (parent := self.parent):
318-
assert isinstance(self, (nodes.Module, nodes.Unknown))
318+
assert isinstance(self, nodes.Module)
319319
return self
320320

321321
while parent.parent:

astroid/protocols.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,13 @@ def _filter_uninferable_nodes(
162162
) -> Iterator[SuccessfulInferenceResult]:
163163
for elt in elts:
164164
if isinstance(elt, util.UninferableBase):
165-
yield nodes.Unknown()
165+
yield node_classes.UNATTACHED_UNKNOWN
166166
else:
167167
for inferred in elt.infer(context):
168168
if not isinstance(inferred, util.UninferableBase):
169169
yield inferred
170170
else:
171-
yield nodes.Unknown()
171+
yield node_classes.UNATTACHED_UNKNOWN
172172

173173

174174
@decorators.yes_if_nothing_inferred

tests/test_helpers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from astroid.builder import AstroidBuilder
1212
from astroid.const import IS_PYPY
1313
from astroid.exceptions import _NonDeducibleTypeHierarchy
14+
from astroid.nodes.node_classes import UNATTACHED_UNKNOWN
1415
from astroid.nodes.scoped_nodes import ClassDef
1516

1617

@@ -269,7 +270,7 @@ def test_uninferable_for_safe_infer() -> None:
269270

270271
def test_safe_infer_shim() -> None:
271272
with pytest.warns(DeprecationWarning) as records:
272-
helpers.safe_infer(nodes.Unknown())
273+
helpers.safe_infer(UNATTACHED_UNKNOWN)
273274

274275
assert (
275276
"Import safe_infer from astroid.util; this shim in astroid.helpers will be removed."

tests/test_nodes.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
StatementMissing,
3838
)
3939
from astroid.nodes.node_classes import (
40+
UNATTACHED_UNKNOWN,
4041
AssignAttr,
4142
AssignName,
4243
Attribute,
@@ -281,8 +282,10 @@ def test_f_strings(self):
281282

282283
@staticmethod
283284
def test_as_string_unknown() -> None:
284-
assert nodes.Unknown().as_string() == "Unknown.Unknown()"
285-
assert nodes.Unknown(lineno=1, col_offset=0).as_string() == "Unknown.Unknown()"
285+
unknown1 = nodes.Unknown(parent=SYNTHETIC_ROOT)
286+
unknown2 = nodes.Unknown(lineno=1, col_offset=0, parent=SYNTHETIC_ROOT)
287+
assert unknown1.as_string() == "Unknown.Unknown()"
288+
assert unknown2.as_string() == "Unknown.Unknown()"
286289

287290
@staticmethod
288291
@pytest.mark.skipif(
@@ -1231,9 +1234,9 @@ def test_starred_store(self) -> None:
12311234

12321235
def test_unknown() -> None:
12331236
"""Test Unknown node."""
1234-
assert isinstance(next(nodes.Unknown().infer()), type(util.Uninferable))
1235-
assert isinstance(nodes.Unknown().name, str)
1236-
assert isinstance(nodes.Unknown().qname(), str)
1237+
assert isinstance(next(UNATTACHED_UNKNOWN.infer()), type(util.Uninferable))
1238+
assert isinstance(UNATTACHED_UNKNOWN.name, str)
1239+
assert isinstance(UNATTACHED_UNKNOWN.qname(), str)
12371240

12381241

12391242
def test_type_comments_with() -> None:
@@ -1963,7 +1966,7 @@ def test_str_repr_no_warnings(node):
19631966
"NodeNG" in param_type.annotation
19641967
or "SuccessfulInferenceResult" in param_type.annotation
19651968
):
1966-
args[name] = nodes.Unknown()
1969+
args[name] = UNATTACHED_UNKNOWN
19671970
elif "str" in param_type.annotation:
19681971
args[name] = ""
19691972
else:

tests/test_regrtest.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ def _get_option(self, option):
502502

503503
def test_regression_root_is_not_a_module() -> None:
504504
"""Regression test for #2672."""
505-
node: nodes.Attribute = _extract_single_node(
505+
node: nodes.ClassDef = _extract_single_node(
506506
textwrap.dedent(
507507
"""
508508
a=eval.__get__(1).__gt__
@@ -515,6 +515,14 @@ class c: ...
515515
assert node.name == "c"
516516

517517

518+
@pytest.mark.xfail(reason="Not fixed yet")
519+
def test_regression_eval_get_of_arg() -> None:
520+
"""Regression test for #2743"""
521+
node = _extract_single_node("eval.__get__(1)")
522+
with pytest.raises(InferenceError):
523+
next(node.infer())
524+
525+
518526
def test_regression_no_crash_during_build() -> None:
519527
node: nodes.Attribute = extract_node("__()")
520528
assert node.args == []

0 commit comments

Comments
 (0)