summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcpopa <devnull@localhost>2013-10-10 14:49:19 +0300
committercpopa <devnull@localhost>2013-10-10 14:49:19 +0300
commit7aa994aad907e9e2b0727fac8e1d81fc953f60db (patch)
treeeaad50ad864805b4d93500045fe6a1b8606a1bdc
parentb24484fd0b3fd43c5714f982a161cd91cf4793b8 (diff)
downloadpylint-7aa994aad907e9e2b0727fac8e1d81fc953f60db.tar.gz
Mappings aren't accepted by reversed().
-rw-r--r--checkers/base.py37
-rw-r--r--test/input/func_bad_reversed_sequence.py48
-rw-r--r--test/messages/func_bad_reversed_sequence.txt8
3 files changed, 82 insertions, 11 deletions
diff --git a/checkers/base.py b/checkers/base.py
index 12bc8b3..2ec6fe9 100644
--- a/checkers/base.py
+++ b/checkers/base.py
@@ -700,18 +700,33 @@ functions, methods
except NoSuchArgumentError:
self.add_message('missing-reversed-argument', node=node)
else:
- if not argument:
- return
-
- for methods in REVERSED_METHODS:
- for meth in methods:
- try:
- argument.getattr(meth)
- except astroid.NotFoundError:
+ if argument is None:
+ # nothing was infered
+ return
+
+ if isinstance(argument, astroid.Instance):
+ if (argument._proxied.name == 'dict' and
+ is_builtin_object(argument._proxied)):
+ self.add_message('bad-reversed-sequence', node=node)
+ return
+ elif any(ancestor.name == 'dict' and is_builtin_object(ancestor)
+ for ancestor in argument._proxied.ancestors()):
+ # mappings aren't accepted by reversed()
+ self.add_message('bad-reversed-sequence', node=node)
+ return
+
+ for methods in REVERSED_METHODS:
+ for meth in methods:
+ try:
+ argument.getattr(meth)
+ except astroid.NotFoundError:
+ break
+ else:
break
- else:
- break
- else:
+ else:
+ self.add_message('bad-reversed-sequence', node=node)
+ elif not isinstance(argument, (astroid.List, astroid.Tuple)):
+ # everything else is not a proper sequence for reversed()
self.add_message('bad-reversed-sequence', node=node)
class NameChecker(_BasicChecker):
diff --git a/test/input/func_bad_reversed_sequence.py b/test/input/func_bad_reversed_sequence.py
new file mode 100644
index 0000000..3bab9b9
--- /dev/null
+++ b/test/input/func_bad_reversed_sequence.py
@@ -0,0 +1,48 @@
+""" Checks that reversed() receive proper argument """
+
+# pylint: disable-msg=too-few-public-methods,no-self-use,incomplete-protocol
+__revision__ = 0
+
+class GoodReversed(object):
+ """ Implements __reversed__ """
+ def __reversed__(self):
+ return [1, 2, 3]
+
+class SecondGoodReversed(object):
+ """ Implements __len__ and __getitem__ """
+ def __len__(self):
+ return 3
+
+ def __getitem__(self, index):
+ return index
+
+class BadReversed(object):
+ """ implements only len() """
+ def __len__(self):
+ return 3
+
+class SecondBadReversed(object):
+ """ implements only __getitem__ """
+ def __getitem__(self, index):
+ return index
+
+class ThirdBadReversed(dict):
+ """ dict subclass """
+
+def test():
+ """ test function """
+ seq = reversed()
+ seq = reversed(None)
+ seq = reversed([1, 2, 3])
+ seq = reversed((1, 2, 3))
+ seq = reversed(set())
+ seq = reversed({'a': 1, 'b': 2})
+ seq = reversed(iter([1, 2, 3]))
+ seq = reversed(GoodReversed())
+ seq = reversed(SecondGoodReversed())
+ seq = reversed(BadReversed())
+ seq = reversed(SecondBadReversed())
+ seq = reversed(range(100))
+ seq = reversed(ThirdBadReversed())
+ seq = reversed(lambda: None)
+ return seq
diff --git a/test/messages/func_bad_reversed_sequence.txt b/test/messages/func_bad_reversed_sequence.txt
new file mode 100644
index 0000000..87771ac
--- /dev/null
+++ b/test/messages/func_bad_reversed_sequence.txt
@@ -0,0 +1,8 @@
+E: 34:test: Missing argument to reversed()
+E: 35:test: The first reversed() argument is not a sequence
+E: 38:test: The first reversed() argument is not a sequence
+E: 39:test: The first reversed() argument is not a sequence
+E: 43:test: The first reversed() argument is not a sequence
+E: 44:test: The first reversed() argument is not a sequence
+E: 46:test: The first reversed() argument is not a sequence
+E: 47:test: The first reversed() argument is not a sequence \ No newline at end of file