From a840901bf819bcebd036144c46c14ff96acb1352 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 26 Jul 2013 17:06:05 +0400 Subject: [PATCH 1/7] Fixed searching for a user skeleton file for a Python package --- .../codeInsight/userSkeletons/PyUserSkeletonsUtil.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java index 84e81ae8b8d0..8e5eca8e53b7 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java @@ -86,7 +86,10 @@ public class PyUserSkeletonsUtil { final VirtualFile directory = getUserSkeletonsDirectory(); if (directory != null) { final PsiDirectory psiDirectory = PsiManager.getInstance(project).findDirectory(directory); - final PsiElement fileSkeleton = new QualifiedNameResolverImpl(qName).resolveModuleAt(psiDirectory); + PsiElement fileSkeleton = new QualifiedNameResolverImpl(qName).resolveModuleAt(psiDirectory); + if (fileSkeleton instanceof PsiDirectory) { + fileSkeleton = PyUtil.getPackageElement((PsiDirectory)fileSkeleton); + } if (fileSkeleton instanceof PyFile) { cache.put(cacheQName, Collections.singletonList(fileSkeleton)); return (PyFile)fileSkeleton; From e6faf2683d5388dc39c78631a8aec8e3cee8fcb2 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 26 Jul 2013 17:47:26 +0400 Subject: [PATCH 2/7] Ask module members providers when resolving names in import statements --- .../python/psi/impl/PyStarImportElementImpl.java | 12 +++++++++--- .../python/psi/resolve/ResolveImportUtil.java | 12 ++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java index 98a3d8ee17ed..a657d8226e70 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java @@ -6,7 +6,10 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.HashSet; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.PyResolveUtil; +import com.jetbrains.python.psi.resolve.RatedResolveResult; +import com.jetbrains.python.psi.types.PyModuleType; import com.jetbrains.python.toolbox.ChainIterable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -53,13 +56,16 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo final PsiElement source = PyUtil.turnDirIntoInit(importedFile); if (source instanceof PyFile) { PyFile sourceFile = (PyFile)source; - final PsiElement exportedName = sourceFile.getElementNamed(name); - if (exportedName != null) { + final PyModuleType moduleType = new PyModuleType(sourceFile); + final List results = moduleType.resolveMember(name, null, AccessDirection.READ, + PyResolveContext.defaultContext()); + final PsiElement result = results != null && !results.isEmpty() ? results.get(0).getElement() : null; + if (result != null) { final List all = sourceFile.getDunderAll(); if (all != null && !all.contains(name)) { continue; } - return exportedName; + return result; } } } diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 9527d30f82ea..1cf482a5fdfd 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -15,6 +15,7 @@ import com.intellij.util.containers.HashSet; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.*; +import com.jetbrains.python.psi.types.PyModuleType; import com.jetbrains.python.psi.types.PyType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -248,6 +249,7 @@ public class ResolveImportUtil { PsiDirectory dir = null; PsiElement ret = null; PsiElement possible_ret = null; + final PyResolveContext resolveContext = PyResolveContext.defaultContext(); if (parent instanceof PyFileImpl) { if (PyNames.INIT_DOT_PY.equals(((PyFile)parent).getName())) { // gobject does weird things like '_gobject = sys.modules['gobject._gobject'], so it's preferable to look at @@ -258,9 +260,12 @@ public class ResolveImportUtil { // OTOH, quite often a module named foo exports a class or function named foo, which is used as a fallback // by a module one level higher (e.g. curses.set_key). Prefer it to submodule if possible. - PsiElement elementNamed = ((PyFile)parent).getElementNamed(referencedName); - if (!fileOnly || PyUtil.instanceOf(elementNamed, PsiFile.class, PsiDirectory.class)) { - ret = elementNamed; + final PyModuleType moduleType = new PyModuleType((PyFile)parent); + final List results = moduleType.resolveMember(referencedName, null, AccessDirection.READ, + resolveContext); + final PsiElement moduleMember = results != null && !results.isEmpty() ? results.get(0).getElement() : null; + if (!fileOnly || PyUtil.instanceOf(moduleMember, PsiFile.class, PsiDirectory.class)) { + ret = moduleMember; } if (ret != null && !PyUtil.instanceOf(ret, PsiFile.class, PsiDirectory.class) && PsiTreeUtil.getStubOrPsiParentOfType(ret, PyExceptPart.class) == null) { @@ -273,7 +278,6 @@ public class ResolveImportUtil { dir = (PsiDirectory)parent; } else if (parent != null) { - final PyResolveContext resolveContext = PyResolveContext.defaultContext(); PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, resolveContext.getTypeEvalContext(), null); if (refType != null) { final List result = refType.resolveMember(referencedName, null, AccessDirection.READ, resolveContext); From 1a754deebd94871243900d977f66b228c92a375f Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 26 Jul 2013 19:35:07 +0400 Subject: [PATCH 3/7] Concatenation instead of StringBuilder --- .../jetbrains/python/psi/impl/PyStarImportElementImpl.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java index a657d8226e70..f8e4afa3676d 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java @@ -97,9 +97,7 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo } public String getLocationString() { - StringBuilder buf = new StringBuilder("| "); - buf.append("from ").append(getName()).append(" import *"); - return buf.toString(); + return "| " + "from " + getName() + " import *"; } public Icon getIcon(final boolean open) { From 1bdd8205621dc3782bf1816240ba37b8605f5a35 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 26 Jul 2013 19:59:44 +0400 Subject: [PATCH 4/7] Code insight for dynamic members of 'nose.tools' (PY-7614) --- .../NoseToolsDynamicMembers/a.py | 16 ++++++++++++++++ .../NoseToolsDynamicMembers/nose/__init__.py | 0 .../nose/tools/__init__.py | 2 ++ .../PyUnresolvedReferencesInspectionTest.java | 5 +++++ 4 files changed, 23 insertions(+) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/a.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/nose/__init__.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/nose/tools/__init__.py diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/a.py new file mode 100644 index 000000000000..ea8c3d9fa2e0 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/a.py @@ -0,0 +1,16 @@ +from nose.tools import assert_equal, ok_ +from nose import tools +import nose.tools + + +def test(): + ok_('foo') + assert_equal('foo', 'bar') + tools.assert_equal('foo', 'bar') + nose.tools.assert_equal('foo', 'bar') + + foo('foo') + tools.foo('foo') + nose.tools.foo('foo') + + diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/nose/__init__.py b/python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/nose/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/nose/tools/__init__.py b/python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/nose/tools/__init__.py new file mode 100644 index 000000000000..e751b7abbdc6 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/NoseToolsDynamicMembers/nose/tools/__init__.py @@ -0,0 +1,2 @@ +def ok_(expr, msg=None): + pass diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index d64bde673520..fe5a51684aa6 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -276,6 +276,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + // PY-7614 + public void testNoseToolsDynamicMembers() { + doMultiFileTest("a.py"); + } + private void doTest() { myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py"); myFixture.enableInspections(PyUnresolvedReferencesInspection.class); From 732aa2e94666caca87098dc97abdd34950d0dbc0 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 26 Jul 2013 19:16:41 +0200 Subject: [PATCH 5/7] deprecate RuntimeConfiguration and remove most of its remaining usages --- .../python/testing/PythonTRunnerConsoleProperties.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/testing/PythonTRunnerConsoleProperties.java b/python/src/com/jetbrains/python/testing/PythonTRunnerConsoleProperties.java index 3ef7e10d4778..2aabe173471a 100644 --- a/python/src/com/jetbrains/python/testing/PythonTRunnerConsoleProperties.java +++ b/python/src/com/jetbrains/python/testing/PythonTRunnerConsoleProperties.java @@ -1,7 +1,7 @@ package com.jetbrains.python.testing; import com.intellij.execution.Executor; -import com.intellij.execution.configurations.RuntimeConfiguration; +import com.intellij.execution.configurations.ModuleRunConfiguration; import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties; import com.jetbrains.django.testRunner.DjangoTestsRunConfiguration; @@ -13,7 +13,7 @@ public class PythonTRunnerConsoleProperties extends SMTRunnerConsoleProperties { private final boolean myIsEditable; - public PythonTRunnerConsoleProperties(final RuntimeConfiguration config, final Executor executor) { + public PythonTRunnerConsoleProperties(final ModuleRunConfiguration config, final Executor executor) { super(config, FRAMEWORK_NAME, executor); myIsEditable = config instanceof DjangoTestsRunConfiguration; From f93540c69e996a38da0743010447f774bbf82058 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 29 Jul 2013 11:23:40 +0400 Subject: [PATCH 6/7] new jira connector --- python/build/plugin-list.txt | 1 - python/main_pycharm.iml | 1 - 2 files changed, 2 deletions(-) diff --git a/python/build/plugin-list.txt b/python/build/plugin-list.txt index 9508ab3add3c..16916991e06d 100644 --- a/python/build/plugin-list.txt +++ b/python/build/plugin-list.txt @@ -26,7 +26,6 @@ hg4idea tasks tasks-core tasks-api -jira-connector github webDeployment jdbc-console diff --git a/python/main_pycharm.iml b/python/main_pycharm.iml index 2306c40fc09d..df3756f3fb34 100644 --- a/python/main_pycharm.iml +++ b/python/main_pycharm.iml @@ -28,7 +28,6 @@ - From facef3b711cdb22454690eaeb7dc7d67d12c420a Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 29 Jul 2013 13:02:51 +0400 Subject: [PATCH 7/7] IDEA-108183 XML: auto-popup completion for attribute values with enum --- python/src/com/jetbrains/python/editor/PythonSpaceHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/editor/PythonSpaceHandler.java b/python/src/com/jetbrains/python/editor/PythonSpaceHandler.java index 8872677f6151..7fa829bded33 100644 --- a/python/src/com/jetbrains/python/editor/PythonSpaceHandler.java +++ b/python/src/com/jetbrains/python/editor/PythonSpaceHandler.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.NotNull; */ public class PythonSpaceHandler extends TypedHandlerDelegate { @Override - public Result charTyped(char c, Project project, Editor editor, @NotNull PsiFile file) { + public Result charTyped(char c, Project project, @NotNull Editor editor, @NotNull PsiFile file) { CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); if (c == ' ' && codeInsightSettings.JAVADOC_STUB_ON_ENTER) { int offset = editor.getCaretModel().getOffset();