diff --git a/astroid/interpreter/objectmodel.py b/astroid/interpreter/objectmodel.py index fd8c0c051..085bd2cc8 100644 --- a/astroid/interpreter/objectmodel.py +++ b/astroid/interpreter/objectmodel.py @@ -228,17 +228,17 @@ def attr___package__(self): @property def attr___spec__(self): # No handling for now. - return node_classes.Unknown() + return node_classes.Unknown(parent=self._instance) @property def attr___loader__(self): # No handling for now. - return node_classes.Unknown() + return node_classes.Unknown(parent=self._instance) @property def attr___cached__(self): # No handling for now. - return node_classes.Unknown() + return node_classes.Unknown(parent=self._instance) class FunctionModel(ObjectModel): @@ -462,7 +462,7 @@ def test(self): # These are here just for completion. @property def attr___ne__(self): - return node_classes.Unknown() + return node_classes.Unknown(parent=self._instance) attr___subclasshook__ = attr___ne__ attr___str__ = attr___ne__ @@ -493,8 +493,8 @@ def __init__(self): super().__init__() @property - def attr___annotations__(self) -> node_classes.Unkown: - return node_classes.Unknown() + def attr___annotations__(self) -> node_classes.Unknown: + return node_classes.Unknown(parent=self._instance) @property def attr___module__(self): diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py index ebfd5ffe8..d3aef1718 100644 --- a/astroid/nodes/node_classes.py +++ b/astroid/nodes/node_classes.py @@ -4963,9 +4963,9 @@ class Unknown(_base_nodes.AssignTypeNode): def __init__( self, + parent: NodeNG, lineno: None = None, col_offset: None = None, - parent: None = None, *, end_lineno: None = None, end_col_offset: None = None, @@ -4986,6 +4986,9 @@ def _infer(self, context: InferenceContext | None = None, **kwargs): yield util.Uninferable +UNATTACHED_UNKNOWN = Unknown(parent=SYNTHETIC_ROOT) + + class EvaluatedObject(NodeNG): """Contains an object that has already been inferred diff --git a/astroid/nodes/node_ng.py b/astroid/nodes/node_ng.py index d3be04720..dc8942b70 100644 --- a/astroid/nodes/node_ng.py +++ b/astroid/nodes/node_ng.py @@ -309,13 +309,13 @@ def scope(self) -> nodes.LocalsDictNodeNG: raise ParentMissingError(target=self) return self.parent.scope() - def root(self) -> nodes.Module | nodes.Unknown: + def root(self) -> nodes.Module: """Return the root node of the syntax tree. :returns: The root node. """ if not (parent := self.parent): - assert isinstance(self, (nodes.Module, nodes.Unknown)) + assert isinstance(self, nodes.Module) return self while parent.parent: diff --git a/astroid/protocols.py b/astroid/protocols.py index 8a837b86b..7cc50810f 100644 --- a/astroid/protocols.py +++ b/astroid/protocols.py @@ -162,13 +162,13 @@ def _filter_uninferable_nodes( ) -> Iterator[SuccessfulInferenceResult]: for elt in elts: if isinstance(elt, util.UninferableBase): - yield nodes.Unknown() + yield node_classes.UNATTACHED_UNKNOWN else: for inferred in elt.infer(context): if not isinstance(inferred, util.UninferableBase): yield inferred else: - yield nodes.Unknown() + yield node_classes.UNATTACHED_UNKNOWN @decorators.yes_if_nothing_inferred diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 170176f93..12168cf64 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -11,6 +11,7 @@ from astroid.builder import AstroidBuilder from astroid.const import IS_PYPY from astroid.exceptions import _NonDeducibleTypeHierarchy +from astroid.nodes.node_classes import UNATTACHED_UNKNOWN from astroid.nodes.scoped_nodes import ClassDef @@ -269,7 +270,7 @@ def test_uninferable_for_safe_infer() -> None: def test_safe_infer_shim() -> None: with pytest.warns(DeprecationWarning) as records: - helpers.safe_infer(nodes.Unknown()) + helpers.safe_infer(UNATTACHED_UNKNOWN) assert ( "Import safe_infer from astroid.util; this shim in astroid.helpers will be removed." diff --git a/tests/test_nodes.py b/tests/test_nodes.py index ffa511581..d6e3152dd 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -37,6 +37,7 @@ StatementMissing, ) from astroid.nodes.node_classes import ( + UNATTACHED_UNKNOWN, AssignAttr, AssignName, Attribute, @@ -281,8 +282,10 @@ def test_f_strings(self): @staticmethod def test_as_string_unknown() -> None: - assert nodes.Unknown().as_string() == "Unknown.Unknown()" - assert nodes.Unknown(lineno=1, col_offset=0).as_string() == "Unknown.Unknown()" + unknown1 = nodes.Unknown(parent=SYNTHETIC_ROOT) + unknown2 = nodes.Unknown(lineno=1, col_offset=0, parent=SYNTHETIC_ROOT) + assert unknown1.as_string() == "Unknown.Unknown()" + assert unknown2.as_string() == "Unknown.Unknown()" @staticmethod @pytest.mark.skipif( @@ -1231,9 +1234,9 @@ def test_starred_store(self) -> None: def test_unknown() -> None: """Test Unknown node.""" - assert isinstance(next(nodes.Unknown().infer()), type(util.Uninferable)) - assert isinstance(nodes.Unknown().name, str) - assert isinstance(nodes.Unknown().qname(), str) + assert isinstance(next(UNATTACHED_UNKNOWN.infer()), type(util.Uninferable)) + assert isinstance(UNATTACHED_UNKNOWN.name, str) + assert isinstance(UNATTACHED_UNKNOWN.qname(), str) def test_type_comments_with() -> None: @@ -1963,7 +1966,7 @@ def test_str_repr_no_warnings(node): "NodeNG" in param_type.annotation or "SuccessfulInferenceResult" in param_type.annotation ): - args[name] = nodes.Unknown() + args[name] = UNATTACHED_UNKNOWN elif "str" in param_type.annotation: args[name] = "" else: diff --git a/tests/test_regrtest.py b/tests/test_regrtest.py index 9b3471772..861f4e262 100644 --- a/tests/test_regrtest.py +++ b/tests/test_regrtest.py @@ -502,7 +502,7 @@ def _get_option(self, option): def test_regression_root_is_not_a_module() -> None: """Regression test for #2672.""" - node: nodes.Attribute = _extract_single_node( + node: nodes.ClassDef = _extract_single_node( textwrap.dedent( """ a=eval.__get__(1).__gt__ @@ -515,6 +515,14 @@ class c: ... assert node.name == "c" +@pytest.mark.xfail(reason="Not fixed yet") +def test_regression_eval_get_of_arg() -> None: + """Regression test for #2743""" + node = _extract_single_node("eval.__get__(1)") + with pytest.raises(InferenceError): + next(node.infer()) + + def test_regression_no_crash_during_build() -> None: node: nodes.Attribute = extract_node("__()") assert node.args == []