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 @@
-
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;
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();
diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java
index 98a3d8ee17ed..f8e4afa3676d 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 extends RatedResolveResult> 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;
}
}
}
@@ -91,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) {
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 extends RatedResolveResult> 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 extends RatedResolveResult> result = refType.resolveMember(referencedName, null, AccessDirection.READ, resolveContext);
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;
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);