From 0adac7f9eac08415728bb814e6dd952d32e04fd3 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 18 Aug 2020 22:20:16 +0300 Subject: [PATCH] i18n: Add initial support in PyCompatibilityInspection All its warnings are extracted into the bundle, but they are still poorly adapted for translation. Each of them in constructed from two separate messages, a common prefix and an individual feature description, with negation of the main verb being split. Only the first message can vary depending on the affected versions number, but both parts of the verb need to agree in many languages other than English. It's not clear how to address it without overhauling inspection internals, thus it will be revised later. I also slightly updated the warnings format. Namely, put "version" in plural, if a warning applies to multiple Python versions, and removed trailing periods from single-sentence messages. GitOrigin-RevId: 51e577201b11fb4e8b6967e1f5ad27143ba9f82e --- .../resources/messages/PyPsiBundle.properties | 55 ++++++- .../PyCompatibilityInspection.java | 15 +- .../validation/CompatibilityVisitor.java | 143 ++++++++++-------- .../highlighting/implicitOctLongInteger.py | 2 +- .../unsupportedFeaturesInPython3.py | 12 +- ...ReplacePrintInsertsFutureImportOnlyOnce.py | 4 +- .../argumentsUnpackingGeneralizations.py | 14 +- .../assignmentExpressions.py | 8 +- .../PyCompatibilityInspection/asyncAwait.py | 12 +- .../asyncComprehensions.py | 4 +- .../awaitInComprehensions.py | 26 ++-- .../binaryExpression.py | 4 +- .../PyCompatibilityInspection/builtinLong.py | 2 +- .../callExpression.py | 8 +- .../doubleStarUnpacking.py | 2 +- .../ellipsisAsStatementPy2.py | 2 +- .../equalitySignInFStrings.py | 4 +- .../PyCompatibilityInspection/exceptBlock.py | 2 +- .../expressionInDecorators.py | 4 +- .../fromImportStatement.py | 2 +- .../importElement.py | 4 +- .../importStatement.py | 2 +- .../listCompExpression.py | 2 +- .../PyCompatibilityInspection/matMul.py | 4 +- .../numericLiteralExpression.py | 6 +- .../printStatement.py | 2 +- .../PyCompatibilityInspection/raiseFrom.py | 2 +- .../raiseMultipleArgs.py | 2 +- .../reprExpression.py | 2 +- .../starExpression.py | 4 +- .../stringLiteralExpression.py | 34 ++--- .../trailingCommaAfterStarArgs.py | 4 +- .../tryFinallyEmptyRaisePy3.py | 2 +- .../underscoreBz2Module.py | 2 +- .../underscoresInNumericLiterals.py | 74 ++++----- ...nNonParenthesizedTuplesInReturnAndYield.py | 6 +- .../variableAnnotations.py | 10 +- .../warningAboutAsyncAndAwaitInPy36.py | 12 +- .../yieldInsideAsyncDef.py | 6 +- .../inspections/ReplaceNotEqOperator.py | 2 +- python/testData/inspections/ReplacePrint.py | 2 +- .../fixl.py | 2 +- .../renameAsyncClassInPy36.py | 2 +- .../renameAsyncFunctionInPy36.py | 2 +- .../renameAsyncVariableInPy36.py | 2 +- .../renameAwaitClassInPy36.py | 2 +- .../renameAwaitFunctionInPy36.py | 2 +- .../renameAwaitVariableInPy36.py | 2 +- .../PyCompatibilityInspectionTest.java | 4 +- 49 files changed, 295 insertions(+), 232 deletions(-) diff --git a/python/python-psi-impl/resources/messages/PyPsiBundle.properties b/python/python-psi-impl/resources/messages/PyPsiBundle.properties index c760ad7fa77f..c750a04b64b8 100644 --- a/python/python-psi-impl/resources/messages/PyPsiBundle.properties +++ b/python/python-psi-impl/resources/messages/PyPsiBundle.properties @@ -434,8 +434,6 @@ python.docstring.select.type=Select Docstring Type ### Inspections: INSP ### INSP.GROUP.python=Python -INSP.compatibility.this.syntax.available.only.since.py3=This syntax available only since py3 -INSP.compatibility.check.for.compatibility.with.python.versions=Check for compatibility with python versions: INSP.abstract.class.set.as.metaclass=Set ''{0}'' as metaclass INSP.abstract.class.add.to.superclasses=Add ''{0}'' to superclasses INSP.pep8.naming=PEP 8 naming convention violation @@ -663,6 +661,59 @@ INSP.oldstyle.class.super=Old-style class contains call for super method # PyCompatibilityInspection INSP.NAME.compatibility=Code compatibility inspection +INSP.compatibility.this.syntax.available.only.since.py3=This syntax available only since py3 +INSP.compatibility.check.for.compatibility.with.python.versions=Check for compatibility with python versions: +INSP.compatibility.inspection.unsupported.feature.prefix=Python {0,choice,1#version|2#versions} {1} {0,choice,1#does|2#do} not {2} +INSP.compatibility.feature.support.variable.annotations=support variable annotations +INSP.compatibility.feature.support.dictionary.comprehensions=support dictionary comprehensions +INSP.compatibility.feature.support.set.literal.expressions=support set literal expressions +INSP.compatibility.feature.support.set.comprehensions=support set comprehensions +INSP.compatibility.feature.support.this.syntax=support this syntax +INSP.compatibility.feature.have.module.builtins=have module builtins +INSP.compatibility.feature.have.module.builtin=have module __builtin__ +INSP.compatibility.feature.support.starred.expressions.as.assignment.targets=support starred expressions as assignment targets +INSP.compatibility.feature.support.starred.expressions.in.tuples.lists.and.sets=support starred expressions in tuples, lists, and sets +INSP.compatibility.feature.support.unpacking.without.parentheses.in.return.statements=support unpacking without parentheses in return statements +INSP.compatibility.feature.support.unpacking.without.parentheses.in.yield.statements=support unpacking without parentheses in yield statements +INSP.compatibility.feature.support.starred.expressions.in.dicts=support starred expressions in dicts +INSP.compatibility.feature.support.diamond.operator=support <>, use != instead +INSP.compatibility.feature.support.matrix.multiplication.operators=support matrix multiplication operators +INSP.compatibility.feature.support.long.integer.literal.suffix=support a trailing ''{0}'' +INSP.compatibility.feature.support.old.style.octal.literals=support this syntax. It requires '0o' prefix for octal literals +INSP.compatibility.feature.support.underscores.in.numeric.literals=support underscores in numeric literals +INSP.compatibility.feature.support.string.literal.prefix=support a ''{0}'' prefix +INSP.compatibility.feature.allow.to.mix.bytes.and.non.bytes.literals=allow to mix bytes and non-bytes literals +INSP.compatibility.feature.support.this.syntax.in.list.comprehensions=support this syntax in list comprehensions +INSP.compatibility.feature.support.raise.with.no.arguments.outside.except.block=support this syntax. Raise with no arguments can only be used in an except block +INSP.compatibility.feature.support.backquotes=support backquotes, use repr() instead +INSP.compatibility.feature.support.multiple.context.managers=support multiple context managers +INSP.compatibility.feature.support.print.statement=support this syntax. The print statement has been replaced with a print() function +INSP.compatibility.feature.support.super.without.arguments=support this syntax. super() should have arguments in Python 2 +INSP.compatibility.py35.does.not.support.yield.inside.async.functions=Python version 3.5 does not support 'yield' inside async functions +INSP.compatibility.feature.support.yield.from=support this syntax. Delegating to a subgenerator is available since Python 3.3; use explicit iteration over subgenerator instead. +INSP.compatibility.pre35.versions.do.not.allow.return.with.argument.inside.generator=Python versions < 3.3 do not allow 'return' with argument inside generator. +INSP.compatibility.feature.support.ellipsis.outside.slices=support '...' outside of sequence slicings +INSP.compatibility.feature.have.nonlocal.keyword=have nonlocal keyword +INSP.compatibility.keyword.argument.repeated=Keyword argument repeated +INSP.compatibility.feature.allow.keyword.arguments.after.kwargs=allow keyword arguments after **expression +INSP.compatibility.feature.allow.duplicate.kwargs=allow duplicate **expressions +INSP.compatibility.feature.allow.duplicate.positional.varargs=allow duplicate *expressions +INSP.compatibility.feature.allow.positional.arguments.after.expression=allow positional arguments after *expression +INSP.compatibility.positional.argument.after.keyword.argument=Positional argument after keyword argument +INSP.compatibility.positional.argument.after.kwargs=Positional argument after **expression +INSP.compatibility.feature.allow.trailing.comma.after.kwargs=allow a trailing comma after **expression +INSP.compatibility.feature.allow.trailing.comma.after.positional.vararg=allow a trailing comma after *expression +INSP.compatibility.py35.does.not.support.async.inside.comprehensions.and.generator.expressions=Python version 3.5 does not support 'async' inside comprehensions and generator expressions +INSP.compatibility.py35.does.not.support.await.inside.comprehensions=Python version 3.5 does not support 'await' inside comprehensions +INSP.compatibility.feature.support.positional.only.parameters=support positional-only parameters +INSP.compatibility.support.equality.signs.in.fstrings=support equality signs in f-strings +INSP.compatibility.feature.support.assignment.expressions=support assignment expressions +INSP.compatibility.feature.support.continue.inside.finally.clause=support 'continue' inside 'finally' clause +INSP.compatibility.feature.support.arbitrary.expressions.as.decorator=support arbitrary expressions as a decorator +INSP.compatibility.feature.have.type.long=have type long. Use int instead. +INSP.compatibility.feature.have.method=have method {0} +INSP.compatibility.feature.have.module=have module {0} +INSP.compatibility.feature.allow.async.and.await.as.names=allow 'async' and 'await' as names # PyUnnecessaryBackslashInspection INSP.NAME.unnecessary.backslash=Unnecessary backslash diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java index d0c9eeac2f52..4c01e652e21f 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java @@ -20,6 +20,7 @@ import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.codeInspection.util.InspectionMessage; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.JDOMExternalizableStringList; @@ -139,7 +140,7 @@ public class PyCompatibilityInspection extends PyInspection { @Override protected void registerProblem(@NotNull PsiElement element, @NotNull TextRange range, - @NotNull String message, + @NotNull @InspectionMessage String message, @Nullable LocalQuickFix quickFix, boolean asError) { if (element.getTextLength() == 0) { @@ -182,7 +183,7 @@ public class PyCompatibilityInspection extends PyInspection { final Map> unsupportedMethods = UnsupportedFeaturesUtil.CLASS_METHODS.get(className); registerForAllMatchingVersions(level -> unsupportedMethods.getOrDefault(level, Collections.emptySet()).contains(functionName), - " not have method " + functionName, + PyPsiBundle.message("INSP.compatibility.feature.have.method", functionName), node); } } @@ -192,7 +193,7 @@ public class PyCompatibilityInspection extends PyInspection { !"exec".equals(functionName) && !myUsedImports.contains(functionName)) { registerForAllMatchingVersions(level -> UnsupportedFeaturesUtil.BUILTINS.get(level).contains(functionName), - " not have method " + functionName, + PyPsiBundle.message("INSP.compatibility.feature.have.method", functionName), node); } } @@ -203,7 +204,7 @@ public class PyCompatibilityInspection extends PyInspection { PyNames.TYPE_LONG.equals(target.getName()) && PyBuiltinCache.getInstance(resolvedCallee).isBuiltin(resolvedCallee)) { registerForAllMatchingVersions(level -> UnsupportedFeaturesUtil.BUILTINS.get(level).contains(PyNames.TYPE_LONG), - " not have type long. Use int instead.", + PyPsiBundle.message("INSP.compatibility.feature.have.type.long"), node); } } @@ -234,7 +235,7 @@ public class PyCompatibilityInspection extends PyInspection { final String moduleName = qName.toString(); registerForAllMatchingVersions(level -> UnsupportedFeaturesUtil.MODULES.get(level).contains(moduleName) && !BACKPORTED_PACKAGES.contains(moduleName), - " not have module " + moduleName, + PyPsiBundle.message("INSP.compatibility.feature.have.module", moduleName), importElement); } } @@ -264,7 +265,7 @@ public class PyCompatibilityInspection extends PyInspection { final String moduleName = name.toString(); registerForAllMatchingVersions(level -> UnsupportedFeaturesUtil.MODULES.get(level).contains(moduleName) && !BACKPORTED_PACKAGES.contains(moduleName), - " not have module " + name, + PyPsiBundle.message("INSP.compatibility.feature.have.module", name), source); } } @@ -353,7 +354,7 @@ public class PyCompatibilityInspection extends PyInspection { ArrayUtil.contains(nameIdentifierOwner.getName(), PyNames.AWAIT, PyNames.ASYNC) && LanguageLevel.forElement(nameIdentifierOwner).isOlderThan(LanguageLevel.PYTHON37)) { registerForAllMatchingVersions(level -> level.isAtLeast(LanguageLevel.PYTHON37), - " not allow 'async' and 'await' as names", + PyPsiBundle.message("INSP.compatibility.feature.allow.async.and.await.as.names"), nameIdentifier, PythonUiService.getInstance().createPyRenameElementQuickFix(nameIdentifierOwner)); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/validation/CompatibilityVisitor.java b/python/python-psi-impl/src/com/jetbrains/python/validation/CompatibilityVisitor.java index e9f0247a669b..a315a4c3279a 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/validation/CompatibilityVisitor.java +++ b/python/python-psi-impl/src/com/jetbrains/python/validation/CompatibilityVisitor.java @@ -3,7 +3,9 @@ package com.jetbrains.python.validation; import com.google.common.collect.Sets; import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.util.InspectionMessage; import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; @@ -17,11 +19,13 @@ import com.intellij.psi.util.QualifiedName; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyNames; +import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.inspections.quickfix.*; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyPsiUtils; +import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,9 +48,6 @@ public abstract class CompatibilityVisitor extends PyAnnotator { @NotNull private static final Set PYTHON36_PREFIXES = Sets.newHashSet("R", "U", "B", "BR", "RB", "F", "FR", "RF"); - @NotNull - protected static final String COMMON_MESSAGE = "Python version "; - @NotNull protected List myVersionsToProcess; @@ -59,7 +60,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final PsiElement parent = node.getParent(); if (!(parent instanceof PyFunction || parent instanceof PyNamedParameter)) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON36) && registerForLanguageLevel(level), - " not support variable annotations", + PyPsiBundle.message("INSP.compatibility.feature.support.variable.annotations"), node); } } @@ -69,7 +70,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { super.visitPyDictCompExpression(node); registerForAllMatchingVersions(level -> !level.supportsSetLiterals() && registerForLanguageLevel(level), - " not support dictionary comprehensions", + PyPsiBundle.message("INSP.compatibility.feature.support.dictionary.comprehensions"), node, new ConvertDictCompQuickFix(), false); @@ -80,7 +81,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { super.visitPySetLiteralExpression(node); registerForAllMatchingVersions(level -> !level.supportsSetLiterals() && registerForLanguageLevel(level), - " not support set literal expressions", + PyPsiBundle.message("INSP.compatibility.feature.support.set.literal.expressions"), node, new ConvertSetLiteralQuickFix(), false); @@ -91,7 +92,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { super.visitPySetCompExpression(node); registerForAllMatchingVersions(level -> !level.supportsSetLiterals() && registerForLanguageLevel(level), - " not support set comprehensions", + PyPsiBundle.message("INSP.compatibility.feature.support.set.comprehensions"), node, null, false); @@ -110,7 +111,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (element != null && ",".equals(element.getText())) { registerForAllMatchingVersions(level -> level.isPy3K() && registerForLanguageLevel(level), - " not support this syntax.", + PyPsiBundle.message("INSP.compatibility.feature.support.this.syntax"), node, new ReplaceExceptPartQuickFix()); } @@ -130,13 +131,13 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (qName != null) { if (qName.matches("builtins")) { registerForAllMatchingVersions(level -> level.isPython2() && registerForLanguageLevel(level), - " not have module builtins", + PyPsiBundle.message("INSP.compatibility.feature.have.module.builtins"), node, new ReplaceBuiltinsQuickFix()); } else if (qName.matches("__builtin__")) { registerForAllMatchingVersions(level -> level.isPy3K() && registerForLanguageLevel(level), - " not have module __builtin__", + PyPsiBundle.message("INSP.compatibility.feature.have.module.builtin"), node, new ReplaceBuiltinsQuickFix()); } @@ -150,13 +151,13 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (node.isAssignmentTarget()) { registerForAllMatchingVersions(level -> level.isPython2() && registerForLanguageLevel(level), - " not support starred expressions as assignment targets", + PyPsiBundle.message("INSP.compatibility.feature.support.starred.expressions.as.assignment.targets"), node); } if (node.isUnpacking()) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not support starred expressions in tuples, lists, and sets", + PyPsiBundle.message("INSP.compatibility.feature.support.starred.expressions.in.tuples.lists.and.sets"), node); final PsiElement container = PsiTreeUtil.skipParentsOfType(node, PyParenthesizedExpression.class); if (container instanceof PyTupleExpression) { @@ -165,7 +166,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { registerForAllMatchingVersions(level -> level.isAtLeast(LanguageLevel.PYTHON35) && level.isOlderThan(LanguageLevel.PYTHON38) && registerForLanguageLevel(level), - " not support unpacking without parentheses in return statements", + PyPsiBundle.message("INSP.compatibility.feature.support.unpacking.without.parentheses.in.return.statements"), node); } @@ -173,7 +174,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { registerForAllMatchingVersions(level -> level.isAtLeast(LanguageLevel.PYTHON35) && level.isOlderThan(LanguageLevel.PYTHON38) && registerForLanguageLevel(level), - " not support unpacking without parentheses in yield statements", + PyPsiBundle.message("INSP.compatibility.feature.support.unpacking.without.parentheses.in.yield.statements"), node); } } @@ -185,7 +186,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { super.visitPyDoubleStarExpression(node); registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not support starred expressions in dicts", + PyPsiBundle.message("INSP.compatibility.feature.support.starred.expressions.in.dicts"), node); } @@ -195,7 +196,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (node.isOperator("<>")) { registerForAllMatchingVersions(level -> level.isPy3K() && registerForLanguageLevel(level), - " not support <>, use != instead.", + PyPsiBundle.message("INSP.compatibility.feature.support.diamond.operator"), node, new ReplaceNotEqOperatorQuickFix()); } @@ -206,7 +207,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { private void checkMatrixMultiplicationOperator(PsiElement node) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not support matrix multiplication operators", + PyPsiBundle.message("INSP.compatibility.feature.support.matrix.multiplication.operators"), node); } @@ -220,7 +221,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { String suffix = node.getIntegerLiteralSuffix(); if ("l".equalsIgnoreCase(suffix)) { registerForAllMatchingVersions(level -> level.isPy3K() && registerForLanguageLevel(level), - " not support a trailing '" + suffix + "'.", + PyPsiBundle.message("INSP.compatibility.feature.support.long.integer.literal.suffix", suffix), node, new RemoveTrailingSuffixQuickFix()); } @@ -229,7 +230,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final char secondChar = Character.toLowerCase(text.charAt(1)); if (secondChar != 'o' && secondChar != 'b' && secondChar != 'x' && text.chars().anyMatch(c -> c != '0')) { registerForAllMatchingVersions(level -> level.isPy3K() && registerForLanguageLevel(level), - " not support this syntax. It requires '0o' prefix for octal literals", + PyPsiBundle.message("INSP.compatibility.feature.support.old.style.octal.literals"), node, new ReplaceOctalNumericLiteralQuickFix()); } @@ -238,7 +239,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (text.contains("_")) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON36) && registerForLanguageLevel(level), - " not support underscores in numeric literals", + PyPsiBundle.message("INSP.compatibility.feature.support.underscores.in.numeric.literals"), node, new PyRemoveUnderscoresInNumericLiteralsQuickFix()); } @@ -260,7 +261,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final int elementStart = element.getTextOffset(); registerForAllMatchingVersions(level -> !getSupportedStringPrefixes(level).contains(prefix) && registerForLanguageLevel(level), - " not support a '" + prefix + "' prefix", + PyPsiBundle.message("INSP.compatibility.feature.support.string.literal.prefix", prefix), node, TextRange.create(elementStart, elementStart + element.getPrefixLength()), new RemovePrefixQuickFix(prefix), @@ -269,7 +270,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (seenBytes && seenNonBytes) { registerForAllMatchingVersions(level -> level.isPy3K() && registerForLanguageLevel(level), - " not allow to mix bytes and non-bytes literals", + PyPsiBundle.message("INSP.compatibility.feature.allow.to.mix.bytes.and.non.bytes.literals"), node); } } @@ -293,7 +294,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { registerForAllMatchingVersions( level -> registerForLanguageLevel(level) && UnsupportedFeaturesUtil.visitPyListCompExpression(node, level), - " not support this syntax in list comprehensions.", + PyPsiBundle.message("INSP.compatibility.feature.support.this.syntax.in.list.comprehensions"), ContainerUtil.map(node.getForComponents(), PyComprehensionForComponent::getIteratedList), new ReplaceListComprehensionsQuickFix() ); @@ -306,19 +307,19 @@ public abstract class CompatibilityVisitor extends PyAnnotator { // empty raise under finally registerForAllMatchingVersions( level -> registerForLanguageLevel(level) && UnsupportedFeaturesUtil.raiseHasNoArgsUnderFinally(node, level), - " not support this syntax. Raise with no arguments can only be used in an except block", + PyPsiBundle.message("INSP.compatibility.feature.support.raise.with.no.arguments.outside.except.block"), node ); // raise 1, 2, 3 registerForAllMatchingVersions(level -> registerForLanguageLevel(level) && UnsupportedFeaturesUtil.raiseHasMoreThenOneArg(node, level), - " not support this syntax.", + PyPsiBundle.message("INSP.compatibility.feature.support.this.syntax"), node, new ReplaceRaiseStatementQuickFix()); // raise exception from cause registerForAllMatchingVersions(level -> registerForLanguageLevel(level) && UnsupportedFeaturesUtil.raiseHasFromKeyword(node, level), - " not support this syntax.", + PyPsiBundle.message("INSP.compatibility.feature.support.this.syntax"), node, new ReplaceRaiseStatementQuickFix()); } @@ -328,7 +329,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { super.visitPyReprExpression(node); registerForAllMatchingVersions(level -> level.isPy3K() && registerForLanguageLevel(level), - " not support backquotes, use repr() instead", + PyPsiBundle.message("INSP.compatibility.feature.support.backquotes"), node, new ReplaceBackquoteExpressionQuickFix()); } @@ -341,7 +342,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final PyWithItem[] items = node.getWithItems(); if (items.length > 1) { registerForAllMatchingVersions(level -> !level.supportsSetLiterals() && registerForLanguageLevel(level), - " not support multiple context managers", + PyPsiBundle.message("INSP.compatibility.feature.support.multiple.context.managers"), Arrays.asList(items).subList(1, items.length), null); } @@ -365,8 +366,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (arguments.length == 0 || Arrays.stream(arguments).anyMatch(nonParenthesesPredicate)) { registerForAllMatchingVersions(level -> level.isPy3K() && registerForLanguageLevel(level), - " not support this syntax. " + - "The print statement has been replaced with a print() function", + PyPsiBundle.message("INSP.compatibility.feature.support.print.statement"), node, new CompatibilityPrintCallQuickFix()); } @@ -379,7 +379,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final PsiElement firstChild = node.getFirstChild(); if (firstChild != null && PyNames.SUPER.equals(firstChild.getText()) && ArrayUtil.isEmpty(node.getArguments())) { registerForAllMatchingVersions(level -> level.isPython2() && registerForLanguageLevel(level), - " not support this syntax. super() should have arguments in Python 2", + PyPsiBundle.message("INSP.compatibility.feature.support.super.without.arguments"), node); } @@ -398,7 +398,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (node.getOperator() == PyTokenTypes.AWAIT_KEYWORD) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not support this syntax", + PyPsiBundle.message("INSP.compatibility.feature.support.this.syntax"), node); } } @@ -416,7 +416,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (!node.isDelegating() && registerForLanguageLevel(LanguageLevel.PYTHON35) && myVersionsToProcess.contains(LanguageLevel.PYTHON35)) { - registerProblem(node, "Python version 3.5 does not support 'yield' inside async functions"); + registerProblem(node, PyPsiBundle.message("INSP.compatibility.py35.does.not.support.yield.inside.async.functions")); } } ); @@ -426,8 +426,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { } registerForAllMatchingVersions(level -> level.isPython2() && registerForLanguageLevel(level), - " not support this syntax. Delegating to a subgenerator is available since " + - "Python 3.3; use explicit iteration over subgenerator instead.", + PyPsiBundle.message("INSP.compatibility.feature.support.yield.from"), node); } @@ -439,7 +438,8 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final YieldVisitor visitor = new YieldVisitor(); function.acceptChildren(visitor); if (visitor.haveYield()) { - registerProblem(node, "Python versions < 3.3 do not allow 'return' with argument inside generator."); + registerProblem(node, + PyPsiBundle.message("INSP.compatibility.pre35.versions.do.not.allow.return.with.argument.inside.generator")); } } } @@ -457,7 +457,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { return; } registerForAllMatchingVersions(level -> level.isPython2() && registerForLanguageLevel(level), - " not support '...' outside of sequence slicings.", + PyPsiBundle.message("INSP.compatibility.feature.support.ellipsis.outside.slices"), node); } } @@ -478,7 +478,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final ASTNode asyncNode = node.getNode().findChildByType(PyTokenTypes.ASYNC_KEYWORD); if (asyncNode != null) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not support this syntax", + PyPsiBundle.message("INSP.compatibility.feature.support.this.syntax"), node, asyncNode.getTextRange(), null, @@ -517,15 +517,17 @@ public abstract class CompatibilityVisitor extends PyAnnotator { protected abstract void registerProblem(@NotNull PsiElement node, @NotNull TextRange range, - @NotNull String message, + @NotNull @InspectionMessage String message, @Nullable LocalQuickFix localQuickFix, boolean asError); - protected void registerProblem(@NotNull PsiElement node, @NotNull String message, @Nullable LocalQuickFix localQuickFix) { + protected void registerProblem(@NotNull PsiElement node, + @NotNull @InspectionMessage String message, + @Nullable LocalQuickFix localQuickFix) { registerProblem(node, node.getTextRange(), message, localQuickFix, true); } - protected void registerProblem(@NotNull PsiElement node, @NotNull String message) { + protected void registerProblem(@NotNull PsiElement node, @NotNull @InspectionMessage String message) { registerProblem(node, message, null); } @@ -534,7 +536,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { } protected void registerForAllMatchingVersions(@NotNull Predicate levelPredicate, - @NotNull String suffix, + @NotNull @Nls String suffix, @NotNull Iterable> nodesWithRanges, @Nullable LocalQuickFix localQuickFix, boolean asError) { @@ -545,15 +547,17 @@ public abstract class CompatibilityVisitor extends PyAnnotator { .collect(Collectors.toList()); if (!levels.isEmpty()) { - final String result = COMMON_MESSAGE + StringUtil.join(levels, ", ") + (levels.size() == 1 ? " does" : " do") + suffix; + @NlsSafe String versions = StringUtil.join(levels, ", "); + @InspectionMessage String message = PyPsiBundle.message("INSP.compatibility.inspection.unsupported.feature.prefix", + levels.size(), versions, suffix); for (Pair nodeWithRange : nodesWithRanges) { - registerProblem(nodeWithRange.first, nodeWithRange.second, result, localQuickFix, asError); + registerProblem(nodeWithRange.first, nodeWithRange.second, message, localQuickFix, asError); } } } protected void registerForAllMatchingVersions(@NotNull Predicate levelPredicate, - @NotNull String suffix, + @NotNull @Nls String suffix, @NotNull Iterable nodes, @Nullable LocalQuickFix localQuickFix) { final List> nodesWithRanges = @@ -562,7 +566,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { } protected void registerForAllMatchingVersions(@NotNull Predicate levelPredicate, - @NotNull String suffix, + @NotNull @Nls String suffix, @NotNull PsiElement node, @NotNull TextRange range, @Nullable LocalQuickFix localQuickFix, @@ -572,7 +576,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { } protected void registerForAllMatchingVersions(@NotNull Predicate levelPredicate, - @NotNull String suffix, + @NotNull @Nls String suffix, @NotNull PsiElement node, @Nullable LocalQuickFix localQuickFix, boolean asError) { @@ -580,14 +584,14 @@ public abstract class CompatibilityVisitor extends PyAnnotator { } protected void registerForAllMatchingVersions(@NotNull Predicate levelPredicate, - @NotNull String suffix, + @NotNull @Nls String suffix, @NotNull PsiElement node, @Nullable LocalQuickFix localQuickFix) { registerForAllMatchingVersions(levelPredicate, suffix, node, localQuickFix, true); } protected void registerForAllMatchingVersions(@NotNull Predicate levelPredicate, - @NotNull String suffix, + @NotNull @Nls String suffix, @NotNull PsiElement node) { registerForAllMatchingVersions(levelPredicate, suffix, node, null, true); } @@ -595,7 +599,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { @Override public void visitPyNonlocalStatement(final PyNonlocalStatement node) { registerForAllMatchingVersions(level -> level.isPython2() && registerForLanguageLevel(level), - " not have nonlocal keyword", + PyPsiBundle.message("INSP.compatibility.feature.have.nonlocal.keyword"), node); } @@ -611,11 +615,11 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final String keyword = ((PyKeywordArgument)argument).getKeyword(); if (keywordArgumentNames.contains(keyword)) { - registerProblem(argument, "Keyword argument repeated", new PyRemoveArgumentQuickFix()); + registerProblem(argument, PyPsiBundle.message("INSP.compatibility.keyword.argument.repeated"), new PyRemoveArgumentQuickFix()); } else if (seenKeywordContainer) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not allow keyword arguments after **expression", + PyPsiBundle.message("INSP.compatibility.feature.allow.keyword.arguments.after.kwargs"), argument, new PyRemoveArgumentQuickFix()); } @@ -628,7 +632,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (starArgument.isKeyword()) { if (seenKeywordContainer) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not allow duplicate **expressions", + PyPsiBundle.message("INSP.compatibility.feature.allow.duplicate.kwargs"), argument, new PyRemoveArgumentQuickFix()); } @@ -637,7 +641,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { else { if (seenPositionalContainer) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not allow duplicate *expressions", + PyPsiBundle.message("INSP.compatibility.feature.allow.duplicate.positional.varargs"), argument, new PyRemoveArgumentQuickFix()); } @@ -646,16 +650,16 @@ public abstract class CompatibilityVisitor extends PyAnnotator { } else { if (seenKeywordArgument) { - registerProblem(argument, "Positional argument after keyword argument", new PyRemoveArgumentQuickFix()); + registerProblem(argument, PyPsiBundle.message("INSP.compatibility.positional.argument.after.keyword.argument"), new PyRemoveArgumentQuickFix()); } else if (seenPositionalContainer) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not allow positional arguments after *expression", + PyPsiBundle.message("INSP.compatibility.feature.allow.positional.arguments.after.expression"), argument, new PyRemoveArgumentQuickFix()); } else if (seenKeywordContainer) { - registerProblem(argument, "Positional argument after **expression", new PyRemoveArgumentQuickFix()); + registerProblem(argument, PyPsiBundle.message("INSP.compatibility.positional.argument.after.kwargs"), new PyRemoveArgumentQuickFix()); } } } @@ -666,9 +670,15 @@ public abstract class CompatibilityVisitor extends PyAnnotator { PsiElement sibling = PyPsiUtils.getNextNonWhitespaceSibling(lastArg); if (sibling != null && sibling.getNode().getElementType() == PyTokenTypes.COMMA) { boolean isKeyword = ((PyStarArgument)lastArg).isKeyword(); + String message; + if (isKeyword) { + message = PyPsiBundle.message("INSP.compatibility.feature.allow.trailing.comma.after.kwargs"); + } + else { + message = PyPsiBundle.message("INSP.compatibility.feature.allow.trailing.comma.after.positional.vararg"); + } registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON35) && registerForLanguageLevel(level), - " not allow a trailing comma after " - + (isKeyword ? "**" : "*") + "expression", + message, sibling); } } @@ -684,7 +694,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { .filter(Objects::nonNull) .map(ASTNode::getPsi) .forEach(element -> registerProblem(element, - "Python version 3.5 does not support 'async' inside comprehensions and generator expressions")); + PyPsiBundle.message("INSP.compatibility.py35.does.not.support.async.inside.comprehensions.and.generator.expressions"))); final Stream resultPrefixExpressions = PsiTreeUtil .collectElementsOfType(node.getResultExpression(), PyPrefixExpression.class) @@ -700,7 +710,8 @@ public abstract class CompatibilityVisitor extends PyAnnotator { .map(expression -> expression.getNode().findChildByType(PyTokenTypes.AWAIT_KEYWORD)) .filter(Objects::nonNull) .map(ASTNode::getPsi) - .forEach(element -> registerProblem(element, "Python version 3.5 does not support 'await' inside comprehensions")); + .forEach(element -> registerProblem(element, + PyPsiBundle.message("INSP.compatibility.py35.does.not.support.await.inside.comprehensions"))); } } @@ -709,7 +720,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { super.visitPySlashParameter(node); registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON38) && registerForLanguageLevel(level), - " not support positional-only parameters", + PyPsiBundle.message("INSP.compatibility.feature.support.positional.only.parameters"), node); } @@ -720,7 +731,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { final ASTNode equalitySignInFStringFragment = node.getNode().findChildByType(PyTokenTypes.EQ); if (equalitySignInFStringFragment != null) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON38) && registerForLanguageLevel(level), - " not support equality signs in f-strings", equalitySignInFStringFragment.getPsi()); + PyPsiBundle.message("INSP.compatibility.support.equality.signs.in.fstrings"), equalitySignInFStringFragment.getPsi()); } } @@ -728,7 +739,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { public void visitPyAssignmentExpression(PyAssignmentExpression node) { super.visitPyAssignmentExpression(node); registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON38) && registerForLanguageLevel(level), - " not support assignment expressions", node); + PyPsiBundle.message("INSP.compatibility.feature.support.assignment.expressions"), node); } @Override @@ -737,7 +748,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { if (PsiTreeUtil.getParentOfType(node, PyFinallyPart.class, false, PyLoopStatement.class) != null) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON38) && registerForLanguageLevel(level), - " not support 'continue' inside 'finally' clause", + PyPsiBundle.message("INSP.compatibility.feature.support.continue.inside.finally.clause"), node); } } @@ -747,7 +758,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { super.visitPyDecorator(decorator); if (PsiTreeUtil.getChildOfType(decorator, PsiErrorElement.class) == null && decorator.getQualifiedName() == null) { registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON39) && registerForLanguageLevel(level), - " not support arbitrary expressions as a decorator", decorator); + PyPsiBundle.message("INSP.compatibility.feature.support.arbitrary.expressions.as.decorator"), decorator); } } } diff --git a/python/testData/highlighting/implicitOctLongInteger.py b/python/testData/highlighting/implicitOctLongInteger.py index 5466dfd85add..d6377f9589f4 100644 --- a/python/testData/highlighting/implicitOctLongInteger.py +++ b/python/testData/highlighting/implicitOctLongInteger.py @@ -1 +1 @@ -01234L \ No newline at end of file +01234L \ No newline at end of file diff --git a/python/testData/highlighting/unsupportedFeaturesInPython3.py b/python/testData/highlighting/unsupportedFeaturesInPython3.py index b04973039ef7..05cb6f5e5951 100644 --- a/python/testData/highlighting/unsupportedFeaturesInPython3.py +++ b/python/testData/highlighting/unsupportedFeaturesInPython3.py @@ -1,6 +1,6 @@ -print(a <> 3) +print(a <> 3) `foo()` -a = 123l +a = 123l a = 043 a = 0X43 a = 0X43 @@ -11,15 +11,15 @@ a = 0B1 a = 0b1 a = 0.0 s = u"text" -raise a, b, c -raise a, b +raise a, b, c +raise a, b try: pass -except a, name: +except a, name: pass -[x * 2 for x in vec1, vec2] +[x * 2 for x in vec1, vec2] import __builtin__ diff --git a/python/testData/inspections/BatchReplacePrintInsertsFutureImportOnlyOnce.py b/python/testData/inspections/BatchReplacePrintInsertsFutureImportOnlyOnce.py index ad746b0c98e8..2da1fec6882c 100644 --- a/python/testData/inspections/BatchReplacePrintInsertsFutureImportOnlyOnce.py +++ b/python/testData/inspections/BatchReplacePrintInsertsFutureImportOnlyOnce.py @@ -1,2 +1,2 @@ -print 'foo' -print 'bar' \ No newline at end of file +print 'foo' +print 'bar' \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/argumentsUnpackingGeneralizations.py b/python/testData/inspections/PyCompatibilityInspection/argumentsUnpackingGeneralizations.py index 3558259797e7..b81b02bc7154 100644 --- a/python/testData/inspections/PyCompatibilityInspection/argumentsUnpackingGeneralizations.py +++ b/python/testData/inspections/PyCompatibilityInspection/argumentsUnpackingGeneralizations.py @@ -4,14 +4,14 @@ def foo(*args, **kwargs): foo(0, *[1], - 2, - *[3], - 4, + 2, + *[3], + 4, a='a', - *[6], + *[6], b='b', - *[7], + *[7], c='c', **{'d': 'd'}, - e='e', - **{'f': 'f'}) + e='e', + **{'f': 'f'}) diff --git a/python/testData/inspections/PyCompatibilityInspection/assignmentExpressions.py b/python/testData/inspections/PyCompatibilityInspection/assignmentExpressions.py index a81156554f14..f8fe9a0831df 100644 --- a/python/testData/inspections/PyCompatibilityInspection/assignmentExpressions.py +++ b/python/testData/inspections/PyCompatibilityInspection/assignmentExpressions.py @@ -1,13 +1,13 @@ # Handle a matched regex -if (match := pattern.search(data)) is not None: +if (match := pattern.search(data)) is not None: pass # A loop that can't be trivially rewritten using 2-arg iter() -while chunk := file.read(8192): +while chunk := file.read(8192): pass # Reuse a value that's expensive to compute -[y := f(x), y**2, y**3] +[y := f(x), y**2, y**3] # Share a subexpression between a comprehension filter clause and its output -filtered_data = [y for x in data if (y := f(x)) is not None] \ No newline at end of file +filtered_data = [y for x in data if (y := f(x)) is not None] \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/asyncAwait.py b/python/testData/inspections/PyCompatibilityInspection/asyncAwait.py index eada4910789f..d1cf6e7cd100 100644 --- a/python/testData/inspections/PyCompatibilityInspection/asyncAwait.py +++ b/python/testData/inspections/PyCompatibilityInspection/asyncAwait.py @@ -1,7 +1,7 @@ -async def foo(x): - async with x: - y = await x - if await y: - return await z - async for y in x: +async def foo(x): + async with x: + y = await x + if await y: + return await z + async for y in x: pass diff --git a/python/testData/inspections/PyCompatibilityInspection/asyncComprehensions.py b/python/testData/inspections/PyCompatibilityInspection/asyncComprehensions.py index bd2da0d56019..b543e029ec9a 100644 --- a/python/testData/inspections/PyCompatibilityInspection/asyncComprehensions.py +++ b/python/testData/inspections/PyCompatibilityInspection/asyncComprehensions.py @@ -1,6 +1,6 @@ -async def asyncgen(): +async def asyncgen(): yield 10 -async def run(): +async def run(): {i async for i in asyncgen()} [i async for i in asyncgen()] {i: i ** 2 async for i in asyncgen()} diff --git a/python/testData/inspections/PyCompatibilityInspection/awaitInComprehensions.py b/python/testData/inspections/PyCompatibilityInspection/awaitInComprehensions.py index 3c22098d1981..c7d9762a9047 100644 --- a/python/testData/inspections/PyCompatibilityInspection/awaitInComprehensions.py +++ b/python/testData/inspections/PyCompatibilityInspection/awaitInComprehensions.py @@ -1,16 +1,16 @@ -async def async2(): - [await fun() for fun in funcs] - {await fun() for fun in funcs} - {fun: await fun() for fun in funcs} +async def async2(): + [await fun() for fun in funcs] + {await fun() for fun in funcs} + {fun: await fun() for fun in funcs} - [await fun() for fun in funcs if await smth] - {await fun() for fun in funcs if await smth} - {fun: await fun() for fun in funcs if await smth} + [await fun() for fun in funcs if await smth] + {await fun() for fun in funcs if await smth} + {fun: await fun() for fun in funcs if await smth} - [await fun() async for fun in funcs] - {await fun() async for fun in funcs} - {fun: await fun() async for fun in funcs} + [await fun() async for fun in funcs] + {await fun() async for fun in funcs} + {fun: await fun() async for fun in funcs} - [await fun() async for fun in funcs if await smth] - {await fun() async for fun in funcs if await smth} - {fun: await fun() async for fun in funcs if await smth} \ No newline at end of file + [await fun() async for fun in funcs if await smth] + {await fun() async for fun in funcs if await smth} + {fun: await fun() async for fun in funcs if await smth} \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/binaryExpression.py b/python/testData/inspections/PyCompatibilityInspection/binaryExpression.py index 18a27e89010c..6aa8b77ec220 100644 --- a/python/testData/inspections/PyCompatibilityInspection/binaryExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/binaryExpression.py @@ -1,4 +1,4 @@ -print(a <> b) +print(a <> b) -if a <> 2: +if a <> 2: var = a \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/builtinLong.py b/python/testData/inspections/PyCompatibilityInspection/builtinLong.py index a31692081e9e..9980b3c97561 100644 --- a/python/testData/inspections/PyCompatibilityInspection/builtinLong.py +++ b/python/testData/inspections/PyCompatibilityInspection/builtinLong.py @@ -1 +1 @@ -long("abc") \ No newline at end of file +long("abc") \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/callExpression.py b/python/testData/inspections/PyCompatibilityInspection/callExpression.py index 3c98ce3091e3..395dbdce8b7d 100644 --- a/python/testData/inspections/PyCompatibilityInspection/callExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/callExpression.py @@ -1,8 +1,8 @@ class A(B): def __init__(self): - super() + super() -cmp() -reduce() +cmp() +reduce() -buffer() \ No newline at end of file +buffer() \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/doubleStarUnpacking.py b/python/testData/inspections/PyCompatibilityInspection/doubleStarUnpacking.py index 0ee45319ece6..31f817553fb2 100644 --- a/python/testData/inspections/PyCompatibilityInspection/doubleStarUnpacking.py +++ b/python/testData/inspections/PyCompatibilityInspection/doubleStarUnpacking.py @@ -1,2 +1,2 @@ xs = {1: 2} -ys = {**xs, 3: 4} +ys = {**xs, 3: 4} diff --git a/python/testData/inspections/PyCompatibilityInspection/ellipsisAsStatementPy2.py b/python/testData/inspections/PyCompatibilityInspection/ellipsisAsStatementPy2.py index b996e0088cab..df4ebc0fe8d0 100644 --- a/python/testData/inspections/PyCompatibilityInspection/ellipsisAsStatementPy2.py +++ b/python/testData/inspections/PyCompatibilityInspection/ellipsisAsStatementPy2.py @@ -1,2 +1,2 @@ def foo(): - ... + ... diff --git a/python/testData/inspections/PyCompatibilityInspection/equalitySignInFStrings.py b/python/testData/inspections/PyCompatibilityInspection/equalitySignInFStrings.py index d5212da63f0a..c8a74eb77eb7 100644 --- a/python/testData/inspections/PyCompatibilityInspection/equalitySignInFStrings.py +++ b/python/testData/inspections/PyCompatibilityInspection/equalitySignInFStrings.py @@ -1,3 +1,3 @@ import math -print(f'{math.pi =:.2f}') -print(f'{f"{3.1415=:.1f}":*^20}') \ No newline at end of file +print(f'{math.pi =:.2f}') +print(f'{f"{3.1415=:.1f}":*^20}') \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/exceptBlock.py b/python/testData/inspections/PyCompatibilityInspection/exceptBlock.py index b206d5774887..4396d55f103b 100644 --- a/python/testData/inspections/PyCompatibilityInspection/exceptBlock.py +++ b/python/testData/inspections/PyCompatibilityInspection/exceptBlock.py @@ -1,4 +1,4 @@ try: do_smth() -except ImportError, ImportWarning: +except ImportError, ImportWarning: do() \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/expressionInDecorators.py b/python/testData/inspections/PyCompatibilityInspection/expressionInDecorators.py index f4622082a300..9f289c90407f 100644 --- a/python/testData/inspections/PyCompatibilityInspection/expressionInDecorators.py +++ b/python/testData/inspections/PyCompatibilityInspection/expressionInDecorators.py @@ -1,9 +1,9 @@ -@x[0][1] +@x[0][1] @my_decorator def say_whee(): print("Whee!") -@foo[0].wrapper +@foo[0].wrapper @foo.bar() def say_whee(): print("Whee!") \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/fromImportStatement.py b/python/testData/inspections/PyCompatibilityInspection/fromImportStatement.py index 45768163cdce..464316ca18c3 100644 --- a/python/testData/inspections/PyCompatibilityInspection/fromImportStatement.py +++ b/python/testData/inspections/PyCompatibilityInspection/fromImportStatement.py @@ -1 +1 @@ -from Bastion import BastionClass \ No newline at end of file +from Bastion import BastionClass \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/importElement.py b/python/testData/inspections/PyCompatibilityInspection/importElement.py index 083e7f36828b..6b9a0db4de1e 100644 --- a/python/testData/inspections/PyCompatibilityInspection/importElement.py +++ b/python/testData/inspections/PyCompatibilityInspection/importElement.py @@ -1,4 +1,4 @@ -import Bastion +import Bastion -from asyncio import Queue +from asyncio import Queue from io import StringIO \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/importStatement.py b/python/testData/inspections/PyCompatibilityInspection/importStatement.py index c3c3fce97cb3..f26b880a1ff6 100644 --- a/python/testData/inspections/PyCompatibilityInspection/importStatement.py +++ b/python/testData/inspections/PyCompatibilityInspection/importStatement.py @@ -1,3 +1,3 @@ import builtins -import __builtin__ \ No newline at end of file +import __builtin__ \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/listCompExpression.py b/python/testData/inspections/PyCompatibilityInspection/listCompExpression.py index e231912e5e1d..1b88b0ab9fce 100644 --- a/python/testData/inspections/PyCompatibilityInspection/listCompExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/listCompExpression.py @@ -1 +1 @@ -var = [x for x in 1, 2, 3] \ No newline at end of file +var = [x for x in 1, 2, 3] \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/matMul.py b/python/testData/inspections/PyCompatibilityInspection/matMul.py index a6c05ef126a6..e4749ef8975e 100644 --- a/python/testData/inspections/PyCompatibilityInspection/matMul.py +++ b/python/testData/inspections/PyCompatibilityInspection/matMul.py @@ -1,2 +1,2 @@ -x @ y -x @= y +x @ y +x @= y diff --git a/python/testData/inspections/PyCompatibilityInspection/numericLiteralExpression.py b/python/testData/inspections/PyCompatibilityInspection/numericLiteralExpression.py index 042efc14cd63..26900b07a824 100644 --- a/python/testData/inspections/PyCompatibilityInspection/numericLiteralExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/numericLiteralExpression.py @@ -1,8 +1,8 @@ a = 12u -b = 12l +b = 12l c = 12ll d = 12U -e = 12L +e = 12L f = 12LL g = 0x12ful h = 0X12fuL @@ -20,4 +20,4 @@ s = 12llu t = 12llU u = 12LLu v = 12LLU -w = 048 \ No newline at end of file +w = 048 \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/printStatement.py b/python/testData/inspections/PyCompatibilityInspection/printStatement.py index 2e1aebee1924..816a3ac1286b 100644 --- a/python/testData/inspections/PyCompatibilityInspection/printStatement.py +++ b/python/testData/inspections/PyCompatibilityInspection/printStatement.py @@ -1 +1 @@ -print "One value" \ No newline at end of file +print "One value" \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/raiseFrom.py b/python/testData/inspections/PyCompatibilityInspection/raiseFrom.py index f7033897e3d2..d09bdf87c7fb 100644 --- a/python/testData/inspections/PyCompatibilityInspection/raiseFrom.py +++ b/python/testData/inspections/PyCompatibilityInspection/raiseFrom.py @@ -1,2 +1,2 @@ -raise exception from cause +raise exception from cause a = 1 \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/raiseMultipleArgs.py b/python/testData/inspections/PyCompatibilityInspection/raiseMultipleArgs.py index 062066bd2164..4489cb6f9978 100644 --- a/python/testData/inspections/PyCompatibilityInspection/raiseMultipleArgs.py +++ b/python/testData/inspections/PyCompatibilityInspection/raiseMultipleArgs.py @@ -1,4 +1,4 @@ try: a except : - raise ImportError, ImportWarning + raise ImportError, ImportWarning diff --git a/python/testData/inspections/PyCompatibilityInspection/reprExpression.py b/python/testData/inspections/PyCompatibilityInspection/reprExpression.py index cf4eab4c1fc1..5385cbe725b8 100644 --- a/python/testData/inspections/PyCompatibilityInspection/reprExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/reprExpression.py @@ -1 +1 @@ -a = `imp.acquire_lock()` +a = `imp.acquire_lock()` diff --git a/python/testData/inspections/PyCompatibilityInspection/starExpression.py b/python/testData/inspections/PyCompatibilityInspection/starExpression.py index a42ade5e4ee5..211af8dfa54c 100644 --- a/python/testData/inspections/PyCompatibilityInspection/starExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/starExpression.py @@ -1,2 +1,2 @@ -t = (1, *(2, 3)) -a, *b, c = t +t = (1, *(2, 3)) +a, *b, c = t diff --git a/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py b/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py index 32827aee12b8..a7e1f3ee5b88 100644 --- a/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py @@ -2,15 +2,15 @@ a = u"String" # Python 3.6 -a = f"" -a = F"" -a = rf"" -a = fr"" -a = fu"" -a = uf"" -a = bf"" -a = fb"" -a = ufr"" +a = f"" +a = F"" +a = rf"" +a = fr"" +a = fu"" +a = uf"" +a = bf"" +a = fb"" +a = ufr"" # python 3.3 @@ -35,7 +35,7 @@ a = b"" a = u"" a = r"" -a = ur"" +a = ur"" a = b"" a = br"" @@ -43,14 +43,14 @@ a = br"" a = u"" a = r"" -a = ur"" +a = ur"" # combined, PY-32321 -b = u"" b"" -b = r"" b"" -b = f"" b"" +b = u"" b"" +b = r"" b"" +b = f"" b"" # never was available -a = rr"" -a = bb"" -a = uu"" \ No newline at end of file +a = rr"" +a = bb"" +a = uu"" \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/trailingCommaAfterStarArgs.py b/python/testData/inspections/PyCompatibilityInspection/trailingCommaAfterStarArgs.py index 3c225470b709..0dfe512412f0 100644 --- a/python/testData/inspections/PyCompatibilityInspection/trailingCommaAfterStarArgs.py +++ b/python/testData/inspections/PyCompatibilityInspection/trailingCommaAfterStarArgs.py @@ -2,5 +2,5 @@ def foo(*args, **kwargs): print(args, kwargs) -foo(1, 2, 3, *[3],) -foo(1, 2, 3, *[3], **{'d': 'd'},) +foo(1, 2, 3, *[3],) +foo(1, 2, 3, *[3], **{'d': 'd'},) diff --git a/python/testData/inspections/PyCompatibilityInspection/tryFinallyEmptyRaisePy3.py b/python/testData/inspections/PyCompatibilityInspection/tryFinallyEmptyRaisePy3.py index f2bf13030630..e68eccf7d1f3 100644 --- a/python/testData/inspections/PyCompatibilityInspection/tryFinallyEmptyRaisePy3.py +++ b/python/testData/inspections/PyCompatibilityInspection/tryFinallyEmptyRaisePy3.py @@ -1,4 +1,4 @@ try: raise ValueError finally: - raise \ No newline at end of file + raise \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/underscoreBz2Module.py b/python/testData/inspections/PyCompatibilityInspection/underscoreBz2Module.py index 870868fb0053..3514027b3be8 100644 --- a/python/testData/inspections/PyCompatibilityInspection/underscoreBz2Module.py +++ b/python/testData/inspections/PyCompatibilityInspection/underscoreBz2Module.py @@ -1 +1 @@ -import _bz2 \ No newline at end of file +import _bz2 \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/underscoresInNumericLiterals.py b/python/testData/inspections/PyCompatibilityInspection/underscoresInNumericLiterals.py index e5d364dcba8e..1729ddc90f54 100644 --- a/python/testData/inspections/PyCompatibilityInspection/underscoresInNumericLiterals.py +++ b/python/testData/inspections/PyCompatibilityInspection/underscoresInNumericLiterals.py @@ -1,58 +1,58 @@ # hex -0xCAFE_F00D +0xCAFE_F00D # oct -0o1_23 -01_23 +0o1_23 +01_23 # bin -0b_0011_1111_0100_1110 +0b_0011_1111_0100_1110 # dec -10_000_000 +10_000_000 # pointfloat -10_00.00_23 -10_00. +10_00.00_23 +10_00. # exponentfloat -10_00.00_23e1_2 -10_00.00_23E1_2 -10_00.e1_2 -10_00.E1_2 +10_00.00_23e1_2 +10_00.00_23E1_2 +10_00.e1_2 +10_00.E1_2 -10_00.00_23e+1_2 -10_00.00_23E+1_2 -10_00.e+1_2 -10_00.E+1_2 +10_00.00_23e+1_2 +10_00.00_23E+1_2 +10_00.e+1_2 +10_00.E+1_2 -10_00.00_23e-1_2 -10_00.00_23E-1_2 -10_00.e-1_2 -10_00.E-1_2 +10_00.00_23e-1_2 +10_00.00_23E-1_2 +10_00.e-1_2 +10_00.E-1_2 -10_0000_23e1_2 -10_0000_23E1_2 -10_00e1_2 -10_00E1_2 +10_0000_23e1_2 +10_0000_23E1_2 +10_00e1_2 +10_00E1_2 -10_0000_23e+1_2 -10_0000_23E+1_2 -10_00e+1_2 -10_00E+1_2 +10_0000_23e+1_2 +10_0000_23E+1_2 +10_00e+1_2 +10_00E+1_2 -10_0000_23e-1_2 -10_0000_23E-1_2 -10_00e-1_2 -10_00E-1_2 +10_0000_23e-1_2 +10_0000_23E-1_2 +10_00e-1_2 +10_00E-1_2 # imag -10_00.00_23j -10_00.00_23J +10_00.00_23j +10_00.00_23J -10_00.00_23e1_2j -10_00.00_23e1_2J +10_00.00_23e1_2j +10_00.00_23e1_2J -10_000_000j -10_000_000J \ No newline at end of file +10_000_000j +10_000_000J \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/unpackingInNonParenthesizedTuplesInReturnAndYield.py b/python/testData/inspections/PyCompatibilityInspection/unpackingInNonParenthesizedTuplesInReturnAndYield.py index e41b329752da..82d3d8cafcb4 100644 --- a/python/testData/inspections/PyCompatibilityInspection/unpackingInNonParenthesizedTuplesInReturnAndYield.py +++ b/python/testData/inspections/PyCompatibilityInspection/unpackingInNonParenthesizedTuplesInReturnAndYield.py @@ -1,7 +1,7 @@ def gen(xs): - yield 42, *xs - yield from 42, *xs + yield 42, *xs + yield from 42, *xs def func(xs): - return 42, *xs + return 42, *xs diff --git a/python/testData/inspections/PyCompatibilityInspection/variableAnnotations.py b/python/testData/inspections/PyCompatibilityInspection/variableAnnotations.py index f5cbb701ec6c..0876a4555bc8 100644 --- a/python/testData/inspections/PyCompatibilityInspection/variableAnnotations.py +++ b/python/testData/inspections/PyCompatibilityInspection/variableAnnotations.py @@ -1,8 +1,8 @@ class C: - x: int - y: None = 42 + x: int + y: None = 42 def m(self, d): - x: List[bool] - d['foo']: str - (d['bar']): float + x: List[bool] + d['foo']: str + (d['bar']): float diff --git a/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy36.py b/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy36.py index ab26323feacb..cd8c0e615196 100644 --- a/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy36.py +++ b/python/testData/inspections/PyCompatibilityInspection/warningAboutAsyncAndAwaitInPy36.py @@ -1,14 +1,14 @@ -class async(object): +class async(object): pass -class await(object): +class await(object): pass -def async(): +def async(): pass -def await(): +def await(): pass -async = 1 -await = 2 \ No newline at end of file +async = 1 +await = 2 \ No newline at end of file diff --git a/python/testData/inspections/PyCompatibilityInspection/yieldInsideAsyncDef.py b/python/testData/inspections/PyCompatibilityInspection/yieldInsideAsyncDef.py index 3573a332b110..91a730eca616 100644 --- a/python/testData/inspections/PyCompatibilityInspection/yieldInsideAsyncDef.py +++ b/python/testData/inspections/PyCompatibilityInspection/yieldInsideAsyncDef.py @@ -1,5 +1,5 @@ -async def foo(x): - await x +async def foo(x): + await x yield x - yield from x + yield from x return x diff --git a/python/testData/inspections/ReplaceNotEqOperator.py b/python/testData/inspections/ReplaceNotEqOperator.py index 31af3639a987..ebf152813f46 100644 --- a/python/testData/inspections/ReplaceNotEqOperator.py +++ b/python/testData/inspections/ReplaceNotEqOperator.py @@ -1 +1 @@ -print(a <> b) \ No newline at end of file +print(a <> b) \ No newline at end of file diff --git a/python/testData/inspections/ReplacePrint.py b/python/testData/inspections/ReplacePrint.py index 66d520df4eeb..4aab7a5a8191 100644 --- a/python/testData/inspections/ReplacePrint.py +++ b/python/testData/inspections/ReplacePrint.py @@ -1 +1 @@ -print "foo" \ No newline at end of file +print "foo" \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveTrailingSuffixQuickFixTest/fixl.py b/python/testData/quickFixes/PyRemoveTrailingSuffixQuickFixTest/fixl.py index f61ec245ccb7..13ac094a923d 100644 --- a/python/testData/quickFixes/PyRemoveTrailingSuffixQuickFixTest/fixl.py +++ b/python/testData/quickFixes/PyRemoveTrailingSuffixQuickFixTest/fixl.py @@ -1 +1 @@ -1000l \ No newline at end of file +1000l \ No newline at end of file diff --git a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncClassInPy36.py b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncClassInPy36.py index 8281f1dba11f..8b6cadcddea8 100644 --- a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncClassInPy36.py +++ b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncClassInPy36.py @@ -1,2 +1,2 @@ -class async(object): +class async(object): pass \ No newline at end of file diff --git a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncFunctionInPy36.py b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncFunctionInPy36.py index e1ca9c6a2993..add7f982609e 100644 --- a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncFunctionInPy36.py +++ b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncFunctionInPy36.py @@ -1,2 +1,2 @@ -def async(): +def async(): pass \ No newline at end of file diff --git a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncVariableInPy36.py b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncVariableInPy36.py index 0b02b513a89b..4a7efc4225f8 100644 --- a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncVariableInPy36.py +++ b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAsyncVariableInPy36.py @@ -1 +1 @@ -async = 1 \ No newline at end of file +async = 1 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitClassInPy36.py b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitClassInPy36.py index f398068f0efe..d1ef03bdc59d 100644 --- a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitClassInPy36.py +++ b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitClassInPy36.py @@ -1,2 +1,2 @@ -class await(object): +class await(object): pass \ No newline at end of file diff --git a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitFunctionInPy36.py b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitFunctionInPy36.py index 412641b13c24..fdcab4a11057 100644 --- a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitFunctionInPy36.py +++ b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitFunctionInPy36.py @@ -1,2 +1,2 @@ -def await(): +def await(): pass \ No newline at end of file diff --git a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitVariableInPy36.py b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitVariableInPy36.py index d62315e04309..ce8563c92eef 100644 --- a/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitVariableInPy36.py +++ b/python/testData/quickFixes/PyRenameElementQuickFixTest/renameAwaitVariableInPy36.py @@ -1 +1 @@ -await = 1 \ No newline at end of file +await = 1 \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java index a93892b34a8e..7abe153c5b1f 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java @@ -229,7 +229,7 @@ public class PyCompatibilityInspectionTest extends PyInspectionTestCase { runWithLanguageLevel( LanguageLevel.PYTHON38, () -> doTestByText( - "def f(pos1, /, pos_or_kwd, *, kwd1):\n" + + "def f(pos1, /, pos_or_kwd, *, kwd1):\n" + " pass" ) ); @@ -248,7 +248,7 @@ public class PyCompatibilityInspectionTest extends PyInspectionTestCase { " try:\n" + " print(\"a\")\n" + " finally:\n" + - " continue") + " continue") ); }