diff options
| author | cpopa <devnull@localhost> | 2013-10-08 20:24:37 +0300 |
|---|---|---|
| committer | cpopa <devnull@localhost> | 2013-10-08 20:24:37 +0300 |
| commit | a37d9460702973e731824768d613544fba9775b2 (patch) | |
| tree | 0a4588f4a5f50220ef42dd83b6fa491753789c59 | |
| parent | 7930f6685c0b4706b0ca9fa1c910049dea7913ee (diff) | |
| download | pylint-a37d9460702973e731824768d613544fba9775b2.tar.gz | |
Check that the argument passed to reversed() is a proper sequence.
| -rw-r--r-- | checkers/base.py | 39 |
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 = { |
