diff --git a/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml b/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml index 8bb1c12111b7..0393b6068c8a 100644 --- a/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml +++ b/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml @@ -131,7 +131,7 @@ - + @@ -171,7 +171,7 @@ - + diff --git a/python/python-psi-impl/resources/messages/PyPsiBundle.properties b/python/python-psi-impl/resources/messages/PyPsiBundle.properties index fa4f31eb719a..5339603bf24c 100644 --- a/python/python-psi-impl/resources/messages/PyPsiBundle.properties +++ b/python/python-psi-impl/resources/messages/PyPsiBundle.properties @@ -442,7 +442,6 @@ INSP.pep8.naming=PEP 8 naming convention violation INSP.pep8.naming.excluded.base.classes=Excluded base classes INSP.pep8.naming.ignored.errors=Ignored errors INSP.shadowing.builtins=Shadowing built-ins -INSP.dunder.slots=Definition of __slots__ in a class INSP.final.classes.methods.and.variables=Final classes, methods and variables INSP.global.undefined=Global variable is undefined at the module level INSP.inconsistent.indentation=Inconsistent indentation @@ -487,7 +486,6 @@ INSP.stub.packages.compatibility.incompatible.packages.message=''{0}{1}{2}'' is INSP.arguments.not.declared.but.provided.by.decorator=Following arguments are not declared but provided by decorator: {0} INSP.abstract.class=Class must implement all abstract methods INSP.assigning.function.call.that.doesnt.return.anything=Assigning function call that doesn't return anything -INSP.deprecated.function.class.or.module=Deprecated function, class or module INSP.mandatory.encoding=No encoding specified for file INSP.missing.type.hints=Missing type hinting for function definition INSP.overloads.in.regular.python.files=Overloads in regular Python files @@ -603,12 +601,15 @@ INSP.classic.class.usage.old.style.class.ancestors=Old-style class, because all # PyExceptionInheritance INSP.NAME.exception.not.inherit=Exception doesn't inherit from standard ''Exception'' class +INSP.exception.inheritance.exception.does.not.inherit.from.base.exception.class=Exception doesn't inherit from base 'Exception' class # PyDefaultArgumentInspection INSP.NAME.default.argument=Default argument is mutable +INSP.default.arguments.default.argument.value.mutable=Default argument value is mutable # PyDocstringTypesInspection INSP.NAME.docstring.types=Type in docstring doesn't match inferred type +INSP.docstring.types.dynamically.inferred.type.does.not.match.specified.type=Dynamically inferred type ''{0}'' doesn''t match specified type ''{1}'' # PyStatementEffectInspection INSP.NAME.statement.effect=Statement has no effect @@ -734,6 +735,7 @@ INSP.NAME.set.function.to.literal=Function call can be replaced with set literal # PyDecoratorInspection INSP.NAME.decorator.outside.class=Class specific decorator on method outside class +INSP.decorators.method.only.decorator.on.method.outside.class=Decorator {0} on method outside class # PyPackageRequirementsInspection INSP.NAME.requirements=Package requirements @@ -786,9 +788,11 @@ INSP.comparison.with.none.performed.with.equality.operators=Comparison with None # PyDictCreationInspection INSP.NAME.dict.creation=Dictionary creation could be rewritten by dictionary literal +INSP.dict.creation.this.dictionary.creation.could.be.rewritten.as.dictionary.literal=This dictionary creation could be rewritten as a dictionary literal # PyDictDuplicateKeysInspection INSP.NAME.duplicate.keys=Dictionary contains duplicate keys +INSP.duplicate.keys.dictionary.contains.duplicate.keys=Dictionary contains duplicate keys ''{0}'' # PyFromFutureImportInspection INSP.NAME.from.future.import=from __future__ import must be the first executable statement @@ -906,6 +910,14 @@ INSP.python.trailing.suffix.not.support=Python does not support a trailing ''{0} # PyInterpreterInspection python.sdk.no.interpreter.configured.owner=No Python interpreter configured for the {0} +# PyDeprecationInspection +INSP.NAME.deprecated.function.class.or.module=Deprecated function, class or module +INSP.deprecation.abc.decorator.deprecated.use.alternative=''{0}'' is deprecated since Python 3.3. Use ''{1}'' with ''{2}'' instead + +INSP.NAME.dunder.slots=Definition of __slots__ in a class +INSP.dunder.slots.name.in.slots.conflicts.with.class.variable=''{0}'' in __slots__ conflicts with class variable +INSP.dunder.slots.class.object.attribute.read.only=''{0}'' object attribute ''{1}'' is read-only + # PyInspectionsSuppressor INSP.python.suppressor.suppress.for.function=Suppress for function INSP.python.suppressor.suppress.for.class=Suppress for class diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDecoratorInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDecoratorInspection.java index 184970aaeb92..9eaa0b051f78 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDecoratorInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDecoratorInspection.java @@ -18,6 +18,7 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElementVisitor; +import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.inspections.quickfix.RemoveDecoratorQuickFix; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyDecorator; @@ -59,7 +60,8 @@ public class PyDecoratorInspection extends PyInspection { for (PyDecorator decorator : decorators.getDecorators()) { String name = decorator.getText(); if (name.equals("@classmethod") || name.equals("@staticmethod")) - registerProblem(decorator, "Decorator " + name + " on method outside class", new RemoveDecoratorQuickFix()); + registerProblem(decorator, PyPsiBundle.message("INSP.decorators.method.only.decorator.on.method.outside.class", name), + new RemoveDecoratorQuickFix()); } } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDefaultArgumentInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDefaultArgumentInspection.java index cca918bdb403..792432d8a6ab 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDefaultArgumentInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDefaultArgumentInspection.java @@ -18,6 +18,7 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElementVisitor; +import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.inspections.quickfix.PyDefaultArgumentQuickFix; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyNamedParameter; @@ -47,7 +48,8 @@ public class PyDefaultArgumentInspection extends PyInspection { public void visitPyNamedParameter(PyNamedParameter node) { final PyExpression defaultValue = node.getDefaultValue(); if (PyUtil.isForbiddenMutableDefault(defaultValue, myTypeEvalContext)) { - registerProblem(defaultValue, "Default argument value is mutable", new PyDefaultArgumentQuickFix()); + registerProblem(defaultValue, PyPsiBundle.message("INSP.default.arguments.default.argument.value.mutable"), + new PyDefaultArgumentQuickFix()); } } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDeprecationInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDeprecationInspection.java index e0e58d05a66d..050f1339c313 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDeprecationInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDeprecationInspection.java @@ -19,9 +19,11 @@ import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.NlsSafe; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator; import com.jetbrains.python.pyi.PyiUtil; @@ -59,7 +61,7 @@ public class PyDeprecationInspection extends PyInspection { final PsiElement element = importStatement.resolveImportSource(); if (resolveResult != null && element != resolveResult.getContainingFile()) return; } - String deprecationMessage = null; + @NlsSafe String deprecationMessage = null; if (resolveResult instanceof PyFunction) { deprecationMessage = ((PyFunction)resolveResult).getDeprecationMessage(); } @@ -100,8 +102,10 @@ public class PyDeprecationInspection extends PyInspection { } final KnownDecorator abcAbsMethod = KnownDecorator.ABC_ABSTRACTMETHOD; - final String message = "'" + deprecated.getQualifiedName() + "' is deprecated since Python 3.3. " + - "Use '" + builtin.getQualifiedName() + "' with '" + abcAbsMethod.getQualifiedName() + "' instead."; + final String message = PyPsiBundle.message("INSP.deprecation.abc.decorator.deprecated.use.alternative", + deprecated.getQualifiedName(), + builtin.getQualifiedName(), + abcAbsMethod.getQualifiedName()); registerProblem(decorator, message, ProblemHighlightType.LIKE_DEPRECATED); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDictCreationInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDictCreationInspection.java index 73492e2fe85c..ffd31972499c 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDictCreationInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDictCreationInspection.java @@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.inspections.quickfix.DictCreationQuickFix; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; @@ -68,7 +69,9 @@ public class PyDictCreationInspection extends PyInspection { if (targets == null) return; if (!targets.isEmpty()) { - registerProblem(node, "This dictionary creation could be rewritten as a dictionary literal", new DictCreationQuickFix(node)); + registerProblem(node, + PyPsiBundle.message("INSP.dict.creation.this.dictionary.creation.could.be.rewritten.as.dictionary.literal"), + new DictCreationQuickFix(node)); break; } statement = PsiTreeUtil.getNextSiblingOfType(assignmentStatement, PyStatement.class); diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java index 88bc48e9ec4b..8bf066fda82f 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java @@ -19,11 +19,13 @@ import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.util.containers.MultiMap; +import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.inspections.quickfix.PyRemoveDictKeyQuickFix; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; @@ -127,12 +129,13 @@ public class PyDictDuplicateKeysInspection extends PyInspection { private void registerProblems(@NotNull MultiMap keyValueAndKeys, LocalQuickFix @NotNull ... quickFixes) { for (Map.Entry> entry : keyValueAndKeys.entrySet()) { - final String keyValue = entry.getKey(); + final @NlsSafe String keyValue = entry.getKey(); final Collection keys = entry.getValue(); if (keys.size() > 1) { for (PsiElement key : keys) { - registerProblem(key, "Dictionary contains duplicate keys '" + unwrapStringKey(keyValue) + "'", quickFixes); + String unquotedKey = unwrapStringKey(keyValue); + registerProblem(key, PyPsiBundle.message("INSP.duplicate.keys.dictionary.contains.duplicate.keys", unquotedKey), quickFixes); } } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java index f392f57118d9..2866148642b9 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java @@ -3,6 +3,7 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.NlsSafe; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.SmartPointerManager; @@ -69,16 +70,14 @@ public class PyDocstringTypesInspection extends PyInspection { } for (String param : docString.getParameters()) { - Substring type = docString.getParamTypeSubstring(param); + @NlsSafe Substring type = docString.getParamTypeSubstring(param); if (type != null) { String dynamicType = signature.getArgTypeQualifiedName(param); if (dynamicType != null) { - String dynamicTypeShortName = getShortestImportableName(function, dynamicType); + @NlsSafe String dynamicTypeShortName = getShortestImportableName(function, dynamicType); if (!match(function, dynamicType, type.getValue())) { - registerProblem(node, "Dynamically inferred type '" + - dynamicTypeShortName + - "' doesn't match specified type '" + - type + "'", + registerProblem(node, PyPsiBundle.message("INSP.docstring.types.dynamically.inferred.type.does.not.match.specified.type", + dynamicTypeShortName, type), ProblemHighlightType.WEAK_WARNING, null, type.getTextRange(), new ChangeTypeQuickFix(param, type, dynamicTypeShortName, node) ); diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDunderSlotsInspection.kt b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDunderSlotsInspection.kt index 4edaa0aa9e3b..3d7b672858bb 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDunderSlotsInspection.kt +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDunderSlotsInspection.kt @@ -5,6 +5,7 @@ import com.intellij.codeInspection.LocalInspectionToolSession import com.intellij.codeInspection.ProblemsHolder import com.intellij.psi.PsiElementVisitor import com.jetbrains.python.PyNames +import com.jetbrains.python.PyPsiBundle import com.jetbrains.python.psi.* import com.jetbrains.python.psi.impl.PyPsiUtils import com.jetbrains.python.psi.types.PyClassType @@ -57,7 +58,7 @@ class PyDunderSlotsInspection : PyInspection() { val classAttribute = pyClass.findClassAttribute(name, false, myTypeEvalContext) if (classAttribute != null && classAttribute.hasAssignedValue()) { - registerProblem(slot, "'$name' in __slots__ conflicts with class variable") + registerProblem(slot, PyPsiBundle.message("INSP.dunder.slots.name.in.slots.conflicts.with.class.variable", name)) } } @@ -71,7 +72,7 @@ class PyDunderSlotsInspection : PyInspection() { val qualifierType = myTypeEvalContext.getType(qualifier) if (qualifierType is PyClassType && !qualifierType.isAttributeWritable(targetName, myTypeEvalContext)) { - registerProblem(target, "'${qualifierType.name}' object attribute '$targetName' is read-only") + registerProblem(target, PyPsiBundle.message("INSP.dunder.slots.class.object.attribute.read.only", qualifierType.name, targetName)) } } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyExceptionInheritInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyExceptionInheritInspection.java index 91003f6920b2..caa92e04909c 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyExceptionInheritInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyExceptionInheritInspection.java @@ -20,6 +20,7 @@ import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiPolyVariantReference; +import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.inspections.quickfix.PyAddExceptionSuperClassQuickFix; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.types.PyClassLikeType; @@ -67,7 +68,9 @@ public class PyExceptionInheritInspection extends PyInspection { return; } } - registerProblem(expression, "Exception doesn't inherit from base 'Exception' class", new PyAddExceptionSuperClassQuickFix()); + registerProblem(expression, + PyPsiBundle.message("INSP.exception.inheritance.exception.does.not.inherit.from.base.exception.class"), + new PyAddExceptionSuperClassQuickFix()); } } } diff --git a/python/testData/deprecation/abcDeprecatedAbstracts.py b/python/testData/deprecation/abcDeprecatedAbstracts.py index 2c4ea6ce8023..81b5af0d51f6 100644 --- a/python/testData/deprecation/abcDeprecatedAbstracts.py +++ b/python/testData/deprecation/abcDeprecatedAbstracts.py @@ -2,7 +2,7 @@ import abc class A(metaclass=abc.ABCMeta): - @abc.abstractproperty + @abc.abstractproperty def prop(self): pass @@ -11,7 +11,7 @@ from abc import abstractproperty class B(metaclass=abc.ABCMeta): - @abstractproperty + @abstractproperty def prop(self): pass @@ -20,7 +20,7 @@ from abc import abstractproperty as ap class C(metaclass=abc.ABCMeta): - @ap + @ap def prop(self): pass @@ -29,16 +29,16 @@ import abc as foo class D(metaclass=abc.ABCMeta): - @foo.abstractproperty + @foo.abstractproperty def prop(self): pass class A: - @abc.abstractclassmethod + @abc.abstractclassmethod def foo(cls): pass - @abc.abstractstaticmethod + @abc.abstractstaticmethod def bar(): pass \ No newline at end of file