diff options
| author | Claudiu Popa <pcmanticore@gmail.com> | 2018-04-25 11:18:56 +0200 |
|---|---|---|
| committer | Claudiu Popa <pcmanticore@gmail.com> | 2018-04-25 11:18:56 +0200 |
| commit | b93cdf863896556c95b064f8405d648c69953ffa (patch) | |
| tree | 4d76d4b6308ad0632c997bf7e2941665abaee67f | |
| parent | 815b4e3c2abbb07e832bfad35444eef78f083c55 (diff) | |
| download | pylint-git-b93cdf863896556c95b064f8405d648c69953ffa.tar.gz | |
`undefined-loop-variable` takes in consideration non-empty iterred objects before emitting
Close #2039
| -rw-r--r-- | ChangeLog | 4 | ||||
| -rw-r--r-- | doc/whatsnew/2.0.rst | 6 | ||||
| -rw-r--r-- | pylint/checkers/variables.py | 37 | ||||
| -rw-r--r-- | pylint/test/functional/undefined_loop_variable.py | 24 |
4 files changed, 66 insertions, 5 deletions
@@ -4,6 +4,10 @@ Pylint's ChangeLog What's New in Pylint 2.0? ========================= + * `undefined-loop-variable` takes in consideration non-empty iterred objects before emitting + + Close #2039 + * Add support for nupmydoc optional return value names. Close #2030 diff --git a/doc/whatsnew/2.0.rst b/doc/whatsnew/2.0.rst index f5fa63b0c..98e1dc3aa 100644 --- a/doc/whatsnew/2.0.rst +++ b/doc/whatsnew/2.0.rst @@ -125,3 +125,9 @@ Other Changes * Suppress false-positive ``not-callable`` messages from certain staticmethod descriptors * `singleton-comparison` will suggest better boolean conditions for negative conditions. + +* `undefined-loop-variable` takes in consideration non-empty iterred objects before emitting. + + For instance, if the loop iterable is not empty, this check will no longer be emitted. + + diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 22468a997..1b960910f 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -38,6 +38,7 @@ import re import astroid from astroid import decorators from astroid import modutils +from astroid import objects from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE, HIGH from pylint.utils import get_global_option from pylint.checkers import BaseChecker @@ -930,11 +931,37 @@ class VariablesChecker(BaseChecker): continue _astmts.append(stmt) astmts = _astmts - if len(astmts) == 1: - assign = astmts[0].assign_type() - if (isinstance(assign, (astroid.For, astroid.Comprehension, - astroid.GeneratorExp)) - and assign.statement() is not node.statement()): + if len(astmts) != 1: + return + + assign = astmts[0].assign_type() + if not (isinstance(assign, (astroid.For, astroid.Comprehension, astroid.GeneratorExp)) + and assign.statement() is not node.statement()): + return + + # For functions we can do more by inferring the length of the iterred object + if not isinstance(assign, astroid.For): + self.add_message('undefined-loop-variable', args=name, node=node) + return + + try: + inferred = next(assign.iter.infer()) + except astroid.InferenceError: + self.add_message('undefined-loop-variable', args=name, node=node) + else: + sequences = ( + astroid.List, + astroid.Tuple, + astroid.Dict, + astroid.Set, + objects.FrozenSet, + ) + if not isinstance(inferred, sequences): + self.add_message('undefined-loop-variable', args=name, node=node) + return + + elements = getattr(inferred, 'elts', getattr(inferred, 'items', [])) + if not elements: self.add_message('undefined-loop-variable', args=name, node=node) def _should_ignore_redefined_builtin(self, stmt): diff --git a/pylint/test/functional/undefined_loop_variable.py b/pylint/test/functional/undefined_loop_variable.py index 6c28a4088..3840003b5 100644 --- a/pylint/test/functional/undefined_loop_variable.py +++ b/pylint/test/functional/undefined_loop_variable.py @@ -35,3 +35,27 @@ for x in []: pass for x in range(3): VAR5 = (lambda: x)() + + +def do_stuff_with_a_list(): + for var in [1, 2, 3]: + pass + return var + + +def do_stuff_with_a_set(): + for var in {1, 2, 3}: + pass + return var + + +def do_stuff_with_a_dict(): + for var in {1: 2, 3: 4}: + pass + return var + + +def do_stuff_with_a_tuple(): + for var in (1, 2, 3): + pass + return var |
