PY-13140 Top-level module names starting with underscore are not imported via wildcard import

This commit is contained in:
Mikhail Golubev
2014-07-10 15:09:49 +04:00
parent b6eee002b0
commit e0ddef7bf1
9 changed files with 61 additions and 2 deletions
@@ -15,6 +15,8 @@
*/
package com.jetbrains.python.psi.impl;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.psi.PsiElement;
@@ -50,7 +52,13 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo
for (PsiElement importedFile : new HashSet<PsiElement>(importedFiles)) { // resolver gives lots of duplicates
final PsiElement source = PyUtil.turnDirIntoInit(importedFile);
if (source instanceof PyFile) {
chain.add(((PyFile) source).iterateNames());
// PY-13140
Iterable<PyElement> declaredNames = ((PyFile)source).iterateNames();
// Filter out names starting with underscore only if __all__ attribute is not defined in the module
if (((PyFile)source).getDunderAll() == null) {
declaredNames = excludeUnderscoredNames(declaredNames);
}
chain.add(declaredNames);
}
}
return chain;
@@ -58,6 +66,19 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo
return Collections.emptyList();
}
private static Iterable<PyElement> excludeUnderscoredNames(Iterable<PyElement> declaredNames) {
return Iterables.filter(declaredNames, new Predicate<PyElement>() {
@Override
public boolean apply(@Nullable PyElement input) {
String name = input != null ? input.getName() : null;
if (name != null && name.startsWith("_")) {
return false;
}
return true;
}
});
}
@Nullable
public PsiElement getElementNamed(final String name) {
if (PyUtil.isClassPrivateName(name)) {
@@ -76,7 +97,8 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo
final PsiElement result = results != null && !results.isEmpty() ? results.get(0).getElement() : null;
if (result != null) {
final List<String> all = sourceFile.getDunderAll();
if (all != null && !all.contains(name)) {
// PY-13140
if (all != null ? !all.contains(name) : name.startsWith("_")) {
continue;
}
return result;
@@ -0,0 +1,5 @@
from lib import *
normal_name
<error descr="Unresolved reference '_private_name'">_private_name</error>
<error descr="Unresolved reference '__magic_name__'">__magic_name__</error>
@@ -0,0 +1,3 @@
normal_name = 'spam'
private_name = 'ham'
__magic_name__ = 'green eggs'
@@ -0,0 +1 @@
_private_name = "spam"
@@ -0,0 +1,5 @@
from ImportedFile import *
_private_name
# <ref>
@@ -0,0 +1,4 @@
__all__ = [
"_private_name",
]
_private_name = "spam"
@@ -0,0 +1,5 @@
from ImportedFile import *
_private_name
# <ref>
@@ -363,4 +363,14 @@ public class PyMultiFileResolveTest extends PyMultiFileResolveTestCase {
public void testFromPackageModuleImportStarElementNamedAsModule() {
assertResolvesTo(PyFunction.class, "foo");
}
// PY-13140
public void testModulePrivateName() {
assertNull(doResolve());
}
// PY-13140
public void testModulePrivateNameInDunderAll() {
assertResolvesTo(PyTargetExpression.class, "_private_name");
}
}
@@ -366,6 +366,10 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase {
doMultiFileTest();
}
public void testPrivateModuleNames() {
doMultiFileTest();
}
@NotNull
@Override
protected Class<? extends PyInspection> getInspectionClass() {