summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <cpopa@cloudbasesolutions.com>2015-04-07 00:06:17 +0300
committerClaudiu Popa <cpopa@cloudbasesolutions.com>2015-04-07 00:06:17 +0300
commitb93723a8db12e161abc8e2e6c56c50ce9d41e477 (patch)
tree512018a0084dab64fde871b71d59b0da381038f1
parent80581e989a94f693fef27561e3fcaada7295b7b6 (diff)
downloadpylint-b93723a8db12e161abc8e2e6c56c50ce9d41e477.tar.gz
Fix a bad-reversed-sequence false positive.
This patch looks for a __reversed__ method for subclasses of dict (this is especially present in OrderedDict implementations).
-rw-r--r--ChangeLog3
-rw-r--r--pylint/checkers/base.py14
-rw-r--r--pylint/test/functional/bad_reversed_sequence.py13
3 files changed, 25 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 4add9d5..dab9381 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -47,6 +47,9 @@ ChangeLog for Pylint
* Don't warn about no-self-use for builtin properties.
+ * Fix a false positive for bad-reversed-sequence, when a subclass
+ of a `dict` provides a __reversed__ method.
+
2015-03-14 -- 1.4.3
diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py
index 7659fa4..6b9cdac 100644
--- a/pylint/checkers/base.py
+++ b/pylint/checkers/base.py
@@ -58,8 +58,10 @@ DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$')
CLASS_ATTRIBUTE_RGX = re.compile(r'([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$')
# do not require a doc string on system methods
NO_REQUIRED_DOC_RGX = re.compile('__.*__')
-REVERSED_METHODS = (('__getitem__', '__len__'),
- ('__reversed__', ))
+REVERSED_PROTOCOL_METHOD = '__reversed__'
+SEQUENCE_PROTOCOL_METHODS = ('__getitem__', '__len__')
+REVERSED_METHODS = (SEQUENCE_PROTOCOL_METHODS,
+ (REVERSED_PROTOCOL_METHOD, ))
PY33 = sys.version_info >= (3, 3)
PY3K = sys.version_info >= (3, 0)
@@ -856,8 +858,12 @@ functions, methods
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)
+ # Mappings aren't accepted by reversed(), unless
+ # they provide explicitly a __reversed__ method.
+ try:
+ argument.getattr(REVERSED_PROTOCOL_METHOD)
+ except astroid.NotFoundError:
+ self.add_message('bad-reversed-sequence', node=node)
return
for methods in REVERSED_METHODS:
diff --git a/pylint/test/functional/bad_reversed_sequence.py b/pylint/test/functional/bad_reversed_sequence.py
index 6fda2c0..852510f 100644
--- a/pylint/test/functional/bad_reversed_sequence.py
+++ b/pylint/test/functional/bad_reversed_sequence.py
@@ -1,5 +1,5 @@
""" Checks that reversed() receive proper argument """
-
+# pylint: disable=missing-docstring
# pylint: disable=too-few-public-methods,no-self-use,no-absolute-import
from collections import deque
@@ -58,3 +58,14 @@ def test(path):
seq = uninferable([1, 2, 3])
seq = reversed(path.split("/"))
return seq
+
+def test_dict_ancestor_and_reversed():
+ """Don't emit for subclasses of dict, with __reversed__ implemented."""
+ from collections import OrderedDict
+
+ class Child(dict):
+ def __reversed__(self):
+ return reversed(range(10))
+
+ seq = reversed(OrderedDict())
+ return reversed(Child()), seq