diff options
author | Marc Mueller <30130371+cdce8p@users.noreply.github.com> | 2021-08-18 22:10:56 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-18 22:10:56 +0200 |
commit | 9cc3ffae26b049e91737fdff8dbcadb3c15b9825 (patch) | |
tree | 858b529a3a9c93f7802191785cca6604fcacf59e | |
parent | e135dc813ea5d60afea5d2931e233d873ded6f4e (diff) | |
download | pylint-git-9cc3ffae26b049e91737fdff8dbcadb3c15b9825.tar.gz |
Use alias for astroid.nodes 03 (#4866)
* Use alias for astroid nodes 03
* Resolve name conflicts
* Apply suggestions from code review
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
-rw-r--r-- | pylint/checkers/refactoring/len_checker.py | 17 | ||||
-rw-r--r-- | pylint/checkers/refactoring/not_checker.py | 7 | ||||
-rw-r--r-- | pylint/checkers/refactoring/recommendation_checker.py | 94 | ||||
-rw-r--r-- | pylint/checkers/utils.py | 367 | ||||
-rw-r--r-- | pylint/checkers/variables.py | 283 | ||||
-rw-r--r-- | pylint/extensions/_check_docs_utils.py | 29 |
6 files changed, 387 insertions, 410 deletions
diff --git a/pylint/checkers/refactoring/len_checker.py b/pylint/checkers/refactoring/len_checker.py index 24cbd546f..6bfe2fdf5 100644 --- a/pylint/checkers/refactoring/len_checker.py +++ b/pylint/checkers/refactoring/len_checker.py @@ -3,6 +3,7 @@ from typing import List import astroid +from astroid import nodes from pylint import checkers, interfaces from pylint.checkers import utils @@ -60,7 +61,7 @@ class LenChecker(checkers.BaseChecker): # the len() call could also be nested together with other # boolean operations, e.g. `if z or len(x):` parent = node.parent - while isinstance(parent, astroid.BoolOp): + while isinstance(parent, nodes.BoolOp): parent = parent.parent # we're finally out of any nested boolean operations so check if # this len() call is part of a test condition @@ -68,10 +69,10 @@ class LenChecker(checkers.BaseChecker): return len_arg = node.args[0] generator_or_comprehension = ( - astroid.ListComp, - astroid.SetComp, - astroid.DictComp, - astroid.GeneratorExp, + nodes.ListComp, + nodes.SetComp, + nodes.DictComp, + nodes.GeneratorExp, ) if isinstance(len_arg, generator_or_comprehension): # The node is a generator or comprehension as in len([x for x in ...]) @@ -92,7 +93,7 @@ class LenChecker(checkers.BaseChecker): self.add_message("len-as-condition", node=node) @staticmethod - def instance_has_bool(class_def: astroid.ClassDef) -> bool: + def instance_has_bool(class_def: nodes.ClassDef) -> bool: try: class_def.getattr("__bool__") return True @@ -106,14 +107,14 @@ class LenChecker(checkers.BaseChecker): is a test condition or something else (boolean expression) e.g. `if not len(S):`""" if ( - isinstance(node, astroid.UnaryOp) + isinstance(node, nodes.UnaryOp) and node.op == "not" and utils.is_call_of_name(node.operand, "len") ): self.add_message("len-as-condition", node=node) @staticmethod - def base_classes_of_node(instance: astroid.nodes.ClassDef) -> List[astroid.Name]: + def base_classes_of_node(instance: nodes.ClassDef) -> List[nodes.Name]: """Return all the classes names that a ClassDef inherit from including 'object'.""" try: return [instance.name] + [x.name for x in instance.ancestors()] diff --git a/pylint/checkers/refactoring/not_checker.py b/pylint/checkers/refactoring/not_checker.py index 5ea8066d5..4a778be5f 100644 --- a/pylint/checkers/refactoring/not_checker.py +++ b/pylint/checkers/refactoring/not_checker.py @@ -3,6 +3,7 @@ import astroid +from astroid import nodes from pylint import checkers, interfaces from pylint.checkers import utils @@ -37,7 +38,7 @@ class NotChecker(checkers.BaseChecker): } # sets are not ordered, so for example "not set(LEFT_VALS) <= set(RIGHT_VALS)" is # not equivalent to "set(LEFT_VALS) > set(RIGHT_VALS)" - skipped_nodes = (astroid.Set,) + skipped_nodes = (nodes.Set,) # 'builtins' py3, '__builtin__' py2 skipped_classnames = [f"{BUILTINS}.{qname}" for qname in ("set", "frozenset")] @@ -47,13 +48,13 @@ class NotChecker(checkers.BaseChecker): return operand = node.operand - if isinstance(operand, astroid.UnaryOp) and operand.op == "not": + if isinstance(operand, nodes.UnaryOp) and operand.op == "not": self.add_message( "unneeded-not", node=node, args=(node.as_string(), operand.operand.as_string()), ) - elif isinstance(operand, astroid.Compare): + elif isinstance(operand, nodes.Compare): left = operand.left # ignore multiple comparisons if len(operand.ops) > 1: diff --git a/pylint/checkers/refactoring/recommendation_checker.py b/pylint/checkers/refactoring/recommendation_checker.py index b7bda5754..7893f9578 100644 --- a/pylint/checkers/refactoring/recommendation_checker.py +++ b/pylint/checkers/refactoring/recommendation_checker.py @@ -3,6 +3,7 @@ from typing import Union, cast import astroid +from astroid import nodes from pylint import checkers, interfaces from pylint.checkers import utils @@ -59,33 +60,33 @@ class RecommendationChecker(checkers.BaseChecker): return utils.is_builtin_object(inferred) and inferred.name == function @utils.check_messages("consider-iterating-dictionary", "use-maxsplit-arg") - def visit_call(self, node: astroid.Call) -> None: + def visit_call(self, node: nodes.Call) -> None: self._check_consider_iterating_dictionary(node) self._check_use_maxsplit_arg(node) - def _check_consider_iterating_dictionary(self, node: astroid.Call) -> None: - if not isinstance(node.func, astroid.Attribute): + def _check_consider_iterating_dictionary(self, node: nodes.Call) -> None: + if not isinstance(node.func, nodes.Attribute): return if node.func.attrname != "keys": return - if not isinstance(node.parent, (astroid.For, astroid.Comprehension)): + if not isinstance(node.parent, (nodes.For, nodes.Comprehension)): return inferred = utils.safe_infer(node.func) if not isinstance(inferred, astroid.BoundMethod) or not isinstance( - inferred.bound, astroid.Dict + inferred.bound, nodes.Dict ): return - if isinstance(node.parent, (astroid.For, astroid.Comprehension)): + if isinstance(node.parent, (nodes.For, nodes.Comprehension)): self.add_message("consider-iterating-dictionary", node=node) - def _check_use_maxsplit_arg(self, node: astroid.Call) -> None: + def _check_use_maxsplit_arg(self, node: nodes.Call) -> None: """Add message when accessing first or last elements of a str.split() or str.rsplit().""" # Check if call is split() or rsplit() if not ( - isinstance(node.func, astroid.Attribute) + isinstance(node.func, nodes.Attribute) and node.func.attrname in ("split", "rsplit") and isinstance(utils.safe_infer(node.func), astroid.BoundMethod) ): @@ -103,28 +104,28 @@ class RecommendationChecker(checkers.BaseChecker): except utils.NoSuchArgumentError: pass - if isinstance(node.parent, astroid.Subscript): + if isinstance(node.parent, nodes.Subscript): try: subscript_value = utils.get_subscript_const_value(node.parent).value except utils.InferredTypeError: return # Check for cases where variable (Name) subscripts may be mutated within a loop - if isinstance(node.parent.slice, astroid.Name): + if isinstance(node.parent.slice, nodes.Name): # Check if loop present within the scope of the node scope = node.scope() - for loop_node in scope.nodes_of_class((astroid.For, astroid.While)): - loop_node = cast(astroid.node_classes.NodeNG, loop_node) + for loop_node in scope.nodes_of_class((nodes.For, nodes.While)): + loop_node = cast(nodes.NodeNG, loop_node) if not loop_node.parent_of(node): continue # Check if var is mutated within loop (Assign/AugAssign) - for assignment_node in loop_node.nodes_of_class(astroid.AugAssign): - assignment_node = cast(astroid.AugAssign, assignment_node) + for assignment_node in loop_node.nodes_of_class(nodes.AugAssign): + assignment_node = cast(nodes.AugAssign, assignment_node) if node.parent.slice.name == assignment_node.target.name: return - for assignment_node in loop_node.nodes_of_class(astroid.Assign): - assignment_node = cast(astroid.Assign, assignment_node) + for assignment_node in loop_node.nodes_of_class(nodes.Assign): + assignment_node = cast(nodes.Assign, assignment_node) if node.parent.slice.name in [ n.name for n in assignment_node.targets ]: @@ -145,27 +146,26 @@ class RecommendationChecker(checkers.BaseChecker): "consider-using-dict-items", "use-sequence-for-iteration", ) - def visit_for(self, node: astroid.For) -> None: + def visit_for(self, node: nodes.For) -> None: self._check_consider_using_enumerate(node) self._check_consider_using_dict_items(node) self._check_use_sequence_for_iteration(node) - def _check_consider_using_enumerate(self, node: astroid.For) -> None: + def _check_consider_using_enumerate(self, node: nodes.For) -> None: """Emit a convention whenever range and len are used for indexing.""" # Verify that we have a `range([start], len(...), [stop])` call and # that the object which is iterated is used as a subscript in the # body of the for. # Is it a proper range call? - if not isinstance(node.iter, astroid.Call): + if not isinstance(node.iter, nodes.Call): return if not self._is_builtin(node.iter.func, "range"): return if not node.iter.args: return is_constant_zero = ( - isinstance(node.iter.args[0], astroid.Const) - and node.iter.args[0].value == 0 + isinstance(node.iter.args[0], nodes.Const) and node.iter.args[0].value == 0 ) if len(node.iter.args) == 2 and not is_constant_zero: return @@ -173,7 +173,7 @@ class RecommendationChecker(checkers.BaseChecker): return # Is it a proper len call? - if not isinstance(node.iter.args[-1], astroid.Call): + if not isinstance(node.iter.args[-1], nodes.Call): return second_func = node.iter.args[-1].func if not self._is_builtin(second_func, "len"): @@ -182,16 +182,16 @@ class RecommendationChecker(checkers.BaseChecker): if not len_args or len(len_args) != 1: return iterating_object = len_args[0] - if isinstance(iterating_object, astroid.Name): - expected_subscript_val_type = astroid.Name - elif isinstance(iterating_object, astroid.Attribute): - expected_subscript_val_type = astroid.Attribute + if isinstance(iterating_object, nodes.Name): + expected_subscript_val_type = nodes.Name + elif isinstance(iterating_object, nodes.Attribute): + expected_subscript_val_type = nodes.Attribute else: return # If we're defining __iter__ on self, enumerate won't work scope = node.scope() if ( - isinstance(iterating_object, astroid.Name) + isinstance(iterating_object, nodes.Name) and iterating_object.name == "self" and scope.name == "__iter__" ): @@ -202,13 +202,13 @@ class RecommendationChecker(checkers.BaseChecker): # in order to make sure that the same object is used in the # for body. for child in node.body: - for subscript in child.nodes_of_class(astroid.Subscript): - subscript = cast(astroid.Subscript, subscript) + for subscript in child.nodes_of_class(nodes.Subscript): + subscript = cast(nodes.Subscript, subscript) if not isinstance(subscript.value, expected_subscript_val_type): continue value = subscript.slice - if not isinstance(value, astroid.Name): + if not isinstance(value, nodes.Name): continue if subscript.value.scope() != node.scope(): # Ignore this subscript if it's not in the same @@ -217,15 +217,15 @@ class RecommendationChecker(checkers.BaseChecker): # name for the iterating object was used. continue if value.name == node.target.name and ( - isinstance(subscript.value, astroid.Name) + isinstance(subscript.value, nodes.Name) and iterating_object.name == subscript.value.name - or isinstance(subscript.value, astroid.Attribute) + or isinstance(subscript.value, nodes.Attribute) and iterating_object.attrname == subscript.value.attrname ): self.add_message("consider-using-enumerate", node=node) return - def _check_consider_using_dict_items(self, node: astroid.For) -> None: + def _check_consider_using_dict_items(self, node: nodes.For) -> None: """Add message when accessing dict values by index lookup.""" # Verify that we have a .keys() call and # that the object which is iterated is used as a subscript in the @@ -240,15 +240,15 @@ class RecommendationChecker(checkers.BaseChecker): # in order to make sure that the same object is used in the # for body. for child in node.body: - for subscript in child.nodes_of_class(astroid.Subscript): - subscript = cast(astroid.Subscript, subscript) + for subscript in child.nodes_of_class(nodes.Subscript): + subscript = cast(nodes.Subscript, subscript) - if not isinstance(subscript.value, (astroid.Name, astroid.Attribute)): + if not isinstance(subscript.value, (nodes.Name, nodes.Attribute)): continue value = subscript.slice if ( - not isinstance(value, astroid.Name) + not isinstance(value, nodes.Name) or value.name != node.target.name or iterating_object_name != subscript.value.as_string() ): @@ -261,9 +261,9 @@ class RecommendationChecker(checkers.BaseChecker): # defined and compare that to the for loop's line number continue if ( - isinstance(subscript.parent, astroid.Assign) + isinstance(subscript.parent, nodes.Assign) and subscript in subscript.parent.targets - or isinstance(subscript.parent, astroid.AugAssign) + or isinstance(subscript.parent, nodes.AugAssign) and subscript == subscript.parent.target ): # Ignore this subscript if it is the target of an assignment @@ -277,12 +277,12 @@ class RecommendationChecker(checkers.BaseChecker): "consider-using-dict-items", "use-sequence-for-iteration", ) - def visit_comprehension(self, node: astroid.Comprehension) -> None: + def visit_comprehension(self, node: nodes.Comprehension) -> None: self._check_consider_using_dict_items_comprehension(node) self._check_use_sequence_for_iteration(node) def _check_consider_using_dict_items_comprehension( - self, node: astroid.Comprehension + self, node: nodes.Comprehension ) -> None: """Add message when accessing dict values by index lookup.""" iterating_object_name = utils.get_iterating_dictionary_name(node) @@ -290,15 +290,15 @@ class RecommendationChecker(checkers.BaseChecker): return for child in node.parent.get_children(): - for subscript in child.nodes_of_class(astroid.Subscript): - subscript = cast(astroid.Subscript, subscript) + for subscript in child.nodes_of_class(nodes.Subscript): + subscript = cast(nodes.Subscript, subscript) - if not isinstance(subscript.value, (astroid.Name, astroid.Attribute)): + if not isinstance(subscript.value, (nodes.Name, nodes.Attribute)): continue value = subscript.slice if ( - not isinstance(value, astroid.Name) + not isinstance(value, nodes.Name) or value.name != node.target.name or iterating_object_name != subscript.value.as_string() ): @@ -308,8 +308,8 @@ class RecommendationChecker(checkers.BaseChecker): return def _check_use_sequence_for_iteration( - self, node: Union[astroid.For, astroid.Comprehension] + self, node: Union[nodes.For, nodes.Comprehension] ) -> None: """Check if code iterates over an in-place defined set.""" - if isinstance(node.iter, astroid.Set): + if isinstance(node.iter, nodes.Set): self.add_message("use-sequence-for-iteration", node=node.iter) diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index aa445a708..58e950ce2 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -73,15 +73,15 @@ from typing import ( import _string import astroid import astroid.objects -from astroid import TooManyLevelsError +from astroid import TooManyLevelsError, nodes from pylint.constants import BUILTINS COMP_NODE_TYPES = ( - astroid.ListComp, - astroid.SetComp, - astroid.DictComp, - astroid.GeneratorExp, + nodes.ListComp, + nodes.SetComp, + nodes.DictComp, + nodes.GeneratorExp, ) EXCEPTIONS_MODULE = "builtins" ABC_MODULES = {"abc", "_py_abc"} @@ -282,44 +282,44 @@ class InferredTypeError(Exception): pass -def is_inside_lambda(node: astroid.node_classes.NodeNG) -> bool: +def is_inside_lambda(node: nodes.NodeNG) -> bool: """Return true if given node is inside lambda""" parent = node.parent while parent is not None: - if isinstance(parent, astroid.Lambda): + if isinstance(parent, nodes.Lambda): return True parent = parent.parent return False def get_all_elements( - node: astroid.node_classes.NodeNG, -) -> Iterable[astroid.node_classes.NodeNG]: + node: nodes.NodeNG, +) -> Iterable[nodes.NodeNG]: """Recursively returns all atoms in nested lists and tuples.""" - if isinstance(node, (astroid.Tuple, astroid.List)): + if isinstance(node, (nodes.Tuple, nodes.List)): for child in node.elts: yield from get_all_elements(child) else: yield node -def is_super(node: astroid.node_classes.NodeNG) -> bool: +def is_super(node: nodes.NodeNG) -> bool: """return True if the node is referencing the "super" builtin function""" if getattr(node, "name", None) == "super" and node.root().name == BUILTINS: return True return False -def is_error(node: astroid.scoped_nodes.FunctionDef) -> bool: +def is_error(node: nodes.FunctionDef) -> bool: """Return true if the given function node only raises an exception""" - return len(node.body) == 1 and isinstance(node.body[0], astroid.Raise) + return len(node.body) == 1 and isinstance(node.body[0], nodes.Raise) builtins = builtins.__dict__.copy() # type: ignore SPECIAL_BUILTINS = ("__builtins__",) # '__path__', '__file__') -def is_builtin_object(node: astroid.node_classes.NodeNG) -> bool: +def is_builtin_object(node: nodes.NodeNG) -> bool: """Returns True if the given node is an object from the __builtin__ module.""" return node and node.root().name == BUILTINS @@ -330,31 +330,31 @@ def is_builtin(name: str) -> bool: def is_defined_in_scope( - var_node: astroid.node_classes.NodeNG, + var_node: nodes.NodeNG, varname: str, - scope: astroid.node_classes.NodeNG, + scope: nodes.NodeNG, ) -> bool: - if isinstance(scope, astroid.If): + if isinstance(scope, nodes.If): for node in scope.body: if ( - isinstance(node, astroid.Assign) + isinstance(node, nodes.Assign) and any( - isinstance(target, astroid.AssignName) and target.name == varname + isinstance(target, nodes.AssignName) and target.name == varname for target in node.targets ) - ) or (isinstance(node, astroid.Nonlocal) and varname in node.names): + ) or (isinstance(node, nodes.Nonlocal) and varname in node.names): return True - elif isinstance(scope, (COMP_NODE_TYPES, astroid.For)): - for ass_node in scope.nodes_of_class(astroid.AssignName): + elif isinstance(scope, (COMP_NODE_TYPES, nodes.For)): + for ass_node in scope.nodes_of_class(nodes.AssignName): if ass_node.name == varname: return True - elif isinstance(scope, astroid.With): + elif isinstance(scope, nodes.With): for expr, ids in scope.items: if expr.parent_of(var_node): break - if ids and isinstance(ids, astroid.AssignName) and ids.name == varname: + if ids and isinstance(ids, nodes.AssignName) and ids.name == varname: return True - elif isinstance(scope, (astroid.Lambda, astroid.FunctionDef)): + elif isinstance(scope, (nodes.Lambda, nodes.FunctionDef)): if scope.args.is_argument(varname): # If the name is found inside a default value # of a function, then let the search continue @@ -369,15 +369,15 @@ def is_defined_in_scope( return True if getattr(scope, "name", None) == varname: return True - elif isinstance(scope, astroid.ExceptHandler): - if isinstance(scope.name, astroid.AssignName): + elif isinstance(scope, nodes.ExceptHandler): + if isinstance(scope.name, nodes.AssignName): ass_node = scope.name if ass_node.name == varname: return True return False -def is_defined_before(var_node: astroid.Name) -> bool: +def is_defined_before(var_node: nodes.Name) -> bool: """Check if the given variable node is defined before Verify that the variable node is defined by a parent node @@ -396,10 +396,10 @@ def is_defined_before(var_node: astroid.Name) -> bool: _node = stmt.previous_sibling() lineno = stmt.fromlineno while _node and _node.fromlineno == lineno: - for assign_node in _node.nodes_of_class(astroid.AssignName): + for assign_node in _node.nodes_of_class(nodes.AssignName): if assign_node.name == varname: return True - for imp_node in _node.nodes_of_class((astroid.ImportFrom, astroid.Import)): + for imp_node in _node.nodes_of_class((nodes.ImportFrom, nodes.Import)): if varname in [name[1] or name[0] for name in imp_node.names]: return True _node = _node.previous_sibling() @@ -407,34 +407,33 @@ def is_defined_before(var_node: astroid.Name) -> bool: def is_default_argument( - node: astroid.node_classes.NodeNG, - scope: Optional[astroid.node_classes.NodeNG] = None, + node: nodes.NodeNG, scope: Optional[nodes.NodeNG] = None ) -> bool: """return true if the given Name node is used in function or lambda default argument's value """ if not scope: scope = node.scope() - if isinstance(scope, (astroid.FunctionDef, astroid.Lambda)): + if isinstance(scope, (nodes.FunctionDef, nodes.Lambda)): for default_node in scope.args.defaults: - for default_name_node in default_node.nodes_of_class(astroid.Name): + for default_name_node in default_node.nodes_of_class(nodes.Name): if default_name_node is node: return True return False -def is_func_decorator(node: astroid.node_classes.NodeNG) -> bool: +def is_func_decorator(node: nodes.NodeNG) -> bool: """return true if the name is used in function decorator""" parent = node.parent while parent is not None: - if isinstance(parent, astroid.Decorators): + if isinstance(parent, nodes.Decorators): return True if parent.is_statement or isinstance( parent, ( - astroid.Lambda, - astroid.scoped_nodes.ComprehensionScope, - astroid.scoped_nodes.ListComp, + nodes.Lambda, + nodes.ComprehensionScope, + nodes.ListComp, ), ): break @@ -442,36 +441,34 @@ def is_func_decorator(node: astroid.node_classes.NodeNG) -> bool: return False -def is_ancestor_name( - frame: astroid.ClassDef, node: astroid.node_classes.NodeNG -) -> bool: +def is_ancestor_name(frame: nodes.ClassDef, node: nodes.NodeNG) -> bool: """return True if `frame` is an astroid.Class node with `node` in the subtree of its bases attribute """ - if not isinstance(frame, astroid.ClassDef): + if not isinstance(frame, nodes.ClassDef): return False for base in frame.bases: - if node in base.nodes_of_class(astroid.Name): + if node in base.nodes_of_class(nodes.Name): return True return False -def is_being_called(node: astroid.node_classes.NodeNG) -> bool: +def is_being_called(node: nodes.NodeNG) -> bool: """return True if node is the function being called in a Call node""" - return isinstance(node.parent, astroid.Call) and node.parent.func is node + return isinstance(node.parent, nodes.Call) and node.parent.func is node -def assign_parent(node: astroid.node_classes.NodeNG) -> astroid.node_classes.NodeNG: +def assign_parent(node: nodes.NodeNG) -> nodes.NodeNG: """return the higher parent which is not an AssignName, Tuple or List node""" - while node and isinstance(node, (astroid.AssignName, astroid.Tuple, astroid.List)): + while node and isinstance(node, (nodes.AssignName, nodes.Tuple, nodes.List)): node = node.parent return node -def overrides_a_method(class_node: astroid.ClassDef, name: str) -> bool: +def overrides_a_method(class_node: nodes.ClassDef, name: str) -> bool: """return True if <name> is a method overridden from an ancestor""" for ancestor in class_node.ancestors(): - if name in ancestor and isinstance(ancestor[name], astroid.FunctionDef): + if name in ancestor and isinstance(ancestor[name], nodes.FunctionDef): return True return False @@ -653,7 +650,7 @@ def is_attr_protected(attrname: str) -> bool: ) -def node_frame_class(node: astroid.node_classes.NodeNG) -> Optional[astroid.ClassDef]: +def node_frame_class(node: nodes.NodeNG) -> Optional[nodes.ClassDef]: """Return the class that is wrapping the given node The function returns a class for a method node (or a staticmethod or a @@ -661,14 +658,14 @@ def node_frame_class(node: astroid.node_classes.NodeNG) -> Optional[astroid.Clas """ klass = node.frame() nodes_to_check = ( - astroid.node_classes.NodeNG, + nodes.NodeNG, astroid.UnboundMethod, astroid.BaseInstance, ) while ( klass and isinstance(klass, nodes_to_check) - and not isinstance(klass, astroid.ClassDef) + and not isinstance(klass, nodes.ClassDef) ): if klass.parent is None: return None @@ -687,16 +684,16 @@ def is_attr_private(attrname: str) -> Optional[Match[str]]: def get_argument_from_call( - call_node: astroid.Call, position: int = None, keyword: str = None -) -> astroid.Name: + call_node: nodes.Call, position: int = None, keyword: str = None +) -> nodes.Name: """Returns the specified argument from a function call. - :param astroid.Call call_node: Node representing a function call to check. + :param nodes.Call call_node: Node representing a function call to check. :param int position: position of the argument. :param str keyword: the keyword of the argument. :returns: The node representing the argument, None if the argument is not found. - :rtype: astroid.Name + :rtype: nodes.Name :raises ValueError: if both position and keyword are None. :raises NoSuchArgumentError: if no argument at the provided position or with the provided keyword. @@ -716,7 +713,7 @@ def get_argument_from_call( raise NoSuchArgumentError -def inherit_from_std_ex(node: astroid.node_classes.NodeNG) -> bool: +def inherit_from_std_ex(node: nodes.NodeNG) -> bool: """ Return true if the given class node is subclass of exceptions.Exception. @@ -731,7 +728,7 @@ def inherit_from_std_ex(node: astroid.node_classes.NodeNG) -> bool: return False -def error_of_type(handler: astroid.ExceptHandler, error_type) -> bool: +def error_of_type(handler: nodes.ExceptHandler, error_type) -> bool: """ Check if the given exception handler catches the given error_type. @@ -756,7 +753,7 @@ def error_of_type(handler: astroid.ExceptHandler, error_type) -> bool: return handler.catch(expected_errors) -def decorated_with_property(node: astroid.FunctionDef) -> bool: +def decorated_with_property(node: nodes.FunctionDef) -> bool: """Detect if the given function node is decorated with a property.""" if not node.decorators: return False @@ -770,65 +767,65 @@ def decorated_with_property(node: astroid.FunctionDef) -> bool: def _is_property_kind(node, *kinds): - if not isinstance(node, (astroid.UnboundMethod, astroid.FunctionDef)): + if not isinstance(node, (astroid.UnboundMethod, nodes.FunctionDef)): return False if node.decorators: for decorator in node.decorators.nodes: - if isinstance(decorator, astroid.Attribute) and decorator.attrname in kinds: + if isinstance(decorator, nodes.Attribute) and decorator.attrname in kinds: return True return False -def is_property_setter(node: astroid.FunctionDef) -> bool: +def is_property_setter(node: nodes.FunctionDef) -> bool: """Check if the given node is a property setter""" return _is_property_kind(node, "setter") -def is_property_deleter(node: astroid.FunctionDef) -> bool: +def is_property_deleter(node: nodes.FunctionDef) -> bool: """Check if the given node is a property deleter""" return _is_property_kind(node, "deleter") -def is_property_setter_or_deleter(node: astroid.FunctionDef) -> bool: +def is_property_setter_or_deleter(node: nodes.FunctionDef) -> bool: """Check if the given node is either a property setter or a deleter""" return _is_property_kind(node, "setter", "deleter") -def _is_property_decorator(decorator: astroid.Name) -> bool: +def _is_property_decorator(decorator: nodes.Name) -> bool: for inferred in decorator.infer(): - if isinstance(inferred, astroid.ClassDef): + if isinstance(inferred, nodes.ClassDef): if inferred.qname() in ("builtins.property", "functools.cached_property"): return True for ancestor in inferred.ancestors(): if ancestor.name == "property" and ancestor.root().name == BUILTINS: return True - elif isinstance(inferred, astroid.FunctionDef): + elif isinstance(inferred, nodes.FunctionDef): # If decorator is function, check if it has exactly one return # and the return is itself a function decorated with property - returns: List[astroid.Return] = list( + returns: List[nodes.Return] = list( inferred._get_return_nodes_skip_functions() ) if len(returns) == 1 and isinstance( - returns[0].value, (astroid.Name, astroid.Attribute) + returns[0].value, (nodes.Name, nodes.Attribute) ): inferred = safe_infer(returns[0].value) if ( inferred and isinstance(inferred, astroid.objects.Property) - and isinstance(inferred.function, astroid.FunctionDef) + and isinstance(inferred.function, nodes.FunctionDef) ): return decorated_with_property(inferred.function) return False def decorated_with( - func: Union[astroid.FunctionDef, astroid.BoundMethod, astroid.UnboundMethod], + func: Union[nodes.FunctionDef, astroid.BoundMethod, astroid.UnboundMethod], qnames: Iterable[str], ) -> bool: """Determine if the `func` node has a decorator with the qualified name `qname`.""" decorators = func.decorators.nodes if func.decorators else [] for decorator_node in decorators: - if isinstance(decorator_node, astroid.Call): + if isinstance(decorator_node, nodes.Call): # We only want to infer the function name decorator_node = decorator_node.func try: @@ -845,8 +842,8 @@ def decorated_with( @lru_cache(maxsize=1024) def unimplemented_abstract_methods( - node: astroid.ClassDef, is_abstract_cb: astroid.FunctionDef = None -) -> Dict[str, astroid.node_classes.NodeNG]: + node: nodes.ClassDef, is_abstract_cb: nodes.FunctionDef = None +) -> Dict[str, nodes.NodeNG]: """ Get the unimplemented abstract methods for the given *node*. @@ -860,7 +857,7 @@ def unimplemented_abstract_methods( """ if is_abstract_cb is None: is_abstract_cb = partial(decorated_with, qnames=ABC_METHODS) - visited: Dict[str, astroid.node_classes.NodeNG] = {} + visited: Dict[str, nodes.NodeNG] = {} try: mro = reversed(node.mro()) except NotImplementedError: @@ -873,7 +870,7 @@ def unimplemented_abstract_methods( for ancestor in mro: for obj in ancestor.values(): inferred = obj - if isinstance(obj, astroid.AssignName): + if isinstance(obj, nodes.AssignName): inferred = safe_infer(obj) if not inferred: # Might be an abstract function, @@ -883,10 +880,10 @@ def unimplemented_abstract_methods( if obj.name in visited: del visited[obj.name] continue - if not isinstance(inferred, astroid.FunctionDef): + if not isinstance(inferred, nodes.FunctionDef): if obj.name in visited: del visited[obj.name] - if isinstance(inferred, astroid.FunctionDef): + if isinstance(inferred, nodes.FunctionDef): # It's critical to use the original name, # since after inferring, an object can be something # else than expected, as in the case of the @@ -904,11 +901,11 @@ def unimplemented_abstract_methods( def find_try_except_wrapper_node( - node: astroid.node_classes.NodeNG, -) -> Optional[Union[astroid.ExceptHandler, astroid.TryExcept]]: + node: nodes.NodeNG, +) -> Optional[Union[nodes.ExceptHandler, nodes.TryExcept]]: """Return the ExceptHandler or the TryExcept node in which the node is.""" current = node - ignores = (astroid.ExceptHandler, astroid.TryExcept) + ignores = (nodes.ExceptHandler, nodes.TryExcept) while current and not isinstance(current.parent, ignores): current = current.parent @@ -918,8 +915,8 @@ def find_try_except_wrapper_node( def find_except_wrapper_node_in_scope( - node: astroid.node_classes.NodeNG, -) -> Optional[Union[astroid.ExceptHandler, astroid.TryExcept]]: + node: nodes.NodeNG, +) -> Optional[Union[nodes.ExceptHandler, nodes.TryExcept]]: """Return the ExceptHandler in which the node is, without going out of scope.""" current = node while current.parent is not None: @@ -930,18 +927,18 @@ def find_except_wrapper_node_in_scope( # function/class was defined in an `except` clause, rather than the current code # actually running in an `except` clause. return None - if isinstance(current, astroid.ExceptHandler): + if isinstance(current, nodes.ExceptHandler): return current return None -def is_from_fallback_block(node: astroid.node_classes.NodeNG) -> bool: +def is_from_fallback_block(node: nodes.NodeNG) -> bool: """Check if the given node is from a fallback import block.""" context = find_try_except_wrapper_node(node) if not context: return False - if isinstance(context, astroid.ExceptHandler): + if isinstance(context, nodes.ExceptHandler): other_body = context.parent.body handlers = context.parent.handlers else: @@ -951,7 +948,7 @@ def is_from_fallback_block(node: astroid.node_classes.NodeNG) -> bool: handlers = context.handlers has_fallback_imports = any( - isinstance(import_node, (astroid.ImportFrom, astroid.Import)) + isinstance(import_node, (nodes.ImportFrom, nodes.Import)) for import_node in other_body ) ignores_import_error = _except_handlers_ignores_exception(handlers, ImportError) @@ -959,19 +956,19 @@ def is_from_fallback_block(node: astroid.node_classes.NodeNG) -> bool: def _except_handlers_ignores_exception( - handlers: astroid.ExceptHandler, exception + handlers: nodes.ExceptHandler, exception ) -> bool: func = partial(error_of_type, error_type=(exception,)) return any(func(handler) for handler in handlers) def get_exception_handlers( - node: astroid.node_classes.NodeNG, exception=Exception -) -> Optional[List[astroid.ExceptHandler]]: + node: nodes.NodeNG, exception=Exception +) -> Optional[List[nodes.ExceptHandler]]: """Return the collections of handlers handling the exception in arguments. Args: - node (astroid.NodeNG): A node that is potentially wrapped in a try except. + node (nodes.NodeNG): A node that is potentially wrapped in a try except. exception (builtin.Exception or str): exception or name of the exception. Returns: @@ -979,30 +976,28 @@ def get_exception_handlers( """ context = find_try_except_wrapper_node(node) - if isinstance(context, astroid.TryExcept): + if isinstance(context, nodes.TryExcept): return [ handler for handler in context.handlers if error_of_type(handler, exception) ] return [] -def is_node_inside_try_except(node: astroid.Raise) -> bool: +def is_node_inside_try_except(node: nodes.Raise) -> bool: """Check if the node is directly under a Try/Except statement. (but not under an ExceptHandler!) Args: - node (astroid.Raise): the node raising the exception. + node (nodes.Raise): the node raising the exception. Returns: bool: True if the node is inside a try/except statement, False otherwise. """ context = find_try_except_wrapper_node(node) - return isinstance(context, astroid.TryExcept) + return isinstance(context, nodes.TryExcept) -def node_ignores_exception( - node: astroid.node_classes.NodeNG, exception=Exception -) -> bool: +def node_ignores_exception(node: nodes.NodeNG, exception=Exception) -> bool: """Check if the node is in a TryExcept which handles the given exception. If the exception is not given, the function is going to look for bare @@ -1014,7 +1009,7 @@ def node_ignores_exception( return any(managing_handlers) -def class_is_abstract(node: astroid.ClassDef) -> bool: +def class_is_abstract(node: nodes.ClassDef) -> bool: """return true if the given class node should be considered as an abstract class """ @@ -1036,58 +1031,58 @@ def class_is_abstract(node: astroid.ClassDef) -> bool: return False -def _supports_protocol_method(value: astroid.node_classes.NodeNG, attr: str) -> bool: +def _supports_protocol_method(value: nodes.NodeNG, attr: str) -> bool: try: attributes = value.getattr(attr) except astroid.NotFoundError: return False first = attributes[0] - if isinstance(first, astroid.AssignName): - if isinstance(first.parent.value, astroid.Const): + if isinstance(first, nodes.AssignName): + if isinstance(first.parent.value, nodes.Const): return False return True -def is_comprehension(node: astroid.node_classes.NodeNG) -> bool: +def is_comprehension(node: nodes.NodeNG) -> bool: comprehensions = ( - astroid.ListComp, - astroid.SetComp, - astroid.DictComp, - astroid.GeneratorExp, + nodes.ListComp, + nodes.SetComp, + nodes.DictComp, + nodes.GeneratorExp, ) return isinstance(node, comprehensions) -def _supports_mapping_protocol(value: astroid.node_classes.NodeNG) -> bool: +def _supports_mapping_protocol(value: nodes.NodeNG) -> bool: return _supports_protocol_method( value, GETITEM_METHOD ) and _supports_protocol_method(value, KEYS_METHOD) -def _supports_membership_test_protocol(value: astroid.node_classes.NodeNG) -> bool: +def _supports_membership_test_protocol(value: nodes.NodeNG) -> bool: return _supports_protocol_method(value, CONTAINS_METHOD) -def _supports_iteration_protocol(value: astroid.node_classes.NodeNG) -> bool: +def _supports_iteration_protocol(value: nodes.NodeNG) -> bool: return _supports_protocol_method(value, ITER_METHOD) or _supports_protocol_method( value, GETITEM_METHOD ) -def _supports_async_iteration_protocol(value: astroid.node_classes.NodeNG) -> bool: +def _supports_async_iteration_protocol(value: nodes.NodeNG) -> bool: return _supports_protocol_method(value, AITER_METHOD) -def _supports_getitem_protocol(value: astroid.node_classes.NodeNG) -> bool: +def _supports_getitem_protocol(value: nodes.NodeNG) -> bool: return _supports_protocol_method(value, GETITEM_METHOD) -def _supports_setitem_protocol(value: astroid.node_classes.NodeNG) -> bool: +def _supports_setitem_protocol(value: nodes.NodeNG) -> bool: return _supports_protocol_method(value, SETITEM_METHOD) -def _supports_delitem_protocol(value: astroid.node_classes.NodeNG) -> bool: +def _supports_delitem_protocol(value: nodes.NodeNG) -> bool: return _supports_protocol_method(value, DELITEM_METHOD) @@ -1099,9 +1094,9 @@ def _is_abstract_class_name(name: str) -> bool: return is_mixin or is_abstract or is_base -def is_inside_abstract_class(node: astroid.node_classes.NodeNG) -> bool: +def is_inside_abstract_class(node: nodes.NodeNG) -> bool: while node is not None: - if isinstance(node, astroid.ClassDef): + if isinstance(node, nodes.ClassDef): if class_is_abstract(node): return True name = getattr(node, "name", None) @@ -1112,9 +1107,9 @@ def is_inside_abstract_class(node: astroid.node_classes.NodeNG) -> bool: def _supports_protocol( - value: astroid.node_classes.NodeNG, protocol_callback: astroid.FunctionDef + value: nodes.NodeNG, protocol_callback: nodes.FunctionDef ) -> bool: - if isinstance(value, astroid.ClassDef): + if isinstance(value, nodes.ClassDef): if not has_known_bases(value): return True # classobj can only be iterable if it has an iterable metaclass @@ -1141,7 +1136,7 @@ def _supports_protocol( return False -def is_iterable(value: astroid.node_classes.NodeNG, check_async: bool = False) -> bool: +def is_iterable(value: nodes.NodeNG, check_async: bool = False) -> bool: if check_async: protocol_check = _supports_async_iteration_protocol else: @@ -1149,19 +1144,17 @@ def is_iterable(value: astroid.node_classes.NodeNG, check_async: bool = False) - return _supports_protocol(value, protocol_check) -def is_mapping(value: astroid.node_classes.NodeNG) -> bool: +def is_mapping(value: nodes.NodeNG) -> bool: return _supports_protocol(value, _supports_mapping_protocol) -def supports_membership_test(value: astroid.node_classes.NodeNG) -> bool: +def supports_membership_test(value: nodes.NodeNG) -> bool: supported = _supports_protocol(value, _supports_membership_test_protocol) return supported or is_iterable(value) -def supports_getitem( - value: astroid.node_classes.NodeNG, node: astroid.node_classes.NodeNG -) -> bool: - if isinstance(value, astroid.ClassDef): +def supports_getitem(value: nodes.NodeNG, node: nodes.NodeNG) -> bool: + if isinstance(value, nodes.ClassDef): if _supports_protocol_method(value, CLASS_GETITEM_METHOD): return True if is_class_subscriptable_pep585_with_postponed_evaluation_enabled(value, node): @@ -1169,11 +1162,11 @@ def supports_getitem( return _supports_protocol(value, _supports_getitem_protocol) -def supports_setitem(value: astroid.node_classes.NodeNG, *_: Any) -> bool: +def supports_setitem(value: nodes.NodeNG, *_: Any) -> bool: return _supports_protocol(value, _supports_setitem_protocol) -def supports_delitem(value: astroid.node_classes.NodeNG, *_: Any) -> bool: +def supports_delitem(value: nodes.NodeNG, *_: Any) -> bool: return _supports_protocol(value, _supports_delitem_protocol) @@ -1185,9 +1178,7 @@ def _get_python_type_of_node(node): @lru_cache(maxsize=1024) -def safe_infer( - node: astroid.node_classes.NodeNG, context=None -) -> Optional[astroid.node_classes.NodeNG]: +def safe_infer(node: nodes.NodeNG, context=None) -> Optional[nodes.NodeNG]: """Return the inferred value for the given node. Return None if inference failed or if there is some ambiguity (more than @@ -1215,7 +1206,7 @@ def safe_infer( return value if len(inferred_types) <= 1 else None -def has_known_bases(klass: astroid.ClassDef, context=None) -> bool: +def has_known_bases(klass: nodes.ClassDef, context=None) -> bool: """Return true if all base classes of a class could be inferred.""" try: return klass._all_bases_known @@ -1224,7 +1215,7 @@ def has_known_bases(klass: astroid.ClassDef, context=None) -> bool: for base in klass.bases: result = safe_infer(base, context=context) if ( - not isinstance(result, astroid.ClassDef) + not isinstance(result, nodes.ClassDef) or result is klass or not has_known_bases(result, context=context) ): @@ -1234,15 +1225,15 @@ def has_known_bases(klass: astroid.ClassDef, context=None) -> bool: return True -def is_none(node: astroid.node_classes.NodeNG) -> bool: +def is_none(node: nodes.NodeNG) -> bool: return ( node is None - or (isinstance(node, astroid.Const) and node.value is None) - or (isinstance(node, astroid.Name) and node.name == "None") + or (isinstance(node, nodes.Const) and node.value is None) + or (isinstance(node, nodes.Name) and node.name == "None") ) -def node_type(node: astroid.node_classes.NodeNG) -> Optional[type]: +def node_type(node: nodes.NodeNG) -> Optional[type]: """Return the inferred type for `node` If there is more than one possible type, or if inferred type is Uninferable or None, @@ -1263,7 +1254,7 @@ def node_type(node: astroid.node_classes.NodeNG) -> Optional[type]: return types.pop() if types else None -def is_registered_in_singledispatch_function(node: astroid.FunctionDef) -> bool: +def is_registered_in_singledispatch_function(node: nodes.FunctionDef) -> bool: """Check if the given function node is a singledispatch function.""" singledispatch_qnames = ( @@ -1271,17 +1262,17 @@ def is_registered_in_singledispatch_function(node: astroid.FunctionDef) -> bool: "singledispatch.singledispatch", ) - if not isinstance(node, astroid.FunctionDef): + if not isinstance(node, nodes.FunctionDef): return False decorators = node.decorators.nodes if node.decorators else [] for decorator in decorators: # func.register are function calls - if not isinstance(decorator, astroid.Call): + if not isinstance(decorator, nodes.Call): continue func = decorator.func - if not isinstance(func, astroid.Attribute) or func.attrname != "register": + if not isinstance(func, nodes.Attribute) or func.attrname != "register": continue try: @@ -1289,14 +1280,14 @@ def is_registered_in_singledispatch_function(node: astroid.FunctionDef) -> bool: except astroid.InferenceError: continue - if isinstance(func_def, astroid.FunctionDef): + if isinstance(func_def, nodes.FunctionDef): # pylint: disable=redundant-keyword-arg; some flow inference goes wrong here return decorated_with(func_def, singledispatch_qnames) return False -def get_node_last_lineno(node: astroid.node_classes.NodeNG) -> int: +def get_node_last_lineno(node: nodes.NodeNG) -> int: """ Get the last lineno of the given node. For a simple statement this will just be node.lineno, but for a node that has child statements (e.g. a method) this will be the lineno of the last @@ -1319,14 +1310,14 @@ def get_node_last_lineno(node: astroid.node_classes.NodeNG) -> int: return node.lineno -def is_postponed_evaluation_enabled(node: astroid.node_classes.NodeNG) -> bool: +def is_postponed_evaluation_enabled(node: nodes.NodeNG) -> bool: """Check if the postponed evaluation of annotations is enabled""" module = node.root() return "annotations" in module.future_imports def is_class_subscriptable_pep585_with_postponed_evaluation_enabled( - value: astroid.ClassDef, node: astroid.node_classes.NodeNG + value: nodes.ClassDef, node: nodes.NodeNG ) -> bool: """Check if class is subscriptable with PEP 585 and postponed evaluation enabled. @@ -1338,7 +1329,7 @@ def is_class_subscriptable_pep585_with_postponed_evaluation_enabled( ) -def is_node_in_type_annotation_context(node: astroid.node_classes.NodeNG) -> bool: +def is_node_in_type_annotation_context(node: nodes.NodeNG) -> bool: """Check if node is in type annotation context. Check for 'AnnAssign', function 'Arguments', @@ -1348,9 +1339,9 @@ def is_node_in_type_annotation_context(node: astroid.node_classes.NodeNG) -> boo current_node, parent_node = node, node.parent while True: if ( - isinstance(parent_node, astroid.AnnAssign) + isinstance(parent_node, nodes.AnnAssign) and parent_node.annotation == current_node - or isinstance(parent_node, astroid.Arguments) + or isinstance(parent_node, nodes.Arguments) and current_node in ( *parent_node.annotations, @@ -1359,23 +1350,23 @@ def is_node_in_type_annotation_context(node: astroid.node_classes.NodeNG) -> boo parent_node.varargannotation, parent_node.kwargannotation, ) - or isinstance(parent_node, astroid.FunctionDef) + or isinstance(parent_node, nodes.FunctionDef) and parent_node.returns == current_node ): return True current_node, parent_node = parent_node, parent_node.parent - if isinstance(parent_node, astroid.Module): + if isinstance(parent_node, nodes.Module): return False -def is_subclass_of(child: astroid.ClassDef, parent: astroid.ClassDef) -> bool: +def is_subclass_of(child: nodes.ClassDef, parent: nodes.ClassDef) -> bool: """ Check if first node is a subclass of second node. :param child: Node to check for subclass. :param parent: Node to check for superclass. :returns: True if child is derived from parent. False otherwise. """ - if not all(isinstance(node, astroid.ClassDef) for node in (child, parent)): + if not all(isinstance(node, nodes.ClassDef) for node in (child, parent)): return False for ancestor in child.ancestors(): @@ -1388,7 +1379,7 @@ def is_subclass_of(child: astroid.ClassDef, parent: astroid.ClassDef) -> bool: @lru_cache(maxsize=1024) -def is_overload_stub(node: astroid.node_classes.NodeNG) -> bool: +def is_overload_stub(node: nodes.NodeNG) -> bool: """Check if a node if is a function stub decorated with typing.overload. :param node: Node to check. @@ -1398,13 +1389,13 @@ def is_overload_stub(node: astroid.node_classes.NodeNG) -> bool: return bool(decorators and decorated_with(node, ["typing.overload", "overload"])) -def is_protocol_class(cls: astroid.node_classes.NodeNG) -> bool: +def is_protocol_class(cls: nodes.NodeNG) -> bool: """Check if the given node represents a protocol class :param cls: The node to check :returns: True if the node is a typing protocol class, false otherwise. """ - if not isinstance(cls, astroid.ClassDef): + if not isinstance(cls, nodes.ClassDef): return False # Use .ancestors() since not all protocol classes can have @@ -1412,40 +1403,40 @@ def is_protocol_class(cls: astroid.node_classes.NodeNG) -> bool: return any(parent.qname() in TYPING_PROTOCOLS for parent in cls.ancestors()) -def is_call_of_name(node: astroid.node_classes.NodeNG, name: str) -> bool: +def is_call_of_name(node: nodes.NodeNG, name: str) -> bool: """Checks if node is a function call with the given name""" return ( - isinstance(node, astroid.Call) - and isinstance(node.func, astroid.Name) + isinstance(node, nodes.Call) + and isinstance(node.func, nodes.Name) and node.func.name == name ) def is_test_condition( - node: astroid.node_classes.NodeNG, - parent: Optional[astroid.node_classes.NodeNG] = None, + node: nodes.NodeNG, + parent: Optional[nodes.NodeNG] = None, ) -> bool: """Returns true if the given node is being tested for truthiness""" parent = parent or node.parent - if isinstance(parent, (astroid.While, astroid.If, astroid.IfExp, astroid.Assert)): + if isinstance(parent, (nodes.While, nodes.If, nodes.IfExp, nodes.Assert)): return node is parent.test or parent.test.parent_of(node) - if isinstance(parent, astroid.Comprehension): + if isinstance(parent, nodes.Comprehension): return node in parent.ifs return is_call_of_name(parent, "bool") and parent.parent_of(node) -def is_classdef_type(node: astroid.ClassDef) -> bool: +def is_classdef_type(node: nodes.ClassDef) -> bool: """Test if ClassDef node is Type.""" if node.name == "type": return True for base in node.bases: - if isinstance(base, astroid.Name) and base.name == "type": + if isinstance(base, nodes.Name) and base.name == "type": return True return False def is_attribute_typed_annotation( - node: Union[astroid.ClassDef, astroid.Instance], attr_name: str + node: Union[nodes.ClassDef, astroid.Instance], attr_name: str ) -> bool: """Test if attribute is typed annotation in current node or any base nodes. @@ -1453,36 +1444,36 @@ def is_attribute_typed_annotation( attribute = node.locals.get(attr_name, [None])[0] if ( attribute - and isinstance(attribute, astroid.AssignName) - and isinstance(attribute.parent, astroid.AnnAssign) + and isinstance(attribute, nodes.AssignName) + and isinstance(attribute.parent, nodes.AnnAssign) ): return True for base in node.bases: inferred = safe_infer(base) if ( inferred - and isinstance(inferred, astroid.ClassDef) + and isinstance(inferred, nodes.ClassDef) and is_attribute_typed_annotation(inferred, attr_name) ): return True return False -def is_assign_name_annotated_with(node: astroid.AssignName, typing_name: str) -> bool: +def is_assign_name_annotated_with(node: nodes.AssignName, typing_name: str) -> bool: """Test if AssignName node has `typing_name` annotation. Especially useful to check for `typing._SpecialForm` instances like: `Union`, `Optional`, `Literal`, `ClassVar`, `Final`. """ - if not isinstance(node.parent, astroid.AnnAssign): + if not isinstance(node.parent, nodes.AnnAssign): return False annotation = node.parent.annotation - if isinstance(annotation, astroid.Subscript): + if isinstance(annotation, nodes.Subscript): annotation = annotation.value if ( - isinstance(annotation, astroid.Name) + isinstance(annotation, nodes.Name) and annotation.name == typing_name - or isinstance(annotation, astroid.Attribute) + or isinstance(annotation, nodes.Attribute) and annotation.attrname == typing_name ): return True @@ -1490,18 +1481,18 @@ def is_assign_name_annotated_with(node: astroid.AssignName, typing_name: str) -> def get_iterating_dictionary_name( - node: Union[astroid.For, astroid.Comprehension] + node: Union[nodes.For, nodes.Comprehension] ) -> Optional[str]: """Get the name of the dictionary which keys are being iterated over on - a `astroid.For` or `astroid.Comprehension` node. + a ``nodes.For`` or ``nodes.Comprehension`` node. If the iterating object is not either the keys method of a dictionary or a dictionary itself, this returns None. """ # Is it a proper keys call? if ( - isinstance(node.iter, astroid.Call) - and isinstance(node.iter.func, astroid.Attribute) + isinstance(node.iter, nodes.Call) + and isinstance(node.iter.func, nodes.Attribute) and node.iter.func.attrname == "keys" ): inferred = safe_infer(node.iter.func) @@ -1510,16 +1501,16 @@ def get_iterating_dictionary_name( return node.iter.as_string().rpartition(".keys")[0] # Is it a dictionary? - if isinstance(node.iter, (astroid.Name, astroid.Attribute)): + if isinstance(node.iter, (nodes.Name, nodes.Attribute)): inferred = safe_infer(node.iter) - if not isinstance(inferred, astroid.Dict): + if not isinstance(inferred, nodes.Dict): return None return node.iter.as_string() return None -def get_subscript_const_value(node: astroid.Subscript) -> astroid.Const: +def get_subscript_const_value(node: nodes.Subscript) -> nodes.Const: """ Returns the value 'subscript.slice' of a Subscript node. @@ -1528,16 +1519,14 @@ def get_subscript_const_value(node: astroid.Subscript) -> astroid.Const: :raises InferredTypeError: if the subscript node cannot be inferred as a Const """ inferred = safe_infer(node.slice) - if not isinstance(inferred, astroid.Const): - raise InferredTypeError( - "Subscript.slice cannot be inferred as an astroid.Const" - ) + if not isinstance(inferred, nodes.Const): + raise InferredTypeError("Subscript.slice cannot be inferred as a nodes.Const") return inferred def get_import_name( - importnode: Union[astroid.Import, astroid.ImportFrom], modname: str + importnode: Union[nodes.Import, nodes.ImportFrom], modname: str ) -> str: """Get a prepared module name from the given import node @@ -1551,9 +1540,9 @@ def get_import_name( :returns: absolute qualified module name of the module used in import. """ - if isinstance(importnode, astroid.ImportFrom) and importnode.level: + if isinstance(importnode, nodes.ImportFrom) and importnode.level: root = importnode.root() - if isinstance(root, astroid.Module): + if isinstance(root, nodes.Module): try: return root.relative_to_absolute_name(modname, level=importnode.level) except TooManyLevelsError: @@ -1561,10 +1550,10 @@ def get_import_name( return modname -def is_node_in_guarded_import_block(node: astroid.NodeNG) -> bool: +def is_node_in_guarded_import_block(node: nodes.NodeNG) -> bool: """Return True if node is part for guarded if block. I.e. `sys.version_info` or `typing.TYPE_CHECKING` """ - return isinstance(node.parent, astroid.If) and ( + return isinstance(node.parent, nodes.If) and ( node.parent.is_sys_guard() or node.parent.is_typing_guard() ) diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 89d98067b..b51fd5ce5 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -59,6 +59,7 @@ import re from functools import lru_cache import astroid +from astroid import nodes from pylint.checkers import BaseChecker, utils from pylint.checkers.utils import is_postponed_evaluation_enabled @@ -144,14 +145,14 @@ def _is_from_future_import(stmt, name): return None for local_node in module.locals.get(name, []): - if isinstance(local_node, astroid.ImportFrom) and local_node.modname == FUTURE: + if isinstance(local_node, nodes.ImportFrom) and local_node.modname == FUTURE: return True return None def in_for_else_branch(parent, stmt): """Returns True if stmt in inside the else branch for a parent For stmt.""" - return isinstance(parent, astroid.For) and any( + return isinstance(parent, nodes.For) and any( else_stmt.parent_of(stmt) or else_stmt == stmt for else_stmt in parent.orelse ) @@ -169,7 +170,7 @@ def overridden_method(klass, name): # We have found an ancestor defining <name> but it's not in the local # dictionary. This may happen with astroid built from living objects. return None - if isinstance(meth_node, astroid.FunctionDef): + if isinstance(meth_node, nodes.FunctionDef): return meth_node return None @@ -212,17 +213,17 @@ def _detect_global_scope(node, frame, defframe): scope = frame.parent.scope() if defframe and defframe.parent: def_scope = defframe.parent.scope() - if isinstance(frame, astroid.FunctionDef): + if isinstance(frame, nodes.FunctionDef): # If the parent of the current node is a # function, then it can be under its scope # (defined in, which doesn't concern us) or # the `->` part of annotations. The same goes # for annotations of function arguments, they'll have # their parent the Arguments node. - if not isinstance(node.parent, (astroid.FunctionDef, astroid.Arguments)): + if not isinstance(node.parent, (nodes.FunctionDef, nodes.Arguments)): return False elif any( - not isinstance(f, (astroid.ClassDef, astroid.Module)) for f in (frame, defframe) + not isinstance(f, (nodes.ClassDef, nodes.Module)) for f in (frame, defframe) ): # Not interested in other frames, since they are already # not in a global scope. @@ -235,7 +236,7 @@ def _detect_global_scope(node, frame, defframe): # share a global scope. parent_scope = current_scope while parent_scope: - if not isinstance(parent_scope, (astroid.ClassDef, astroid.Module)): + if not isinstance(parent_scope, (nodes.ClassDef, nodes.Module)): break_scopes.append(parent_scope) break if parent_scope.parent: @@ -270,13 +271,13 @@ def _fix_dot_imports(not_consumed): names = {} for name, stmts in not_consumed.items(): if any( - isinstance(stmt, astroid.AssignName) - and isinstance(stmt.assign_type(), astroid.AugAssign) + isinstance(stmt, nodes.AssignName) + and isinstance(stmt.assign_type(), nodes.AugAssign) for stmt in stmts ): continue for stmt in stmts: - if not isinstance(stmt, (astroid.ImportFrom, astroid.Import)): + if not isinstance(stmt, (nodes.ImportFrom, nodes.Import)): continue for imports in stmt.names: second_name = None @@ -309,7 +310,7 @@ def _find_frame_imports(name, frame): *name*. Such imports can be considered assignments. Returns True if an import for the given name was found. """ - imports = frame.nodes_of_class((astroid.Import, astroid.ImportFrom)) + imports = frame.nodes_of_class((nodes.Import, nodes.ImportFrom)) for import_node in imports: for import_name, import_alias in import_node.names: # If the import uses an alias, check only that. @@ -343,13 +344,13 @@ def _assigned_locally(name_node): """ Checks if name_node has corresponding assign statement in same scope """ - assign_stmts = name_node.scope().nodes_of_class(astroid.AssignName) + assign_stmts = name_node.scope().nodes_of_class(nodes.AssignName) return any(a.name == name_node.name for a in assign_stmts) def _is_type_checking_import(node): parent = node.parent - if not isinstance(parent, astroid.If): + if not isinstance(parent, nodes.If): return False test = parent.test return test.as_string() in TYPING_TYPE_CHECKS_GUARDS @@ -357,12 +358,12 @@ def _is_type_checking_import(node): def _has_locals_call_after_node(stmt, scope): skip_nodes = ( - astroid.FunctionDef, - astroid.ClassDef, - astroid.Import, - astroid.ImportFrom, + nodes.FunctionDef, + nodes.ClassDef, + nodes.Import, + nodes.ImportFrom, ) - for call in scope.nodes_of_class(astroid.Call, skip_klass=skip_nodes): + for call in scope.nodes_of_class(nodes.Call, skip_klass=skip_nodes): inferred = utils.safe_infer(call.func) if ( utils.is_builtin_object(inferred) @@ -569,7 +570,7 @@ scope_type : {self._atomic.scope_type} found_nodes = self.to_consume.get(name) if ( found_nodes - and isinstance(parent_node, astroid.Assign) + and isinstance(parent_node, nodes.Assign) and parent_node == found_nodes[0].parent ): lhs = found_nodes[0].parent.targets[0] @@ -578,7 +579,7 @@ scope_type : {self._atomic.scope_type} if ( found_nodes - and isinstance(parent_node, astroid.For) + and isinstance(parent_node, nodes.For) and parent_node.iter == node and parent_node.target in found_nodes ): @@ -589,7 +590,7 @@ scope_type : {self._atomic.scope_type} found_nodes = [ n for n in found_nodes - if not isinstance(n.statement(), astroid.ExceptHandler) + if not isinstance(n.statement(), nodes.ExceptHandler) or n.statement().parent_of(node) ] @@ -713,9 +714,7 @@ class VariablesChecker(BaseChecker): @utils.check_messages("redefined-outer-name") def visit_for(self, node): - assigned_to = [ - var.name for var in node.target.nodes_of_class(astroid.AssignName) - ] + assigned_to = [a.name for a in node.target.nodes_of_class(nodes.AssignName)] # Only check variables that are used dummy_rgx = self.config.dummy_variables_rgx @@ -836,10 +835,10 @@ class VariablesChecker(BaseChecker): return globs = node.root().globals for name, stmt in node.items(): - if name in globs and not isinstance(stmt, astroid.Global): + if name in globs and not isinstance(stmt, nodes.Global): definition = globs[name][0] if ( - isinstance(definition, astroid.ImportFrom) + isinstance(definition, nodes.ImportFrom) and definition.modname == FUTURE ): # It is a __future__ directive, not a symbol. @@ -848,7 +847,7 @@ class VariablesChecker(BaseChecker): # Do not take in account redefined names for the purpose # of type checking.: if any( - isinstance(definition.parent, astroid.If) + isinstance(definition.parent, nodes.If) and definition.parent.test.as_string() in TYPING_TYPE_CHECKS_GUARDS for definition in globs[name] ): @@ -895,8 +894,8 @@ class VariablesChecker(BaseChecker): if is_method and node.is_abstract(): return - global_names = _flattened_scope_names(node.nodes_of_class(astroid.Global)) - nonlocal_names = _flattened_scope_names(node.nodes_of_class(astroid.Nonlocal)) + global_names = _flattened_scope_names(node.nodes_of_class(nodes.Global)) + nonlocal_names = _flattened_scope_names(node.nodes_of_class(nodes.Nonlocal)) for name, stmts in not_consumed.items(): self._check_is_unused(name, node, stmts[0], global_names, nonlocal_names) @@ -913,7 +912,7 @@ class VariablesChecker(BaseChecker): def visit_global(self, node): """check names imported exists in the global scope""" frame = node.frame() - if isinstance(frame, astroid.Module): + if isinstance(frame, nodes.Module): self.add_message("global-at-module-level", node=node) return @@ -928,8 +927,7 @@ class VariablesChecker(BaseChecker): assign_nodes = [] not_defined_locally_by_import = not any( - isinstance(local, astroid.node_classes.Import) - for local in locals_.get(name, ()) + isinstance(local, nodes.Import) for local in locals_.get(name, ()) ) if not assign_nodes and not_defined_locally_by_import: self.add_message("global-variable-not-assigned", args=name, node=node) @@ -938,7 +936,7 @@ class VariablesChecker(BaseChecker): for anode in assign_nodes: if ( - isinstance(anode, astroid.AssignName) + isinstance(anode, nodes.AssignName) and anode.name in module.special_attributes ): self.add_message("redefined-builtin", args=name, node=node) @@ -956,7 +954,7 @@ class VariablesChecker(BaseChecker): self.add_message("global-statement", node=node) def visit_assignname(self, node): - if isinstance(node.assign_type(), astroid.AugAssign): + if isinstance(node.assign_type(), nodes.AugAssign): self.visit_name(node) def visit_delname(self, node): @@ -1003,8 +1001,8 @@ class VariablesChecker(BaseChecker): # Ignore inner class scope for keywords in class definition if ( current_consumer.scope_type == "class" - and isinstance(node.parent, astroid.Keyword) - and isinstance(node.parent.parent, astroid.ClassDef) + and isinstance(node.parent, nodes.Keyword) + and isinstance(node.parent.parent, nodes.ClassDef) ): continue @@ -1061,7 +1059,7 @@ class VariablesChecker(BaseChecker): recursive_klass = ( frame is defframe and defframe.parent_of(node) - and isinstance(defframe, astroid.ClassDef) + and isinstance(defframe, nodes.ClassDef) and node.name == defframe.name ) @@ -1119,13 +1117,13 @@ class VariablesChecker(BaseChecker): # Used and defined in the same place, e.g `x += 1` and `del x` defined_by_stmt = defstmt is stmt and isinstance( - node, (astroid.DelName, astroid.AssignName) + node, (nodes.DelName, nodes.AssignName) ) if ( recursive_klass or defined_by_stmt or annotation_return - or isinstance(defstmt, astroid.Delete) + or isinstance(defstmt, nodes.Delete) ): if not utils.node_ignores_exception(node, NameError): @@ -1135,9 +1133,9 @@ class VariablesChecker(BaseChecker): and isinstance( stmt, ( - astroid.AnnAssign, - astroid.FunctionDef, - astroid.Arguments, + nodes.AnnAssign, + nodes.FunctionDef, + nodes.Arguments, ), ) and name in node.root().locals @@ -1151,9 +1149,7 @@ class VariablesChecker(BaseChecker): # Handle postponed evaluation of annotations if not ( self._postponed_evaluation_enabled - and isinstance( - stmt, (astroid.AnnAssign, astroid.FunctionDef) - ) + and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef)) ): self.add_message( "used-before-assignment", args=name, node=node @@ -1164,8 +1160,8 @@ class VariablesChecker(BaseChecker): # class A: # x = lambda attr: f + attr # f = 42 - if isinstance(frame, astroid.ClassDef) and name in frame.locals: - if isinstance(node.parent, astroid.Arguments): + if isinstance(frame, nodes.ClassDef) and name in frame.locals: + if isinstance(node.parent, nodes.Arguments): if stmt.fromlineno <= defstmt.fromlineno: # Doing the following is fine: # class A: @@ -1189,12 +1185,12 @@ class VariablesChecker(BaseChecker): # we have not found the name, if it isn't a builtin, that's an # undefined name ! if undefined_variable_is_enabled and not ( - name in astroid.Module.scope_attrs + name in nodes.Module.scope_attrs or utils.is_builtin(name) or name in self.config.additional_builtins or ( name == "__class__" - and isinstance(frame, astroid.FunctionDef) + and isinstance(frame, nodes.FunctionDef) and frame.is_method() ) ): @@ -1202,7 +1198,7 @@ class VariablesChecker(BaseChecker): self.add_message("undefined-variable", args=name, node=node) @utils.check_messages("no-name-in-module") - def visit_import(self, node: astroid.Import) -> None: + def visit_import(self, node: nodes.Import) -> None: """check modules attribute accesses""" if not self._analyse_fallback_blocks and utils.is_from_fallback_block(node): # No need to verify this, since ImportError is already @@ -1219,12 +1215,12 @@ class VariablesChecker(BaseChecker): module = next(_infer_name_module(node, parts[0])) except astroid.ResolveError: continue - if not isinstance(module, astroid.Module): + if not isinstance(module, nodes.Module): continue self._check_module_attrs(node, module, parts[1:]) @utils.check_messages("no-name-in-module") - def visit_importfrom(self, node: astroid.ImportFrom) -> None: + def visit_importfrom(self, node: nodes.ImportFrom) -> None: """check modules attribute accesses""" if not self._analyse_fallback_blocks and utils.is_from_fallback_block(node): # No need to verify this, since ImportError is already @@ -1257,7 +1253,7 @@ class VariablesChecker(BaseChecker): get assigned. """ self._check_self_cls_assign(node) - if not isinstance(node.targets[0], (astroid.Tuple, astroid.List)): + if not isinstance(node.targets[0], (nodes.Tuple, nodes.List)): return targets = node.targets[0].itered() @@ -1304,7 +1300,7 @@ class VariablesChecker(BaseChecker): @staticmethod def _defined_in_function_definition(node, frame): in_annotation_or_default_or_decorator = False - if isinstance(frame, astroid.FunctionDef) and node.statement() is frame: + if isinstance(frame, nodes.FunctionDef) and node.statement() is frame: in_annotation_or_default_or_decorator = ( ( node in frame.args.annotations @@ -1324,7 +1320,7 @@ class VariablesChecker(BaseChecker): @staticmethod def _in_lambda_or_comprehension_body( - node: astroid.node_classes.NodeNG, frame: astroid.node_classes.NodeNG + node: nodes.NodeNG, frame: nodes.NodeNG ) -> bool: """return True if node within a lambda/comprehension body (or similar) and thus should not have access to class attributes in frame""" child = node @@ -1332,16 +1328,13 @@ class VariablesChecker(BaseChecker): while parent is not None: if parent is frame: return False - if isinstance(parent, astroid.Lambda) and child is not parent.args: + if isinstance(parent, nodes.Lambda) and child is not parent.args: # Body of lambda should not have access to class attributes. return True - if ( - isinstance(parent, astroid.node_classes.Comprehension) - and child is not parent.iter - ): + if isinstance(parent, nodes.Comprehension) and child is not parent.iter: # Only iter of list/set/dict/generator comprehension should have access. return True - if isinstance(parent, astroid.scoped_nodes.ComprehensionScope) and not ( + if isinstance(parent, nodes.ComprehensionScope) and not ( parent.generators and child is parent.generators[0] ): # Body of list/set/dict/generator comprehension should not have access to class attributes. @@ -1385,24 +1378,24 @@ class VariablesChecker(BaseChecker): # Note: the node.frame() is not the same as the `frame` argument which is # equivalent to frame.statement().scope() forbid_lookup = ( - isinstance(frame, astroid.FunctionDef) - or isinstance(node.frame(), astroid.Lambda) + isinstance(frame, nodes.FunctionDef) + or isinstance(node.frame(), nodes.Lambda) ) and _assigned_locally(node) if not forbid_lookup and defframe.root().lookup(name)[1]: maybee0601 = False use_outer_definition = stmt == defstmt and not isinstance( - defnode, astroid.node_classes.Comprehension + defnode, nodes.Comprehension ) # check if we have a nonlocal elif name in defframe.locals: maybee0601 = not any( - isinstance(child, astroid.Nonlocal) and name in child.names + isinstance(child, nodes.Nonlocal) and name in child.names for child in defframe.get_children() ) if ( base_scope_type == "lambda" - and isinstance(frame, astroid.ClassDef) + and isinstance(frame, nodes.ClassDef) and name in frame.locals ): @@ -1418,12 +1411,12 @@ class VariablesChecker(BaseChecker): # In this case, maybee0601 should be False, otherwise # it should be True. maybee0601 = not ( - isinstance(defnode, astroid.Arguments) + isinstance(defnode, nodes.Arguments) and node in defnode.defaults and frame.locals[name][0].fromlineno < defstmt.fromlineno ) - elif isinstance(defframe, astroid.ClassDef) and isinstance( - frame, astroid.FunctionDef + elif isinstance(defframe, nodes.ClassDef) and isinstance( + frame, nodes.FunctionDef ): # Special rule for function return annotations, # which uses the same name as the class where @@ -1440,7 +1433,7 @@ class VariablesChecker(BaseChecker): # name as the class. In this case, no warning # should be raised. maybee0601 = False - if isinstance(node.parent, astroid.Arguments): + if isinstance(node.parent, nodes.Arguments): maybee0601 = stmt.fromlineno <= defstmt.fromlineno elif recursive_klass: maybee0601 = True @@ -1448,7 +1441,7 @@ class VariablesChecker(BaseChecker): maybee0601 = maybee0601 and stmt.fromlineno <= defstmt.fromlineno if maybee0601 and stmt.fromlineno == defstmt.fromlineno: if ( - isinstance(defframe, astroid.FunctionDef) + isinstance(defframe, nodes.FunctionDef) and frame is defframe and defframe.parent_of(node) and stmt is not defstmt @@ -1460,14 +1453,14 @@ class VariablesChecker(BaseChecker): isinstance( defstmt, ( - astroid.Assign, - astroid.AnnAssign, - astroid.AugAssign, - astroid.Expr, - astroid.Return, + nodes.Assign, + nodes.AnnAssign, + nodes.AugAssign, + nodes.Expr, + nodes.Return, ), ) - and isinstance(defstmt.value, astroid.IfExp) + and isinstance(defstmt.value, nodes.IfExp) and frame is defframe and defframe.parent_of(node) and stmt is defstmt @@ -1478,7 +1471,7 @@ class VariablesChecker(BaseChecker): maybee0601 = False elif ( isinstance( # pylint: disable=too-many-boolean-expressions - defnode, astroid.NamedExpr + defnode, nodes.NamedExpr ) and frame is defframe and defframe.parent_of(stmt) @@ -1498,13 +1491,13 @@ class VariablesChecker(BaseChecker): and isinstance( defstmt, ( - astroid.Assign, - astroid.AnnAssign, - astroid.AugAssign, - astroid.Return, + nodes.Assign, + nodes.AnnAssign, + nodes.AugAssign, + nodes.Return, ), ) - and isinstance(defstmt.value, astroid.JoinedStr) + and isinstance(defstmt.value, nodes.JoinedStr) ) ) ): @@ -1514,11 +1507,11 @@ class VariablesChecker(BaseChecker): maybee0601 = False # Look for type checking definitions inside a type checking guard. - if isinstance(defstmt, (astroid.Import, astroid.ImportFrom)): + if isinstance(defstmt, (nodes.Import, nodes.ImportFrom)): defstmt_parent = defstmt.parent if ( - isinstance(defstmt_parent, astroid.If) + isinstance(defstmt_parent, nodes.If) and defstmt_parent.test.as_string() in TYPING_TYPE_CHECKS_GUARDS ): # Exempt those definitions that are used inside the type checking @@ -1527,7 +1520,7 @@ class VariablesChecker(BaseChecker): defined_in_or_else = False for definition in defstmt_parent.orelse: - if isinstance(definition, astroid.Assign): + if isinstance(definition, nodes.Assign): defined_in_or_else = any( target.name == name for target in definition.targets ) @@ -1580,10 +1573,7 @@ class VariablesChecker(BaseChecker): else: frame_locals = frame.locals return not ( - ( - isinstance(frame, astroid.ClassDef) - or in_annotation_or_default_or_decorator - ) + (isinstance(frame, nodes.ClassDef) or in_annotation_or_default_or_decorator) and not self._in_lambda_or_comprehension_body(node, frame) and name in frame_locals ) @@ -1598,7 +1588,7 @@ class VariablesChecker(BaseChecker): # the usage is safe because the function will not be defined either if # the variable is not defined. scope = node.scope() - if isinstance(scope, astroid.FunctionDef) and any( + if isinstance(scope, nodes.FunctionDef) and any( asmt.statement().parent_of(scope) for asmt in astmts ): return @@ -1630,15 +1620,13 @@ class VariablesChecker(BaseChecker): assign = astmts[0].assign_type() if not ( - isinstance( - assign, (astroid.For, astroid.Comprehension, astroid.GeneratorExp) - ) + isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp)) and assign.statement() is not node.statement() ): return # For functions we can do more by inferring the length of the itered object - if not isinstance(assign, astroid.For): + if not isinstance(assign, nodes.For): self.add_message("undefined-loop-variable", args=name, node=node) return @@ -1656,10 +1644,10 @@ class VariablesChecker(BaseChecker): # Consider sequences. sequences = ( - astroid.List, - astroid.Tuple, - astroid.Dict, - astroid.Set, + nodes.List, + nodes.Tuple, + nodes.Dict, + nodes.Set, astroid.objects.FrozenSet, ) if not isinstance(inferred, sequences): @@ -1677,15 +1665,15 @@ class VariablesChecker(BaseChecker): return # Ignore names that were added dynamically to the Function scope if ( - isinstance(node, astroid.FunctionDef) + isinstance(node, nodes.FunctionDef) and name == "__class__" and len(node.locals["__class__"]) == 1 - and isinstance(node.locals["__class__"][0], astroid.ClassDef) + and isinstance(node.locals["__class__"][0], nodes.ClassDef) ): return # Ignore names imported by the global statement. - if isinstance(stmt, (astroid.Global, astroid.Import, astroid.ImportFrom)): + if isinstance(stmt, (nodes.Global, nodes.Import, nodes.ImportFrom)): # Detect imports, assigned to global statements. if global_names and _import_name_is_global(stmt, global_names): return @@ -1697,14 +1685,12 @@ class VariablesChecker(BaseChecker): if name in argnames: self._check_unused_arguments(name, node, stmt, argnames) else: - if stmt.parent and isinstance( - stmt.parent, (astroid.Assign, astroid.AnnAssign) - ): + if stmt.parent and isinstance(stmt.parent, (nodes.Assign, nodes.AnnAssign)): if name in nonlocal_names: return qname = asname = None - if isinstance(stmt, (astroid.Import, astroid.ImportFrom)): + if isinstance(stmt, (nodes.Import, nodes.ImportFrom)): # Need the complete name, which we don't have in .locals. if len(stmt.names) > 1: import_names = next( @@ -1719,14 +1705,14 @@ class VariablesChecker(BaseChecker): if _has_locals_call_after_node(stmt, node.scope()): message_name = "possibly-unused-variable" else: - if isinstance(stmt, astroid.Import): + if isinstance(stmt, nodes.Import): if asname is not None: msg = f"{qname} imported as {asname}" else: msg = "import %s" % name self.add_message("unused-import", args=msg, node=stmt) return - if isinstance(stmt, astroid.ImportFrom): + if isinstance(stmt, nodes.ImportFrom): if asname is not None: msg = f"{qname} imported from {stmt.modname} as {asname}" else: @@ -1735,7 +1721,7 @@ class VariablesChecker(BaseChecker): return message_name = "unused-variable" - if isinstance(stmt, astroid.FunctionDef) and stmt.decorators: + if isinstance(stmt, nodes.FunctionDef) and stmt.decorators: return # Don't check function stubs created only for type information @@ -1743,8 +1729,8 @@ class VariablesChecker(BaseChecker): return # Special case for exception variable - if isinstance(stmt.parent, astroid.ExceptHandler) and any( - n.name == name for n in stmt.parent.nodes_of_class(astroid.Name) + if isinstance(stmt.parent, nodes.ExceptHandler) and any( + n.name == name for n in stmt.parent.nodes_of_class(nodes.Name) ): return @@ -1753,9 +1739,9 @@ class VariablesChecker(BaseChecker): def _is_name_ignored(self, stmt, name): authorized_rgx = self.config.dummy_variables_rgx if ( - isinstance(stmt, astroid.AssignName) - and isinstance(stmt.parent, astroid.Arguments) - or isinstance(stmt, astroid.Arguments) + isinstance(stmt, nodes.AssignName) + and isinstance(stmt.parent, nodes.Arguments) + or isinstance(stmt, nodes.Arguments) ): regex = self.config.ignored_argument_names else: @@ -1765,7 +1751,7 @@ class VariablesChecker(BaseChecker): def _check_unused_arguments(self, name, node, stmt, argnames): is_method = node.is_method() klass = node.parent.frame() - if is_method and isinstance(klass, astroid.ClassDef): + if is_method and isinstance(klass, nodes.ClassDef): confidence = ( INFERENCE if utils.has_known_bases(klass) else INFERENCE_FAILURE ) @@ -1805,7 +1791,7 @@ class VariablesChecker(BaseChecker): self.add_message("unused-argument", args=name, node=stmt, confidence=confidence) - def _check_late_binding_closure(self, node: astroid.Name) -> None: + def _check_late_binding_closure(self, node: nodes.Name) -> None: """Check whether node is a cell var that is assigned within a containing loop. Special cases where we don't care about the error: @@ -1824,7 +1810,7 @@ class VariablesChecker(BaseChecker): # Check if node is a cell var if ( - not isinstance(node_scope, (astroid.Lambda, astroid.FunctionDef)) + not isinstance(node_scope, (nodes.Lambda, nodes.FunctionDef)) or node.name in node_scope.locals ): return @@ -1841,7 +1827,7 @@ class VariablesChecker(BaseChecker): assignment_node = stmts[0] maybe_for = assignment_node - while maybe_for and not isinstance(maybe_for, astroid.For): + while maybe_for and not isinstance(maybe_for, nodes.For): if maybe_for is assign_scope: break maybe_for = maybe_for.parent @@ -1850,12 +1836,12 @@ class VariablesChecker(BaseChecker): maybe_for and maybe_for.parent_of(node_scope) and not utils.is_being_called(node_scope) - and not isinstance(node_scope.statement(), astroid.Return) + and not isinstance(node_scope.statement(), nodes.Return) ): self.add_message("cell-var-from-loop", node=node, args=node.name) def _should_ignore_redefined_builtin(self, stmt): - if not isinstance(stmt, astroid.ImportFrom): + if not isinstance(stmt, nodes.ImportFrom): return False return stmt.modname in self.config.redefining_builtins_modules @@ -1882,28 +1868,27 @@ class VariablesChecker(BaseChecker): def _store_type_annotation_node(self, type_annotation): """Given a type annotation, store all the name nodes it refers to""" - if isinstance(type_annotation, astroid.Name): + if isinstance(type_annotation, nodes.Name): self._type_annotation_names.append(type_annotation.name) return - if isinstance(type_annotation, astroid.Attribute): + if isinstance(type_annotation, nodes.Attribute): self._store_type_annotation_node(type_annotation.expr) return - if not isinstance(type_annotation, astroid.Subscript): + if not isinstance(type_annotation, nodes.Subscript): return if ( - isinstance(type_annotation.value, astroid.Attribute) - and isinstance(type_annotation.value.expr, astroid.Name) + isinstance(type_annotation.value, nodes.Attribute) + and isinstance(type_annotation.value.expr, nodes.Name) and type_annotation.value.expr.name == TYPING_MODULE ): self._type_annotation_names.append(TYPING_MODULE) return self._type_annotation_names.extend( - annotation.name - for annotation in type_annotation.nodes_of_class(astroid.Name) + annotation.name for annotation in type_annotation.nodes_of_class(nodes.Name) ) def _store_type_annotation_names(self, node): @@ -1917,19 +1902,19 @@ class VariablesChecker(BaseChecker): assign_names = { target.name for target in node.targets - if isinstance(target, astroid.AssignName) + if isinstance(target, nodes.AssignName) } scope = node.scope() nonlocals_with_same_name = any( child for child in scope.body - if isinstance(child, astroid.Nonlocal) and assign_names & set(child.names) + if isinstance(child, nodes.Nonlocal) and assign_names & set(child.names) ) if nonlocals_with_same_name: scope = node.scope().parent.scope() if not ( - isinstance(scope, astroid.scoped_nodes.FunctionDef) + isinstance(scope, nodes.FunctionDef) and scope.is_method() and "builtins.staticmethod" not in scope.decoratornames() ): @@ -1941,7 +1926,7 @@ class VariablesChecker(BaseChecker): target_assign_names = ( target.name for target in node.targets - if isinstance(target, astroid.node_classes.AssignName) + if isinstance(target, nodes.AssignName) ) if self_cls_name in target_assign_names: self.add_message("self-cls-assignment", node=node, args=(self_cls_name,)) @@ -1957,18 +1942,18 @@ class VariablesChecker(BaseChecker): if inferred is astroid.Uninferable: return if ( - isinstance(inferred.parent, astroid.Arguments) - and isinstance(node.value, astroid.Name) + isinstance(inferred.parent, nodes.Arguments) + and isinstance(node.value, nodes.Name) and node.value.name == inferred.parent.vararg ): # Variable-length argument, we can't determine the length. return - if isinstance(inferred, (astroid.Tuple, astroid.List)): + if isinstance(inferred, (nodes.Tuple, nodes.List)): # attempt to check unpacking is properly balanced values = inferred.itered() if len(targets) != len(values): # Check if we have starred nodes. - if any(isinstance(target, astroid.Starred) for target in targets): + if any(isinstance(target, nodes.Starred) for target in targets): return self.add_message( "unbalanced-tuple-unpacking", @@ -2016,7 +2001,7 @@ class VariablesChecker(BaseChecker): "no-name-in-module", node=node, args=(".".join(module_names), modname) ) return None - if isinstance(module, astroid.Module): + if isinstance(module, nodes.Module): return module return None @@ -2025,7 +2010,7 @@ class VariablesChecker(BaseChecker): if assigned is astroid.Uninferable: return - if not isinstance(assigned, (astroid.Tuple, astroid.List, list, tuple)): + if not isinstance(assigned, (nodes.Tuple, nodes.List, list, tuple)): self.add_message("invalid-all-format", node=assigned) return @@ -2039,7 +2024,7 @@ class VariablesChecker(BaseChecker): if not elt_name.parent: continue - if not isinstance(elt_name, astroid.Const) or not isinstance( + if not isinstance(elt_name, nodes.Const) or not isinstance( elt_name.value, str ): self.add_message("invalid-all-object", args=elt.as_string(), node=elt) @@ -2075,8 +2060,8 @@ class VariablesChecker(BaseChecker): def _check_globals(self, not_consumed): if self._allow_global_unused_variables: return - for name, nodes in not_consumed.items(): - for node in nodes: + for name, node_lst in not_consumed.items(): + for node in node_lst: self.add_message("unused-variable", args=(name,), node=node) def _check_imports(self, not_consumed): @@ -2098,10 +2083,10 @@ class VariablesChecker(BaseChecker): imported_name in self._type_annotation_names or as_name in self._type_annotation_names ) - if isinstance(stmt, astroid.Import) or ( - isinstance(stmt, astroid.ImportFrom) and not stmt.modname + if isinstance(stmt, nodes.Import) or ( + isinstance(stmt, nodes.ImportFrom) and not stmt.modname ): - if isinstance(stmt, astroid.ImportFrom) and SPECIAL_OBJ.search( + if isinstance(stmt, nodes.ImportFrom) and SPECIAL_OBJ.search( imported_name ): # Filter special objects (__doc__, __all__) etc., @@ -2120,7 +2105,7 @@ class VariablesChecker(BaseChecker): msg = f"{imported_name} imported as {as_name}" if not _is_type_checking_import(stmt): self.add_message("unused-import", args=msg, node=stmt) - elif isinstance(stmt, astroid.ImportFrom) and stmt.modname != FUTURE: + elif isinstance(stmt, nodes.ImportFrom) and stmt.modname != FUTURE: if SPECIAL_OBJ.search(imported_name): # Filter special objects (__doc__, __all__) etc., # because they can be imported for exporting. @@ -2152,7 +2137,7 @@ class VariablesChecker(BaseChecker): consumed = [] # [(scope_locals, consumed_key)] for child_node in node.get_children(): - if isinstance(child_node, astroid.ClassDef): + if isinstance(child_node, nodes.ClassDef): consumed.extend(self._check_classdef_metaclasses(child_node, node)) # Pop the consumed items, in order to avoid having @@ -2168,11 +2153,11 @@ class VariablesChecker(BaseChecker): consumed = [] # [(scope_locals, consumed_key)] metaclass = klass.metaclass() name = None - if isinstance(klass._metaclass, astroid.Name): + if isinstance(klass._metaclass, nodes.Name): name = klass._metaclass.name - elif isinstance(klass._metaclass, astroid.Attribute) and klass._metaclass.expr: + elif isinstance(klass._metaclass, nodes.Attribute) and klass._metaclass.expr: attr = klass._metaclass.expr - while not isinstance(attr, astroid.Name): + while not isinstance(attr, nodes.Name): attr = attr.expr name = attr.name elif metaclass: @@ -2191,7 +2176,7 @@ class VariablesChecker(BaseChecker): found is None and not metaclass and not ( - name in astroid.Module.scope_attrs + name in nodes.Module.scope_attrs or utils.is_builtin(name) or name in self.config.additional_builtins or name in parent_node.locals diff --git a/pylint/extensions/_check_docs_utils.py b/pylint/extensions/_check_docs_utils.py index db615edbd..d41988414 100644 --- a/pylint/extensions/_check_docs_utils.py +++ b/pylint/extensions/_check_docs_utils.py @@ -25,6 +25,7 @@ import re from typing import List import astroid +from astroid import nodes from pylint.checkers import utils @@ -53,9 +54,9 @@ def get_setters_property_name(node): decorators = node.decorators.nodes if node.decorators else [] for decorator in decorators: if ( - isinstance(decorator, astroid.Attribute) + isinstance(decorator, nodes.Attribute) and decorator.attrname == "setter" - and isinstance(decorator.expr, astroid.Name) + and isinstance(decorator.expr, nodes.Name) ): return decorator.expr.name return None @@ -65,9 +66,9 @@ def get_setters_property(node): """Get the property node for the given setter node. :param node: The node to get the property for. - :type node: astroid.FunctionDef + :type node: nodes.FunctionDef - :rtype: astroid.FunctionDef or None + :rtype: nodes.FunctionDef or None :returns: The node relating to the property of the given setter node, or None if one could not be found. """ @@ -100,13 +101,13 @@ def returns_something(return_node): if returns is None: return False - return not (isinstance(returns, astroid.Const) and returns.value is None) + return not (isinstance(returns, nodes.Const) and returns.value is None) def _get_raise_target(node): - if isinstance(node.exc, astroid.Call): + if isinstance(node.exc, nodes.Call): func = node.exc.func - if isinstance(func, (astroid.Name, astroid.Attribute)): + if isinstance(func, (nodes.Name, nodes.Attribute)): return utils.safe_infer(func) return None @@ -126,19 +127,19 @@ def possible_exc_types(node): :param node: The raise node to find exception types for. - :type node: astroid.node_classes.NodeNG + :type node: nodes.NodeNG :returns: A list of exception types possibly raised by :param:`node`. :rtype: set(str) """ excs = [] - if isinstance(node.exc, astroid.Name): + if isinstance(node.exc, nodes.Name): inferred = utils.safe_infer(node.exc) if inferred: excs = [inferred.name] elif node.exc is None: handler = node.parent - while handler and not isinstance(handler, astroid.ExceptHandler): + while handler and not isinstance(handler, nodes.ExceptHandler): handler = handler.parent if handler and handler.type: @@ -146,10 +147,10 @@ def possible_exc_types(node): excs = (exc.name for exc in inferred_excs if exc is not astroid.Uninferable) else: target = _get_raise_target(node) - if isinstance(target, astroid.ClassDef): + if isinstance(target, nodes.ClassDef): excs = [target.name] - elif isinstance(target, astroid.FunctionDef): - for ret in target.nodes_of_class(astroid.Return): + elif isinstance(target, nodes.FunctionDef): + for ret in target.nodes_of_class(nodes.Return): if ret.frame() != target: # return from inner function - ignore it continue @@ -157,7 +158,7 @@ def possible_exc_types(node): val = utils.safe_infer(ret.value) if ( val - and isinstance(val, (astroid.Instance, astroid.ClassDef)) + and isinstance(val, (astroid.Instance, nodes.ClassDef)) and utils.inherit_from_std_ex(val) ): excs.append(val.name) |