diff options
author | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-04-07 00:06:17 +0300 |
---|---|---|
committer | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-04-07 00:06:17 +0300 |
commit | b93723a8db12e161abc8e2e6c56c50ce9d41e477 (patch) | |
tree | 512018a0084dab64fde871b71d59b0da381038f1 | |
parent | 80581e989a94f693fef27561e3fcaada7295b7b6 (diff) | |
download | pylint-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-- | ChangeLog | 3 | ||||
-rw-r--r-- | pylint/checkers/base.py | 14 | ||||
-rw-r--r-- | pylint/test/functional/bad_reversed_sequence.py | 13 |
3 files changed, 25 insertions, 5 deletions
@@ -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 |