From f1333e28bf9ab8a6584ca13aacf244a1a1165f87 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Thu, 17 Jun 2021 18:43:03 +0200 Subject: Refactor Variable checker to use less argument in function We only need the node because we can get the name from the node. --- pylint/checkers/variables.py | 97 +++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 44044f76b..ef53f19cb 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -979,7 +979,6 @@ class VariablesChecker(BaseChecker): assert not stmt.root().file.endswith(".py") return - name = node.name frame = stmt.scope() start_index = len(self._to_consume) - 1 @@ -1035,7 +1034,7 @@ class VariablesChecker(BaseChecker): # variable used outside the loop # avoid the case where there are homonyms inside function scope and # comprehension current scope (avoid bug #1731) - if name in current_consumer.consumed and ( + if node.name in current_consumer.consumed and ( utils.is_func_decorator(current_consumer.node) or not ( current_consumer.scope_type == "comprehension" @@ -1043,7 +1042,7 @@ class VariablesChecker(BaseChecker): ) ): self._check_late_binding_closure(node) - self._loopvar_name(node, name) + self._loopvar_name(node) break found_nodes = current_consumer.get_next_to_consume(node) @@ -1056,7 +1055,9 @@ class VariablesChecker(BaseChecker): else: defnode = None if used_before_assignment_is_enabled: - self.add_message("used-before-assignment", args=name, node=node) + self.add_message( + "used-before-assignment", args=node.name, node=node + ) self._check_late_binding_closure(node) @@ -1106,7 +1107,6 @@ class VariablesChecker(BaseChecker): use_outer_definition, ) = self._is_variable_violation( node, - name, defnode, stmt, defstmt, @@ -1148,10 +1148,10 @@ class VariablesChecker(BaseChecker): nodes.Arguments, ), ) - and name in node.root().locals + and node.name in node.root().locals ): self.add_message( - "undefined-variable", args=name, node=node + "undefined-variable", args=node.name, node=node ) elif base_scope_type != "lambda": # E0601 may *not* occurs in lambda scope. @@ -1162,7 +1162,7 @@ class VariablesChecker(BaseChecker): and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef)) ): self.add_message( - "used-before-assignment", args=name, node=node + "used-before-assignment", args=node.name, node=node ) elif base_scope_type == "lambda": # E0601 can occur in class-level scope in lambdas, as in @@ -1170,7 +1170,10 @@ class VariablesChecker(BaseChecker): # class A: # x = lambda attr: f + attr # f = 42 - if isinstance(frame, nodes.ClassDef) and name in frame.locals: + if ( + isinstance(frame, nodes.ClassDef) + and node.name in frame.locals + ): if isinstance(node.parent, nodes.Arguments): if stmt.fromlineno <= defstmt.fromlineno: # Doing the following is fine: @@ -1178,36 +1181,40 @@ class VariablesChecker(BaseChecker): # x = 42 # y = lambda attr=x: attr self.add_message( - "used-before-assignment", args=name, node=node + "used-before-assignment", + args=node.name, + node=node, ) else: self.add_message( - "undefined-variable", args=name, node=node + "undefined-variable", args=node.name, node=node ) elif current_consumer.scope_type == "lambda": - self.add_message("undefined-variable", node=node, args=name) - elif self._is_only_type_assignment(node, name, defstmt): - self.add_message("undefined-variable", node=node, args=name) + self.add_message( + "undefined-variable", node=node, args=node.name + ) + elif self._is_only_type_assignment(node, defstmt): + self.add_message("undefined-variable", node=node, args=node.name) - current_consumer.mark_as_consumed(name, found_nodes) + current_consumer.mark_as_consumed(node.name, found_nodes) # check it's not a loop variable used outside the loop - self._loopvar_name(node, name) + self._loopvar_name(node) break else: # 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 nodes.Module.scope_attrs - or utils.is_builtin(name) - or name in self.config.additional_builtins + node.name in nodes.Module.scope_attrs + or utils.is_builtin(node.name) + or node.name in self.config.additional_builtins or ( - name == "__class__" + node.name == "__class__" and isinstance(frame, nodes.FunctionDef) and frame.is_method() ) ): if not utils.node_ignores_exception(node, NameError): - self.add_message("undefined-variable", args=name, node=node) + self.add_message("undefined-variable", args=node.name, node=node) @utils.check_messages("no-name-in-module") def visit_import(self, node: nodes.Import) -> None: @@ -1358,21 +1365,16 @@ class VariablesChecker(BaseChecker): @staticmethod def _is_variable_violation( - node, - name, + node: nodes.Name, defnode, stmt, defstmt, - frame, + frame, # scope of statement of node defframe, base_scope_type, recursive_klass, - ): + ) -> Tuple[bool, bool, bool]: # pylint: disable=too-many-nested-blocks - # node: Node to check for violation - # name: name of node to check violation for - # frame: Scope of statement of node - # base_scope_type: local scope type maybee0601 = True annotation_return = False use_outer_definition = False @@ -1381,7 +1383,10 @@ class VariablesChecker(BaseChecker): elif defframe.parent is None: # we are at the module level, check the name is not # defined in builtins - if name in defframe.scope_attrs or astroid.builtin_lookup(name)[1]: + if ( + node.name in defframe.scope_attrs + or astroid.builtin_lookup(node.name)[1] + ): maybee0601 = False else: # we are in a local scope, check the name is not @@ -1393,22 +1398,22 @@ class VariablesChecker(BaseChecker): isinstance(frame, nodes.FunctionDef) or isinstance(node.frame(), nodes.Lambda) ) and _assigned_locally(node) - if not forbid_lookup and defframe.root().lookup(name)[1]: + if not forbid_lookup and defframe.root().lookup(node.name)[1]: maybee0601 = False use_outer_definition = stmt == defstmt and not isinstance( defnode, nodes.Comprehension ) # check if we have a nonlocal - elif name in defframe.locals: + elif node.name in defframe.locals: maybee0601 = not any( - isinstance(child, nodes.Nonlocal) and name in child.names + isinstance(child, nodes.Nonlocal) and node.name in child.names for child in defframe.get_children() ) if ( base_scope_type == "lambda" and isinstance(frame, nodes.ClassDef) - and name in frame.locals + and node.name in frame.locals ): # This rule verifies that if the definition node of the @@ -1425,7 +1430,7 @@ class VariablesChecker(BaseChecker): maybee0601 = not ( isinstance(defnode, nodes.Arguments) and node in defnode.defaults - and frame.locals[name][0].fromlineno < defstmt.fromlineno + and frame.locals[node.name][0].fromlineno < defstmt.fromlineno ) elif isinstance(defframe, nodes.ClassDef) and isinstance( frame, nodes.FunctionDef @@ -1439,7 +1444,7 @@ class VariablesChecker(BaseChecker): if ( maybee0601 and defframe.name in defframe.locals - and defframe.locals[name][0].lineno < frame.lineno + and defframe.locals[node.name][0].lineno < frame.lineno ): # Detect class assignments with the same # name as the class. In this case, no warning @@ -1538,7 +1543,7 @@ class VariablesChecker(BaseChecker): for definition in defstmt_parent.orelse: if isinstance(definition, nodes.Assign): defined_in_or_else = any( - target.name == name + target.name == node.name for target in definition.targets if isinstance(target, nodes.AssignName) ) @@ -1551,13 +1556,11 @@ class VariablesChecker(BaseChecker): return maybee0601, annotation_return, use_outer_definition @staticmethod - def _is_only_type_assignment( - node: nodes.Name, name: str, defstmt: nodes.Statement - ) -> bool: + def _is_only_type_assignment(node: nodes.Name, defstmt: nodes.Statement) -> bool: """Check if variable only gets assigned a type and never a value""" if not isinstance(defstmt, nodes.AnnAssign) or defstmt.value: return False - for ref_node in node.scope().locals[name][1:]: + for ref_node in node.scope().locals[node.name][1:]: if ref_node.lineno < node.lineno: if not ( isinstance(ref_node.parent, nodes.AnnAssign) @@ -1612,11 +1615,11 @@ class VariablesChecker(BaseChecker): and name in frame_locals ) - def _loopvar_name(self, node, name): + def _loopvar_name(self, node: astroid.Name) -> None: # filter variables according to node's scope if not self.linter.is_message_enabled("undefined-loop-variable"): return - astmts = [stmt for stmt in node.lookup(name)[1] if hasattr(stmt, "assign_type")] + astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")] # If this variable usage exists inside a function definition # that exists in the same loop, # the usage is safe because the function will not be defined either if @@ -1661,13 +1664,13 @@ class VariablesChecker(BaseChecker): # For functions we can do more by inferring the length of the itered object if not isinstance(assign, nodes.For): - self.add_message("undefined-loop-variable", args=name, node=node) + self.add_message("undefined-loop-variable", args=node.name, node=node) return try: inferred = next(assign.iter.infer()) except astroid.InferenceError: - self.add_message("undefined-loop-variable", args=name, node=node) + self.add_message("undefined-loop-variable", args=node.name, node=node) else: if ( isinstance(inferred, astroid.Instance) @@ -1685,12 +1688,12 @@ class VariablesChecker(BaseChecker): astroid.objects.FrozenSet, ) if not isinstance(inferred, sequences): - self.add_message("undefined-loop-variable", args=name, node=node) + self.add_message("undefined-loop-variable", args=node.name, node=node) return elements = getattr(inferred, "elts", getattr(inferred, "items", [])) if not elements: - self.add_message("undefined-loop-variable", args=name, node=node) + self.add_message("undefined-loop-variable", args=node.name, node=node) def _check_is_unused(self, name, node, stmt, global_names, nonlocal_names): # pylint: disable=too-many-branches -- cgit v1.2.1