From a37d9460702973e731824768d613544fba9775b2 Mon Sep 17 00:00:00 2001 From: cpopa Date: Tue, 8 Oct 2013 20:24:37 +0300 Subject: Check that the argument passed to reversed() is a proper sequence. --- checkers/base.py | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) 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 = { -- cgit v1.2.1 From 7aa994aad907e9e2b0727fac8e1d81fc953f60db Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 10 Oct 2013 14:49:19 +0300 Subject: Mappings aren't accepted by reversed(). --- checkers/base.py | 37 ++++++++++++++------- test/input/func_bad_reversed_sequence.py | 48 ++++++++++++++++++++++++++++ test/messages/func_bad_reversed_sequence.txt | 8 +++++ 3 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 test/input/func_bad_reversed_sequence.py create mode 100644 test/messages/func_bad_reversed_sequence.txt 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 -- cgit v1.2.1 From 5f4d34b2bb79abb661aeabf249fcf0259dfdf396 Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 10 Oct 2013 14:50:57 +0300 Subject: Add ChangeLog entry. --- ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index b6b4f8b..15cc4b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,11 @@ ChangeLog for Pylint * Add new warning for unpacking non-sequences in assignments + * Add new warning, 'bad-reversed-sequence', for checking that the + reversed() builtin receive a sequence (implements __getitem__ and __len__, + without being a dict or a dict subclass) or an instance which implements + __reversed__. + 2013-08-06 -- 1.0.0 -- cgit v1.2.1 From 34f02fb9bfe466a80e941faa088b8a5d2d35585a Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 10 Oct 2013 14:52:57 +0300 Subject: Update message. --- checkers/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/checkers/base.py b/checkers/base.py index 2ec6fe9..afe6fd2 100644 --- a/checkers/base.py +++ b/checkers/base.py @@ -613,7 +613,8 @@ functions, methods self.add_message('exec-used', node=node) @check_messages('bad-builtin', 'star-args', - 'exec-used', 'missing-reversed-argument') + 'exec-used', 'missing-reversed-argument', + 'bad-reversed-sequence') def visit_callfunc(self, node): """visit a CallFunc node -> check if this is not a blacklisted builtin call and check for * or ** use -- cgit v1.2.1 From 80f6ff3444aacd78914d7b311d81c7236fa41d5f Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 10 Oct 2013 15:26:30 +0300 Subject: Ignore deques (can't retrieve special methods). --- checkers/base.py | 7 ++++++- test/input/func_bad_reversed_sequence.py | 3 +++ test/messages/func_bad_reversed_sequence.txt | 14 +++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/checkers/base.py b/checkers/base.py index afe6fd2..db5f2cc 100644 --- a/checkers/base.py +++ b/checkers/base.py @@ -724,7 +724,12 @@ functions, methods break else: break - else: + else: + # check if it is a .deque. It doesn't seem that + # we can retrieve special methods + # from C implemented constructs + if argument._proxied.qname().endswith(".deque"): + return 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() diff --git a/test/input/func_bad_reversed_sequence.py b/test/input/func_bad_reversed_sequence.py index 3bab9b9..71e9067 100644 --- a/test/input/func_bad_reversed_sequence.py +++ b/test/input/func_bad_reversed_sequence.py @@ -1,6 +1,8 @@ """ Checks that reversed() receive proper argument """ # pylint: disable-msg=too-few-public-methods,no-self-use,incomplete-protocol +from collections import deque + __revision__ = 0 class GoodReversed(object): @@ -45,4 +47,5 @@ def test(): seq = reversed(range(100)) seq = reversed(ThirdBadReversed()) seq = reversed(lambda: None) + seq = reversed(deque([])) return seq diff --git a/test/messages/func_bad_reversed_sequence.txt b/test/messages/func_bad_reversed_sequence.txt index 87771ac..62792f1 100644 --- a/test/messages/func_bad_reversed_sequence.txt +++ b/test/messages/func_bad_reversed_sequence.txt @@ -1,8 +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: 36:test: Missing argument to reversed() +E: 37:test: The first reversed() argument is not a sequence +E: 40:test: The first reversed() argument is not a sequence +E: 41:test: The first reversed() argument is not a sequence +E: 45: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 +E: 48:test: The first reversed() argument is not a sequence +E: 49:test: The first reversed() argument is not a sequence \ No newline at end of file -- cgit v1.2.1 From 1de5d120e16f407b745fee5cf93ebd76c38c4055 Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 10 Oct 2013 16:07:20 +0300 Subject: Handle iter builtin. --- checkers/base.py | 8 +++++++- test/input/func_bad_reversed_sequence.py | 1 + test/messages/func_bad_reversed_sequence.txt | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/checkers/base.py b/checkers/base.py index db5f2cc..6aae709 100644 --- a/checkers/base.py +++ b/checkers/base.py @@ -703,7 +703,13 @@ functions, methods else: if argument is None: # nothing was infered - return + # try to see if we have iter() + if (isinstance(node.args[0], astroid.CallFunc) and + node.args[0].func.name == 'iter'): + func = node.args[0].func.infer().next() + if is_builtin_object(func): + self.add_message('bad-reversed-sequence', node=node) + return if isinstance(argument, astroid.Instance): if (argument._proxied.name == 'dict' and diff --git a/test/input/func_bad_reversed_sequence.py b/test/input/func_bad_reversed_sequence.py index 71e9067..7abf18e 100644 --- a/test/input/func_bad_reversed_sequence.py +++ b/test/input/func_bad_reversed_sequence.py @@ -48,4 +48,5 @@ def test(): seq = reversed(ThirdBadReversed()) seq = reversed(lambda: None) seq = reversed(deque([])) + seq = reversed("123") return seq diff --git a/test/messages/func_bad_reversed_sequence.txt b/test/messages/func_bad_reversed_sequence.txt index 62792f1..712cff2 100644 --- a/test/messages/func_bad_reversed_sequence.txt +++ b/test/messages/func_bad_reversed_sequence.txt @@ -2,6 +2,7 @@ E: 36:test: Missing argument to reversed() E: 37:test: The first reversed() argument is not a sequence E: 40:test: The first reversed() argument is not a sequence E: 41:test: The first reversed() argument is not a sequence +E: 42:test: The first reversed() argument is not a sequence E: 45:test: The first reversed() argument is not a sequence E: 46:test: The first reversed() argument is not a sequence E: 48:test: The first reversed() argument is not a sequence -- cgit v1.2.1 From 12a7edcc811c921875eb794e5e1e8985fe978c68 Mon Sep 17 00:00:00 2001 From: cpopa Date: Fri, 3 Jan 2014 19:22:35 +0200 Subject: Fix bitbucket #126, don't crash when encountering an AssAttr node in is_defined_before. --- ChangeLog | 5 +++++ checkers/utils.py | 6 ++++-- test/input/func_with_e0601.py | 12 ++++++++++++ test/messages/func_with_e0601.txt | 2 ++ 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 test/input/func_with_e0601.py create mode 100644 test/messages/func_with_e0601.txt diff --git a/ChangeLog b/ChangeLog index f5b7192..f24d7c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ ChangeLog for Pylint ==================== +-- + * bitbucket #128: pylint doesn't crash when looking + for used-before-assignment in context manager + assignments. + 2013-12-22 -- 1.1.0 * Add new check for use of deprecated pragma directives "pylint:disable-msg" or "pylint:enable-msg" (I0022, deprecated-pragma) which was previously diff --git a/checkers/utils.py b/checkers/utils.py index 53b40a6..a193220 100644 --- a/checkers/utils.py +++ b/checkers/utils.py @@ -154,8 +154,10 @@ def is_defined_before(var_node): elif isinstance(_node, astroid.With): for expr, vars in _node.items: if expr.parent_of(var_node): - break - if vars and vars.name == varname: + break + if (vars and + not isinstance(vars, astroid.AssAttr) and + vars.name == varname): return True elif isinstance(_node, (astroid.Lambda, astroid.Function)): if _node.args.is_argument(varname): diff --git a/test/input/func_with_e0601.py b/test/input/func_with_e0601.py new file mode 100644 index 0000000..c79815c --- /dev/null +++ b/test/input/func_with_e0601.py @@ -0,0 +1,12 @@ +''' +Regression test for +https://bitbucket.org/logilab/pylint/issue/128/attributeerror-when-parsing +''' +from __future__ import with_statement +__revision__ = 1 + +def do_nothing(): + """ empty """ + with open("") as ctx.obj: + context.do() + context = None diff --git a/test/messages/func_with_e0601.txt b/test/messages/func_with_e0601.txt new file mode 100644 index 0000000..dc6e386 --- /dev/null +++ b/test/messages/func_with_e0601.txt @@ -0,0 +1,2 @@ +E: 10:do_nothing: Undefined variable 'ctx' +E: 11:do_nothing: Using variable 'context' before assignment \ No newline at end of file -- cgit v1.2.1 -- cgit v1.2.1 -- cgit v1.2.1 From 42bafa2540b5ed5b3f5e78647b7fe781657aa925 Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 8 Jan 2014 22:13:48 +0100 Subject: changelog cleanup --- ChangeLog | 2 -- 1 file changed, 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index f5b7192..3528b1a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -57,8 +57,6 @@ ChangeLog for Pylint * Various documentation fixes and enhancements - * Added a __main__.py file so you can run "python -m pylint" - * Fix issue #55 (false-positive trailing-whitespace on Windows) -- cgit v1.2.1 From f02fb1f0f582ff8a66cd50e1a08bce5a507a3cdc Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 9 Jan 2014 11:12:15 +0200 Subject: Various fixes for #128 --- checkers/utils.py | 2 +- test/input/func_with_e0601.py | 12 ------------ test/input/func_with_used_before_assignment.py | 12 ++++++++++++ test/messages/func_with_e0601.txt | 2 -- test/messages/func_with_used_before_assignment.txt | 2 ++ 5 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 test/input/func_with_e0601.py create mode 100644 test/input/func_with_used_before_assignment.py delete mode 100644 test/messages/func_with_e0601.txt create mode 100644 test/messages/func_with_used_before_assignment.txt diff --git a/checkers/utils.py b/checkers/utils.py index a193220..7387711 100644 --- a/checkers/utils.py +++ b/checkers/utils.py @@ -156,7 +156,7 @@ def is_defined_before(var_node): if expr.parent_of(var_node): break if (vars and - not isinstance(vars, astroid.AssAttr) and + isinstance(vars, astroid.AssName) and vars.name == varname): return True elif isinstance(_node, (astroid.Lambda, astroid.Function)): diff --git a/test/input/func_with_e0601.py b/test/input/func_with_e0601.py deleted file mode 100644 index c79815c..0000000 --- a/test/input/func_with_e0601.py +++ /dev/null @@ -1,12 +0,0 @@ -''' -Regression test for -https://bitbucket.org/logilab/pylint/issue/128/attributeerror-when-parsing -''' -from __future__ import with_statement -__revision__ = 1 - -def do_nothing(): - """ empty """ - with open("") as ctx.obj: - context.do() - context = None diff --git a/test/input/func_with_used_before_assignment.py b/test/input/func_with_used_before_assignment.py new file mode 100644 index 0000000..c79815c --- /dev/null +++ b/test/input/func_with_used_before_assignment.py @@ -0,0 +1,12 @@ +''' +Regression test for +https://bitbucket.org/logilab/pylint/issue/128/attributeerror-when-parsing +''' +from __future__ import with_statement +__revision__ = 1 + +def do_nothing(): + """ empty """ + with open("") as ctx.obj: + context.do() + context = None diff --git a/test/messages/func_with_e0601.txt b/test/messages/func_with_e0601.txt deleted file mode 100644 index dc6e386..0000000 --- a/test/messages/func_with_e0601.txt +++ /dev/null @@ -1,2 +0,0 @@ -E: 10:do_nothing: Undefined variable 'ctx' -E: 11:do_nothing: Using variable 'context' before assignment \ No newline at end of file diff --git a/test/messages/func_with_used_before_assignment.txt b/test/messages/func_with_used_before_assignment.txt new file mode 100644 index 0000000..dc6e386 --- /dev/null +++ b/test/messages/func_with_used_before_assignment.txt @@ -0,0 +1,2 @@ +E: 10:do_nothing: Undefined variable 'ctx' +E: 11:do_nothing: Using variable 'context' before assignment \ No newline at end of file -- cgit v1.2.1 From 95ec900f33bae5dcf71a00cdf4ca4ab7392d604f Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 9 Jan 2014 14:48:43 +0200 Subject: Don't use deprecated pragma --- test/input/func_bad_reversed_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/input/func_bad_reversed_sequence.py b/test/input/func_bad_reversed_sequence.py index 7abf18e..836c6f3 100644 --- a/test/input/func_bad_reversed_sequence.py +++ b/test/input/func_bad_reversed_sequence.py @@ -1,6 +1,6 @@ """ Checks that reversed() receive proper argument """ -# pylint: disable-msg=too-few-public-methods,no-self-use,incomplete-protocol +# pylint: disable=too-few-public-methods,no-self-use,incomplete-protocol from collections import deque __revision__ = 0 -- cgit v1.2.1 From 6ec7db585fa5b6787fd316483b3c5536a0432464 Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 9 Jan 2014 14:53:16 +0200 Subject: Move ChangeLog entry upper. --- ChangeLog | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index a27bc5f..fafcf93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,12 @@ ChangeLog for Pylint for used-before-assignment in context manager assignments. + * Add new warning, 'bad-reversed-sequence', for checking that the + reversed() builtin receive a sequence (implements __getitem__ and __len__, + without being a dict or a dict subclass) or an instance which implements + __reversed__. + + 2013-12-22 -- 1.1.0 * Add new check for use of deprecated pragma directives "pylint:disable-msg" or "pylint:enable-msg" (I0022, deprecated-pragma) which was previously @@ -65,12 +71,6 @@ ChangeLog for Pylint * Fix issue #55 (false-positive trailing-whitespace on Windows) - * Add new warning, 'bad-reversed-sequence', for checking that the - reversed() builtin receive a sequence (implements __getitem__ and __len__, - without being a dict or a dict subclass) or an instance which implements - __reversed__. - - 2013-08-06 -- 1.0.0 * Add check for the use of 'exec' function -- cgit v1.2.1 From 37bc17e49dc640e8c2c7839aa3069c4256bd02de Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 9 Jan 2014 15:12:33 +0200 Subject: Fix builtin module name for Python 3. --- checkers/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checkers/utils.py b/checkers/utils.py index 7387711..728893e 100644 --- a/checkers/utils.py +++ b/checkers/utils.py @@ -124,7 +124,7 @@ SPECIAL_BUILTINS = ('__builtins__',) # '__path__', '__file__') def is_builtin_object(node): """Returns True if the given node is an object from the __builtin__ module.""" - return node and node.root().name == '__builtin__' + return node and node.root().name == BUILTINS_NAME def is_builtin(name): # was is_native_builtin """return true if could be considered as a builtin defined by python -- cgit v1.2.1 From 083eea1072f926ab1c34a8f7b08d8f587dab839e Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 9 Jan 2014 15:21:40 +0200 Subject: Remove incomplete-protocol warning. --- test/input/func_bad_reversed_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/input/func_bad_reversed_sequence.py b/test/input/func_bad_reversed_sequence.py index 836c6f3..31c59c0 100644 --- a/test/input/func_bad_reversed_sequence.py +++ b/test/input/func_bad_reversed_sequence.py @@ -1,6 +1,6 @@ """ Checks that reversed() receive proper argument """ -# pylint: disable=too-few-public-methods,no-self-use,incomplete-protocol +# pylint: disable=too-few-public-methods,no-self-use from collections import deque __revision__ = 0 -- cgit v1.2.1 From 558da6531006902e446b30d4f2b7dbddad768ef3 Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 9 Jan 2014 15:38:28 +0200 Subject: Ignore non-inferable nodes, add test case for non-inferable nodes. --- checkers/base.py | 2 ++ test/input/func_bad_reversed_sequence.py | 7 +++++++ test/messages/func_bad_reversed_sequence.txt | 14 +++++++------- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/checkers/base.py b/checkers/base.py index 5df0477..cf4304c 100644 --- a/checkers/base.py +++ b/checkers/base.py @@ -711,6 +711,8 @@ functions, methods except NoSuchArgumentError: self.add_message('missing-reversed-argument', node=node) else: + if argument is astroid.YES: + return if argument is None: # nothing was infered # try to see if we have iter() diff --git a/test/input/func_bad_reversed_sequence.py b/test/input/func_bad_reversed_sequence.py index 31c59c0..a394e53 100644 --- a/test/input/func_bad_reversed_sequence.py +++ b/test/input/func_bad_reversed_sequence.py @@ -31,6 +31,12 @@ class SecondBadReversed(object): class ThirdBadReversed(dict): """ dict subclass """ +def uninferable(seq): + """ This can't be infered at this moment, + make sure we don't have a false positive. + """ + return reversed(seq) + def test(): """ test function """ seq = reversed() @@ -49,4 +55,5 @@ def test(): seq = reversed(lambda: None) seq = reversed(deque([])) seq = reversed("123") + seq = uninferable([1, 2, 3]) return seq diff --git a/test/messages/func_bad_reversed_sequence.txt b/test/messages/func_bad_reversed_sequence.txt index 712cff2..6e85197 100644 --- a/test/messages/func_bad_reversed_sequence.txt +++ b/test/messages/func_bad_reversed_sequence.txt @@ -1,9 +1,9 @@ -E: 36:test: Missing argument to reversed() -E: 37:test: The first reversed() argument is not a sequence -E: 40:test: The first reversed() argument is not a sequence -E: 41:test: The first reversed() argument is not a sequence -E: 42:test: The first reversed() argument is not a sequence -E: 45:test: The first reversed() argument is not a sequence +E: 42:test: Missing argument to reversed() +E: 43: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 E: 48:test: The first reversed() argument is not a sequence -E: 49:test: The first reversed() argument is not a sequence \ No newline at end of file +E: 51:test: The first reversed() argument is not a sequence +E: 52:test: The first reversed() argument is not a sequence +E: 54:test: The first reversed() argument is not a sequence +E: 55:test: The first reversed() argument is not a sequence \ No newline at end of file -- cgit v1.2.1