diff --git a/python/helpers/pydev/pydev_monkey.py b/python/helpers/pydev/pydev_monkey.py index 8a5471dd959d..33569151ef56 100644 --- a/python/helpers/pydev/pydev_monkey.py +++ b/python/helpers/pydev/pydev_monkey.py @@ -63,7 +63,14 @@ def patch_args(args): return new_args def args_to_str(args): - return ' '.join(x if x.startswith('"') and x.endswith('"') else '"%s"' % x for x in args) + quoted_args = [] + for x in args: + if x.startswith('"') and x.endswith('"'): + quoted_args.append(x) + else: + quoted_args.append('"%s"' % x) + + return ' '.join(quoted_args) def remove_quotes(str): if str.startswith('"') and str.endswith('"'): diff --git a/python/main_pycharm.iml b/python/main_pycharm.iml index a30072725174..598ba4739eb0 100644 --- a/python/main_pycharm.iml +++ b/python/main_pycharm.iml @@ -25,6 +25,9 @@ + + + diff --git a/python/src/com/jetbrains/python/codeInsight/PyDunderAllReference.java b/python/src/com/jetbrains/python/codeInsight/PyDunderAllReference.java index b06a549f2f69..73e987c90e9e 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyDunderAllReference.java +++ b/python/src/com/jetbrains/python/codeInsight/PyDunderAllReference.java @@ -1,5 +1,8 @@ package com.jetbrains.python.codeInsight; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; @@ -9,6 +12,7 @@ import com.intellij.psi.ResolveState; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.util.ArrayUtil; import com.jetbrains.python.psi.PyFile; +import com.jetbrains.python.psi.PyImportElement; import com.jetbrains.python.psi.PyStringLiteralExpression; import com.jetbrains.python.psi.PyUtil; import com.jetbrains.python.psi.impl.LightNamedElement; @@ -41,7 +45,7 @@ public class PyDunderAllReference extends PsiReferenceBase result = new ArrayList(); + final List result = new ArrayList(); PyFile containingFile = (PyFile) getElement().getContainingFile().getOriginalFile(); final List dunderAll = containingFile.getDunderAll(); containingFile.processDeclarations(new PsiScopeProcessor() { @@ -50,7 +54,13 @@ public class PyDunderAllReference extends PsiReferenceBase> computeScopeVariables() throws DFALimitExceededException { + private synchronized void computeScopeVariables() throws DFALimitExceededException { computeFlow(); if (myCachedScopeVariables == null) { final PyReachingDefsDfaInstance dfaInstance = new PyReachingDefsDfaInstance(); @@ -62,7 +62,6 @@ public class ScopeImpl implements Scope { final DFAMapEngine engine = new DFAMapEngine(myFlow, dfaInstance, semilattice); myCachedScopeVariables = engine.performDFA(); } - return myCachedScopeVariables; } public boolean isGlobal(final String name) { @@ -196,6 +195,21 @@ public class ScopeImpl implements Scope { } } }); + + Collections.sort(nameDefiners, new Comparator() { + @Override + public int compare(NameDefiner d1, NameDefiner d2) { + return getPriority(d2) - getPriority(d1); + }; + + private int getPriority(NameDefiner nameDefiner) { + if (nameDefiner instanceof PyStarImportElement) { + return -10; + } + return 0; + } + }); + myNamedElements = namedElements; myNameDefiners = nameDefiners; myNestedScopes = nestedScopes; diff --git a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java index e76c4ab5f56c..7b4cd06c6d35 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java @@ -191,6 +191,9 @@ public class AddImportHelper { if (target != null && existingImport.getTextRange().getStartOffset() > target.getTextRange().getStartOffset()) { continue; } + if (existingImport.isStarImport()) { + continue; + } final PyQualifiedName qName = existingImport.getImportSourceQName(); if (qName != null && qName.toString().equals(path)) { for (PyImportElement el : existingImport.getImportElements()) { @@ -220,7 +223,7 @@ public class AddImportHelper { else if (useQualified) { addImportStatement(file, path, null, priority); final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(file.getProject()); - element.replace(elementGenerator.createExpressionFromText(qName + "." + target.getName())); + element.replace(elementGenerator.createExpressionFromText(LanguageLevel.forElement(target), qName + "." + target.getName())); } else { addImportFrom(file, null, path, target.getName(), null, priority); diff --git a/python/src/com/jetbrains/python/findUsages/PyClassFindUsagesHandler.java b/python/src/com/jetbrains/python/findUsages/PyClassFindUsagesHandler.java index 5ff7942a2228..72d52d3a9e49 100644 --- a/python/src/com/jetbrains/python/findUsages/PyClassFindUsagesHandler.java +++ b/python/src/com/jetbrains/python/findUsages/PyClassFindUsagesHandler.java @@ -7,6 +7,9 @@ import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.Collections; + /** * @author yole */ @@ -32,4 +35,12 @@ public class PyClassFindUsagesHandler extends FindUsagesHandler { protected boolean isSearchForTextOccurencesAvailable(PsiElement psiElement, boolean isSingleFile) { return true; } + + @Override + protected Collection getStringsToSearch(PsiElement element) { + if (element instanceof PyFunction && PyNames.INIT.equals(((PyFunction) element).getName())) { + return Collections.emptyList(); + } + return super.getStringsToSearch(element); + } } diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 53b14f82241d..676dba6b0d17 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -154,10 +154,24 @@ public class PyUnresolvedReferencesInspection extends PyInspection { final PyClass pyClass = ((PyClassType)type).getPyClass(); if (pyClass != null && pyClass.isNewStyleClass()) { final List slots = pyClass.getSlots(); - if (slots != null && !slots.contains(node.getReferencedName()) && !slots.contains("__dict__")) { + final String attrName = node.getReferencedName(); + if (slots != null && !slots.contains(attrName) && !slots.contains(PyNames.DICT)) { + for (PyClassRef ref : pyClass.iterateAncestors()) { + final PyClass ancestor = ref.getPyClass(); + if (ancestor == null) { + return; + } + if (PyNames.OBJECT.equals(ancestor.getName())) { + break; + } + final List ancestorSlots = ancestor.getSlots(); + if (ancestorSlots == null || ancestorSlots.contains(attrName) || ancestorSlots.contains(PyNames.DICT)) { + return; + } + } final ASTNode nameNode = node.getNameElement(); final PsiElement e = nameNode != null ? nameNode.getPsi() : node; - registerProblem(e, "'" + pyClass.getName() + "' object has no attribute '" + node.getReferencedName() + "'"); + registerProblem(e, "'" + pyClass.getName() + "' object has no attribute '" + attrName + "'"); } } } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManager.java b/python/src/com/jetbrains/python/packaging/PyPackageManager.java index 38cd937e6139..69a45b068993 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManager.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManager.java @@ -16,7 +16,6 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkAdditionalData; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.SystemInfo; @@ -28,7 +27,6 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.SystemProperties; import com.intellij.util.net.HttpConfigurable; -import com.intellij.util.ui.UIUtil; import com.jetbrains.python.PythonHelpersLocator; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyListLiteralExpression; @@ -564,19 +562,7 @@ public class PyPackageManager { do { processOutput = manager.runRemoteProcess(null, remoteSdkData, ArrayUtil.toStringArray(cmdline), askForSudo); if (askForSudo && processOutput.getStderr().contains("sudo: 3 incorrect password attempts")) { - final Ref cont = Ref.create(false); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - if (Messages.showOkCancelDialog("Incorrect sudo password", "Incorrect Password Attempt", Messages.getErrorIcon()) == - Messages.OK) { - cont.set(true); - } - } - }); - if (cont.get()) { - continue; - } + continue; } break; } diff --git a/python/src/com/jetbrains/python/packaging/PyRequirement.java b/python/src/com/jetbrains/python/packaging/PyRequirement.java index feb06b424df8..181b4c7e6d28 100644 --- a/python/src/com/jetbrains/python/packaging/PyRequirement.java +++ b/python/src/com/jetbrains/python/packaging/PyRequirement.java @@ -271,7 +271,7 @@ public class PyRequirement { @Nullable public PyPackage match(@NotNull List packages) { for (PyPackage pkg : packages) { - if (myName.equalsIgnoreCase(pkg.getName())) { + if (normalizeName(myName).equalsIgnoreCase(pkg.getName())) { for (VersionSpec spec : myVersionSpecs) { final int cmp = VERSION_COMPARATOR.compare(pkg.getVersion(), spec.getVersion()); final Relation relation = spec.getRelation(); diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java index f7bcb9668701..35512c774fac 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -183,9 +183,11 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { return null; } + @Nullable private PsiElement resolveDeclaration(String name, PsiElement result) { if (result instanceof PyImportElement) { - return findNameInImportElement(name, (PyImportElement)result); + final PyImportElement importElement = (PyImportElement)result; + return findNameInImportElement(name, importElement, importElement.getContainingImportStatement() instanceof PyFromImportStatement); } else if (result instanceof PyFromImportStatement) { return ((PyFromImportStatement) result).resolveImportSource(); @@ -557,7 +559,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { @Nullable private PsiElement findNameInImportStatement(String name, PyImportStatement child) { for (PyImportElement importElement: child.getImportElements()) { - final PsiElement result = findNameInImportElement(name, importElement); + final PsiElement result = findNameInImportElement(name, importElement, false); if (result != null) { return result; } @@ -566,8 +568,8 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { } @Nullable - private PsiElement findNameInImportElement(String name, PyImportElement importElement) { - final PsiElement result = importElement.getElementNamed(name, false); + private PsiElement findNameInImportElement(String name, PyImportElement importElement, final boolean resolveImportElement) { + final PsiElement result = importElement.getElementNamed(name, resolveImportElement); if (result != null) { return result; } diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java index b7556bc63820..c922230690c5 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java @@ -167,7 +167,7 @@ public class PyImportReference extends PyReferenceImpl { } public Object[] execute() { - int relative_level = -1; + int relativeLevel = -1; InsertHandler insertHandler = null; // NOTE: could use getPointInImport() @@ -191,9 +191,9 @@ public class PyImportReference extends PyReferenceImpl { } } else { // null source, must be a "from ... import" - relative_level = from_import.getRelativeLevel(); - if (relative_level > 0) { - PsiDirectory relative_dir = ResolveImportUtil.stepBackFrom(myCurrentFile, relative_level); + relativeLevel = from_import.getRelativeLevel(); + if (relativeLevel > 0) { + PsiDirectory relative_dir = ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel); if (relative_dir != null) { addImportedNames(from_import.getImportElements()); fillFromDir(relative_dir, null); @@ -204,7 +204,7 @@ public class PyImportReference extends PyReferenceImpl { else { // in "import _" or "from _ import" ASTNode n = myElement.getNode().getTreePrev(); while (n != null && n.getElementType() == PyTokenTypes.DOT) { - relative_level += 1; + relativeLevel += 1; n = n.getTreePrev(); } if (from_import != null) { @@ -221,21 +221,21 @@ public class PyImportReference extends PyReferenceImpl { } } // look at dir by level - if (myCurrentFile != null && (relative_level >= 0 || !ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile))) { + if (myCurrentFile != null && (relativeLevel >= 0 || !ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile))) { final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); if (containingDirectory != null) { PyQualifiedName thisQName = ResolveImportUtil.findShortestImportableQName(containingDirectory); - if (thisQName == null) { - fillFromDir(ResolveImportUtil.stepBackFrom(myCurrentFile, relative_level), insertHandler); + if (thisQName == null || thisQName.getComponentCount() == relativeLevel) { + fillFromDir(ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel), insertHandler); } - else if (thisQName.getComponentCount() >= relative_level) { - thisQName = thisQName.removeTail(relative_level); + else if (thisQName.getComponentCount() > relativeLevel) { + thisQName = thisQName.removeTail(relativeLevel); fillFromQName(thisQName, insertHandler); } } } } - if (relative_level == -1) { + if (relativeLevel == -1) { fillFromQName(PyQualifiedName.fromComponents(), insertHandler); } 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 0362c6d4d1cf..96ee92a8f3c8 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -75,6 +75,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference } // it is *not* final so that it can be changed in debug time. if set to false, caching is off + @SuppressWarnings("FieldCanBeLocal") private static boolean USE_CACHE = true; /** diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionProcessor.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionProcessor.java index 05bb77c03268..b627ea1fc73e 100644 --- a/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionProcessor.java +++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionProcessor.java @@ -4,10 +4,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiNamedElement; -import com.intellij.psi.PsiReference; +import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.ui.UsageViewDescriptorAdapter; @@ -100,10 +97,10 @@ public class PyMoveClassOrFunctionProcessor extends BaseRefactoringProcessor { PyClassRefactoringUtil.rememberNamedReferences(oldElement); final PsiNamedElement newElement = (PsiNamedElement)(dest.add(oldElement)); for (UsageInfo usage : usages) { - final PsiElement oldExpr = usage.getElement(); + final PsiElement usageElement = usage.getElement(); // TODO: Respect the qualified import style - if (oldExpr instanceof PyQualifiedExpression) { - PyQualifiedExpression qexpr = (PyQualifiedExpression)oldExpr; + if (usageElement instanceof PyQualifiedExpression) { + PyQualifiedExpression qexpr = (PyQualifiedExpression)usageElement; if (oldElement instanceof PyClass && PyNames.INIT.equals(qexpr.getName())) { continue; } @@ -112,22 +109,25 @@ public class PyMoveClassOrFunctionProcessor extends BaseRefactoringProcessor { PyClassRefactoringUtil.insertImport(newExpr, newElement, null, true); } } - if (oldExpr instanceof PyStringLiteralExpression) { - final PsiReference[] references = oldExpr.getReferences(); - for (PsiReference ref : references) { + if (usageElement instanceof PyStringLiteralExpression) { + for (PsiReference ref : usageElement.getReferences()) { if (ref instanceof DocStringTypeReference && ref.isReferenceTo(oldElement)) { ref.bindToElement(newElement); } } } else { - final PyImportStatementBase importStmt = PsiTreeUtil.getParentOfType(usage.getElement(), PyImportStatementBase.class); + final PyImportStatementBase importStmt = PsiTreeUtil.getParentOfType(usageElement, PyImportStatementBase.class); if (importStmt != null) { PyClassRefactoringUtil.updateImportOfElement(importStmt, newElement); } - if (usage.getFile() == oldFile && (oldExpr == null || !PsiTreeUtil.isAncestor(oldElement, oldExpr, false))) { + if (usage.getFile() == oldFile && (usageElement == null || !PsiTreeUtil.isAncestor(oldElement, usageElement, false))) { PyClassRefactoringUtil.insertImport(oldElement, newElement); } + if (usageElement != null && resolvesToLocalStarImport(usageElement)) { + PyClassRefactoringUtil.insertImport(usageElement, newElement); + new PyImportOptimizer().processFile(usageElement.getContainingFile()).run(); + } } } PyClassRefactoringUtil.restoreNamedReferences(newElement, oldElement); @@ -141,16 +141,38 @@ public class PyMoveClassOrFunctionProcessor extends BaseRefactoringProcessor { }, REFACTORING_NAME, null); } + @Override + protected String getCommandName() { + return REFACTORING_NAME; + } + + private boolean resolvesToLocalStarImport(@NotNull PsiElement element) { + final PsiReference ref = element.getReference(); + final List resolvedElements = new ArrayList(); + if (ref instanceof PsiPolyVariantReference) { + for (ResolveResult result : ((PsiPolyVariantReference)ref).multiResolve(false)) { + resolvedElements.add(result.getElement()); + } + } + else if (ref != null) { + resolvedElements.add(ref.resolve()); + } + final PsiFile containingFile = element.getContainingFile(); + if (containingFile != null) { + for (PsiElement resolved : resolvedElements) { + if (resolved instanceof PyStarImportElement && resolved.getContainingFile() == containingFile) { + return true; + } + } + } + return false; + } + private static void checkValidImportableFile(PsiElement anchor, VirtualFile file) { final PyQualifiedName qName = ResolveImportUtil.findShortestImportableQName(anchor, file); if (!PyClassRefactoringUtil.isValidQualifiedName(qName)) { throw new IncorrectOperationException(PyBundle.message("refactoring.move.class.or.function.error.cannot.use.module.name.$0", qName)); } } - - @Override - protected String getCommandName() { - return REFACTORING_NAME; - } } diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java index 6d01082b129c..4940f0018a5b 100644 --- a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java +++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java @@ -4,6 +4,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.RefactoringSettings; import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler; import com.intellij.usageView.UsageInfo; import com.intellij.util.IncorrectOperationException; @@ -38,7 +39,8 @@ public class PyMoveFileHandler extends MoveFileHandler { while (root != null && !roots.contains(root.getVirtualFile())) { root = root.getParentDirectory(); } - if (moveDestination != root && root != null) { + final boolean searchForReferences = RefactoringSettings.getInstance().MOVE_SEARCH_FOR_REFERENCES_FOR_FILE; + if (moveDestination != root && root != null && searchForReferences) { CreatePackageAction.createInitPyInHierarchy(moveDestination, root); } } diff --git a/python/src/com/jetbrains/python/remote/PyRemoteCancelledException.java b/python/src/com/jetbrains/python/remote/PyRemoteCancelledException.java new file mode 100644 index 000000000000..425747922612 --- /dev/null +++ b/python/src/com/jetbrains/python/remote/PyRemoteCancelledException.java @@ -0,0 +1,10 @@ +package com.jetbrains.python.remote; + +/** + * @author traff + */ +public class PyRemoteCancelledException extends PyRemoteInterpreterException { + public PyRemoteCancelledException(String s) { + super(s); + } +} diff --git a/python/src/com/jetbrains/python/remote/RemoteFile.java b/python/src/com/jetbrains/python/remote/RemoteFile.java index 3e80e0a22259..e5585c4a32dd 100644 --- a/python/src/com/jetbrains/python/remote/RemoteFile.java +++ b/python/src/com/jetbrains/python/remote/RemoteFile.java @@ -2,16 +2,19 @@ package com.jetbrains.python.remote; import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author traff */ public class RemoteFile { + private final boolean myWin; private final String myPath; public RemoteFile(@NotNull String path, boolean isWin) { myPath = toSystemDependent(path, isWin); + myWin = isWin; } public RemoteFile(@NotNull String parent, String child) { @@ -22,14 +25,19 @@ public class RemoteFile { this(resolveChild(parent, child, isWin), isWin); } - private static String resolveChild(@NotNull String parent, @NotNull String child, boolean win) { - String separator; - if (win) { - separator = "\\"; + @Nullable + public String getName() { + int ind = myPath.lastIndexOf(getSeparator(myWin)); + if (ind != -1 && ind < myPath.length() - 1) { //not last char + return myPath.substring(ind + 1); } else { - separator = "/"; + return null; } + } + + private static String resolveChild(@NotNull String parent, @NotNull String child, boolean win) { + String separator = getSeparator(win); String path; if (parent.endsWith(separator)) { @@ -41,6 +49,17 @@ public class RemoteFile { return path; } + private static String getSeparator(boolean win) { + String separator; + if (win) { + separator = "\\"; + } + else { + separator = "/"; + } + return separator; + } + public String getPath() { return myPath; diff --git a/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java b/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java index 4fbc2afe9bbe..ea75bc2f1ba4 100644 --- a/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java +++ b/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java @@ -24,7 +24,6 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.PythonModuleTypeBase; import com.jetbrains.python.debugger.remote.PyPathMappingSettings; import com.jetbrains.python.sdk.PythonEnvUtil; -import com.jetbrains.python.sdk.PythonSdkFlavor; import com.jetbrains.python.sdk.PythonSdkType; import org.jdom.Element; import org.jetbrains.annotations.Nullable; @@ -186,12 +185,6 @@ public abstract class AbstractPythonRunConfiguration suggestHomePaths() { + return Lists.newArrayList(); + } + + @Override + public boolean isValidSdkHome(String path) { + return StringUtil.isNotEmpty(path) && path.startsWith("ssh:") && checkName(NAMES, getExecutableName(path)); + } + + private static boolean checkName(String[] names, @Nullable String name) { + if (name == null) { + return false; + } + for (String n : names) { + if (name.startsWith(n)) { + return true; + } + } + return false; + } + + @Nullable + private static String getExecutableName(String path) { + return RemoteFile.detectSystemByPath(path).createRemoteFile(path).getName(); + } +} diff --git a/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java b/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java index e7098bb9af0f..64b22c1785ae 100644 --- a/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java +++ b/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java @@ -4,20 +4,20 @@ import com.google.common.collect.Maps; import com.intellij.execution.process.ProcessOutput; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; -import com.intellij.util.Processor; import com.jetbrains.python.PythonHelpersLocator; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.io.File; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import static com.jetbrains.python.sdk.SkeletonVersionChecker.fromVersionString; @@ -36,7 +36,11 @@ public class PySkeletonGenerator { public void finishSkeletonsGeneration() { } - static class ListBinariesResult { + public boolean exists(String name) { + return new File(name).exists(); + } + + protected static class ListBinariesResult { public final int generatorVersion; public final Map modules; diff --git a/python/src/com/jetbrains/python/sdk/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/PySkeletonRefresher.java index b9796826f6ef..b4b620df0a8d 100644 --- a/python/src/com/jetbrains/python/sdk/PySkeletonRefresher.java +++ b/python/src/com/jetbrains/python/sdk/PySkeletonRefresher.java @@ -18,7 +18,6 @@ import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; -import com.intellij.util.Processor; import com.intellij.util.SmartList; import com.intellij.util.io.ZipUtil; import com.jetbrains.python.PyBundle; @@ -425,7 +424,8 @@ public class PySkeletonRefresher { boolean canLive = headerMatcher != null && headerMatcher.matches(); if (canLive) { String sourceName = headerMatcher.group(1); - canLive = sourceName != null && (SkeletonVersionChecker.BUILTIN_NAME.equals(sourceName) || new File(sourceName).exists()); + canLive = + sourceName != null && (SkeletonVersionChecker.BUILTIN_NAME.equals(sourceName) || mySkeletonsGenerator.exists(sourceName)); } if (!canLive) { mySkeletonsGenerator.deleteOrLog(item); @@ -566,7 +566,7 @@ public class PySkeletonRefresher { return false; } - static class PyBinaryItem { + public static class PyBinaryItem { private String myPath; private String myModule; private long myLength; @@ -647,6 +647,11 @@ public class PySkeletonRefresher { if (versionString == null) { return null; } + + if (PySdkUtil.isRemote(mySdk)) { + return null; + } + String version = versionString.toLowerCase().replace(" ", "-"); File f; if (SystemInfo.isMac) { diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/PythonSdkFlavor.java index e93aa40c75f8..13d89bba101d 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkFlavor.java @@ -49,7 +49,7 @@ public abstract class PythonSdkFlavor { public static List getApplicableFlavors() { List result = new ArrayList(); - result.add(VirtualEnvSdkFlavor.INSTANCE); + if (SystemInfo.isWindows) { result.add(WinPythonSdkFlavor.INSTANCE); } @@ -71,6 +71,9 @@ public abstract class PythonSdkFlavor { result.add(JythonSdkFlavor.INSTANCE); result.add(IronPythonSdkFlavor.INSTANCE); result.add(PyPySdkFlavor.INSTANCE); + result.add(VirtualEnvSdkFlavor.INSTANCE); + result.add(PyRemoteSdkFlavor.INSTANCE); + return result; } diff --git a/python/testData/completion/dunderAllReferenceImport.after.py b/python/testData/completion/dunderAllReferenceImport.after.py new file mode 100644 index 000000000000..2011874196d6 --- /dev/null +++ b/python/testData/completion/dunderAllReferenceImport.after.py @@ -0,0 +1,3 @@ +from sys import hexversion + +__all__ = ['hexversion'] diff --git a/python/testData/completion/dunderAllReferenceImport.py b/python/testData/completion/dunderAllReferenceImport.py new file mode 100644 index 000000000000..d091b755ca27 --- /dev/null +++ b/python/testData/completion/dunderAllReferenceImport.py @@ -0,0 +1,3 @@ +from sys import hexversion + +__all__ = ['hexve'] diff --git a/python/testData/completion/relativeImportExcludeToplevel/pack/__init__.py b/python/testData/completion/relativeImportExcludeToplevel/pack/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/relativeImportExcludeToplevel/pack/subpack/__init__.py b/python/testData/completion/relativeImportExcludeToplevel/pack/subpack/__init__.py new file mode 100644 index 000000000000..6509788aae52 --- /dev/null +++ b/python/testData/completion/relativeImportExcludeToplevel/pack/subpack/__init__.py @@ -0,0 +1 @@ +__author__ = 'yole' diff --git a/python/testData/completion/relativeImportExcludeToplevel/pack/subpack/modX.py b/python/testData/completion/relativeImportExcludeToplevel/pack/subpack/modX.py new file mode 100644 index 000000000000..136608600f80 --- /dev/null +++ b/python/testData/completion/relativeImportExcludeToplevel/pack/subpack/modX.py @@ -0,0 +1 @@ +from ... import \ No newline at end of file diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/compoundDunderAll.py b/python/testData/inspections/PyUnresolvedReferencesInspection/compoundDunderAll.py new file mode 100644 index 000000000000..9533fc64871b --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/compoundDunderAll.py @@ -0,0 +1,2 @@ +__all__ = [ name for name, obj in locals().items() + if not (name.startswith('_')) ] diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/slotsSubclass.py b/python/testData/inspections/PyUnresolvedReferencesInspection/slotsSubclass.py new file mode 100644 index 000000000000..dfd3f5e4cc50 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/slotsSubclass.py @@ -0,0 +1,15 @@ +class A(object): + __slots__ = ['a', 'b'] + def __init__(self): + self.a = None # <- all ok here + self.b = None # <- all ok here + +class C(A): + __slots__ = ['c', 'd'] + + def __init__(self, c): + super(C, self).__init__() + self.c = c + self.d = self.b + if self.c: + self.a = 10 diff --git a/python/testData/inspections/importFromModuleStar/source.py b/python/testData/inspections/importFromModuleStar/source.py new file mode 100644 index 000000000000..55c27e1fb049 --- /dev/null +++ b/python/testData/inspections/importFromModuleStar/source.py @@ -0,0 +1,4 @@ +from target import * + +xyzzy +shazam() diff --git a/python/testData/inspections/importFromModuleStar/source_after.py b/python/testData/inspections/importFromModuleStar/source_after.py new file mode 100644 index 000000000000..b118609972b6 --- /dev/null +++ b/python/testData/inspections/importFromModuleStar/source_after.py @@ -0,0 +1,5 @@ +from target import * +from target import xyzzy + +xyzzy +shazam() diff --git a/python/testData/inspections/importFromModuleStar/target.py b/python/testData/inspections/importFromModuleStar/target.py new file mode 100644 index 000000000000..2214231d716c --- /dev/null +++ b/python/testData/inspections/importFromModuleStar/target.py @@ -0,0 +1,4 @@ +__all__ = ['shazam'] + +def shazam(): pass +def xyzzy(): pass diff --git a/python/testData/inspections/unusedImport/unusedAfterStarImport/test1.py b/python/testData/inspections/unusedImport/unusedAfterStarImport/test1.py new file mode 100644 index 000000000000..1cd116611054 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedAfterStarImport/test1.py @@ -0,0 +1,6 @@ +from test2 import * +from test2 import f #pass +from test3 import * #pass +from test4 import * + +print(f, g) diff --git a/python/testData/inspections/unusedImport/unusedAfterStarImport/test2.py b/python/testData/inspections/unusedImport/unusedAfterStarImport/test2.py new file mode 100644 index 000000000000..001f2e6d84c8 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedAfterStarImport/test2.py @@ -0,0 +1,2 @@ +def f(x): + return x \ No newline at end of file diff --git a/python/testData/inspections/unusedImport/unusedAfterStarImport/test3.py b/python/testData/inspections/unusedImport/unusedAfterStarImport/test3.py new file mode 100644 index 000000000000..504363eab9af --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedAfterStarImport/test3.py @@ -0,0 +1,2 @@ +def g(): + pass \ No newline at end of file diff --git a/python/testData/inspections/unusedImport/unusedAfterStarImport/test4.py b/python/testData/inspections/unusedImport/unusedAfterStarImport/test4.py new file mode 100644 index 000000000000..09d9cea3d574 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedAfterStarImport/test4.py @@ -0,0 +1,2 @@ +def h(): + pass \ No newline at end of file diff --git a/python/testData/refactoring/move/starImportUsage/after/src/a.py b/python/testData/refactoring/move/starImportUsage/after/src/a.py new file mode 100644 index 000000000000..b51e032b9bbe --- /dev/null +++ b/python/testData/refactoring/move/starImportUsage/after/src/a.py @@ -0,0 +1,3 @@ +from c import f + +print(f()) \ No newline at end of file diff --git a/python/testData/refactoring/move/starImportUsage/after/src/b.py b/python/testData/refactoring/move/starImportUsage/after/src/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/starImportUsage/after/src/c.py b/python/testData/refactoring/move/starImportUsage/after/src/c.py new file mode 100644 index 000000000000..39e1b2079d04 --- /dev/null +++ b/python/testData/refactoring/move/starImportUsage/after/src/c.py @@ -0,0 +1,2 @@ +def f(): + pass \ No newline at end of file diff --git a/python/testData/refactoring/move/starImportUsage/before/src/a.py b/python/testData/refactoring/move/starImportUsage/before/src/a.py new file mode 100644 index 000000000000..6c3eacab5b29 --- /dev/null +++ b/python/testData/refactoring/move/starImportUsage/before/src/a.py @@ -0,0 +1,3 @@ +from b import * + +print(f()) \ No newline at end of file diff --git a/python/testData/refactoring/move/starImportUsage/before/src/b.py b/python/testData/refactoring/move/starImportUsage/before/src/b.py new file mode 100644 index 000000000000..39e1b2079d04 --- /dev/null +++ b/python/testData/refactoring/move/starImportUsage/before/src/b.py @@ -0,0 +1,2 @@ +def f(): + pass \ No newline at end of file diff --git a/python/testData/refactoring/move/starImportUsage/before/src/c.py b/python/testData/refactoring/move/starImportUsage/before/src/c.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/resolve/LambdaParameterInDefaultValue.py b/python/testData/resolve/LambdaParameterInDefaultValue.py new file mode 100644 index 000000000000..1e0c6c0191cf --- /dev/null +++ b/python/testData/resolve/LambdaParameterInDefaultValue.py @@ -0,0 +1,2 @@ +def f(g=lambda xx: xx): + pass # \ No newline at end of file diff --git a/python/testData/resolve/multiFile/fromPackageImportIntoInit/pack/__init__.py b/python/testData/resolve/multiFile/fromPackageImportIntoInit/pack/__init__.py new file mode 100644 index 000000000000..d84254aa0698 --- /dev/null +++ b/python/testData/resolve/multiFile/fromPackageImportIntoInit/pack/__init__.py @@ -0,0 +1,2 @@ +from pack import mod +# diff --git a/python/testData/resolve/multiFile/fromPackageImportIntoInit/pack/mod.py b/python/testData/resolve/multiFile/fromPackageImportIntoInit/pack/mod.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java index 4540eb1a1480..250977bd7e2f 100644 --- a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java @@ -96,6 +96,14 @@ public class PyMultiFileResolveTest extends PyResolveTestCase { assertTrue("is target?", elt instanceof PyTargetExpression); } + public void testFromPackageImportIntoInit() { // PY-6305 + myFixture.copyDirectoryToProject("fromPackageImportIntoInit/pack", "pack"); + final PsiFile psiFile = myFixture.configureByFile("pack/__init__.py"); + final PsiElement result = doResolve(psiFile); + assertInstanceOf(result, PyFile.class); + assertEquals("mod.py", ((PyFile) result).getName()); + } + public void testResolveInPkg() { ResolveResult[] results = doMultiResolve(); assertTrue(results.length == 2); // func and import stmt diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index dd8aac6b309b..c0758fc44ae9 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -36,6 +36,17 @@ public class PyQuickFixTest extends PyTestCase { PyUnresolvedReferencesInspection.class, PyBundle.message("ACT.NAME.use.import"), true, true); } + public void testImportFromModuleStar() { // PY-6302 + myFixture.enableInspections(PyUnresolvedReferencesInspection.class); + myFixture.copyDirectoryToProject("importFromModuleStar", ""); + myFixture.configureFromTempProjectFile("source.py"); + myFixture.checkHighlighting(true, false, false); + final IntentionAction intentionAction = myFixture.findSingleIntention(PyBundle.message("ACT.NAME.use.import")); + assertNotNull(intentionAction); + myFixture.launchAction(intentionAction); + myFixture.checkResultByFile("importFromModuleStar/source_after.py"); + } + public void testQualifyByImport() { final PyCodeInsightSettings settings = PyCodeInsightSettings.getInstance(); boolean oldPreferFrom = settings.PREFER_FROM_IMPORT; diff --git a/python/testSrc/com/jetbrains/python/PyResolveTest.java b/python/testSrc/com/jetbrains/python/PyResolveTest.java index 0331ccfeb0ac..d0fde0cc6b62 100644 --- a/python/testSrc/com/jetbrains/python/PyResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyResolveTest.java @@ -462,4 +462,9 @@ public class PyResolveTest extends PyResolveTestCase { public void testLambdaParameterInDecorator() { assertResolvesTo(PyNamedParameter.class, "xx"); } + + // PY-6435 + public void testLambdaParameterInDefaultValue() { + assertResolvesTo(PyNamedParameter.class, "xx"); + } } diff --git a/python/testSrc/com/jetbrains/python/PyStubsTest.java b/python/testSrc/com/jetbrains/python/PyStubsTest.java index afeeee9be96b..62647916c668 100644 --- a/python/testSrc/com/jetbrains/python/PyStubsTest.java +++ b/python/testSrc/com/jetbrains/python/PyStubsTest.java @@ -2,10 +2,15 @@ package com.jetbrains.python; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.DumbServiceImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubUpdatingIndex; @@ -16,6 +21,7 @@ import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyFileImpl; import com.jetbrains.python.psi.impl.PyQualifiedName; import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher; +import com.jetbrains.python.psi.stubs.PyClassNameIndex; import com.jetbrains.python.psi.stubs.PyClassStub; import com.jetbrains.python.psi.stubs.PyVariableNameIndex; import com.jetbrains.python.toolbox.Maybe; @@ -365,4 +371,32 @@ public class PyStubsTest extends PyTestCase { PsiFile psiFile = myFixture.getPsiManager().findFile(sourceFile); return (PyFile)psiFile; } + + public void testStubIndexMismatch() { + VirtualFile vFile = myFixture.getTempDirFixture().createFile("foo.py"); + final Project project = myFixture.getProject(); + PsiFileImpl fooPyFile = (PsiFileImpl) PsiManager.getInstance(project).findFile(vFile); + final Document fooDocument = fooPyFile.getViewProvider().getDocument(); + Collection classes = PyClassNameIndex.find("Foo", project, GlobalSearchScope.allScope(project)); + assertEquals(classes.size(), 0); + new WriteCommandAction.Simple(project, fooPyFile) { + public void run() { + fooDocument.setText("class Foo: pass"); + } + }.execute(); + PsiDocumentManager.getInstance(project).commitDocument(fooDocument); + fooPyFile.setTreeElementPointer(null); + //classes = PyClassNameIndex.find("Foo", project, GlobalSearchScope.allScope(project)); + //fooPyFile.unloadContent(); + DumbServiceImpl.getInstance(project).setDumb(true); + try { + assertEquals(1, ((PyFile) fooPyFile).getTopLevelClasses().size()); + } + finally { + DumbServiceImpl.getInstance(project).setDumb(false); + } + classes = PyClassNameIndex.find("Foo", project, GlobalSearchScope.allScope(project)); + assertEquals(classes.size(), 1); + + } } diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index 92a4a2599df7..9bf9201be865 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -529,6 +529,10 @@ public class PythonCompletionTest extends PyTestCase { doTest(); } + public void testDunderAllReferenceImport() { // PY-6306 + doTest(); + } + public void testOldStyleClassAttributes() { doTest(); } @@ -546,4 +550,17 @@ public class PythonCompletionTest extends PyTestCase { public void testQualifiedAssignment() { // PY-6121 doTest(); } + + public void testRelativeImportExcludeToplevel() { // PY-6304 + setLanguageLevel(LanguageLevel.PYTHON27); + try { + myFixture.copyDirectoryToProject("completion/relativeImportExcludeToplevel", ""); + myFixture.configureByFile("pack/subpack/modX.py"); + myFixture.completeBasic(); + assertFalse(myFixture.getLookupElementStrings().contains("sys")); + } + finally { + setLanguageLevel(null); + } + } } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 559dd988529d..b74ba65d5de4 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -32,6 +32,10 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + public void testSlotsSubclass() { // PY-5939 + doTest(); + } + public void testImportExceptImportError() { doTest(); } @@ -102,6 +106,10 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + public void testCompoundDunderAll() { // PY-6370 + doTest(); + } + private void doMultiFileTest() { myFixture.copyFileToProject("inspections/PyUnresolvedReferencesInspection/__init__.py", "PyUnresolvedReferencesInspection/__init__.py"); myFixture.copyFileToProject("inspections/PyUnresolvedReferencesInspection/" + getTestName(true) + ".py", diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java index 820e18277352..5faf7790ba97 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java @@ -1,34 +1,40 @@ package com.jetbrains.python.inspections; import com.jetbrains.python.fixtures.PyTestCase; +import org.jetbrains.annotations.NotNull; /** * @author yole */ public class PyUnusedImportTest extends PyTestCase { - public void testModuleAndSubmodule() { // PY-3626 - myFixture.copyDirectoryToProject("inspections/unusedImport/moduleAndSubmodule", ""); - myFixture.enableInspections(PyUnresolvedReferencesInspection.class); - myFixture.testHighlighting(true, false, false, "py3626.py"); + // PY-3626 + public void testModuleAndSubmodule() { + doTest("py3626.py"); } - public void testSubpackageInInitPy() { // PY-3201 - myFixture.copyDirectoryToProject("inspections/unusedImport/subpackageInInitPy", ""); - myFixture.enableInspections(PyUnresolvedReferencesInspection.class); - myFixture.testHighlighting(true, false, false, "package1/__init__.py"); + // PY-3201 + public void testSubpackageInInitPy() { + doTest("package1/__init__.py"); } // PY-5589 public void testUnusedPackageAndSubmodule() { - myFixture.copyDirectoryToProject("inspections/unusedImport/unusedPackageAndSubmodule", ""); - myFixture.enableInspections(PyUnresolvedReferencesInspection.class); - myFixture.testHighlighting(true, false, false, "test1.py"); + doTest("test1.py"); } // PY-5621 public void testUnusedSubmodule() { - myFixture.copyDirectoryToProject("inspections/unusedImport/unusedSubmodule", ""); + doTest("test1.py"); + } + + // PY-6380 + public void testUnusedAfterStarImport() { + doTest("test1.py"); + } + + private void doTest(@NotNull String filename) { + myFixture.copyDirectoryToProject("inspections/unusedImport/" + getTestName(true), ""); myFixture.enableInspections(PyUnresolvedReferencesInspection.class); - myFixture.testHighlighting(true, false, false, "test1.py"); + myFixture.testHighlighting(true, false, false, filename); } } diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java index 0738e56a286d..cb8645d368f6 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java @@ -90,6 +90,11 @@ public class PyMoveTest extends PyTestCase { doMoveFileTest("p1/p2/m1.py", "nonp3"); } + // PY-6432 + public void testStarImportUsage() { + doMoveSymbolTest("f", "c.py"); + } + private void doMoveFileTest(String fileName, String toDirName) { Project project = myFixture.getProject(); PsiManager manager = PsiManager.getInstance(project);