From 6dbebc943eb44e302ef313aa4b0aae7046f56fbb Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 27 Aug 2012 17:09:04 +0400 Subject: [PATCH 01/13] fixed PY-7306 Packaging: do not run separate background tasks for multi-selection upgrade --- .../python/packaging/ui/PyPackagesPanel.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/python/src/com/jetbrains/python/packaging/ui/PyPackagesPanel.java b/python/src/com/jetbrains/python/packaging/ui/PyPackagesPanel.java index 070403435431..d7c7d50bdeb3 100644 --- a/python/src/com/jetbrains/python/packaging/ui/PyPackagesPanel.java +++ b/python/src/com/jetbrains/python/packaging/ui/PyPackagesPanel.java @@ -183,7 +183,6 @@ public class PyPackagesPanel extends JPanel { final int[] rows = myPackagesTable.getSelectedRows(); final Sdk selectedSdk = mySelectedSdk; if (selectedSdk != null) { - final List requirements = new ArrayList(); for (int row : rows) { final Object pyPackage = myPackagesTableModel.getValueAt(row, 0); if (pyPackage instanceof PyPackage) { @@ -195,10 +194,10 @@ public class PyPackagesPanel extends JPanel { public void handleResult(Object result, URL url, String method) { final List releases = (List)result; PyPIPackageUtil.INSTANCE.addPackageReleases(packageName, releases); - if (releases.isEmpty() || - PyRequirement.VERSION_COMPARATOR.compare((String)currentVersion, releases.get(0)) < 0) { - requirements.add(new PyRequirement(packageName)); - } + if (!releases.isEmpty() && + PyRequirement.VERSION_COMPARATOR.compare((String)currentVersion, releases.get(0)) >= 0) + return; + ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { @@ -227,7 +226,7 @@ public class PyPackagesPanel extends JPanel { } } }); - ui.install(requirements, Collections.singletonList("-U")); + ui.install(Collections.singletonList(new PyRequirement(packageName)), Collections.singletonList("-U")); myUpgradeButton.setEnabled(false); } }, ModalityState.any()); From 3d6d9d370ae6cb746cdc9d19ff8ae649fdd699b8 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 27 Aug 2012 18:03:18 +0400 Subject: [PATCH 02/13] fixed PY-7294 Invalid warning about encodings in Python files --- .../jetbrains/python/inspections/PyNonAsciiCharInspection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java b/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java index 1ea1aae25773..f24d4e6cbc1b 100644 --- a/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyNonAsciiCharInspection.java @@ -76,7 +76,7 @@ public class PyNonAsciiCharInspection extends PyInspection { @Override public void visitPyStringLiteralExpression(PyStringLiteralExpression node) { - checkString(node, node.getStringValue()); + checkString(node, node.getText()); } } From fb2957ff6fb76f44ae4b7fd60bfbbbc774ec2617 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 27 Aug 2012 19:06:03 +0400 Subject: [PATCH 03/13] fixed PY-7096 Insert type assertion should be disabled for references introduced in list comprehensions --- .../python/codeInsight/intentions/TypeAssertionIntention.java | 1 + 1 file changed, 1 insertion(+) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java index fe8fd6f985da..cbaccf3b6f9d 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java @@ -54,6 +54,7 @@ public class TypeAssertionIntention implements IntentionAction { if (problemElement.getParent() instanceof PyCallExpression || PsiTreeUtil.getParentOfType(problemElement, PyListCompExpression.class) != null || PsiTreeUtil.getParentOfType(problemElement, PyLambdaExpression.class) != null || + PsiTreeUtil.getParentOfType(problemElement, PyGeneratorExpression.class) != null || (reference != null && reference.resolve() == null)) { return false; } From 1fae7b975401ee258ebaeb91d9296c1b8de53d73 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 27 Aug 2012 16:59:40 +0200 Subject: [PATCH 04/13] don't highlight first parameter of staticmethods in metaclasses (PY-6648) --- .../PyMethodParametersInspection.java | 23 +++--- .../PyMethodParametersInspection/expected.xml | 58 -------------- .../PyMethodParametersInspection/test.py | 80 +++++++++++++++++++ .../python/PythonInspectionsTest.java | 3 +- 4 files changed, 94 insertions(+), 70 deletions(-) delete mode 100644 python/testData/inspections/PyMethodParametersInspection/expected.xml create mode 100644 python/testData/inspections/PyMethodParametersInspection/test.py diff --git a/python/src/com/jetbrains/python/inspections/PyMethodParametersInspection.java b/python/src/com/jetbrains/python/inspections/PyMethodParametersInspection.java index a09b7a4d8507..54ea4dc26c67 100644 --- a/python/src/com/jetbrains/python/inspections/PyMethodParametersInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyMethodParametersInspection.java @@ -83,7 +83,7 @@ public class PyMethodParametersInspection extends PyInspection { if (flags != null) { PyParameterList plist = node.getParameterList(); PyParameter[] params = plist.getParameters(); - final String method_name = node.getName(); + final String methodName = node.getName(); final String CLS = "cls"; // TODO: move to style settings final String MCS = "mcs"; // as per pylint inspection C0203 if (params.length == 0) { // fix: add @@ -138,27 +138,30 @@ public class PyMethodParametersInspection extends PyInspection { return; } if (flags.isMetaclassMethod()) { - String expected_name; + if (flags.isStaticMethod() && !PyNames.NEW.equals(methodName)) { + return; + } + String expectedName; String alternativeName = null; - if (PyNames.NEW.equals(method_name) || flags.isClassMethod()) { - expected_name = MCS; + if (PyNames.NEW.equals(methodName) || flags.isClassMethod()) { + expectedName = MCS; } else if (flags.isSpecialMetaclassMethod()) { - expected_name = CLS; + expectedName = CLS; } else { - expected_name = PyNames.CANONICAL_SELF; + expectedName = PyNames.CANONICAL_SELF; alternativeName = CLS; } - if (!expected_name.equals(pname) && (alternativeName == null || !alternativeName.equals(pname))) { + if (!expectedName.equals(pname) && (alternativeName == null || !alternativeName.equals(pname))) { registerProblem( PyUtil.sure(params[0].getNode()).getPsi(), - PyBundle.message("INSP.usually.named.$0", expected_name), - new RenameParameterQuickFix(expected_name) + PyBundle.message("INSP.usually.named.$0", expectedName), + new RenameParameterQuickFix(expectedName) ); } } - else if (flags.isClassMethod() || PyNames.NEW.equals(method_name)) { + else if (flags.isClassMethod() || PyNames.NEW.equals(methodName)) { if (!CLS.equals(pname)) { registerProblem( PyUtil.sure(params[0].getNode()).getPsi(), diff --git a/python/testData/inspections/PyMethodParametersInspection/expected.xml b/python/testData/inspections/PyMethodParametersInspection/expected.xml deleted file mode 100644 index 6eb21015da29..000000000000 --- a/python/testData/inspections/PyMethodParametersInspection/expected.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - first_arg.py - 13 - Usually first parameter of a method is named 'self' - - - first_arg.py - 16 - Method must have a first parameter, usually called 'self' - - - first_arg.py - 19 - First parameter of a non-static method must not be a tuple - - - first_arg.py - 25 - Usually first parameter of such methods is named 'cls' - - - first_arg.py - 29 - Usually first parameter of such methods is named 'cls' - - - first_arg.py - 34 - Usually first parameter of such methods is named 'cls' - - - first_arg.py - 39 - Usually first parameter of such methods is named 'cls' - - - first_arg.py - 62 - Usually first parameter of such methods is named 'self' - - - first_arg.py - 65 - Usually first parameter of such methods is named 'mcs' - - - first_arg.py - 68 - Usually first parameter of such methods is named 'cls' - - - first_arg.py - 75 - Usually first parameter of such methods is named 'mcs' - - diff --git a/python/testData/inspections/PyMethodParametersInspection/test.py b/python/testData/inspections/PyMethodParametersInspection/test.py new file mode 100644 index 000000000000..e03b8e9bd366 --- /dev/null +++ b/python/testData/inspections/PyMethodParametersInspection/test.py @@ -0,0 +1,80 @@ +def foo(bar): + pass # nothing + +def __call__(foo): + pass # nothing, out of class + +def innocent(f): + "innocent deco" + return f + +class Foo(object): + + def __init__(a, b): + pass # rename a + + def foo(): + pass # propose self + + def loo((l, g), *rest): + pass # complain at tuple + + def zoo(*animals): + pass # nothing + + def __new__(self): + pass # propose cls + + @classmethod + def boo(self): + pass # propose cls + + @classmethod + @innocent + def boo(self): + pass # propose cls + + @innocent + @classmethod + def boo(self): + pass # propose cls + + @staticmethod + def moo(a): + pass # nothing + + @staticmethod + def qoo((x, y, z), t): + pass # nothing + + @staticmethod + @innocent + def qoo((x, y, z), t): + pass # nothing + + @innocent + @staticmethod + def qoo((x, y, z), t): + pass # nothing + +class Meta(type): + + def foo(first): # rename to "self" + pass + + def __new__(self, *rest): # rename to "mcs" + pass + + def __call__(self): # rename to "cls" + pass + + def bar(cls): # <- rename to "self" + return "foobar" + + @classmethod + def baz(moo): # <- rename to "mcs" + return "foobar" + + @staticmethod + def bazz(param1): + return "foobar" diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java index 8f63f47a57ab..2952720da43d 100644 --- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java +++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java @@ -49,8 +49,7 @@ public class PythonInspectionsTest extends PyTestCase { } public void testPyMethodParametersInspection() { - LocalInspectionTool inspection = new PyMethodParametersInspection(); - doTest(getTestName(false), inspection); + doHighlightingTest(PyMethodParametersInspection.class); } public void testPyNestedDecoratorsInspection() { From 7eaf3be1b04aed76867cc066e5d6390c43727805 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 27 Aug 2012 17:07:52 +0200 Subject: [PATCH 05/13] highlight first parameter of __new__ (PY-5942) --- .../jetbrains/python/validation/HighlightingAnnotator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java b/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java index 99ea5b579f11..9b66ae61d5f1 100644 --- a/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java +++ b/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java @@ -4,6 +4,7 @@ import com.intellij.lang.annotation.Annotation; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import com.jetbrains.cython.psi.CythonClass; +import com.jetbrains.python.PyNames; import com.jetbrains.python.highlighting.PyHighlighter; import com.jetbrains.python.psi.*; @@ -48,6 +49,9 @@ public class HighlightingAnnotator extends PyAnnotator { if (cls instanceof CythonClass && ((CythonClass)cls).isCppClass()) { return false; } + if (PyNames.NEW.equals(function.getName())) { + return true; + } final PyFunction.Modifier modifier = function.getModifier(); if (modifier != PyFunction.Modifier.CLASSMETHOD && modifier != PyFunction.Modifier.STATICMETHOD) { return true; From 7d0e6a2f58d075b82b0b069a82cfac3333b4ca17 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 27 Aug 2012 19:29:05 +0400 Subject: [PATCH 06/13] Fixed platform-independent SDK flavor for Python 3.3 virtualenvs --- .../jetbrains/python/sdk/VirtualEnvSdkFlavor.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/python/src/com/jetbrains/python/sdk/VirtualEnvSdkFlavor.java b/python/src/com/jetbrains/python/sdk/VirtualEnvSdkFlavor.java index aa31aa950cc0..c9ea879fbcfd 100644 --- a/python/src/com/jetbrains/python/sdk/VirtualEnvSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/VirtualEnvSdkFlavor.java @@ -112,19 +112,7 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { @Override public boolean isValidSdkPath(@NotNull File file) { if (!super.isValidSdkPath(file)) return false; - File bin = file.getParentFile(); - if (bin != null) { - File[] children = bin.listFiles(); - if (children != null) { - for (File f : children) { - //is it good enough to determine virtual env? - if (f.getName().equals("activate_this.py")) { - return true; - } - } - } - } - return false; + return PythonSdkType.getVirtualEnvRoot(file.getPath()) != null; } @Override From 5ee402d1c690bac6f169e87ac2a60c82dfbccedc Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 27 Aug 2012 19:30:08 +0400 Subject: [PATCH 07/13] Don't cache temporary SDK packaging manager for setting up Python 3.3 virtualenv --- .../com/jetbrains/python/packaging/PyPackageManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index f252bc25e109..58d71a17787f 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -498,7 +498,7 @@ public class PyPackageManagerImpl extends PyPackageManager { if (binaryFile != null) { final ProjectJdkImpl tmpSdk = new ProjectJdkImpl("", PythonSdkType.getInstance()); tmpSdk.setHomePath(path); - final PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManagers.getInstance().forSdk(tmpSdk); + final PyPackageManagerImpl manager = new PyPackageManagerImpl(tmpSdk); manager.installManagement(DISTRIBUTE); manager.installManagement(PIP); } From 21941c4f51ada48fe61270d190a9413a955db103 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 27 Aug 2012 19:39:45 +0400 Subject: [PATCH 08/13] fixed PY-7089 Insert type assertion: leads to syntactically incorrect code when invoked for one-line function --- .../python/codeInsight/intentions/TypeAssertionIntention.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java index cbaccf3b6f9d..1292036bbc39 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java @@ -44,7 +44,7 @@ public class TypeAssertionIntention implements IntentionAction { PyExpression problemElement = PsiTreeUtil.getTopmostParentOfType(file.findElementAt(editor.getCaretModel().getOffset()-1), PyQualifiedExpression.class); if (problemElement == null) return false; - if (problemElement instanceof PyQualifiedExpression && ((PyQualifiedExpression)problemElement).getReferencedName() == null) { + if (problemElement instanceof PyQualifiedExpression) { final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier(); if (qualifier != null && !qualifier.getText().equals(PyNames.CANONICAL_SELF)) { problemElement = qualifier; From 5db6ed1df7a0a8b122a02d61b9ccf7daff7a5024 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 27 Aug 2012 20:00:06 +0400 Subject: [PATCH 09/13] Support for implicit namespace packages in Python 3.3 (PY-7156) --- .../src/com/jetbrains/python/psi/PyUtil.java | 3 +++ .../FromPython33NamespacePackageImport.py | 4 ++++ .../p1/m1.py | 2 ++ .../Python33NamespacePackage.py | 4 ++++ .../python33NamespacePackage/p1/m1.py | 2 ++ .../python/PyMultiFileResolveTest.java | 23 +++++++++++++++++++ 6 files changed, 38 insertions(+) create mode 100644 python/testData/resolve/multiFile/fromPython33NamespacePackageImport/FromPython33NamespacePackageImport.py create mode 100644 python/testData/resolve/multiFile/fromPython33NamespacePackageImport/p1/m1.py create mode 100644 python/testData/resolve/multiFile/python33NamespacePackage/Python33NamespacePackage.py create mode 100644 python/testData/resolve/multiFile/python33NamespacePackage/p1/m1.py diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index a741eb981fd9..7cd8ea4f44bc 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -648,6 +648,9 @@ public class PyUtil { if (turnDirIntoInit(directory) != null) { return true; } + if (LanguageLevel.forFile(directory.getVirtualFile()).isAtLeast(LanguageLevel.PYTHON33)) { + return true; + } return hasNamespacePackageFile(directory); } diff --git a/python/testData/resolve/multiFile/fromPython33NamespacePackageImport/FromPython33NamespacePackageImport.py b/python/testData/resolve/multiFile/fromPython33NamespacePackageImport/FromPython33NamespacePackageImport.py new file mode 100644 index 000000000000..e5b0a6241440 --- /dev/null +++ b/python/testData/resolve/multiFile/fromPython33NamespacePackageImport/FromPython33NamespacePackageImport.py @@ -0,0 +1,4 @@ +from p1.m1 import foo + +foo() +# diff --git a/python/testData/resolve/multiFile/fromPython33NamespacePackageImport/p1/m1.py b/python/testData/resolve/multiFile/fromPython33NamespacePackageImport/p1/m1.py new file mode 100644 index 000000000000..6584985db844 --- /dev/null +++ b/python/testData/resolve/multiFile/fromPython33NamespacePackageImport/p1/m1.py @@ -0,0 +1,2 @@ +def foo(): + pass \ No newline at end of file diff --git a/python/testData/resolve/multiFile/python33NamespacePackage/Python33NamespacePackage.py b/python/testData/resolve/multiFile/python33NamespacePackage/Python33NamespacePackage.py new file mode 100644 index 000000000000..259a9bd59848 --- /dev/null +++ b/python/testData/resolve/multiFile/python33NamespacePackage/Python33NamespacePackage.py @@ -0,0 +1,4 @@ +import p1 + +p1 +# diff --git a/python/testData/resolve/multiFile/python33NamespacePackage/p1/m1.py b/python/testData/resolve/multiFile/python33NamespacePackage/p1/m1.py new file mode 100644 index 000000000000..6584985db844 --- /dev/null +++ b/python/testData/resolve/multiFile/python33NamespacePackage/p1/m1.py @@ -0,0 +1,2 @@ +def foo(): + pass \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java index 1166b9921072..68440e23bb0e 100644 --- a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java @@ -404,6 +404,29 @@ public class PyMultiFileResolveTest extends PyResolveTestCase { assertResolvesTo(PyFunction.class, "foo"); } + // PY-7156 + public void testPython33NamespacePackage() { + setLanguageLevel(LanguageLevel.PYTHON33); + try { + final PsiElement element = doResolve(); + assertInstanceOf(element, PyImportedModule.class); + final PyImportedModule module = (PyImportedModule)element; + assertEquals("p1", module.getImportedPrefix().toString()); + } finally { + setLanguageLevel(null); + } + } + + // PY-7156 + public void testFromPython33NamespacePackageImport() { + setLanguageLevel(LanguageLevel.PYTHON33); + try { + assertResolvesTo(PyFunction.class, "foo"); + } finally { + setLanguageLevel(null); + } + } + private void prepareTestDirectory() { final String testName = getTestName(true); myFixture.copyDirectoryToProject(testName, ""); From 7723851c902c4647447db53c87b9b830a95a01b1 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 27 Aug 2012 20:59:00 +0400 Subject: [PATCH 10/13] Fixed unresolved reference false negative when referencing a class within its definition's suite (PY-5995) --- .../python/psi/impl/references/PyReferenceImpl.java | 5 ++++- .../PyUnresolvedReferencesInspection/classInClassBody.py | 4 ++++ .../inspections/PyUnresolvedReferencesInspectionTest.java | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/classInClassBody.py diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index b6b927948913..18a343707758 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -215,7 +215,10 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference final ScopeOwner owner = ScopeUtil.getScopeOwner(uexpr); if (owner != null) { final Scope scope = ControlFlowCache.getScope(owner); - if (owner == originalOwner && !scope.isGlobal(referencedName)) { + if (uexpr == originalOwner && originalOwner instanceof PyClass) { + uexpr = null; + } + else if (owner == originalOwner && !scope.isGlobal(referencedName)) { final ResolveResultList latest = resolveToLatestDefs(owner, myElement, referencedName); if (!latest.isEmpty()) { return latest; diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/classInClassBody.py b/python/testData/inspections/PyUnresolvedReferencesInspection/classInClassBody.py new file mode 100644 index 000000000000..4429bc65b2cb --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/classInClassBody.py @@ -0,0 +1,4 @@ +class C: + print(C) #fail + def f(self): + print(C) #pass \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index b4a532e133df..49d530b3777f 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -180,6 +180,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + // PY-5995 + public void testClassInClassBody() { + doTest(); + } + private void doTest() { myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py"); myFixture.enableInspections(PyUnresolvedReferencesInspection.class); From 67633f3d097c181b31bcafe25c984022ddbf947b Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 27 Aug 2012 18:05:29 +0200 Subject: [PATCH 11/13] complete 'as' keyword in 'except' (PY-1846) --- .../PyKeywordCompletionContributor.java | 9 +++++++- .../python/PythonCompletionTest.java | 22 +++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java index d20e65754516..7d750beaf938 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java @@ -236,6 +236,13 @@ public class PyKeywordCompletionContributor extends CompletionContributor { .inside(PyWithStatement.class) ); + private static final PsiElementPattern.Capture IN_EXCEPT_AFTER_REF = + psiElement().afterLeaf(psiElement() + .withElementType(PyTokenTypes.IDENTIFIER) + .inside(PyReferenceExpression.class) + .inside(PyExceptPart.class) + ); + private static final PsiElementPattern.Capture IN_COND_STMT = psiElement().inside(psiElement(PyStatementList.class).inside(psiElement(PyConditionalStatementPart.class))); @@ -526,7 +533,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { extend( CompletionType.BASIC, psiElement() .withLanguage(PythonLanguage.getInstance()) - .andOr(IN_IMPORT_AFTER_REF, IN_WITH_AFTER_REF) + .andOr(IN_IMPORT_AFTER_REF, IN_WITH_AFTER_REF, IN_EXCEPT_AFTER_REF) .andNot(AFTER_QUALIFIER) , new PyKeywordCompletionProvider("as") diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index c91ecf6fd1e3..c2c0c3442a11 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -523,12 +523,14 @@ public class PythonCompletionTest extends PyTestCase { } public void testTypeMembers() { // PY-5311 - myFixture.configureByText(PythonFileType.INSTANCE, "a = 'string'\n" + - "a."); + assertFalse(doTestByText("a = 'string'\n" + + "a.").contains("mro")); + } + private List doTestByText(String text) { + myFixture.configureByText(PythonFileType.INSTANCE, text); myFixture.completeBasic(); - final List strings = myFixture.getLookupElementStrings(); - assertFalse(strings.contains("mro")); + return myFixture.getLookupElementStrings(); } public void testDunderAllReference() { // PY-5502 @@ -588,4 +590,16 @@ public class PythonCompletionTest extends PyTestCase { public void testUnknownNewReturnType() { // PY-6671 doTest(); } + + public void testAsInWith() { // PY-3701 + setLanguageLevel(LanguageLevel.PYTHON27); + assertTrue(doTestByText("with foo ").contains("as")); + } + + public void testAsInExcept() { // PY-1846 + setLanguageLevel(LanguageLevel.PYTHON27); + assertTrue(doTestByText("try:\n" + + " pass\n" + + "except IOError ").contains("as")); + } } From c7580aa265943ed6583a2d7007b558cef35c0071 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 27 Aug 2012 18:24:29 +0200 Subject: [PATCH 12/13] skip building skeleton for pynestkernel (PY-2087) --- python/helpers/generator3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 6a3be8d504fd..f2ab969f76cf 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -2280,7 +2280,7 @@ def is_mac_skipped_module(path, f): return 0 def is_skipped_module(path, f): - return is_mac_skipped_module(path, f) or is_posix_skipped_module(path, f[:f.rindex('.')]) + return is_mac_skipped_module(path, f) or is_posix_skipped_module(path, f[:f.rindex('.')]) or 'pynestkernel' in path def is_module(d, root): From bc43da0bce81eccf1c95e4da3a8533737978af64 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 27 Aug 2012 19:09:49 +0200 Subject: [PATCH 13/13] when looking for target element, if the previous write of a reference is an augmented assignment, resolve to original declaration (PY-3698) --- python/src/META-INF/python-plugin-common.xml | 2 + .../codeInsight/PyTargetElementEvaluator.java | 42 +++++++++++++++++++ .../refactoring/rename/renameAugAssigned.py | 3 ++ .../rename/renameAugAssigned_after.py | 3 ++ .../python/refactoring/PyRenameTest.java | 4 ++ 5 files changed, 54 insertions(+) create mode 100644 python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java create mode 100644 python/testData/refactoring/rename/renameAugAssigned.py create mode 100644 python/testData/refactoring/rename/renameAugAssigned_after.py diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index a10887e3ebdf..d91bb7d804aa 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -88,6 +88,8 @@ + + diff --git a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java new file mode 100644 index 000000000000..75056b874fce --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java @@ -0,0 +1,42 @@ +package com.jetbrains.python.codeInsight; + +import com.intellij.codeInsight.TargetElementEvaluator; +import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; +import com.jetbrains.python.psi.PyReferenceExpression; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.resolve.QualifiedResolveResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author yole + */ +public class PyTargetElementEvaluator implements TargetElementEvaluator { + @Override + public boolean includeSelfInGotoImplementation(@NotNull PsiElement element) { + return false; + } + + @Nullable + @Override + public PsiElement getElementByReference(PsiReference ref, int flags) { + if ((flags & TargetElementUtilBase.ELEMENT_NAME_ACCEPTED) == 0){ + return null; + } + final PsiElement element = ref.getElement(); + PsiElement result = ref.resolve(); + if (result instanceof PyReferenceExpression && + PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == PsiTreeUtil.getParentOfType(result, ScopeOwner.class)) { + QualifiedResolveResult resolveResult = ((PyReferenceExpression)result).followAssignmentsChain(PyResolveContext.noImplicits()); + PsiElement finalResult = resolveResult.getElement(); + if (PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == PsiTreeUtil.getParentOfType(finalResult, ScopeOwner.class)) { + return finalResult; + } + } + return result; + } +} diff --git a/python/testData/refactoring/rename/renameAugAssigned.py b/python/testData/refactoring/rename/renameAugAssigned.py new file mode 100644 index 000000000000..ac3483ed7c03 --- /dev/null +++ b/python/testData/refactoring/rename/renameAugAssigned.py @@ -0,0 +1,3 @@ +def cover(lab=1): + lab += 1 + return lab diff --git a/python/testData/refactoring/rename/renameAugAssigned_after.py b/python/testData/refactoring/rename/renameAugAssigned_after.py new file mode 100644 index 000000000000..214457f8878f --- /dev/null +++ b/python/testData/refactoring/rename/renameAugAssigned_after.py @@ -0,0 +1,3 @@ +def cover(bar=1): + bar += 1 + return bar diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java index f196e27d3f4d..58cf712cfcec 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java @@ -87,6 +87,10 @@ public class PyRenameTest extends PyTestCase { doTest("bar"); } + public void testRenameAugAssigned() { // PY-3698 + doTest("bar"); + } + public void testRenameProperty() { // PY-5948 setLanguageLevel(LanguageLevel.PYTHON26); try {