From 44a9986bdb27f3fbe3e4be520f8b3678ce30c4a2 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Mon, 16 Oct 2017 19:24:08 +0300 Subject: [PATCH] Mark duplicated `*args` and `**kwargs` as not allowed (PY-26491) --- .../src/com/jetbrains/python/PyBundle.properties | 4 +++- .../changeSignature/PyChangeSignatureDialog.java | 4 ++-- .../validation/ParameterListAnnotator.java | 16 ++++++++++------ .../highlighting/keywordOnlyArguments.py | 4 ++-- .../highlighting/multipleKeywordContainers.py | 5 +++++ .../highlighting/multiplePositionalContainers.py | 5 +++++ python/testData/highlighting/starArgs.py | 6 +++--- .../jetbrains/python/PythonHighlightingTest.java | 11 ++++++++++- 8 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 python/testData/highlighting/multipleKeywordContainers.py create mode 100644 python/testData/highlighting/multiplePositionalContainers.py diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index b0580a8872c6..e39bd9be35c7 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -755,8 +755,10 @@ ANN.starred.param.after.kwparam=* parameter after ** parameter ANN.regular.param.after.vararg=regular parameter after * parameter ANN.regular.param.after.keyword=regular parameter after ** parameter ANN.non.default.param.after.default=non-default parameter follows default parameter -ANN.named.arguments.after.star=named arguments must follow bare * +ANN.named.parameters.after.star=named parameters must follow bare * ANN.tuple.py3=tuple parameter unpacking is not supported in Python 3 +ANN.multiple.args=multiple * parameters are not allowed +ANN.multiple.kwargs=multiple ** parameters are not allowed ANN.star.import.at.top.only='import *' only allowed at module level diff --git a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureDialog.java b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureDialog.java index 1c59de290e8b..b31390afc07d 100644 --- a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureDialog.java +++ b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureDialog.java @@ -149,7 +149,7 @@ public class PyChangeSignatureDialog extends if (name.equals("*")) { hadSingleStar = true; if (index == parametersLength - 1) { - return PyBundle.message("ANN.named.arguments.after.star"); + return PyBundle.message("ANN.named.parameters.after.star"); } } else if (name.startsWith("*") && !name.startsWith("**")) { @@ -166,7 +166,7 @@ public class PyChangeSignatureDialog extends } else if (name.startsWith("**")) { if (hadSingleStar && !hadParamsAfterSingleStar) { - return PyBundle.message("ANN.named.arguments.after.star"); + return PyBundle.message("ANN.named.parameters.after.star"); } if (hadKeywordContainer) { return PyBundle.message("refactoring.change.signature.dialog.validation.multiple.double.star"); diff --git a/python/src/com/jetbrains/python/validation/ParameterListAnnotator.java b/python/src/com/jetbrains/python/validation/ParameterListAnnotator.java index d0b59622cf73..576d867f16e9 100644 --- a/python/src/com/jetbrains/python/validation/ParameterListAnnotator.java +++ b/python/src/com/jetbrains/python/validation/ParameterListAnnotator.java @@ -28,11 +28,11 @@ import java.util.Set; public class ParameterListAnnotator extends PyAnnotator { @Override public void visitPyParameterList(final PyParameterList paramlist) { - final LanguageLevel languageLevel = ((PyFile)paramlist.getContainingFile()).getLanguageLevel(); + final LanguageLevel languageLevel = LanguageLevel.forElement(paramlist); ParamHelper.walkDownParamArray( paramlist.getParameters(), new ParamHelper.ParamVisitor() { - Set parameterNames = new HashSet<>(); + final Set parameterNames = new HashSet<>(); boolean hadPositionalContainer = false; boolean hadKeywordContainer = false; boolean hadDefaultValue = false; @@ -50,14 +50,18 @@ public class ParameterListAnnotator extends PyAnnotator { markError(parameter, PyBundle.message("ANN.starred.param.after.kwparam")); } if (hadSingleStar) { - markError(parameter, "Multiple * arguments are not allowed"); + markError(parameter, PyBundle.message("ANN.multiple.args")); } + + if (hadPositionalContainer) markError(parameter, PyBundle.message("ANN.multiple.args")); hadPositionalContainer = true; } else if (parameter.isKeywordContainer()) { + if (hadKeywordContainer) markError(parameter, PyBundle.message("ANN.multiple.kwargs")); hadKeywordContainer = true; + if (hadSingleStar && !hadParamsAfterSingleStar) { - markError(parameter, PyBundle.message("ANN.named.arguments.after.star")); + markError(parameter, PyBundle.message("ANN.named.parameters.after.star")); } } else { @@ -100,11 +104,11 @@ public class ParameterListAnnotator extends PyAnnotator { @Override public void visitSingleStarParameter(PySingleStarParameter param, boolean first, boolean last) { if (hadPositionalContainer || hadSingleStar) { - markError(param, "Multiple * arguments are not allowed"); + markError(param, PyBundle.message("ANN.multiple.args")); } hadSingleStar = true; if (last) { - markError(param, PyBundle.message("ANN.named.arguments.after.star")); + markError(param, PyBundle.message("ANN.named.parameters.after.star")); } } } diff --git a/python/testData/highlighting/keywordOnlyArguments.py b/python/testData/highlighting/keywordOnlyArguments.py index 0e5f10baf995..874de5f14e9e 100644 --- a/python/testData/highlighting/keywordOnlyArguments.py +++ b/python/testData/highlighting/keywordOnlyArguments.py @@ -1,10 +1,10 @@ def keywordonly_sum(*, k1=0, k2): return k1 + k2 -def keywordonly_sum_bad1(p, *): +def keywordonly_sum_bad1(p, *): pass -def keywordonly_sum_bad2(p1, *, **k1): +def keywordonly_sum_bad2(p1, *, **k1): pass def keywordonly_and_kwarg_sum(*, k1, k2, **kwarg): diff --git a/python/testData/highlighting/multipleKeywordContainers.py b/python/testData/highlighting/multipleKeywordContainers.py new file mode 100644 index 000000000000..f708c78dacdd --- /dev/null +++ b/python/testData/highlighting/multipleKeywordContainers.py @@ -0,0 +1,5 @@ +def handle(foo, **args, **moreargs): + print(foo, args, moreargs) + +def handle(foo, **args: int, **moreargs: int): + print(foo, args, moreargs) \ No newline at end of file diff --git a/python/testData/highlighting/multiplePositionalContainers.py b/python/testData/highlighting/multiplePositionalContainers.py new file mode 100644 index 000000000000..ad38840b2bf9 --- /dev/null +++ b/python/testData/highlighting/multiplePositionalContainers.py @@ -0,0 +1,5 @@ +def handle(foo, *args, *moreargs): + print(foo, args, moreargs) + +def handle(foo, *args: int, *moreargs: int): + print(foo, args, moreargs) \ No newline at end of file diff --git a/python/testData/highlighting/starArgs.py b/python/testData/highlighting/starArgs.py index a0bbacb393c6..d3bf031cb54c 100644 --- a/python/testData/highlighting/starArgs.py +++ b/python/testData/highlighting/starArgs.py @@ -1,8 +1,8 @@ -def f1(*args, *, a): +def f1(*args, *, a): pass -def f2(*, *, d): +def f2(*, *, d): pass -def f3(*, *args): +def f3(*, *args): pass diff --git a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java index a525fae6835a..72de2e84c24f 100644 --- a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java +++ b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java @@ -20,7 +20,6 @@ import java.awt.*; * @author yole */ public class PythonHighlightingTest extends PyTestCase { - private static final String TEST_PATH = "/highlighting/"; public void testBuiltins() { EditorColorsScheme scheme = createTemporaryColorScheme(); @@ -362,6 +361,16 @@ public class PythonHighlightingTest extends PyTestCase { runWithLanguageLevel(LanguageLevel.PYTHON30, this::doTest); } + // PY-26491 + public void testMultiplePositionalContainers() { + doTest(LanguageLevel.PYTHON35, true, false); + } + + // PY-26491 + public void testMultipleKeywordContainers() { + doTest(LanguageLevel.PYTHON35, true, false); + } + // PY-26510 public void testEmptyRaise() { doTest(false, false);