diff options
author | Dmitry Pribysh <dmand@yandex.ru> | 2015-11-07 19:09:00 +0300 |
---|---|---|
committer | Dmitry Pribysh <dmand@yandex.ru> | 2015-11-07 19:09:00 +0300 |
commit | 66c1d7ea3b40b1bb95e46b96f503aca9b23cec64 (patch) | |
tree | c300bd8aa98251d7f41b310eebb35ce8aa23bbcd | |
parent | cfc0f8a29c36855914d5cb04572796663e4ad627 (diff) | |
download | pylint-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.py | 11 | ||||
-rw-r--r-- | pylint/test/functional/non_iterator_returned.py | 21 | ||||
-rw-r--r-- | pylint/test/functional/non_iterator_returned.txt | 9 | ||||
-rw-r--r-- | tox.ini | 5 |
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 @@ -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} |