Method: pylint.checkers.variables.VariablesChecker._check_consumer
Calls: 20940, Exceptions: 0, Paths: 39Back
Path 1: 9356 calls (0.45)
Name (9347) AssignName (7) DelName (2)
Expr (3350) Assign (1458) AnnAssign (908) FunctionDef (696) Return (618) ExceptHandler (548) Raise (476) For (419) ClassDef (283) If (260)
FunctionDef (6137) Module (2245) ClassDef (898) AsyncFunctionDef (76)
NamesConsumer (9356)
'function' (5941) 'module' (1774) 'class' (867) 'comprehension' (601) 'lambda' (173)
tuple (9356)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 2: 5040 calls (0.24)
Name (4886) AssignName (152) DelName (2)
Expr (1602) Assign (1330) If (552) Return (315) FunctionDef (260) AugAssign (225) ClassDef (195) AnnAssign (175) With (116) For (113)
FunctionDef (2397) Module (2342) ClassDef (273) AsyncFunctionDef (28)
NamesConsumer (5040)
'function' (2387) 'module' (2120) 'class' (271) 'comprehension' (195) 'lambda' (67)
tuple (5040)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 3: 4182 calls (0.2)
Name (4096) AssignName (76) DelName (10)
Expr (1153) Return (988) Assign (871) If (597) For (170) AugAssign (115) AnnAssign (94) Raise (60) With (60) Assert (46)
FunctionDef (3258) Module (878) AsyncFunctionDef (46)
NamesConsumer (4182)
'function' (3268) 'module' (852) 'comprehension' (36) 'lambda' (26)
tuple (4182)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 4: 996 calls (0.05)
Name (996)
FunctionDef (236) Expr (208) ClassDef (167) Assign (166) Return (106) AnnAssign (37) If (22) With (20) Raise (11) For (6)
FunctionDef (596) ClassDef (271) Module (115) AsyncFunctionDef (14)
NamesConsumer (996)
'function' (607) 'class' (259) 'module' (113) 'lambda' (13) 'comprehension' (4)
tuple (996)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 5: 644 calls (0.03)
Name (644)
ClassDef (237) Assign (144) Expr (127) Return (50) FunctionDef (26) Raise (12) AnnAssign (10) AsyncWith (9) For (8) With (6)
ClassDef (255) Module (200) FunctionDef (178) AsyncFunctionDef (11)
NamesConsumer (644)
'class' (255) 'module' (200) 'function' (189)
tuple (644)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 6: 472 calls (0.02)
Name (471) AssignName (1)
Assign (285) Expr (133) Return (30) FunctionDef (8) Assert (7) For (4) If (3) Raise (1) AugAssign (1)
Module (369) FunctionDef (96) AsyncFunctionDef (7)
NamesConsumer (472)
'comprehension' (285) 'lambda' (181) 'module' (4) 'function' (2)
tuple (472)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 7: 46 calls (0.0)
Name (46)
Expr (33) Raise (9) If (4)
FunctionDef (37) Module (9)
NamesConsumer (46)
'function' (37) 'module' (9)
tuple (46)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 8: 33 calls (0.0)
Name (33)
Expr (20) Assign (6) Assert (2) If (2) AnnAssign (1) AugAssign (1) Return (1)
Module (25) FunctionDef (8)
NamesConsumer (33)
'module' (23) 'function' (8) 'lambda' (2)
tuple (33)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 9: 23 calls (0.0)
Name (23)
Assign (14) Expr (4) Return (3) AnnAssign (1) AugAssign (1)
FunctionDef (16) Module (7)
NamesConsumer (23)
'function' (15) 'module' (7) 'lambda' (1)
tuple (23)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 10: 20 calls (0.0)
Name (20)
Assign (19) If (1)
ClassDef (20)
NamesConsumer (20)
'lambda' (17) 'comprehension' (3)
tuple (20)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 11: 16 calls (0.0)
Name (16)
Assign (16)
Module (15) FunctionDef (1)
NamesConsumer (16)
'lambda' (16)
tuple (16)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 12: 14 calls (0.0)
Name (14)
If (6) Expr (5) Assign (3)
FunctionDef (12) Module (2)
NamesConsumer (14)
'function' (12) 'module' (2)
tuple (14)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 13: 13 calls (0.0)
Name (13)
FunctionDef (9) ClassDef (3) Expr (1)
FunctionDef (10) ClassDef (3)
NamesConsumer (13)
'function' (10) 'class' (3)
tuple (13)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 14: 11 calls (0.0)
Name (11)
Assign (6) If (2) Assert (1) Expr (1) Return (1)
Module (7) FunctionDef (4)
NamesConsumer (11)
'module' (7) 'function' (4)
tuple (11)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 15: 10 calls (0.0)
Name (10)
If (6) Assign (4)
ClassDef (10)
NamesConsumer (10)
'class' (9) 'comprehension' (1)
tuple (10)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 16: 7 calls (0.0)
Name (7)
FunctionDef (5) AnnAssign (2)
FunctionDef (5) ClassDef (2)
NamesConsumer (7)
'function' (5) 'class' (2)
tuple (7)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 17: 7 calls (0.0)
Name (5) AssignName (2)
Assign (5) AugAssign (2)
ClassDef (7)
NamesConsumer (7)
'class' (7)
tuple (7)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 18: 6 calls (0.0)
Name (6)
Expr (5) If (1)
FunctionDef (6)
NamesConsumer (6)
'function' (6)
tuple (6)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 19: 5 calls (0.0)
Name (5)
FunctionDef (5)
FunctionDef (5)
NamesConsumer (5)
'function' (5)
tuple (5)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 20: 5 calls (0.0)
AssignName (3) DelName (2)
AugAssign (3) Delete (2)
FunctionDef (4) Module (1)
NamesConsumer (5)
'function' (4) 'module' (1)
tuple (5)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 21: 4 calls (0.0)
Name (4)
FunctionDef (3) AsyncFunctionDef (1)
FunctionDef (3) AsyncFunctionDef (1)
NamesConsumer (4)
'function' (4)
tuple (4)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 22: 3 calls (0.0)
Name (3)
Assign (3)
ClassDef (3)
NamesConsumer (3)
'lambda' (2) 'comprehension' (1)
tuple (3)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 23: 3 calls (0.0)
Name (3)
FunctionDef (3)
FunctionDef (3)
NamesConsumer (3)
'comprehension' (3)
tuple (3)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 24: 3 calls (0.0)
Name (3)
Expr (3)
Module (3)
NamesConsumer (3)
'module' (3)
tuple (3)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 25: 2 calls (0.0)
Name (2)
Assign (1) Expr (1)
Module (1) FunctionDef (1)
NamesConsumer (2)
'comprehension' (2)
tuple (2)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 26: 2 calls (0.0)
Name (2)
Assign (2)
ClassDef (2)
NamesConsumer (2)
'lambda' (2)
tuple (2)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 27: 2 calls (0.0)
Name (2)
AnnAssign (2)
ClassDef (2)
NamesConsumer (2)
'class' (2)
tuple (2)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 28: 2 calls (0.0)
Name (2)
Assign (2)
ClassDef (2)
NamesConsumer (2)
'lambda' (2)
tuple (2)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 29: 2 calls (0.0)
Name (2)
Expr (2)
FunctionDef (2)
NamesConsumer (2)
'function' (2)
tuple (2)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 30: 2 calls (0.0)
Name (2)
Expr (2)
Module (2)
NamesConsumer (2)
'module' (2)
tuple (2)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 31: 1 calls (0.0)
Name (1)
Assign (1)
ClassDef (1)
NamesConsumer (1)
'lambda' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 32: 1 calls (0.0)
Name (1)
Assign (1)
ClassDef (1)
NamesConsumer (1)
'class' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 33: 1 calls (0.0)
Name (1)
Assign (1)
Module (1)
NamesConsumer (1)
'module' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 34: 1 calls (0.0)
Name (1)
ClassDef (1)
ClassDef (1)
NamesConsumer (1)
'class' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 35: 1 calls (0.0)
Name (1)
Assign (1)
ClassDef (1)
NamesConsumer (1)
'lambda' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 36: 1 calls (0.0)
Name (1)
ClassDef (1)
ClassDef (1)
NamesConsumer (1)
'comprehension' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 37: 1 calls (0.0)
Name (1)
Assign (1)
Module (1)
NamesConsumer (1)
'lambda' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 38: 1 calls (0.0)
Name (1)
AnnAssign (1)
ClassDef (1)
NamesConsumer (1)
'class' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)
Path 39: 1 calls (0.0)
Name (1)
AnnAssign (1)
FunctionDef (1)
NamesConsumer (1)
'function' (1)
tuple (1)
1def _check_consumer(
2 self,
3 node: nodes.Name,
4 stmt: nodes.NodeNG,
5 frame: nodes.LocalsDictNodeNG,
6 current_consumer: NamesConsumer,
7 base_scope_type: str,
8 ) -> tuple[VariableVisitConsumerAction, list[nodes.NodeNG] | None]:
9 """Checks a consumer for conditions that should trigger messages."""
10 # If the name has already been consumed, only check it's not a loop
11 # variable used outside the loop.
12 if node.name in current_consumer.consumed:
13 # Avoid the case where there are homonyms inside function scope and
14 # comprehension current scope (avoid bug #1731)
15 if utils.is_func_decorator(current_consumer.node) or not isinstance(
16 node, nodes.ComprehensionScope
17 ):
18 self._check_late_binding_closure(node)
19 return (VariableVisitConsumerAction.RETURN, None)
20
21 found_nodes = current_consumer.get_next_to_consume(node)
22 if found_nodes is None:
23 return (VariableVisitConsumerAction.CONTINUE, None)
24 if not found_nodes:
25 if node.name in current_consumer.consumed_uncertain:
26 confidence = CONTROL_FLOW
27 else:
28 confidence = HIGH
29 self.add_message(
30 "used-before-assignment",
31 args=node.name,
32 node=node,
33 confidence=confidence,
34 )
35 # Mark for consumption any nodes added to consumed_uncertain by
36 # get_next_to_consume() because they might not have executed.
37 return (
38 VariableVisitConsumerAction.RETURN,
39 current_consumer.consumed_uncertain[node.name],
40 )
41
42 self._check_late_binding_closure(node)
43
44 defnode = utils.assign_parent(found_nodes[0])
45 defstmt = defnode.statement(future=True)
46 defframe = defstmt.frame(future=True)
47
48 # The class reuses itself in the class scope.
49 is_recursive_klass: bool = (
50 frame is defframe
51 and defframe.parent_of(node)
52 and isinstance(defframe, nodes.ClassDef)
53 and node.name == defframe.name
54 )
55
56 if (
57 is_recursive_klass
58 and utils.get_node_first_ancestor_of_type(node, nodes.Lambda)
59 and (
60 not utils.is_default_argument(node)
61 or node.scope().parent.scope() is not defframe
62 )
63 ):
64 # Self-referential class references are fine in lambda's --
65 # As long as they are not part of the default argument directly
66 # under the scope of the parent self-referring class.
67 # Example of valid default argument:
68 # class MyName3:
69 # myattr = 1
70 # mylambda3 = lambda: lambda a=MyName3: a
71 # Example of invalid default argument:
72 # class MyName4:
73 # myattr = 1
74 # mylambda4 = lambda a=MyName4: lambda: a
75
76 # If the above conditional is True,
77 # there is no possibility of undefined-variable
78 # Also do not consume class name
79 # (since consuming blocks subsequent checks)
80 # -- quit
81 return (VariableVisitConsumerAction.RETURN, None)
82
83 (
84 maybe_before_assign,
85 annotation_return,
86 use_outer_definition,
87 ) = self._is_variable_violation(
88 node,
89 defnode,
90 stmt,
91 defstmt,
92 frame,
93 defframe,
94 base_scope_type,
95 is_recursive_klass,
96 )
97
98 if use_outer_definition:
99 return (VariableVisitConsumerAction.CONTINUE, None)
100
101 if (
102 maybe_before_assign
103 and not utils.is_defined_before(node)
104 and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
105 ):
106 # Used and defined in the same place, e.g `x += 1` and `del x`
107 defined_by_stmt = defstmt is stmt and isinstance(
108 node, (nodes.DelName, nodes.AssignName)
109 )
110 if (
111 is_recursive_klass
112 or defined_by_stmt
113 or annotation_return
114 or isinstance(defstmt, nodes.Delete)
115 ):
116 if not utils.node_ignores_exception(node, NameError):
117 # Handle postponed evaluation of annotations
118 if not (
119 self._postponed_evaluation_enabled
120 and isinstance(
121 stmt,
122 (
123 nodes.AnnAssign,
124 nodes.FunctionDef,
125 nodes.Arguments,
126 ),
127 )
128 and node.name in node.root().locals
129 ):
130 if defined_by_stmt:
131 return (VariableVisitConsumerAction.CONTINUE, [node])
132 return (VariableVisitConsumerAction.CONTINUE, None)
133
134 elif base_scope_type != "lambda":
135 # E0601 may *not* occurs in lambda scope.
136
137 # Skip postponed evaluation of annotations
138 # and unevaluated annotations inside a function body
139 if not (
140 self._postponed_evaluation_enabled
141 and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
142 ) and not (
143 isinstance(stmt, nodes.AnnAssign)
144 and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
145 ):
146 self.add_message(
147 "used-before-assignment",
148 args=node.name,
149 node=node,
150 confidence=HIGH,
151 )
152 return (VariableVisitConsumerAction.RETURN, found_nodes)
153
154 elif base_scope_type == "lambda":
155 # E0601 can occur in class-level scope in lambdas, as in
156 # the following example:
157 # class A:
158 # x = lambda attr: f + attr
159 # f = 42
160 # We check lineno because doing the following is fine:
161 # class A:
162 # x = 42
163 # y = lambda attr: x + attr
164 if (
165 isinstance(frame, nodes.ClassDef)
166 and node.name in frame.locals
167 and stmt.fromlineno <= defstmt.fromlineno
168 ):
169 self.add_message(
170 "used-before-assignment",
171 args=node.name,
172 node=node,
173 confidence=HIGH,
174 )
175
176 elif self._is_only_type_assignment(node, defstmt):
177 if node.scope().locals.get(node.name):
178 self.add_message(
179 "used-before-assignment", args=node.name, node=node, confidence=HIGH
180 )
181 else:
182 self.add_message(
183 "undefined-variable", args=node.name, node=node, confidence=HIGH
184 )
185 return (VariableVisitConsumerAction.RETURN, found_nodes)
186
187 elif isinstance(defstmt, nodes.ClassDef):
188 return self._is_first_level_self_reference(node, defstmt, found_nodes)
189
190 elif isinstance(defnode, nodes.NamedExpr):
191 if isinstance(defnode.parent, nodes.IfExp):
192 if self._is_never_evaluated(defnode, defnode.parent):
193 self.add_message(
194 "undefined-variable",
195 args=node.name,
196 node=node,
197 confidence=INFERENCE,
198 )
199 return (VariableVisitConsumerAction.RETURN, found_nodes)
200
201 return (VariableVisitConsumerAction.RETURN, found_nodes)