summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcpopa <devnull@localhost>2013-10-08 20:24:37 +0300
committercpopa <devnull@localhost>2013-10-08 20:24:37 +0300
commita37d9460702973e731824768d613544fba9775b2 (patch)
tree0a4588f4a5f50220ef42dd83b6fa491753789c59
parent7930f6685c0b4706b0ca9fa1c910049dea7913ee (diff)
downloadpylint-a37d9460702973e731824768d613544fba9775b2.tar.gz
Check that the argument passed to reversed() is a proper sequence.
-rw-r--r--checkers/base.py39
1 files changed, 38 insertions, 1 deletions
diff --git a/checkers/base.py b/checkers/base.py
index de40c4c..12bc8b3 100644
--- a/checkers/base.py
+++ b/checkers/base.py
@@ -33,6 +33,8 @@ from pylint.checkers.utils import (
is_inside_except,
overrides_a_method,
safe_infer,
+ get_argument_from_call,
+ NoSuchArgumentError,
)
@@ -47,6 +49,8 @@ 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__', ))
del re
@@ -409,6 +413,16 @@ functions, methods
'C0121': ('Missing required attribute "%s"', # W0103
'missing-module-attribute',
'Used when an attribute required for modules is missing.'),
+
+ 'E0109': ('Missing argument to reversed()',
+ 'missing-reversed-argument',
+ 'Used when reversed() builtin didn\'t receive an argument.'),
+ 'E0111': ('The first reversed() argument is not a sequence',
+ 'bad-reversed-sequence',
+ 'Used when the first argument to reversed() builtin '
+ 'isn\'t a sequence (does not implement __reversed__, '
+ 'nor __getitem__ and __len__'),
+
}
options = (('required-attributes',
@@ -598,7 +612,8 @@ functions, methods
"""just print a warning on exec statements"""
self.add_message('exec-used', node=node)
- @check_messages('bad-builtin', 'star-args', 'exec-used')
+ @check_messages('bad-builtin', 'star-args',
+ 'exec-used', 'missing-reversed-argument')
def visit_callfunc(self, node):
"""visit a CallFunc node -> check if this is not a blacklisted builtin
call and check for * or ** use
@@ -611,6 +626,8 @@ functions, methods
name in node.root()):
if name == 'exec':
self.add_message('exec-used', node=node)
+ elif name == 'reversed':
+ self._check_reversed(node)
if name in self.config.bad_functions:
self.add_message('bad-builtin', node=node, args=name)
if node.starargs or node.kwargs:
@@ -675,7 +692,27 @@ functions, methods
return
_node = _parent
_parent = _node.parent
+
+ def _check_reversed(self, node):
+ """ check that the argument to `reversed` is a sequence """
+ try:
+ argument = safe_infer(get_argument_from_call(node, position=0))
+ 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:
+ break
+ else:
+ break
+ else:
+ self.add_message('bad-reversed-sequence', node=node)
class NameChecker(_BasicChecker):
msgs = {