Method: pylint.checkers.variables.VariablesChecker._loopvar_name
Calls: 16687, Exceptions: 1112, Paths: 36Back
Path 1: 3480 calls (0.21)
Name (3466) AssignName (13) DelName (1)
None (3480)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 2: 2663 calls (0.16)
Name (2657) DelName (3) AssignName (3)
None (2663)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 3: 2420 calls (0.15)
Name (2420)
None (2420)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 4: 2417 calls (0.14)
Name (2417)
None (2417)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 5: 1359 calls (0.08)
Name (1225) AssignName (134)
None (1359)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 6: 1351 calls (0.08)
Name (1323) AssignName (26) DelName (2)
None (1351)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 7: 1112 calls (0.07)
Name (1103) AssignName (8) DelName (1)
None (1112)
GeneratorExit (1112)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 8: 660 calls (0.04)
Name (655) DelName (4) AssignName (1)
None (660)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 9: 337 calls (0.02)
Name (337)
None (337)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 10: 224 calls (0.01)
Name (223) DelName (1)
None (224)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 11: 181 calls (0.01)
Name (177) AssignName (3) DelName (1)
None (181)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 12: 129 calls (0.01)
Name (124) AssignName (4) DelName (1)
None (129)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 13: 102 calls (0.01)
Name (100) AssignName (2)
None (102)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 14: 92 calls (0.01)
Name (52) AssignName (40)
None (92)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 15: 87 calls (0.01)
Name (87)
None (87)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 16: 16 calls (0.0)
Name (16)
None (16)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 17: 11 calls (0.0)
Name (11)
None (11)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 18: 7 calls (0.0)
Name (7)
None (7)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 19: 5 calls (0.0)
Name (5)
None (5)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 20: 5 calls (0.0)
Name (5)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 21: 4 calls (0.0)
Name (4)
None (4)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 22: 4 calls (0.0)
Name (4)
None (4)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 23: 3 calls (0.0)
Name (3)
None (3)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 24: 3 calls (0.0)
Name (3)
None (3)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 25: 2 calls (0.0)
Name (2)
None (2)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 26: 2 calls (0.0)
Name (2)
None (2)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 27: 2 calls (0.0)
Name (2)
None (2)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 28: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 29: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 30: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 31: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 32: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 33: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 34: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 35: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)
Path 36: 1 calls (0.0)
Name (1)
None (1)
1def _loopvar_name(self, node: astroid.Name) -> None:
2 # filter variables according to node's scope
3 astmts = [s for s in node.lookup(node.name)[1] if hasattr(s, "assign_type")]
4 # If this variable usage exists inside a function definition
5 # that exists in the same loop,
6 # the usage is safe because the function will not be defined either if
7 # the variable is not defined.
8 scope = node.scope()
9 # FunctionDef subclasses Lambda due to a curious ontology. Check both.
10 # See https://github.com/PyCQA/astroid/issues/291
11 # TODO: Revisit when astroid 3.0 includes the change
12 if isinstance(scope, nodes.Lambda) and any(
13 asmt.scope().parent_of(scope) for asmt in astmts
14 ):
15 return
16 # Filter variables according to their respective scope. Test parent
17 # and statement to avoid #74747. This is not a total fix, which would
18 # introduce a mechanism similar to special attribute lookup in
19 # modules. Also, in order to get correct inference in this case, the
20 # scope lookup rules would need to be changed to return the initial
21 # assignment (which does not exist in code per se) as well as any later
22 # modifications.
23 if (
24 not astmts # pylint: disable=too-many-boolean-expressions
25 or (
26 astmts[0].parent == astmts[0].root()
27 and astmts[0].parent.parent_of(node)
28 )
29 or (
30 astmts[0].is_statement
31 or not isinstance(astmts[0].parent, nodes.Module)
32 and astmts[0].statement(future=True).parent_of(node)
33 )
34 ):
35 _astmts = []
36 else:
37 _astmts = astmts[:1]
38 for i, stmt in enumerate(astmts[1:]):
39 if astmts[i].statement(future=True).parent_of(
40 stmt
41 ) and not utils.in_for_else_branch(astmts[i].statement(future=True), stmt):
42 continue
43 _astmts.append(stmt)
44 astmts = _astmts
45 if len(astmts) != 1:
46 return
47
48 assign = astmts[0].assign_type()
49 if not (
50 isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
51 and assign.statement(future=True) is not node.statement(future=True)
52 ):
53 return
54
55 if not isinstance(assign, nodes.For):
56 self.add_message("undefined-loop-variable", args=node.name, node=node)
57 return
58 for else_stmt in assign.orelse:
59 if isinstance(
60 else_stmt, (nodes.Return, nodes.Raise, nodes.Break, nodes.Continue)
61 ):
62 return
63 # TODO: 2.16: Consider using RefactoringChecker._is_function_def_never_returning
64 if isinstance(else_stmt, nodes.Expr) and isinstance(
65 else_stmt.value, nodes.Call
66 ):
67 inferred_func = utils.safe_infer(else_stmt.value.func)
68 if (
69 isinstance(inferred_func, nodes.FunctionDef)
70 and inferred_func.returns
71 ):
72 inferred_return = utils.safe_infer(inferred_func.returns)
73 if isinstance(
74 inferred_return, nodes.FunctionDef
75 ) and inferred_return.qname() in {
76 *TYPING_NORETURN,
77 *TYPING_NEVER,
78 "typing._SpecialForm",
79 }:
80 return
81 # typing_extensions.NoReturn returns a _SpecialForm
82 if (
83 isinstance(inferred_return, bases.Instance)
84 and inferred_return.qname() == "typing._SpecialForm"
85 ):
86 return
87
88 maybe_walrus = utils.get_node_first_ancestor_of_type(node, nodes.NamedExpr)
89 if maybe_walrus:
90 maybe_comprehension = utils.get_node_first_ancestor_of_type(
91 maybe_walrus, nodes.Comprehension
92 )
93 if maybe_comprehension:
94 comprehension_scope = utils.get_node_first_ancestor_of_type(
95 maybe_comprehension, nodes.ComprehensionScope
96 )
97 if comprehension_scope is None:
98 # Should not be possible.
99 pass
100 elif (
101 comprehension_scope.parent.scope() is scope
102 and node.name in comprehension_scope.locals
103 ):
104 return
105
106 # For functions we can do more by inferring the length of the itered object
107 try:
108 inferred = next(assign.iter.infer())
109 # Prefer the target of enumerate() rather than the enumerate object itself
110 if (
111 isinstance(inferred, astroid.Instance)
112 and inferred.qname() == "builtins.enumerate"
113 ):
114 likely_call = assign.iter
115 if isinstance(assign.iter, nodes.IfExp):
116 likely_call = assign.iter.body
117 if isinstance(likely_call, nodes.Call):
118 inferred = next(likely_call.args[0].infer())
119 except astroid.InferenceError:
120 self.add_message("undefined-loop-variable", args=node.name, node=node)
121 else:
122 if (
123 isinstance(inferred, astroid.Instance)
124 and inferred.qname() == BUILTIN_RANGE
125 ):
126 # Consider range() objects safe, even if they might not yield any results.
127 return
128
129 # Consider sequences.
130 sequences = (
131 nodes.List,
132 nodes.Tuple,
133 nodes.Dict,
134 nodes.Set,
135 astroid.objects.FrozenSet,
136 )
137 if not isinstance(inferred, sequences):
138 self.add_message("undefined-loop-variable", args=node.name, node=node)
139 return
140
141 elements = getattr(inferred, "elts", getattr(inferred, "items", []))
142 if not elements:
143 self.add_message("undefined-loop-variable", args=node.name, node=node)