Skip to content

Remove three mixin nodes from #2171 #2231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion astroid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
Instance attributes are added by a
builder object, which can either generate extended ast (let's call
them astroid ;) by visiting an existent ast tree or by inspecting living
object. Methods are added by monkey patching ast classes.
object.

Main modules are:

Expand Down
113 changes: 4 additions & 109 deletions astroid/nodes/_base_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,23 @@
from functools import cached_property, lru_cache, partial
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Optional, Union

from astroid import bases, decorators, nodes, util
from astroid import bases, nodes, util
from astroid.const import PY310_PLUS
from astroid.context import (
CallContext,
InferenceContext,
bind_context_to_node,
copy_context,
)
from astroid.exceptions import (
AttributeInferenceError,
InferenceError,
NameInferenceError,
)
from astroid.interpreter import dunder_lookup
from astroid.nodes.node_ng import NodeNG
from astroid.typing import InferenceErrorInfo, InferenceResult
from astroid.typing import InferenceResult

if TYPE_CHECKING:
from astroid.nodes.node_classes import AssignedStmtsPossibleNode, LocalsDictNodeNG
from astroid.nodes.node_classes import LocalsDictNodeNG

GetFlowFactory = Callable[
[
Expand Down Expand Up @@ -331,7 +329,7 @@ def _filter_operation_errors(
for result in infer_callable(context):
if isinstance(result, error):
# For the sake of .infer(), we don't care about operation
# errors, which is the job of pylint. So return something
# errors, which is the job of a linter. So return something
# which shows that we can't infer the result.
yield util.Uninferable
else:
Expand Down Expand Up @@ -670,106 +668,3 @@ def _infer_binary_operation(

# The operation doesn't seem to be supported so let the caller know about it
yield util.BadBinaryOperationMessage(left_type, binary_opnode.op, right_type)


class AttributeNode(NodeNG):
expr: NodeNG
"""The name that this node represents."""
attrname: str

@decorators.raise_if_nothing_inferred
def _infer_attribute(
self,
context: InferenceContext | None = None,
**kwargs: Any,
) -> Generator[InferenceResult, None, InferenceErrorInfo]:
"""Infer an Attribute node by using getattr on the associated object."""
# pylint: disable=import-outside-toplevel
from astroid.constraint import get_constraints

for owner in self.expr.infer(context):
if isinstance(owner, util.UninferableBase):
yield owner
continue

context = copy_context(context)
old_boundnode = context.boundnode
try:
context.boundnode = owner
if isinstance(owner, (nodes.ClassDef, bases.Instance)):
frame = (
owner if isinstance(owner, nodes.ClassDef) else owner._proxied
)
context.constraints[self.attrname] = get_constraints(
self, frame=frame
)
yield from owner.igetattr(self.attrname, context)
except (
AttributeInferenceError,
InferenceError,
AttributeError,
):
pass
finally:
context.boundnode = old_boundnode
return InferenceErrorInfo(node=self, context=context)


class AssignNode(NodeNG):
@decorators.raise_if_nothing_inferred
@decorators.path_wrapper
def _infer_assign(
self,
context: InferenceContext | None = None,
**kwargs: Any,
) -> Generator[InferenceResult, None, None]:
"""Infer a AssignName/AssignAttr: need to inspect the RHS part of the
assign node.
"""
if isinstance(self.parent, nodes.AugAssign):
return self.parent.infer(context)

stmts = list(self.assigned_stmts(context=context))
return bases._infer_stmts(stmts, context)

def assigned_stmts(
self: nodes.AssignName | nodes.AssignAttr,
node: AssignedStmtsPossibleNode = None,
context: InferenceContext | None = None,
assign_path: list[int] | None = None,
) -> Any:
"""Returns the assigned statement (non inferred) according to the assignment type."""
return self.parent.assigned_stmts(node=self, context=context)


class NameNode(LookupMixIn):
name: str

@decorators.raise_if_nothing_inferred
def _infer_name_node(
self,
context: InferenceContext | None = None,
**kwargs: Any,
) -> Generator[InferenceResult, None, None]:
"""Infer a Name: use name lookup rules."""
# pylint: disable=import-outside-toplevel
from astroid.constraint import get_constraints
from astroid.helpers import _higher_function_scope

frame, stmts = self.lookup(self.name)
if not stmts:
# Try to see if the name is enclosed in a nested function
# and use the higher (first function) scope for searching.
parent_function = _higher_function_scope(self.scope())
if parent_function:
_, stmts = parent_function.lookup(self.name)

if not stmts:
raise NameInferenceError(
name=self.name, scope=self.scope(), context=context
)
context = copy_context(context)
context.lookupname = self.name
context.constraints[self.name] = get_constraints(self, frame)

return bases._infer_stmts(stmts, context, frame)
123 changes: 106 additions & 17 deletions astroid/nodes/node_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
AstroidValueError,
AttributeInferenceError,
InferenceError,
NameInferenceError,
NoDefault,
ParentMissingError,
_NonDeducibleTypeHierarchy,
Expand Down Expand Up @@ -396,8 +397,6 @@ def _infer_sequence_helper(


class AssignName(
_base_nodes.NameNode,
_base_nodes.AssignNode,
_base_nodes.NoChildrenNode,
_base_nodes.LookupMixIn,
_base_nodes.ParentAssignNode,
Expand Down Expand Up @@ -445,16 +444,48 @@ def __init__(
See astroid/protocols.py for actual implementation.
"""

@decorators.raise_if_nothing_inferred
@decorators.path_wrapper
def _infer(
self, context: InferenceContext | None = None, **kwargs: Any
) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
return self._infer_assign(context, **kwargs)
"""Infer an AssignName: need to inspect the RHS part of the
assign node.
"""
if isinstance(self.parent, AugAssign):
return self.parent.infer(context)

stmts = list(self.assigned_stmts(context=context))
return _infer_stmts(stmts, context)

@decorators.raise_if_nothing_inferred
def infer_lhs(
self, context: InferenceContext | None = None, **kwargs: Any
) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
return self._infer_name_node(context, **kwargs)
"""Infer a Name: use name lookup rules.

Same implementation as Name._infer."""
# pylint: disable=import-outside-toplevel
from astroid.constraint import get_constraints
from astroid.helpers import _higher_function_scope

frame, stmts = self.lookup(self.name)
if not stmts:
# Try to see if the name is enclosed in a nested function
# and use the higher (first function) scope for searching.
parent_function = _higher_function_scope(self.scope())
if parent_function:
_, stmts = parent_function.lookup(self.name)

if not stmts:
raise NameInferenceError(
name=self.name, scope=self.scope(), context=context
)
context = copy_context(context)
context.lookupname = self.name
context.constraints[self.name] = get_constraints(self, frame)

return _infer_stmts(stmts, context, frame)


class DelName(
Expand Down Expand Up @@ -496,7 +527,7 @@ def __init__(
)


class Name(_base_nodes.NameNode, _base_nodes.NoChildrenNode):
class Name(_base_nodes.LookupMixIn, _base_nodes.NoChildrenNode):
"""Class representing an :class:`ast.Name` node.

A :class:`Name` node is something that is named, but not covered by
Expand Down Expand Up @@ -545,7 +576,30 @@ def _get_name_nodes(self):
def _infer(
self, context: InferenceContext | None = None, **kwargs: Any
) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
return self._infer_name_node(context, **kwargs)
"""Infer a Name: use name lookup rules

Same implementation as AssignName._infer_lhs."""
# pylint: disable=import-outside-toplevel
from astroid.constraint import get_constraints
from astroid.helpers import _higher_function_scope

frame, stmts = self.lookup(self.name)
if not stmts:
# Try to see if the name is enclosed in a nested function
# and use the higher (first function) scope for searching.
parent_function = _higher_function_scope(self.scope())
if parent_function:
_, stmts = parent_function.lookup(self.name)

if not stmts:
raise NameInferenceError(
name=self.name, scope=self.scope(), context=context
)
context = copy_context(context)
context.lookupname = self.name
context.constraints[self.name] = get_constraints(self, frame)

return _infer_stmts(stmts, context, frame)


DEPRECATED_ARGUMENT_DEFAULT = object()
Expand Down Expand Up @@ -987,9 +1041,7 @@ def _format_args(
return ", ".join(values)


class AssignAttr(
_base_nodes.AttributeNode, _base_nodes.AssignNode, _base_nodes.ParentAssignNode
):
class AssignAttr(_base_nodes.LookupMixIn, _base_nodes.ParentAssignNode):
"""Variation of :class:`ast.Assign` representing assignment to an attribute.

>>> import astroid
Expand All @@ -1002,6 +1054,8 @@ class AssignAttr(
'self.attribute'
"""

expr: NodeNG

_astroid_fields = ("expr",)
_other_fields = ("attrname",)

Expand Down Expand Up @@ -1037,15 +1091,19 @@ def postinit(self, expr: NodeNG) -> None:
def get_children(self):
yield self.expr

@decorators.raise_if_nothing_inferred
@decorators.path_wrapper
def _infer(
self, context: InferenceContext | None = None, **kwargs: Any
) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
return self._infer_assign(context, **kwargs)
"""Infer an AssignAttr: need to inspect the RHS part of the
assign node.
"""
if isinstance(self.parent, AugAssign):
return self.parent.infer(context)

def infer_lhs(
self, context: InferenceContext | None = None, **kwargs: Any
) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
return self._infer_attribute(context, **kwargs)
Comment on lines -1045 to -1048
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the cause of pylint-dev/pylint#8823

stmts = list(self.assigned_stmts(context=context))
return _infer_stmts(stmts, context)


class Assert(_base_nodes.Statement):
Expand Down Expand Up @@ -2727,9 +2785,11 @@ def _infer(
) from error


class Attribute(_base_nodes.AttributeNode):
class Attribute(NodeNG):
"""Class representing an :class:`ast.Attribute` node."""

expr: NodeNG

_astroid_fields = ("expr",)
_other_fields = ("attrname",)

Expand Down Expand Up @@ -2760,11 +2820,40 @@ def postinit(self, expr: NodeNG) -> None:
def get_children(self):
yield self.expr

@decorators.raise_if_nothing_inferred
@decorators.path_wrapper
def _infer(
self, context: InferenceContext | None = None, **kwargs: Any
) -> Generator[InferenceResult, None, None]:
return self._infer_attribute(context, **kwargs)
) -> Generator[InferenceResult, None, InferenceErrorInfo]:
"""Infer an Attribute node by using getattr on the associated object."""
# pylint: disable=import-outside-toplevel
from astroid.constraint import get_constraints
from astroid.nodes import ClassDef

for owner in self.expr.infer(context):
if isinstance(owner, util.UninferableBase):
yield owner
continue

context = copy_context(context)
old_boundnode = context.boundnode
try:
context.boundnode = owner
if isinstance(owner, (ClassDef, Instance)):
frame = owner if isinstance(owner, ClassDef) else owner._proxied
context.constraints[self.attrname] = get_constraints(
self, frame=frame
)
yield from owner.igetattr(self.attrname, context)
except (
AttributeInferenceError,
InferenceError,
AttributeError,
):
pass
finally:
context.boundnode = old_boundnode
return InferenceErrorInfo(node=self, context=context)


class Global(_base_nodes.NoChildrenNode, _base_nodes.Statement):
Expand Down