summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Pribysh <dmand@yandex.ru>2015-11-07 19:09:00 +0300
committerDmitry Pribysh <dmand@yandex.ru>2015-11-07 19:09:00 +0300
commit66c1d7ea3b40b1bb95e46b96f503aca9b23cec64 (patch)
treec300bd8aa98251d7f41b310eebb35ce8aa23bbcd
parentcfc0f8a29c36855914d5cb04572796663e4ad627 (diff)
downloadpylint-git-66c1d7ea3b40b1bb95e46b96f503aca9b23cec64.tar.gz
Reduce number of false positives emitted by non-iterator-returned checker
By disabling checker for cases when there're multiple possible values infered for node. This way we lose some of the inference power, but throw a lot less false positives. Fixes issue #695.
-rw-r--r--pylint/checkers/classes.py11
-rw-r--r--pylint/test/functional/non_iterator_returned.py21
-rw-r--r--pylint/test/functional/non_iterator_returned.txt9
-rw-r--r--tox.ini5
4 files changed, 27 insertions, 19 deletions
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 3d9144d34..24b862fd7 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -1067,12 +1067,15 @@ class SpecialMethodsChecker(BaseChecker):
def _check_iter(self, node):
try:
- infered = node.infer_call_result(node)
+ infered_values = list(node.infer_call_result(node))
except astroid.InferenceError:
return
-
- if not all(map(self._is_iterator, infered)):
- self.add_message('non-iterator-returned', node=node)
+ # cases when there're multiple values infered
+ # are skipped to reduce the number of false positives
+ if len(infered_values) == 1:
+ infered = infered_values[0]
+ if not self._is_iterator(infered):
+ self.add_message('non-iterator-returned', node=node)
def _ancestors_to_call(klass_node, method='__init__'):
diff --git a/pylint/test/functional/non_iterator_returned.py b/pylint/test/functional/non_iterator_returned.py
index 804ceee7c..d2fa75804 100644
--- a/pylint/test/functional/non_iterator_returned.py
+++ b/pylint/test/functional/non_iterator_returned.py
@@ -56,6 +56,19 @@ class FifthGoodIterator(object):
def __iter__(self):
return IteratorClass
+class FileBasedIterator(object):
+ def __init__(self, path):
+ self.path = path
+ self.file = None
+
+ def __iter__(self):
+ if self.file is not None:
+ self.file.close()
+ self.file = open(self.path)
+ # self file has two infered values: None and <instance of 'file'>
+ # we don't want to emit error in this case
+ return self.file
+
class FirstBadIterator(object):
""" __iter__ returns a list """
@@ -80,11 +93,3 @@ class FourthBadIterator(object):
def __iter__(self): # [non-iterator-returned]
return ThirdBadIterator
-
-class FifthBadIterator(object):
- """All branches should return an iterator."""
-
- def __iter__(self): # [non-iterator-returned]
- if self:
- return 1
- return SecondGoodIterator()
diff --git a/pylint/test/functional/non_iterator_returned.txt b/pylint/test/functional/non_iterator_returned.txt
index fe3db101d..fa1d5bec5 100644
--- a/pylint/test/functional/non_iterator_returned.txt
+++ b/pylint/test/functional/non_iterator_returned.txt
@@ -1,5 +1,4 @@
-non-iterator-returned:63:FirstBadIterator.__iter__:__iter__ returns non-iterator
-non-iterator-returned:69:SecondBadIterator.__iter__:__iter__ returns non-iterator
-non-iterator-returned:75:ThirdBadIterator.__iter__:__iter__ returns non-iterator
-non-iterator-returned:81:FourthBadIterator.__iter__:__iter__ returns non-iterator
-non-iterator-returned:87:FifthBadIterator.__iter__:__iter__ returns non-iterator \ No newline at end of file
+non-iterator-returned:76:FirstBadIterator.__iter__:__iter__ returns non-iterator
+non-iterator-returned:82:SecondBadIterator.__iter__:__iter__ returns non-iterator
+non-iterator-returned:88:ThirdBadIterator.__iter__:__iter__ returns non-iterator
+non-iterator-returned:94:FourthBadIterator.__iter__:__iter__ returns non-iterator
diff --git a/tox.ini b/tox.ini
index d9fcff1d4..7c911da8b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,7 @@
[tox]
# official list is
#envlist = py27, py32, py33, py34
-envlist = py27, py33, pylint
+envlist = py27, py34, pylint
[testenv:pylint]
deps =
@@ -14,5 +14,6 @@ commands = pylint -rn --rcfile={toxinidir}/pylintrc {envsitepackagesdir}/pylint
deps =
hg+https://bitbucket.org/logilab/astroid@master
six
+ pudb
commands = python -Wi -m unittest discover -s {envsitepackagesdir}/pylint/test/ -p {posargs:*test_*}.py
-changedir = {toxworkdir} \ No newline at end of file
+changedir = {toxworkdir}