From 28323597be5777e09364ef999e162417437d05fc Mon Sep 17 00:00:00 2001 From: Claudiu Popa Date: Sun, 19 Apr 2015 12:41:30 +0300 Subject: Look for __init__ instead of __new__ in _determine_callable_obj if __new__ comes from builtins. Since the __new__ comes from builtins, it will not have attached any information regarding what parameters it expects, so the check will be useless. Retrieving __init__ in that case will at least detect a couple of false negatives. Closes issue #429. --- ChangeLog | 8 ++++++++ pylint/checkers/typecheck.py | 10 +++++++--- pylint/test/functional/ctor_arguments.py | 7 +++++++ pylint/test/functional/ctor_arguments.txt | 2 ++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4c0d67a..025e922 100644 --- a/ChangeLog +++ b/ChangeLog @@ -57,6 +57,14 @@ ChangeLog for Pylint * Provide some hints for the bad-builtin message. Closes issue #522. + * When checking for invalid arguments to a callable, in typecheck.py, + look up for the __init__ in case the found __new__ comes from builtins. + + Since the __new__ comes from builtins, it will not have attached any + information regarding what parameters it expects, so the check + will be useless. Retrieving __init__ in that case will at least + detect a couple of false negatives. Closes issue #429. + 2015-03-14 -- 1.4.3 diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 58ce4be..ef3b799 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -103,14 +103,18 @@ def _determine_callable(callable_obj): elif isinstance(callable_obj, astroid.Class): # Class instantiation, lookup __new__ instead. # If we only find object.__new__, we can safely check __init__ - # instead. + # instead. If __new__ belongs to builtins, then we look + # again for __init__ in the locals, since we won't have + # argument information for the builtin __new__ function. try: # Use the last definition of __new__. new = callable_obj.local_attr('__new__')[-1] except astroid.NotFoundError: new = None - if not new or new.parent.scope().name == 'object': + from_object = new and new.parent.scope().name == 'object' + from_builtins = new and new.root().name == BUILTINS + if not new or from_object or from_builtins: try: # Use the last definition of __init__. callable_obj = callable_obj.local_attr('__init__')[-1] @@ -122,7 +126,7 @@ def _determine_callable(callable_obj): if not isinstance(callable_obj, astroid.Function): raise ValueError - # both have an extra implicit 'cls'/'self' argument. + # both have an extra implicit 'cls'/'self' argument. return callable_obj, 1, 'constructor' else: raise ValueError diff --git a/pylint/test/functional/ctor_arguments.py b/pylint/test/functional/ctor_arguments.py index 7dc0a09..f052831 100644 --- a/pylint/test/functional/ctor_arguments.py +++ b/pylint/test/functional/ctor_arguments.py @@ -76,3 +76,10 @@ class ClassWithMeta(with_metaclass(Metaclass)): pass ClassWithMeta() + + +class BuiltinExc(Exception): + def __init__(self, val=True): + self.val = val + +BuiltinExc(42, 24, badarg=1) # [too-many-function-args,unexpected-keyword-arg] diff --git a/pylint/test/functional/ctor_arguments.txt b/pylint/test/functional/ctor_arguments.txt index 85cf139..817e805 100644 --- a/pylint/test/functional/ctor_arguments.txt +++ b/pylint/test/functional/ctor_arguments.txt @@ -15,3 +15,5 @@ too-many-function-args:60::Too many positional arguments for constructor call too-many-function-args:63::Too many positional arguments for constructor call no-value-for-parameter:64::No value for argument 'first_argument' in constructor call unexpected-keyword-arg:64::Unexpected keyword argument 'one' in constructor call +too-many-function-args:85::Too many positional arguments for constructor call +unexpected-keyword-arg:85::Unexpected keyword argument 'badarg' in constructor call -- cgit v1.2.1