diff --git a/python/psi-api/src/com/jetbrains/python/psi/resolve/PyCanonicalPathProvider.java b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyCanonicalPathProvider.java new file mode 100644 index 000000000000..e8a367182ccf --- /dev/null +++ b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyCanonicalPathProvider.java @@ -0,0 +1,15 @@ +package com.jetbrains.python.psi.resolve; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.jetbrains.python.psi.impl.PyQualifiedName; +import org.jetbrains.annotations.Nullable; + +/** + * @author yole + */ +public interface PyCanonicalPathProvider { + ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.canonicalPathProvider"); + + @Nullable + PyQualifiedName getCanonicalPath(PyQualifiedName qName); +} diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index bc9052c66c95..1f08b32a97e7 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -761,6 +761,7 @@ + @@ -780,6 +781,7 @@ + diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibCanonicalPathProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibCanonicalPathProvider.java new file mode 100644 index 000000000000..80bb33481f70 --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibCanonicalPathProvider.java @@ -0,0 +1,58 @@ +package com.jetbrains.python.codeInsight.stdlib; + +import com.jetbrains.python.psi.impl.PyQualifiedName; +import com.jetbrains.python.psi.resolve.PyCanonicalPathProvider; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author yole + */ +public class PyStdlibCanonicalPathProvider implements PyCanonicalPathProvider { + @Nullable + @Override + public PyQualifiedName getCanonicalPath(PyQualifiedName qName) { + return restoreStdlibCanonicalPath(qName); + } + + public static PyQualifiedName restoreStdlibCanonicalPath(PyQualifiedName qName) { + if (qName.getComponentCount() > 0) { + final List components = qName.getComponents(); + final String head = components.get(0); + if (head.equals("_abcoll") || head.equals("_collections")) { + components.set(0, "collections"); + return PyQualifiedName.fromComponents(components); + } + else if (head.equals("posix") || head.equals("nt")) { + components.set(0, "os"); + return PyQualifiedName.fromComponents(components); + } + else if (head.equals("_functools")) { + components.set(0, "functools"); + return PyQualifiedName.fromComponents(components); + } + else if (head.equals("_struct")) { + components.set(0, "struct"); + return PyQualifiedName.fromComponents(components); + } + else if (head.equals("_io") || head.equals("_pyio") || head.equals("_fileio")) { + components.set(0, "io"); + return PyQualifiedName.fromComponents(components); + } + else if (head.equals("_datetime")) { + components.set(0, "datetime"); + return PyQualifiedName.fromComponents(components); + } + else if (head.equals("ntpath") || head.equals("posixpath") || head.equals("path")) { + final List result = new ArrayList(); + result.add("os"); + components.set(0, "path"); + result.addAll(components); + return PyQualifiedName.fromComponents(result); + } + } + return null; + } +} diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 6fa3dfca271c..6ff38392c1b5 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -71,7 +71,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { public PyType getConstructorType(@NotNull PyClass cls) { final String classQName = cls.getQualifiedName(); if (classQName != null) { - final PyQualifiedName canonicalQName = ResolveImportUtil.restoreStdlibCanonicalPath(PyQualifiedName.fromDottedString(classQName)); + final PyQualifiedName canonicalQName = PyStdlibCanonicalPathProvider.restoreStdlibCanonicalPath(PyQualifiedName.fromDottedString(classQName)); if (canonicalQName != null) { final PyQualifiedName qname = canonicalQName.append(PyNames.INIT); return getReturnTypeByQName(qname.toString(), cls); @@ -224,7 +224,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { module, c != null ? c.getName() + "." : "", result); - final PyQualifiedName qname = ResolveImportUtil.restoreStdlibCanonicalPath(PyQualifiedName.fromDottedString(result)); + final PyQualifiedName qname = PyStdlibCanonicalPathProvider.restoreStdlibCanonicalPath(PyQualifiedName.fromDottedString(result)); if (qname != null) { return qname.toString(); } diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index f4f06d7ca332..801e35f11953 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -2,7 +2,7 @@ package com.jetbrains.python.psi.resolve; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -260,7 +260,7 @@ public class ResolveImportUtil { @Nullable private static PythonPathCache getPathCache(PsiElement foothold) { PythonPathCache cache = null; - final Module module = ModuleUtil.findModuleForPsiElement(foothold); + final Module module = ModuleUtilCore.findModuleForPsiElement(foothold); if (module != null) { cache = PythonModulePathCache.getInstance(module); } @@ -545,54 +545,16 @@ public class ResolveImportUtil { } final PyQualifiedName qname = findShortestImportableQName(foothold != null ? foothold : symbol, virtualFile); if (qname != null) { - final PyQualifiedName restored = restoreStdlibCanonicalPath(qname); - if (restored != null) { - return restored; + for (PyCanonicalPathProvider provider : Extensions.getExtensions(PyCanonicalPathProvider.EP_NAME)) { + final PyQualifiedName restored = provider.getCanonicalPath(qname); + if (restored != null) { + return restored; + } } } return qname; } - @Nullable - public static PyQualifiedName restoreStdlibCanonicalPath(PyQualifiedName qname) { - if (qname.getComponentCount() > 0) { - final List components = qname.getComponents(); - final String head = components.get(0); - if (head.equals("_abcoll") || head.equals("_collections")) { - components.set(0, "collections"); - return PyQualifiedName.fromComponents(components); - } - else if (head.equals("posix") || head.equals("nt")) { - components.set(0, "os"); - return PyQualifiedName.fromComponents(components); - } - else if (head.equals("_functools")) { - components.set(0, "functools"); - return PyQualifiedName.fromComponents(components); - } - else if (head.equals("_struct")) { - components.set(0, "struct"); - return PyQualifiedName.fromComponents(components); - } - else if (head.equals("_io") || head.equals("_pyio") || head.equals("_fileio")) { - components.set(0, "io"); - return PyQualifiedName.fromComponents(components); - } - else if (head.equals("_datetime")) { - components.set(0, "datetime"); - return PyQualifiedName.fromComponents(components); - } - else if (head.equals("ntpath") || head.equals("posixpath") || head.equals("path")) { - final List result = new ArrayList(); - result.add("os"); - components.set(0, "path"); - result.addAll(components); - return PyQualifiedName.fromComponents(result); - } - } - return null; - } - /** * @param element what we test (identifier, reference, import element, etc) * @return the how the element relates to an enclosing import statement, if any