diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | pylint/checkers/typecheck.py | 23 | ||||
-rw-r--r-- | pylint/test/functional/arguments.py | 14 | ||||
-rw-r--r-- | pylint/test/functional/repeated_keyword.py | 13 | ||||
-rw-r--r-- | pylint/test/functional/repeated_keyword.txt | 1 | ||||
-rw-r--r-- | pylint/test/functional/unpacking_generalizations.py | 29 | ||||
-rw-r--r-- | pylint/test/functional/unpacking_generalizations.rc | 2 | ||||
-rw-r--r-- | pylint/test/functional/unpacking_generalizations.txt | 6 |
8 files changed, 88 insertions, 6 deletions
@@ -327,6 +327,12 @@ ChangeLog for Pylint * Don't emit 'assigning-non-slot' for descriptors. Closes issue #652. + * Add a new error, 'repeated-keyword', when a keyword argument is passed + multiple times into a function call. + + This is similar with redundant-keyword-arg, but it's mildly different + that it needs to be a separate error. + 2015-03-14 -- 1.4.3 diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index b6ba698..865508e 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -24,6 +24,7 @@ import sys import astroid import astroid.context +import astroid.arguments from astroid import bases from astroid import exceptions from astroid import objects @@ -143,6 +144,9 @@ MSGS = { 'unsupported-binary-operation', 'Emitted when a binary arithmetic operation between two ' 'operands is not supported.'), + 'E1132': ('Got multiple values for keyword argument %r in function call', + 'repeated-keyword', + 'Emitted when a function call got multiple values for a keyword.'), } # builtin sequence types in Python 2 and 3. @@ -458,9 +462,9 @@ accessed. Python regular expressions are accepted.'} """ # Build the set of keyword arguments, checking for duplicate keywords, # and count the positional arguments. - keyword_args = {keyword.arg for keyword in node.keywords or [] - if keyword.arg is not None} - num_positional_args = len(node.args) + call_site = astroid.arguments.CallSite.from_call(node) + num_positional_args = len(call_site.positional_arguments) + keyword_args = list(call_site.keyword_arguments.keys()) called = helpers.safe_infer(node.func) # only function, generator and object defining __call__ are allowed @@ -482,8 +486,17 @@ accessed. Python regular expressions are accepted.'} return if len(called.argnames()) != len(set(called.argnames())): - # Duplicate parameter name (see E9801). We can't really make sense - # of the function call in this case, so just return. + # Duplicate parameter name (see duplicate-argument). We can't really + # make sense of the function call in this case, so just return. + return + + # Warn about duplicated keyword arguments, such as `f=24, **{'f': 24}` + for keyword in call_site.duplicated_keywords: + self.add_message('repeated-keyword', + node=node, args=(keyword, )) + + if call_site.has_invalid_arguments() or call_site.has_invalid_keywords(): + # Can't make sense of this. return # Analyze the list of formal parameters. diff --git a/pylint/test/functional/arguments.py b/pylint/test/functional/arguments.py index f8db22c..9f0dc63 100644 --- a/pylint/test/functional/arguments.py +++ b/pylint/test/functional/arguments.py @@ -1,4 +1,4 @@ -# pylint: disable=too-few-public-methods, no-absolute-import,missing-docstring +# pylint: disable=too-few-public-methods, no-absolute-import,missing-docstring,import-error """Test function argument checker""" def decorator(fun): @@ -142,3 +142,15 @@ class Issue642(object): attr = 0 def __str__(self): return "{self.attr}".format(self=self) + +# These should not emit anything regarding the number of arguments, +# since they have something invalid. +from ala_bala_portocola import unknown + +function_1_arg(*unknown) +function_1_arg(1, *2) +function_1_arg(1, 2, 3, **unknown) +function_1_arg(4, 5, **1) +function_1_arg(5, 6, **{unknown: 1}) +function_1_arg(**{object: 1}) +function_1_arg(**{1: 2}) diff --git a/pylint/test/functional/repeated_keyword.py b/pylint/test/functional/repeated_keyword.py new file mode 100644 index 0000000..786c53b --- /dev/null +++ b/pylint/test/functional/repeated_keyword.py @@ -0,0 +1,13 @@ +"""Check that a keyword is not repeated in a function call
+
+This is somehow related to redundant-keyword, but it's not the same.
+"""
+
+# pylint: disable=missing-docstring, invalid-name
+
+def test(a, b):
+ return a, b
+
+test(1, 24)
+test(1, b=24, **{})
+test(1, b=24, **{'b': 24}) # [repeated-keyword]
diff --git a/pylint/test/functional/repeated_keyword.txt b/pylint/test/functional/repeated_keyword.txt new file mode 100644 index 0000000..1344b15 --- /dev/null +++ b/pylint/test/functional/repeated_keyword.txt @@ -0,0 +1 @@ +repeated-keyword:13::"Got multiple values for keyword argument 'b' in function call"
\ No newline at end of file diff --git a/pylint/test/functional/unpacking_generalizations.py b/pylint/test/functional/unpacking_generalizations.py new file mode 100644 index 0000000..1c5fb16 --- /dev/null +++ b/pylint/test/functional/unpacking_generalizations.py @@ -0,0 +1,29 @@ +"""Various tests for unpacking generalizations added in Python 3.5"""
+
+# pylint: disable=missing-docstring, invalid-name
+
+def func_variadic_args(*args):
+ return args
+
+
+def func_variadic_positional_args(a, b, *args):
+ return a, b, args
+
+def func_positional_args(a, b, c, d):
+ return a, b, c, d
+
+
+func_variadic_args(*(2, 3), *(3, 4), *(4, 5))
+func_variadic_args(1, 2, *(2, 3), 2, 3, *(4, 5))
+func_variadic_positional_args(1, 2, *(4, 5), *(5, 6))
+func_variadic_positional_args(*(2, 3), *(4, 5), *(5, 6))
+func_variadic_positional_args(*(2, 3))
+func_variadic_positional_args(*(2, 3, 4))
+func_variadic_positional_args(1, 2, 3, *(3, 4))
+
+func_positional_args(*(2, 3, 4), *(2, 3)) # [too-many-function-args]
+func_positional_args(*(1, 2), 3) # [no-value-for-parameter]
+func_positional_args(1, *(2, ), 3, *(4, 5)) # [too-many-function-args]
+func_positional_args(1, 2, c=24, d=32, **{'d': 32}) # [repeated-keyword]
+# +1: [repeated-keyword,repeated-keyword]
+func_positional_args(1, 2, c=24, **{'c': 34, 'd': 33}, **{'d': 24})
diff --git a/pylint/test/functional/unpacking_generalizations.rc b/pylint/test/functional/unpacking_generalizations.rc new file mode 100644 index 0000000..03004f2 --- /dev/null +++ b/pylint/test/functional/unpacking_generalizations.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.5
\ No newline at end of file diff --git a/pylint/test/functional/unpacking_generalizations.txt b/pylint/test/functional/unpacking_generalizations.txt new file mode 100644 index 0000000..d92fcc9 --- /dev/null +++ b/pylint/test/functional/unpacking_generalizations.txt @@ -0,0 +1,6 @@ +too-many-function-args:24::Too many positional arguments for function call +no-value-for-parameter:25::"No value for argument 'd' in function call" +too-many-function-args:26::Too many positional arguments for function call +repeated-keyword:27::Got multiple values for keyword argument 'd' in function call +repeated-keyword:29::Got multiple values for keyword argument 'c' in function call +repeated-keyword:29::Got multiple values for keyword argument 'd' in function call
\ No newline at end of file |