summaryrefslogtreecommitdiff
path: root/python/src
diff options
context:
space:
mode:
Diffstat (limited to 'python/src')
-rw-r--r--python/src/META-INF/PyCharmCorePlugin.xml2
-rw-r--r--python/src/META-INF/pycharm-community.xml11
-rw-r--r--python/src/META-INF/pycharm-core.xml10
-rw-r--r--python/src/META-INF/python-core.xml19
-rw-r--r--python/src/com/jetbrains/python/actions/PyExecuteSelectionAction.java (renamed from python/src/com/jetbrains/python/actions/ExecuteInConsoleAction.java)49
-rw-r--r--python/src/com/jetbrains/python/buildout/BuildoutConfigPanel.java3
-rw-r--r--python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java69
-rw-r--r--python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java34
-rw-r--r--python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java75
-rw-r--r--python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java30
-rw-r--r--python/src/com/jetbrains/python/codeInsight/imports/PyImportOptimizer.java2
-rw-r--r--python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java19
-rw-r--r--python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java3
-rw-r--r--python/src/com/jetbrains/python/console/PyConsoleOptions.java2
-rw-r--r--python/src/com/jetbrains/python/console/PydevConsoleRunner.java167
-rw-r--r--python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.java122
-rw-r--r--python/src/com/jetbrains/python/console/PythonConsoleRunnerFactory.java34
-rw-r--r--python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java39
-rw-r--r--python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.java13
-rw-r--r--python/src/com/jetbrains/python/console/PythonConsoleView.java69
-rw-r--r--python/src/com/jetbrains/python/console/PythonToolWindowConsoleRunner.java85
-rw-r--r--python/src/com/jetbrains/python/console/PythonToolWindowConsoleRunnerFactory.java34
-rw-r--r--python/src/com/jetbrains/python/console/RunPythonConsoleAction.java240
-rw-r--r--python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java3
-rw-r--r--python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java5
-rw-r--r--python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java4
-rw-r--r--python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java2
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java24
-rw-r--r--python/src/com/jetbrains/python/psi/types/PyFunctionType.java76
-rw-r--r--python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java2
-rw-r--r--python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java9
-rw-r--r--python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java2
-rw-r--r--python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java7
-rw-r--r--python/src/com/jetbrains/python/refactoring/introduce/constant/PyIntroduceConstantHandler.java6
-rw-r--r--python/src/com/jetbrains/python/run/PythonCommandLineState.java14
-rw-r--r--python/src/com/jetbrains/python/run/PythonRunner.java5
-rw-r--r--python/src/com/jetbrains/python/sdk/PythonSdkType.java12
-rw-r--r--python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java36
-rw-r--r--python/src/com/jetbrains/python/sdk/skeletons/SkeletonErrorsDialog.form61
-rw-r--r--python/src/com/jetbrains/python/sdk/skeletons/SkeletonErrorsDialog.java94
-rw-r--r--python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java2
41 files changed, 856 insertions, 639 deletions
diff --git a/python/src/META-INF/PyCharmCorePlugin.xml b/python/src/META-INF/PyCharmCorePlugin.xml
index a250bdc539d7..99a39a1d0cc7 100644
--- a/python/src/META-INF/PyCharmCorePlugin.xml
+++ b/python/src/META-INF/PyCharmCorePlugin.xml
@@ -1,4 +1,4 @@
<idea-plugin version="2" xmlns:xi="http://www.w3.org/2001/XInclude">
- <xi:include href="/META-INF/pycharm-core.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <xi:include href="/META-INF/pycharm-community.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/python-core.xml" xpointer="xpointer(/idea-plugin/*)"/>
</idea-plugin>
diff --git a/python/src/META-INF/pycharm-community.xml b/python/src/META-INF/pycharm-community.xml
new file mode 100644
index 000000000000..68518574169d
--- /dev/null
+++ b/python/src/META-INF/pycharm-community.xml
@@ -0,0 +1,11 @@
+<idea-plugin version="2" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <!-- Components and extensions declared in this file work ONLY in PyCharm, not in Python plugin. -->
+ <xi:include href="/META-INF/pycharm-core.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <application-components>
+ <component>
+ <interface-class>com.jetbrains.python.console.PythonConsoleRunnerFactory</interface-class>
+ <implementation-class>com.jetbrains.python.console.PythonToolWindowConsoleRunnerFactory</implementation-class>
+ </component>
+ </application-components>
+</idea-plugin>
diff --git a/python/src/META-INF/pycharm-core.xml b/python/src/META-INF/pycharm-core.xml
index 13ba05db63f0..4732ad084b32 100644
--- a/python/src/META-INF/pycharm-core.xml
+++ b/python/src/META-INF/pycharm-core.xml
@@ -24,6 +24,12 @@
</component>
</project-components>
+ <project-components>
+ <component>
+ <implementation-class>com.jetbrains.python.console.PythonConsoleToolWindow</implementation-class>
+ </component>
+ </project-components>
+
<module value="com.intellij.modules.xml"/>
<extensions defaultExtensionNs="com.intellij">
@@ -75,6 +81,10 @@
<renameHandler implementation="com.intellij.platform.renameProject.RenameProjectHandler"/>
<renameHandler implementation="com.intellij.platform.renameProject.ProjectFolderRenameHandler"/>
+
+ <!-- Console -->
+ <toolWindow id="Python Console" anchor="bottom" icon="PythonIcons.Python.PythonConsoleToolWindow"
+ factoryClass="com.jetbrains.python.console.PythonConsoleToolWindowFactory" secondary="false"/>
</extensions>
<actions>
diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml
index a27eb44ae3af..292237aac6ac 100644
--- a/python/src/META-INF/python-core.xml
+++ b/python/src/META-INF/python-core.xml
@@ -529,11 +529,6 @@
<moduleService serviceInterface="com.jetbrains.python.packaging.PyPackageRequirementsSettings"
serviceImplementation="com.jetbrains.python.packaging.PyPackageRequirementsSettings"/>
- <!-- Console -->
- <toolWindow id="Python Console" anchor="bottom" icon=""
- factoryClass="com.jetbrains.python.console.PythonConsoleToolWindowFactory" secondary="false"/>
-
-
</extensions>
<extensionPoints>
@@ -621,12 +616,6 @@
</component>
</project-components>
- <project-components>
- <component>
- <implementation-class>com.jetbrains.python.console.PythonConsoleToolWindow</implementation-class>
- </component>
- </project-components>
-
<actions>
<group id="PyTypeHierarchyPopupMenu">
<reference ref="TypeHierarchyBase.BaseOnThisType"/>
@@ -655,11 +644,7 @@
<reference ref="CompareFileWithEditor"/>
</group>
- <action id="com.jetbrains.python.console.RunPythonConsoleAction"
- class="com.jetbrains.python.console.RunPythonConsoleAction"
- text="Run Python Console..." description="Allows to quickly run Python console">
- <add-to-group group-id="ToolsMenu" anchor="last"/>
- </action>
+
<action id="com.jetbrains.python.console.PyOpenDebugConsoleAction"
class="com.jetbrains.python.console.PyOpenDebugConsoleAction"
@@ -669,7 +654,7 @@
<action id="ExecuteInPyConsoleAction"
- class="com.jetbrains.python.actions.ExecuteInConsoleAction"
+ class="com.jetbrains.python.actions.PyExecuteSelectionAction"
text="Execute selection in console"
description="Executes selected code fragment in Python/Django console">
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="CompareClipboardWithSelection"/>
diff --git a/python/src/com/jetbrains/python/actions/ExecuteInConsoleAction.java b/python/src/com/jetbrains/python/actions/PyExecuteSelectionAction.java
index cb90d498e663..4aea63a8a196 100644
--- a/python/src/com/jetbrains/python/actions/ExecuteInConsoleAction.java
+++ b/python/src/com/jetbrains/python/actions/PyExecuteSelectionAction.java
@@ -32,18 +32,20 @@ import com.intellij.util.Consumer;
import com.intellij.util.NotNullFunction;
import com.jetbrains.python.console.PyCodeExecutor;
import com.jetbrains.python.console.PydevConsoleRunner;
-import com.jetbrains.python.console.RunPythonConsoleAction;
+import com.jetbrains.python.console.PythonConsoleRunnerFactory;
+import com.jetbrains.python.console.PythonConsoleToolWindow;
import com.jetbrains.python.psi.PyFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
+import java.util.List;
-public class ExecuteInConsoleAction extends AnAction {
+public class PyExecuteSelectionAction extends AnAction {
public static final String EXECUTE_SELECTION_IN_CONSOLE = "Execute Selection in Console";
- public ExecuteInConsoleAction() {
+ public PyExecuteSelectionAction() {
super(EXECUTE_SELECTION_IN_CONSOLE);
}
@@ -186,6 +188,12 @@ public class ExecuteInConsoleAction extends AnAction {
}
private static Collection<RunContentDescriptor> getConsoles(Project project) {
+ PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(project);
+
+ if (toolWindow != null) {
+ return toolWindow.getConsoleContentDescriptors();
+ }
+
return ExecutionHelper.findRunningConsole(project, new NotNullFunction<RunContentDescriptor, Boolean>() {
@NotNull
@Override
@@ -214,15 +222,34 @@ public class ExecuteInConsoleAction extends AnAction {
private static void startConsole(final Project project,
final Consumer<PyCodeExecutor> consumer,
Module context) {
- PydevConsoleRunner runner = RunPythonConsoleAction.runPythonConsole(project, context, null);
- runner.addConsoleListener(new PydevConsoleRunner.ConsoleListener() {
- @Override
- public void handleConsoleInitialized(LanguageConsoleView consoleView) {
- if (consoleView instanceof PyCodeExecutor) {
- consumer.consume((PyCodeExecutor)consoleView);
+ final PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(project);
+
+ if (toolWindow != null) {
+ toolWindow.activate(new Runnable() {
+ @Override
+ public void run() {
+ List<RunContentDescriptor> descs = toolWindow.getConsoleContentDescriptors();
+
+ RunContentDescriptor descriptor = descs.get(0);
+ if (descriptor != null && descriptor.getExecutionConsole() instanceof PyCodeExecutor) {
+ consumer.consume((PyCodeExecutor)descriptor.getExecutionConsole());
+ }
}
- }
- });
+ });
+ }
+ else {
+ PythonConsoleRunnerFactory consoleRunnerFactory = PythonConsoleRunnerFactory.getInstance();
+ PydevConsoleRunner runner = consoleRunnerFactory.createConsoleRunner(project, null);
+ runner.addConsoleListener(new PydevConsoleRunner.ConsoleListener() {
+ @Override
+ public void handleConsoleInitialized(LanguageConsoleView consoleView) {
+ if (consoleView instanceof PyCodeExecutor) {
+ consumer.consume((PyCodeExecutor)consoleView);
+ }
+ }
+ });
+ runner.run();
+ }
}
private static boolean canFindConsole(AnActionEvent e) {
diff --git a/python/src/com/jetbrains/python/buildout/BuildoutConfigPanel.java b/python/src/com/jetbrains/python/buildout/BuildoutConfigPanel.java
index 394de6160cbc..eceedeb00050 100644
--- a/python/src/com/jetbrains/python/buildout/BuildoutConfigPanel.java
+++ b/python/src/com/jetbrains/python/buildout/BuildoutConfigPanel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,6 +81,7 @@ public class BuildoutConfigPanel extends JPanel {
myErrorPanel.add(facetErrorPanel.getComponent(), BorderLayout.CENTER);
facetErrorPanel.getValidatorsManager().registerValidator(new FacetEditorValidator() {
+ @NotNull
@Override
public ValidationResult check() {
if (!myFacetEnabled) {
diff --git a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java
index 1c09ee24f7dd..d33e97c1e7f9 100644
--- a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java
+++ b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java
@@ -21,14 +21,14 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ProjectRootManager;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.QualifiedName;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
import com.jetbrains.python.documentation.DocStringUtil;
import com.jetbrains.python.psi.*;
-import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
@@ -36,6 +36,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
+import static com.jetbrains.python.psi.PyUtil.sure;
+
/**
* Does the actual job of adding an import statement into a file.
* User: dcheryasov
@@ -47,6 +49,34 @@ public class AddImportHelper {
private AddImportHelper() {
}
+ public static void addLocalImportStatement(@NotNull PyElement element, @NotNull String name) {
+ final PyElementGenerator generator = PyElementGenerator.getInstance(element.getProject());
+ final LanguageLevel languageLevel = LanguageLevel.forElement(element);
+
+ final PsiElement anchor = getLocalInsertPosition(element);
+ final PsiElement parentElement = sure(anchor).getParent();
+ if (parentElement != null) {
+ parentElement.addBefore(generator.createImportStatement(languageLevel, name, null), anchor);
+ }
+ }
+
+ public static void addLocalFromImportStatement(@NotNull PyElement element, @NotNull String qualifier, @NotNull String name) {
+ final PyElementGenerator generator = PyElementGenerator.getInstance(element.getProject());
+ final LanguageLevel languageLevel = LanguageLevel.forElement(element);
+
+ final PsiElement anchor = getLocalInsertPosition(element);
+ final PsiElement parentElement = sure(anchor).getParent();
+ if (parentElement != null) {
+ parentElement.addBefore(generator.createFromImportStatement(languageLevel, qualifier, name, null), anchor);
+ }
+
+ }
+
+ @Nullable
+ public static PsiElement getLocalInsertPosition(@NotNull PyElement anchor) {
+ return PsiTreeUtil.getParentOfType(anchor, PyStatement.class, false);
+ }
+
public enum ImportPriority {
BUILTIN, THIRD_PARTY, PROJECT
}
@@ -81,7 +111,8 @@ public class AddImportHelper {
// maybe we arrived at the doc comment stmt; skip over it, too
else if (!skippedOverImports && !skippedOverDoc && file instanceof PyFile) {
PsiElement doc_elt =
- DocStringUtil.findDocStringExpression((PyElement)file); // this gives the literal; its parent is the expr seeker may have encountered
+ DocStringUtil
+ .findDocStringExpression((PyElement)file); // this gives the literal; its parent is the expr seeker may have encountered
if (doc_elt != null && doc_elt.getParent() == feeler) {
feeler = feeler.getNextSibling();
seeker = feeler; // skip over doc even if there's nothing below it
@@ -147,19 +178,13 @@ public class AddImportHelper {
* @param file where to operate
* @param name which to import (qualified is OK)
* @param asName optional name for 'as' clause
+ * @return whether import statement was actually added
*/
public static boolean addImportStatement(PsiFile file, String name, @Nullable String asName, ImportPriority priority) {
- String as_clause;
- if (asName == null) {
- as_clause = "";
- }
- else {
- as_clause = " as " + asName;
- }
if (!(file instanceof PyFile)) {
return false;
}
- List<PyImportElement> existingImports = ((PyFile)file).getImportTargets();
+ final List<PyImportElement> existingImports = ((PyFile)file).getImportTargets();
for (PyImportElement element : existingImports) {
final QualifiedName qName = element.getImportedQName();
if (qName != null && name.equals(qName.toString())) {
@@ -171,7 +196,7 @@ public class AddImportHelper {
final PyElementGenerator generator = PyElementGenerator.getInstance(file.getProject());
final LanguageLevel languageLevel = LanguageLevel.forElement(file);
- final PyImportStatement importNodeToInsert = generator.createImportStatementFromText(languageLevel, "import " + name + as_clause);
+ final PyImportStatement importNodeToInsert = generator.createImportStatement(languageLevel, name, asName);
try {
file.addBefore(importNodeToInsert, getInsertPosition(file, name, priority));
}
@@ -180,6 +205,7 @@ public class AddImportHelper {
}
return true;
}
+
/**
* Adds an "import ... from ..." statement below other top-level imports.
*
@@ -189,20 +215,20 @@ public class AddImportHelper {
* @param asName optional name for 'as' clause
*/
public static void addImportFromStatement(PsiFile file, String from, String name, @Nullable String asName, ImportPriority priority) {
- String asClause = asName == null ? "" : " as " + asName;
-
- final PyFromImportStatement importNodeToInsert = PyElementGenerator.getInstance(file.getProject()).createFromText(
- LanguageLevel.forElement(file), PyFromImportStatement.class, "from " + from + " import " + name + asClause);
+ final PyElementGenerator generator = PyElementGenerator.getInstance(file.getProject());
+ final LanguageLevel languageLevel = LanguageLevel.forElement(file);
+ final PyFromImportStatement nodeToInsert = generator.createFromImportStatement(languageLevel, from, name, asName);
try {
if (InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) {
- final PsiElement element = file.addBefore(importNodeToInsert, getInsertPosition(file, from, priority));
+ final PsiElement element = file.addBefore(nodeToInsert, getInsertPosition(file, from, priority));
PsiElement whitespace = element.getNextSibling();
- if (!(whitespace instanceof PsiWhiteSpace))
+ if (!(whitespace instanceof PsiWhiteSpace)) {
whitespace = PsiParserFacade.SERVICE.getInstance(file.getProject()).createWhiteSpaceFromText(" >>> ");
+ }
file.addBefore(whitespace, element);
}
else {
- file.addBefore(importNodeToInsert, getInsertPosition(file, from, priority));
+ file.addBefore(nodeToInsert, getInsertPosition(file, from, priority));
}
}
catch (IncorrectOperationException e) {
@@ -228,7 +254,7 @@ public class AddImportHelper {
}
}
final PyElementGenerator generator = PyElementGenerator.getInstance(file.getProject());
- PyImportElement importElement = generator.createImportElement(LanguageLevel.forElement(file), name);
+ final PyImportElement importElement = generator.createImportElement(LanguageLevel.forElement(file), name);
existingImport.add(importElement);
return true;
}
@@ -239,7 +265,8 @@ public class AddImportHelper {
public static void addImport(final PsiNamedElement target, final PsiFile file, final PyElement element) {
final boolean useQualified = !PyCodeInsightSettings.getInstance().PREFER_FROM_IMPORT;
- final PsiFileSystemItem toImport = target instanceof PsiFileSystemItem ? ((PsiFileSystemItem)target).getParent() : target.getContainingFile();
+ final PsiFileSystemItem toImport =
+ target instanceof PsiFileSystemItem ? ((PsiFileSystemItem)target).getParent() : target.getContainingFile();
final ImportPriority priority = getImportPriority(file, toImport);
final QualifiedName qName = QualifiedNameFinder.findCanonicalImportPath(target, element);
if (qName == null) return;
diff --git a/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java b/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java
index 47c9ca9f8ee5..ce3c07932eb4 100644
--- a/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java
+++ b/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java
@@ -29,6 +29,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.PsiReference;
+import com.intellij.psi.util.QualifiedName;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
@@ -36,7 +37,6 @@ import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyImportElement;
import com.jetbrains.python.psi.PyQualifiedExpression;
-import com.intellij.psi.util.QualifiedName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -138,7 +138,7 @@ public class AutoImportQuickFix implements LocalQuickFix, HighPriorityAction {
myImports.size() > 1,
ImportCandidateHolder.getQualifiedName(name, myImports.get(0).getPath(), myImports.get(0).getImportElement())
);
- final ImportFromExistingAction action = new ImportFromExistingAction(myNode, myImports, name, myUseQualifiedImport);
+ final ImportFromExistingAction action = new ImportFromExistingAction(myNode, myImports, name, myUseQualifiedImport, false);
action.onDone(new Runnable() {
public void run() {
myExpended = true;
@@ -166,11 +166,16 @@ public class AutoImportQuickFix implements LocalQuickFix, HighPriorityAction {
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
if (ImportFromExistingAction.isResolved(myReference)) return;
// act
- ImportFromExistingAction action = new ImportFromExistingAction(myNode, myImports, getNameToImport(), myUseQualifiedImport);
+ ImportFromExistingAction action = createAction();
action.execute(); // assume that action runs in WriteAction on its own behalf
myExpended = true;
}
+ @NotNull
+ protected ImportFromExistingAction createAction() {
+ return new ImportFromExistingAction(myNode, myImports, getNameToImport(), myUseQualifiedImport, false);
+ }
+
public void sortCandidates() {
Collections.sort(myImports);
}
@@ -203,4 +208,27 @@ public class AutoImportQuickFix implements LocalQuickFix, HighPriorityAction {
}
return false;
}
+
+ @NotNull
+ public AutoImportQuickFix forLocalImport() {
+ return new AutoImportQuickFix(myNode, myReference, myUseQualifiedImport) {
+ @NotNull
+ @Override
+ public String getName() {
+ return super.getName() + " locally";
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return "import locally";
+ }
+
+ @NotNull
+ @Override
+ protected ImportFromExistingAction createAction() {
+ return new ImportFromExistingAction(myNode, myImports, getNameToImport(), myUseQualifiedImport, true);
+ }
+ };
+ }
}
diff --git a/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java b/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java
index b60348d34938..e75df5b9a0d0 100644
--- a/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java
+++ b/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java
@@ -24,18 +24,25 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
-import com.jetbrains.python.psi.*;
import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An immutable holder of information for one auto-import candidate.
- * User: dcheryasov
- * Date: Apr 23, 2009 4:17:50 PM
+ * <p/>
+ * There can be do different flavors of such candidates:
+ * <ul>
+ * <li>Candidates based on existing imports in module. In this case {@link #getImportElement()} must return not {@code null}.</li>
+ * <li>Candidates not yet imported. In this case {@link #getPath()} must return not {@code null}.</li>
+ * </ul>
+ * <p/>
+ *
+ * @author dcheryasov
*/
// visibility is intentionally package-level
-class ImportCandidateHolder implements Comparable {
+class ImportCandidateHolder implements Comparable<ImportCandidateHolder> {
private final PsiElement myImportable;
private final PyImportElement myImportElement;
private final PsiFileSystemItem myFile;
@@ -43,15 +50,19 @@ class ImportCandidateHolder implements Comparable {
/**
* Creates new instance.
- * @param importable an element that could be imported either from import element or from file.
- * @param file the file which is the source of the importable
+ *
+ * @param importable an element that could be imported either from import element or from file.
+ * @param file the file which is the source of the importable (module for symbols, containing directory for modules and packages)
* @param importElement an existing import element that can be a source for the importable.
- * @param path import path for the file, as a qualified name (a.b.c)
+ * @param path import path for the file, as a qualified name (a.b.c)
+ * For top-level imported symbols it's <em>qualified name of containing module</em> (or package for __init__.py).
+ * For modules and packages it should be <em>qualified name of their parental package</em>
+ * (empty for modules and packages located at source roots).
+ *
+ * @see com.jetbrains.python.codeInsight.imports.PythonReferenceImporter#proposeImportFix
*/
- public ImportCandidateHolder(
- @NotNull PsiElement importable, @NotNull PsiFileSystemItem file,
- @Nullable PyImportElement importElement, @Nullable QualifiedName path
- ) {
+ public ImportCandidateHolder(@NotNull PsiElement importable, @NotNull PsiFileSystemItem file,
+ @Nullable PyImportElement importElement, @Nullable QualifiedName path) {
myFile = file;
myImportable = importable;
myImportElement = importElement;
@@ -59,18 +70,22 @@ class ImportCandidateHolder implements Comparable {
assert importElement != null || path != null; // one of these must be present
}
+ @NotNull
public PsiElement getImportable() {
return myImportable;
}
+ @Nullable
public PyImportElement getImportElement() {
return myImportElement;
}
+ @NotNull
public PsiFileSystemItem getFile() {
return myFile;
}
+ @Nullable
public QualifiedName getPath() {
return myPath;
}
@@ -78,15 +93,17 @@ class ImportCandidateHolder implements Comparable {
/**
* Helper method that builds an import path, handling all these "import foo", "import foo as bar", "from bar import foo", etc.
* Either importPath or importSource must be not null.
- * @param name what is ultimately imported.
+ *
+ * @param name what is ultimately imported.
* @param importPath known path to import the name.
- * @param source known ImportElement to import the name; its 'as' clause is used if present.
+ * @param source known ImportElement to import the name; its 'as' clause is used if present.
* @return a properly qualified name.
*/
- public static String getQualifiedName(String name, QualifiedName importPath, PyImportElement source) {
- StringBuilder sb = new StringBuilder();
+ @NotNull
+ public static String getQualifiedName(@NotNull String name, @Nullable QualifiedName importPath, @Nullable PyImportElement source) {
+ final StringBuilder sb = new StringBuilder();
if (source != null) {
- PsiElement parent = source.getParent();
+ final PsiElement parent = source.getParent();
if (parent instanceof PyFromImportStatement) {
sb.append(name);
}
@@ -95,7 +112,7 @@ class ImportCandidateHolder implements Comparable {
}
}
else {
- if (importPath.getComponentCount() > 0) {
+ if (importPath != null && importPath.getComponentCount() > 0) {
sb.append(importPath).append(".");
}
sb.append(name);
@@ -103,8 +120,9 @@ class ImportCandidateHolder implements Comparable {
return sb.toString();
}
- public String getPresentableText(String myName) {
- StringBuilder sb = new StringBuilder(getQualifiedName(myName, myPath, myImportElement));
+ @NotNull
+ public String getPresentableText(@NotNull String myName) {
+ final StringBuilder sb = new StringBuilder(getQualifiedName(myName, myPath, myImportElement));
PsiElement parent = null;
if (myImportElement != null) {
parent = myImportElement.getParent();
@@ -113,13 +131,15 @@ class ImportCandidateHolder implements Comparable {
sb.append(((PyFunction)myImportable).getParameterList().getPresentableText(false));
}
else if (myImportable instanceof PyClass) {
- PyClass[] supers = ((PyClass)myImportable).getSuperClasses();
+ final PyClass[] supers = ((PyClass)myImportable).getSuperClasses();
if (supers.length > 0) {
sb.append("(");
// ", ".join(x.getName() for x in getSuperClasses())
- String[] super_names = new String[supers.length];
- for (int i=0; i < supers.length; i += 1) super_names[i] = supers[i].getName();
- sb.append(StringUtil.join(super_names, ", "));
+ final String[] superNames = new String[supers.length];
+ for (int i = 0; i < supers.length; i += 1) {
+ superNames[i] = supers[i].getName();
+ }
+ sb.append(StringUtil.join(superNames, ", "));
sb.append(")");
}
}
@@ -135,10 +155,9 @@ class ImportCandidateHolder implements Comparable {
return sb.toString();
}
- public int compareTo(Object o) {
- ImportCandidateHolder rhs = (ImportCandidateHolder) o;
- int lRelevance = getRelevance();
- int rRelevance = rhs.getRelevance();
+ public int compareTo(@NotNull ImportCandidateHolder rhs) {
+ final int lRelevance = getRelevance();
+ final int rRelevance = rhs.getRelevance();
if (rRelevance != lRelevance) {
return rRelevance - lRelevance;
}
@@ -150,7 +169,7 @@ class ImportCandidateHolder implements Comparable {
}
int getRelevance() {
- Project project = myImportable.getProject();
+ final Project project = myImportable.getProject();
final PsiFile psiFile = myImportable.getContainingFile();
final VirtualFile vFile = psiFile == null ? null : psiFile.getVirtualFile();
if (vFile == null) return 0;
diff --git a/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java b/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java
index 58254d999a90..e7a8151bf52d 100644
--- a/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java
+++ b/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java
@@ -53,6 +53,7 @@ public class ImportFromExistingAction implements QuestionAction {
String myName;
boolean myUseQualifiedImport;
private Runnable myOnDoneCallback;
+ private final boolean myImportLocally;
/**
* @param target element to become qualified as imported.
@@ -60,12 +61,13 @@ public class ImportFromExistingAction implements QuestionAction {
* @param name relevant name ot the target element (e.g. of identifier in an expression).
* @param useQualified if True, use qualified "import modulename" instead of "from modulename import ...".
*/
- public ImportFromExistingAction(@NotNull PyElement target, @NotNull List<ImportCandidateHolder> sources, String name,
- boolean useQualified) {
+ public ImportFromExistingAction(@NotNull PyElement target, @NotNull List<ImportCandidateHolder> sources, @NotNull String name,
+ boolean useQualified, boolean importLocally) {
myTarget = target;
mySources = sources;
myName = name;
myUseQualifiedImport = useQualified;
+ myImportLocally = importLocally;
}
public void onDone(Runnable callback) {
@@ -151,25 +153,41 @@ public class ImportFromExistingAction implements QuestionAction {
if (manager.isInjectedFragment(file)) {
file = manager.getTopLevelFile(myTarget);
}
+ // We are trying to import top-level module or package which thus cannot be qualified
if (isRoot(item.getFile())) {
- AddImportHelper.addImportStatement(file, myName, null, priority);
+ if (myImportLocally) {
+ AddImportHelper.addLocalImportStatement(myTarget, myName);
+ } else {
+ AddImportHelper.addImportStatement(file, myName, null, priority);
+ }
}
else {
- String qualifiedName = item.getPath().toString();
+ final String qualifiedName = item.getPath().toString();
if (myUseQualifiedImport) {
String nameToImport = qualifiedName;
if (item.getImportable() instanceof PsiFileSystemItem) {
nameToImport += "." + myName;
}
- AddImportHelper.addImportStatement(file, nameToImport, null, priority);
+ if (myImportLocally) {
+ AddImportHelper.addLocalImportStatement(myTarget, nameToImport);
+ }
+ else {
+ AddImportHelper.addImportStatement(file, nameToImport, null, priority);
+ }
myTarget.replace(gen.createExpressionFromText(LanguageLevel.forElement(myTarget), qualifiedName + "." + myName));
}
else {
- AddImportHelper.addImportFrom(file, myTarget, qualifiedName, myName, null, priority);
+ if (myImportLocally) {
+ AddImportHelper.addLocalFromImportStatement(myTarget, qualifiedName, myName);
+ }
+ else {
+ AddImportHelper.addImportFromStatement(file, qualifiedName, myName, null, priority);
+ }
}
}
}
+
private void addToExistingImport(PyImportElement src) {
final PyElementGenerator gen = PyElementGenerator.getInstance(myTarget.getProject());
// did user choose 'import' or 'from import'?
diff --git a/python/src/com/jetbrains/python/codeInsight/imports/PyImportOptimizer.java b/python/src/com/jetbrains/python/codeInsight/imports/PyImportOptimizer.java
index 5d24e3b89332..d5fd5a64495e 100644
--- a/python/src/com/jetbrains/python/codeInsight/imports/PyImportOptimizer.java
+++ b/python/src/com/jetbrains/python/codeInsight/imports/PyImportOptimizer.java
@@ -92,7 +92,7 @@ public class PyImportOptimizer implements ImportOptimizer {
for (PyImportElement importElement : importStatement.getImportElements()) {
myMissorted = true;
PsiElement toImport = importElement.resolve();
- final PyImportStatement splitImport = myGenerator.createImportStatementFromText(langLevel, "import " + importElement.getText());
+ final PyImportStatement splitImport = myGenerator.createImportStatement(langLevel, importElement.getText(), null);
prioritize(splitImport, toImport);
}
}
diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
index 346d40f3273e..c28bc29455c9 100644
--- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
+++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
@@ -36,6 +36,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import static com.jetbrains.python.psi.PyUtil.as;
+
/**
* @author yole
*/
@@ -132,6 +134,23 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
}
}
}
+ else if ("__builtin__.tuple.__add__".equals(qname) && callSite instanceof PyBinaryExpression) {
+ final PyBinaryExpression expression = (PyBinaryExpression)callSite;
+ final PyTupleType leftTupleType = as(context.getType(expression.getLeftExpression()), PyTupleType.class);
+ if (expression.getRightExpression() != null) {
+ final PyTupleType rightTupleType = as(context.getType(expression.getRightExpression()), PyTupleType.class);
+ if (leftTupleType != null && rightTupleType != null) {
+ final PyType[] elementTypes = new PyType[leftTupleType.getElementCount() + rightTupleType.getElementCount()];
+ for (int i = 0; i < leftTupleType.getElementCount(); i++) {
+ elementTypes[i] = leftTupleType.getElementType(i);
+ }
+ for (int i = 0; i < rightTupleType.getElementCount(); i++) {
+ elementTypes[i + leftTupleType.getElementCount()] = rightTupleType.getElementType(i);
+ }
+ return PyTupleType.create(function, elementTypes);
+ }
+ }
+ }
}
return null;
}
diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
index 8afd9cc4e674..fa869bfca359 100644
--- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
+++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -120,6 +120,7 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No
myErrorPanel.add(facetErrorPanel.getComponent(), BorderLayout.CENTER);
facetErrorPanel.getValidatorsManager().registerValidator(new FacetEditorValidator() {
+ @NotNull
@Override
public ValidationResult check() {
final Sdk sdk = PythonSdkType.findPythonSdk(myModule);
diff --git a/python/src/com/jetbrains/python/console/PyConsoleOptions.java b/python/src/com/jetbrains/python/console/PyConsoleOptions.java
index e76c2ae576b0..59ae6875d1e9 100644
--- a/python/src/com/jetbrains/python/console/PyConsoleOptions.java
+++ b/python/src/com/jetbrains/python/console/PyConsoleOptions.java
@@ -95,7 +95,7 @@ public class PyConsoleOptions implements PersistentStateComponent<PyConsoleOptio
@Tag("console-settings")
public static class PyConsoleSettings {
- public String myCustomStartScript = RunPythonConsoleAction.CONSOLE_START_COMMAND;
+ public String myCustomStartScript = PydevConsoleRunner.CONSOLE_START_COMMAND;
public String mySdkHome = null;
public String myInterpreterOptions = "";
public boolean myUseModuleSdk;
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
index 848818b95e27..b3ebacd83ae3 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
@@ -17,9 +17,8 @@ package com.jetbrains.python.console;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Lists;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Collections2;
import com.google.common.collect.Maps;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionHelper;
@@ -48,6 +47,8 @@ import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
import com.intellij.openapi.editor.actions.SplitLineAction;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
@@ -58,19 +59,17 @@ import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.EncodingManager;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.FileElement;
import com.intellij.remote.RemoteSshProcess;
import com.intellij.testFramework.LightVirtualFile;
-import com.intellij.ui.content.Content;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.PathMappingSettings;
@@ -94,6 +93,7 @@ import com.jetbrains.python.run.ProcessRunner;
import com.jetbrains.python.run.PythonCommandLineState;
import com.jetbrains.python.run.PythonTracebackFilter;
import com.jetbrains.python.sdk.PySdkUtil;
+import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import icons.PythonIcons;
import org.apache.xmlrpc.XmlRpcException;
@@ -115,6 +115,9 @@ import static com.jetbrains.python.sdk.PythonEnvUtil.setPythonUnbuffered;
* @author oleg
*/
public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonConsoleView> {
+ public static final String WORKING_DIR_ENV = "WORKING_DIR_AND_PYTHON_PATHS";
+ public static final String CONSOLE_START_COMMAND = "import sys; print('Python %s on %s' % (sys.version, sys.platform))\n" +
+ "sys.path.extend([" + WORKING_DIR_ENV + "])\n";
private static final Logger LOG = Logger.getInstance(PydevConsoleRunner.class.getName());
@SuppressWarnings("SpellCheckingInspection")
public static final String PYDEV_PYDEVCONSOLE_PY = "pydev/pydevconsole.py";
@@ -139,18 +142,100 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
private static final long APPROPRIATE_TO_WAIT = 60000;
private PyRemoteSdkCredentials myRemoteCredentials;
- private ToolWindow myToolWindow;
private String myConsoleTitle = null;
- protected PydevConsoleRunner(@NotNull final Project project,
+ public PydevConsoleRunner(@NotNull final Project project,
@NotNull Sdk sdk, @NotNull final PyConsoleType consoleType,
@Nullable final String workingDir,
- Map<String, String> environmentVariables) {
+ Map<String, String> environmentVariables, String ... statementsToExecute) {
super(project, consoleType.getTitle(), workingDir);
mySdk = sdk;
myConsoleType = consoleType;
myEnvironmentVariables = environmentVariables;
+ myStatementsToExecute = statementsToExecute;
+ }
+
+ public static PathMappingSettings getMappings(Project project, Sdk sdk) {
+ PathMappingSettings mappingSettings = null;
+ if (PySdkUtil.isRemote(sdk)) {
+ PythonRemoteInterpreterManager instance = PythonRemoteInterpreterManager.getInstance();
+ if (instance != null) {
+ //noinspection ConstantConditions
+ mappingSettings =
+ instance.setupMappings(project, (PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData(), null);
+ }
+ }
+ return mappingSettings;
+ }
+
+ @NotNull
+ public static Pair<Sdk, Module> findPythonSdkAndModule(@NotNull Project project, @Nullable Module contextModule) {
+ Sdk sdk = null;
+ Module module = null;
+ PyConsoleOptions.PyConsoleSettings settings = PyConsoleOptions.getInstance(project).getPythonConsoleSettings();
+ String sdkHome = settings.getSdkHome();
+ if (sdkHome != null) {
+ sdk = PythonSdkType.findSdkByPath(sdkHome);
+ if (settings.getModuleName() != null) {
+ module = ModuleManager.getInstance(project).findModuleByName(settings.getModuleName());
+ }
+ else {
+ module = contextModule;
+ if (module == null && ModuleManager.getInstance(project).getModules().length > 0) {
+ module = ModuleManager.getInstance(project).getModules()[0];
+ }
+ }
+ }
+ if (sdk == null && settings.isUseModuleSdk()) {
+ if (contextModule != null) {
+ module = contextModule;
+ }
+ else if (settings.getModuleName() != null) {
+ module = ModuleManager.getInstance(project).findModuleByName(settings.getModuleName());
+ }
+ if (module != null) {
+ if (PythonSdkType.findPythonSdk(module) != null) {
+ sdk = PythonSdkType.findPythonSdk(module);
+ }
+ }
+ }
+ else if (contextModule != null) {
+ if (module == null) {
+ module = contextModule;
+ }
+ if (sdk == null) {
+ sdk = PythonSdkType.findPythonSdk(module);
+ }
+ }
+
+ if (sdk == null) {
+ for (Module m : ModuleManager.getInstance(project).getModules()) {
+ if (PythonSdkType.findPythonSdk(m) != null) {
+ sdk = PythonSdkType.findPythonSdk(m);
+ module = m;
+ break;
+ }
+ }
+ }
+ if (sdk == null) {
+ if (PythonSdkType.getAllSdks().size() > 0) {
+ //noinspection UnusedAssignment
+ sdk = PythonSdkType.getAllSdks().get(0); //take any python sdk
+ }
+ }
+ return Pair.create(sdk, module);
+ }
+
+ public static String constructPythonPathCommand(Collection<String> pythonPath, String command) {
+ final String path = Joiner.on(", ").join(Collections2.transform(pythonPath, new Function<String, String>() {
+ @Override
+ public String apply(String input) {
+ return "'" + input.replace("\\", "\\\\").replace("'", "\\'") + "'";
+ }
+ }));
+
+ return command.replace(WORKING_DIR_ENV, path);
}
public void setStatementsToExecute(String... statementsToExecute) {
@@ -196,21 +281,6 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
return actions;
}
- @NotNull
- public static PydevConsoleRunner createAndRun(@NotNull final Project project,
- @NotNull final Sdk sdk,
- @NotNull final PyConsoleType consoleType,
- @Nullable final String workingDirectory,
- @NotNull final Map<String, String> environmentVariables,
- @Nullable final ToolWindow toolWindow,
- final String... statements2execute) {
- final PydevConsoleRunner consoleRunner = create(project, sdk, consoleType, workingDirectory, environmentVariables);
- consoleRunner.setToolWindow(toolWindow);
- consoleRunner.setStatementsToExecute(statements2execute);
- consoleRunner.run();
- return consoleRunner;
- }
-
public void run() {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
@@ -250,16 +320,7 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
Sdk sdk,
PyConsoleType consoleType,
String workingDirectory) {
- return create(project, sdk, consoleType, workingDirectory, Maps.<String, String>newHashMap());
- }
-
- @NotNull
- private static PydevConsoleRunner create(@NotNull final Project project,
- @NotNull final Sdk sdk,
- @NotNull final PyConsoleType consoleType,
- @Nullable final String workingDirectory,
- @NotNull final Map<String, String> environmentVariables) {
- return new PydevConsoleRunner(project, sdk, consoleType, workingDirectory, environmentVariables);
+ return new PydevConsoleRunner(project, sdk, consoleType, workingDirectory, Maps.<String, String>newHashMap(), new String[]{});
}
private static int[] findAvailablePorts(Project project, PyConsoleType consoleType) {
@@ -501,12 +562,6 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
return myConsoleTitle;
}
- @Override
- protected void showConsole(Executor defaultExecutor, RunContentDescriptor contentDescriptor) {
- PythonConsoleToolWindow terminalView = PythonConsoleToolWindow.getInstance(getProject());
- terminalView.init(getToolWindow(), contentDescriptor);
- }
-
protected AnAction createRerunAction() {
return new RestartAction(this);
}
@@ -631,10 +686,7 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
return stopAction;
}
- private void clearContent(RunContentDescriptor descriptor) {
- Content content = getToolWindow().getContentManager().findContent(descriptor.getDisplayName());
- assert content != null;
- getToolWindow().getContentManager().removeContent(content, true);
+ protected void clearContent(RunContentDescriptor descriptor) {
}
private AnAction createConsoleStoppingAction(final AnAction generalStopAction) {
@@ -792,16 +844,6 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
}
}
- public ToolWindow getToolWindow() {
- if (myToolWindow == null) {
- myToolWindow = ToolWindowManager.getInstance(getProject()).getToolWindow(PythonConsoleToolWindowFactory.ID);
- }
- return myToolWindow;
- }
-
- public void setToolWindow(ToolWindow toolWindow) {
- myToolWindow = toolWindow;
- }
public interface ConsoleListener {
void handleConsoleInitialized(LanguageConsoleView consoleView);
@@ -955,20 +997,7 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
return session;
}
- @Override
- protected List<String> getActiveConsoleNames(final String consoleTitle) {
- return FluentIterable.from(
- Lists.newArrayList(PythonConsoleToolWindow.getInstance(getProject()).getToolWindow().getContentManager().getContents())).transform(
- new Function<Content, String>() {
- @Override
- public String apply(Content input) {
- return input.getDisplayName();
- }
- }).filter(new Predicate<String>() {
- @Override
- public boolean apply(String input) {
- return input.contains(consoleTitle);
- }
- }).toList();
+ public static PythonConsoleRunnerFactory factory() {
+ return new PydevConsoleRunnerFactory();
}
}
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.java b/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.java
new file mode 100644
index 000000000000..5bed751d204e
--- /dev/null
+++ b/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.console;
+
+import com.google.common.collect.Maps;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.PathMappingSettings;
+import com.jetbrains.python.buildout.BuildoutFacet;
+import com.jetbrains.python.run.PythonCommandLineState;
+import com.jetbrains.python.sdk.PythonEnvUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+* @author traff
+*/
+public class PydevConsoleRunnerFactory extends PythonConsoleRunnerFactory {
+ @Override
+ public PydevConsoleRunner createConsoleRunner(@NotNull Project project,
+ @Nullable Module contextModule) {
+ Pair<Sdk, Module> sdkAndModule = PydevConsoleRunner.findPythonSdkAndModule(project, contextModule);
+
+ Module module = sdkAndModule.second;
+ Sdk sdk = sdkAndModule.first;
+
+ assert sdk != null;
+
+ PathMappingSettings mappingSettings = PydevConsoleRunner.getMappings(project, sdk);
+
+ String[] setupFragment;
+
+ PyConsoleOptions.PyConsoleSettings settingsProvider = PyConsoleOptions.getInstance(project).getPythonConsoleSettings();
+ Collection<String> pythonPath = PythonCommandLineState.collectPythonPath(module, settingsProvider.addContentRoots(),
+ settingsProvider.addSourceRoots());
+
+ if (mappingSettings != null) {
+ pythonPath = mappingSettings.convertToRemote(pythonPath);
+ }
+
+ String customStartScript = settingsProvider == null ? "" : settingsProvider.getCustomStartScript();
+
+ if (customStartScript.trim().length() > 0) {
+ customStartScript = "\n" + customStartScript;
+ }
+
+ String selfPathAppend = PydevConsoleRunner.constructPythonPathCommand(pythonPath, customStartScript);
+
+ String workingDir = settingsProvider.getWorkingDirectory();
+ if (StringUtil.isEmpty(workingDir)) {
+ if (module != null && ModuleRootManager.getInstance(module).getContentRoots().length > 0) {
+ workingDir = ModuleRootManager.getInstance(module).getContentRoots()[0].getPath();
+ }
+ else {
+ if (ModuleManager.getInstance(project).getModules().length > 0) {
+ VirtualFile[] roots = ModuleRootManager.getInstance(ModuleManager.getInstance(project).getModules()[0]).getContentRoots();
+ if (roots.length > 0) {
+ workingDir = roots[0].getPath();
+ }
+ }
+ }
+ }
+
+ if (mappingSettings != null) {
+ workingDir = mappingSettings.convertToRemote(workingDir);
+ }
+
+ BuildoutFacet facet = null;
+ if (module != null) {
+ facet = BuildoutFacet.getInstance(module);
+ }
+
+ if (facet != null) {
+ List<String> path = facet.getAdditionalPythonPath();
+ if (mappingSettings != null) {
+ path = mappingSettings.convertToRemote(path);
+ }
+ String prependStatement = facet.getPathPrependStatement(path);
+ setupFragment = new String[]{prependStatement, selfPathAppend};
+ }
+ else {
+ setupFragment = new String[]{selfPathAppend};
+ }
+
+ Map<String, String> envs = Maps.newHashMap(settingsProvider.getEnvs());
+ String ipythonEnabled = PyConsoleOptions.getInstance(project).isIpythonEnabled() ? "True" : "False";
+ envs.put(PythonEnvUtil.IPYTHONENABLE, ipythonEnabled);
+
+
+ return createConsoleRunner(project, sdk, workingDir, envs, PyConsoleType.PYTHON, setupFragment);
+ }
+
+ protected PydevConsoleRunner createConsoleRunner(Project project,
+ Sdk sdk,
+ String workingDir,
+ Map<String, String> envs, PyConsoleType consoleType, String ... setupFragment) {
+ return new PydevConsoleRunner(project, sdk, consoleType, workingDir, envs, setupFragment);
+ }
+}
diff --git a/python/src/com/jetbrains/python/console/PythonConsoleRunnerFactory.java b/python/src/com/jetbrains/python/console/PythonConsoleRunnerFactory.java
new file mode 100644
index 000000000000..09638656df02
--- /dev/null
+++ b/python/src/com/jetbrains/python/console/PythonConsoleRunnerFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.console;
+
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+* @author traff
+*/
+public abstract class PythonConsoleRunnerFactory {
+ @NotNull
+ public static PythonConsoleRunnerFactory getInstance() {
+ return ServiceManager.getService(PythonConsoleRunnerFactory.class);
+ }
+ public abstract PydevConsoleRunner createConsoleRunner(@NotNull final Project project,
+ @Nullable Module contextModule);
+}
diff --git a/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java b/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java
index e8c50e49280a..177c3528496f 100644
--- a/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java
+++ b/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java
@@ -1,8 +1,14 @@
package com.jetbrains.python.console;
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
+import com.intellij.openapi.util.ActionCallback;
+import com.intellij.openapi.util.Key;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
@@ -11,20 +17,25 @@ import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
+import java.util.List;
/**
* @author traff
*/
public class PythonConsoleToolWindow {
+ public static final Key<RunContentDescriptor> CONTENT_DESCRIPTOR = Key.create("CONTENT_DESCRIPTOR");
private final Project myProject;
private boolean myInitialized = false;
+ private ActionCallback myActivation = new ActionCallback();
+
public PythonConsoleToolWindow(Project project) {
myProject = project;
}
@@ -33,6 +44,17 @@ public class PythonConsoleToolWindow {
return project.getComponent(PythonConsoleToolWindow.class);
}
+ public List<RunContentDescriptor> getConsoleContentDescriptors() {
+ return FluentIterable.from(Lists.newArrayList(getToolWindow().getContentManager().getContents()))
+ .transform(new Function<Content, RunContentDescriptor>() {
+ @Override
+ public RunContentDescriptor apply(@Nullable Content input) {
+ return input != null ? input.getUserData(CONTENT_DESCRIPTOR) : null;
+ }
+ }).filter(
+ Predicates.notNull()).toList();
+ }
+
public void init(final @NotNull ToolWindow toolWindow, final @NotNull RunContentDescriptor contentDescriptor) {
addContent(toolWindow, contentDescriptor);
@@ -42,7 +64,7 @@ public class PythonConsoleToolWindow {
}
}
- private void doInit(final ToolWindow toolWindow) {
+ private void doInit(@NotNull final ToolWindow toolWindow) {
myInitialized = true;
toolWindow.setToHideOnEmptyContent(true);
@@ -58,7 +80,8 @@ public class PythonConsoleToolWindow {
if (window != null) {
boolean visible = window.isVisible();
if (visible && toolWindow.getContentManager().getContentCount() == 0) {
- RunPythonConsoleAction.runPythonConsole(myProject, null, toolWindow);
+ PydevConsoleRunner runner = PythonConsoleRunnerFactory.getInstance().createConsoleRunner(myProject, null);
+ runner.run();
}
}
}
@@ -98,10 +121,11 @@ public class PythonConsoleToolWindow {
private static void resetContent(RunContentDescriptor contentDescriptor, SimpleToolWindowPanel panel, Content content) {
panel.setContent(contentDescriptor.getComponent());
- //panel.addFocusListener(createFocusListener(toolWindow));
content.setComponent(panel);
content.setPreferredFocusableComponent(contentDescriptor.getComponent());
+
+ content.putUserData(CONTENT_DESCRIPTOR, contentDescriptor);
}
private static FocusListener createFocusListener(final ToolWindow toolWindow) {
@@ -124,4 +148,13 @@ public class PythonConsoleToolWindow {
private static JComponent getComponentToFocus(ToolWindow window) {
return window.getContentManager().getComponent();
}
+
+ public void initialized() {
+ myActivation.setDone();
+ }
+
+ public void activate(@NotNull Runnable runnable) {
+ myActivation.doWhenDone(runnable);
+ getToolWindow().activate(null);
+ }
}
diff --git a/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.java b/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.java
index f042a539bc22..2a49d5efedd3 100644
--- a/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.java
+++ b/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.java
@@ -15,10 +15,12 @@
*/
package com.jetbrains.python.console;
+import com.intellij.execution.console.LanguageConsoleView;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
+import org.jetbrains.annotations.NotNull;
/**
* @author traff
@@ -27,7 +29,14 @@ public class PythonConsoleToolWindowFactory implements ToolWindowFactory, DumbAw
public static final String ID = "Python Console";
@Override
- public void createToolWindowContent(Project project, ToolWindow toolWindow) {
- RunPythonConsoleAction.runPythonConsole(project, null, toolWindow);
+ public void createToolWindowContent(final @NotNull Project project, final @NotNull ToolWindow toolWindow) {
+ PydevConsoleRunner runner = PythonConsoleRunnerFactory.getInstance().createConsoleRunner(project, null);
+ runner.addConsoleListener(new PydevConsoleRunner.ConsoleListener() {
+ @Override
+ public void handleConsoleInitialized(LanguageConsoleView consoleView) {
+ PythonConsoleToolWindow.getInstance(project).initialized();
+ }
+ });
+ runner.run();
}
}
diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java
index 699294eb1c8d..86cb0e98e05c 100644
--- a/python/src/com/jetbrains/python/console/PythonConsoleView.java
+++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java
@@ -29,6 +29,7 @@ import com.intellij.execution.ui.ObservableConsoleView;
import com.intellij.ide.GeneralSettings;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
@@ -119,7 +120,7 @@ public class PythonConsoleView extends JPanel implements LanguageConsoleView, Ob
myExecuteActionHandler = consoleExecuteActionHandler;
}
- private void addSaveContentFocusListener(JComponent component){
+ private void addSaveContentFocusListener(JComponent component) {
component.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
@@ -129,7 +130,8 @@ public class PythonConsoleView extends JPanel implements LanguageConsoleView, Ob
}
@Override
- public void focusLost(FocusEvent e) {}
+ public void focusLost(FocusEvent e) {
+ }
});
}
@@ -150,38 +152,53 @@ public class PythonConsoleView extends JPanel implements LanguageConsoleView, Ob
@Override
public void executeCode(final @NotNull String code, @Nullable final Editor editor) {
- ProgressManager.getInstance().run(new Task.Backgroundable(null, "Executing code in console...", false) {
+ showConsole(new Runnable() {
@Override
- public void run(@NotNull final ProgressIndicator indicator) {
- long time = System.currentTimeMillis();
- while (!myExecuteActionHandler.isEnabled() || !myExecuteActionHandler.canExecuteNow()) {
- if (indicator.isCanceled()) {
- break;
- }
- if (System.currentTimeMillis() - time > 1000) {
- if (editor != null) {
- UIUtil.invokeLaterIfNeeded(new Runnable() {
- @Override
- public void run() {
- HintManager.getInstance().showErrorHint(editor, myExecuteActionHandler.getCantExecuteMessage());
+ public void run() {
+ ProgressManager.getInstance().run(new Task.Backgroundable(null, "Executing code in console...", false) {
+ @Override
+ public void run(@NotNull final ProgressIndicator indicator) {
+ long time = System.currentTimeMillis();
+ while (!myExecuteActionHandler.isEnabled() || !myExecuteActionHandler.canExecuteNow()) {
+ if (indicator.isCanceled()) {
+ break;
+ }
+ if (System.currentTimeMillis() - time > 1000) {
+ if (editor != null) {
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ HintManager.getInstance().showErrorHint(editor, myExecuteActionHandler.getCantExecuteMessage());
+ }
+ });
}
- });
+ return;
+ }
+ try {
+ Thread.sleep(300);
+ }
+ catch (InterruptedException ignored) {
+ }
+ }
+ if (!indicator.isCanceled()) {
+ doExecute(code);
}
- return;
- }
- try {
- Thread.sleep(300);
- }
- catch (InterruptedException ignored) {
}
- }
- if (!indicator.isCanceled()) {
- doExecute(code);
- }
+ });
}
});
}
+ private void showConsole(@NotNull Runnable runnable) {
+ PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(myProject);
+ if (toolWindow != null && !ApplicationManager.getApplication().isUnitTestMode()) {
+ toolWindow.getToolWindow().activate(runnable);
+ }
+ else {
+ runnable.run();
+ }
+ }
+
private void doExecute(String code) {
String codeFragment = PyConsoleIndentUtil.normalize(code, myExecuteActionHandler.getCurrentIndentSize());
diff --git a/python/src/com/jetbrains/python/console/PythonToolWindowConsoleRunner.java b/python/src/com/jetbrains/python/console/PythonToolWindowConsoleRunner.java
new file mode 100644
index 000000000000..5c98bd5110b1
--- /dev/null
+++ b/python/src/com/jetbrains/python/console/PythonToolWindowConsoleRunner.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.console;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import com.intellij.execution.Executor;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowManager;
+import com.intellij.ui.content.Content;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author traff
+ */
+public class PythonToolWindowConsoleRunner extends PydevConsoleRunner {
+ private ToolWindow myToolWindow;
+
+ public PythonToolWindowConsoleRunner(@NotNull Project project,
+ @NotNull Sdk sdk,
+ @NotNull PyConsoleType consoleType,
+ @Nullable String workingDir, Map<String, String> environmentVariables,
+ String ... statementsToExecute) {
+ super(project, sdk, consoleType, workingDir, environmentVariables, statementsToExecute);
+ }
+
+ public ToolWindow getToolWindow() {
+ if (myToolWindow == null) {
+ myToolWindow = ToolWindowManager.getInstance(getProject()).getToolWindow(PythonConsoleToolWindowFactory.ID);
+ }
+ return myToolWindow;
+ }
+
+ @Override
+ protected void showConsole(Executor defaultExecutor, @NotNull RunContentDescriptor contentDescriptor) {
+ PythonConsoleToolWindow terminalView = PythonConsoleToolWindow.getInstance(getProject());
+ terminalView.init(getToolWindow(), contentDescriptor);
+ }
+
+ @Override
+ protected void clearContent(RunContentDescriptor descriptor) {
+ Content content = getToolWindow().getContentManager().findContent(descriptor.getDisplayName());
+ assert content != null;
+ getToolWindow().getContentManager().removeContent(content, true);
+ }
+
+ @Override
+ protected List<String> getActiveConsoleNames(final String consoleTitle) {
+ return FluentIterable.from(
+ Lists.newArrayList(PythonConsoleToolWindow.getInstance(getProject()).getToolWindow().getContentManager().getContents())).transform(
+ new Function<Content, String>() {
+ @Override
+ public String apply(Content input) {
+ return input.getDisplayName();
+ }
+ }).filter(new Predicate<String>() {
+ @Override
+ public boolean apply(String input) {
+ return input.contains(consoleTitle);
+ }
+ }).toList();
+ }
+}
diff --git a/python/src/com/jetbrains/python/console/PythonToolWindowConsoleRunnerFactory.java b/python/src/com/jetbrains/python/console/PythonToolWindowConsoleRunnerFactory.java
new file mode 100644
index 000000000000..240f3ab48cf2
--- /dev/null
+++ b/python/src/com/jetbrains/python/console/PythonToolWindowConsoleRunnerFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.console;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+
+import java.util.Map;
+
+/**
+ * @author traff
+ */
+public class PythonToolWindowConsoleRunnerFactory extends PydevConsoleRunnerFactory {
+ @Override
+ protected PydevConsoleRunner createConsoleRunner(Project project,
+ Sdk sdk,
+ String workingDir,
+ Map<String, String> envs, PyConsoleType consoleType, String ... setupFragment) {
+ return new PythonToolWindowConsoleRunner(project, sdk, consoleType, workingDir, envs, setupFragment);
+ }
+}
diff --git a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java
deleted file mode 100644
index 566adea43c87..000000000000
--- a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.console;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Maps;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleManager;
-import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.roots.ModuleRootManager;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.util.PathMappingSettings;
-import com.jetbrains.python.buildout.BuildoutFacet;
-import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
-import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
-import com.jetbrains.python.run.PythonCommandLineState;
-import com.jetbrains.python.sdk.PySdkUtil;
-import com.jetbrains.python.sdk.PythonEnvUtil;
-import com.jetbrains.python.sdk.PythonSdkType;
-import icons.PythonIcons;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author oleg
- */
-public class RunPythonConsoleAction extends AnAction implements DumbAware {
-
- public static final String WORKING_DIR_ENV = "WORKING_DIR_AND_PYTHON_PATHS";
-
- public static final String CONSOLE_START_COMMAND = "import sys; print('Python %s on %s' % (sys.version, sys.platform))\n" +
- "sys.path.extend([" + WORKING_DIR_ENV + "])\n";
-
- public RunPythonConsoleAction() {
- super();
- getTemplatePresentation().setIcon(PythonIcons.Python.Python);
- }
-
- @Override
- public void update(final AnActionEvent e) {
- e.getPresentation().setVisible(true);
- e.getPresentation().setEnabled(false);
- final Project project = e.getData(CommonDataKeys.PROJECT);
- if (project != null) {
- Pair<Sdk, Module> sdkAndModule = findPythonSdkAndModule(project, e.getData(LangDataKeys.MODULE));
- if (sdkAndModule.first != null) {
- e.getPresentation().setEnabled(true);
- }
- }
- }
-
- public void actionPerformed(final AnActionEvent e) {
- final Project project = e.getData(CommonDataKeys.PROJECT);
- runPythonConsole(project, e.getData(LangDataKeys.MODULE), null);
- }
-
- @NotNull
- public static PydevConsoleRunner runPythonConsole(Project project, Module contextModule, @Nullable ToolWindow toolWindow) {
- assert project != null : "Project is null";
-
- Pair<Sdk, Module> sdkAndModule = findPythonSdkAndModule(project, contextModule);
-
- Module module = sdkAndModule.second;
- Sdk sdk = sdkAndModule.first;
-
- assert sdk != null;
-
- PathMappingSettings mappingSettings = getMappings(project, sdk);
-
- String[] setupFragment;
-
- PyConsoleOptions.PyConsoleSettings settingsProvider = PyConsoleOptions.getInstance(project).getPythonConsoleSettings();
- Collection<String> pythonPath = PythonCommandLineState.collectPythonPath(module, settingsProvider.addContentRoots(),
- settingsProvider.addSourceRoots());
-
- if (mappingSettings != null) {
- pythonPath = mappingSettings.convertToRemote(pythonPath);
- }
-
- String customStartScript = settingsProvider == null ? "" : settingsProvider.getCustomStartScript();
-
- if(customStartScript.trim().length() > 0){
- customStartScript = "\n" + customStartScript;
- }
-
- String selfPathAppend = constructPythonPathCommand(pythonPath, customStartScript);
-
- String workingDir = settingsProvider.getWorkingDirectory();
- if (StringUtil.isEmpty(workingDir)) {
- if (module != null && ModuleRootManager.getInstance(module).getContentRoots().length > 0) {
- workingDir = ModuleRootManager.getInstance(module).getContentRoots()[0].getPath();
- }
- else {
- if (ModuleManager.getInstance(project).getModules().length > 0) {
- VirtualFile[] roots = ModuleRootManager.getInstance(ModuleManager.getInstance(project).getModules()[0]).getContentRoots();
- if (roots.length > 0) {
- workingDir = roots[0].getPath();
- }
- }
- }
- }
-
- if (mappingSettings != null) {
- workingDir = mappingSettings.convertToRemote(workingDir);
- }
-
- BuildoutFacet facet = null;
- if (module != null) {
- facet = BuildoutFacet.getInstance(module);
- }
-
- if (facet != null) {
- List<String> path = facet.getAdditionalPythonPath();
- if (mappingSettings != null) {
- path = mappingSettings.convertToRemote(path);
- }
- String prependStatement = facet.getPathPrependStatement(path);
- setupFragment = new String[]{prependStatement, selfPathAppend};
- }
- else {
- setupFragment = new String[]{selfPathAppend};
- }
-
- Map<String, String> envs = Maps.newHashMap(settingsProvider.getEnvs());
- String ipythonEnabled = PyConsoleOptions.getInstance(project).isIpythonEnabled() ? "True" : "False";
- envs.put(PythonEnvUtil.IPYTHONENABLE, ipythonEnabled);
-
- return PydevConsoleRunner
- .createAndRun(project, sdk, PyConsoleType.PYTHON, workingDir, envs, toolWindow, setupFragment);
- }
-
- public static PathMappingSettings getMappings(Project project, Sdk sdk) {
- PathMappingSettings mappingSettings = null;
- if (PySdkUtil.isRemote(sdk)) {
- PythonRemoteInterpreterManager instance = PythonRemoteInterpreterManager.getInstance();
- if (instance != null) {
- mappingSettings =
- instance.setupMappings(project, (PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData(), null);
- }
- }
- return mappingSettings;
- }
-
- @NotNull
- private static Pair<Sdk, Module> findPythonSdkAndModule(Project project, Module contextModule) {
- Sdk sdk = null;
- Module module = null;
- PyConsoleOptions.PyConsoleSettings settings = PyConsoleOptions.getInstance(project).getPythonConsoleSettings();
- String sdkHome = settings.getSdkHome();
- if (sdkHome != null) {
- sdk = PythonSdkType.findSdkByPath(sdkHome);
- if (settings.getModuleName() != null) {
- module = ModuleManager.getInstance(project).findModuleByName(settings.getModuleName());
- }
- else {
- module = contextModule;
- if (module == null && ModuleManager.getInstance(project).getModules().length > 0) {
- module = ModuleManager.getInstance(project).getModules()[0];
- }
- }
- }
- if (sdk == null && settings.isUseModuleSdk()) {
- if (contextModule != null) {
- module = contextModule;
- }
- else if (settings.getModuleName() != null) {
- module = ModuleManager.getInstance(project).findModuleByName(settings.getModuleName());
- }
- if (module != null) {
- if (PythonSdkType.findPythonSdk(module) != null) {
- sdk = PythonSdkType.findPythonSdk(module);
- }
- }
- }
- else if (contextModule != null) {
- if (module == null) {
- module = contextModule;
- }
- if (sdk == null) {
- sdk = PythonSdkType.findPythonSdk(module);
- }
- }
-
- if (sdk == null) {
- for (Module m : ModuleManager.getInstance(project).getModules()) {
- if (PythonSdkType.findPythonSdk(m) != null) {
- sdk = PythonSdkType.findPythonSdk(m);
- module = m;
- break;
- }
- }
- }
- if (sdk == null) {
- if (PythonSdkType.getAllSdks().size() > 0) {
- //noinspection UnusedAssignment
- sdk = PythonSdkType.getAllSdks().get(0); //take any python sdk
- }
- }
- return Pair.create(sdk, module);
- }
-
- public static String constructPythonPathCommand(Collection<String> pythonPath, String command) {
- final String path = Joiner.on(", ").join(Collections2.transform(pythonPath, new Function<String, String>() {
- @Override
- public String apply(String input) {
- return "'" + input.replace("\\", "\\\\").replace("'", "\\'") + "'";
- }
- }));
-
- return command.replace(WORKING_DIR_ENV, path);
- }
-}
diff --git a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java
index 32ad8a31b003..4acfcbd60f74 100644
--- a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java
+++ b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java
@@ -89,7 +89,8 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin
BLANK_LINES);
}
else if (settingsType == SettingsType.WRAPPING_AND_BRACES_SETTINGS) {
- consumer.showStandardOptions("KEEP_LINE_BREAKS",
+ consumer.showStandardOptions("RIGHT_MARGIN",
+ "KEEP_LINE_BREAKS",
"WRAP_LONG_LINES",
"ALIGN_MULTILINE_PARAMETERS",
"ALIGN_MULTILINE_PARAMETERS_IN_CALLS");
diff --git a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java
index 162fa0b9bc60..40efca3663a0 100644
--- a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java
@@ -41,6 +41,7 @@ import java.util.Map;
import static com.jetbrains.python.inspections.PyStringFormatParser.filterSubstitutions;
import static com.jetbrains.python.inspections.PyStringFormatParser.parsePercentFormat;
+import static com.jetbrains.python.psi.PyUtil.as;
/**
* @author Alexey.Ivanov
@@ -416,9 +417,9 @@ public class PyStringFormatInspection extends PyInspection {
inspectValues(((PyParenthesizedExpression)rightExpression).getContainedExpression());
}
else {
- final PyType type = myTypeEvalContext.getType(rightExpression);
+ final PyClassType type = as(myTypeEvalContext.getType(rightExpression), PyClassType.class);
if (type != null) {
- if (myUsedMappingKeys.size() > 0 && !("dict".equals(type.getName()))) {
+ if (myUsedMappingKeys.size() > 0 && !PyABCUtil.isSubclass(type.getPyClass(), PyNames.MAPPING)) {
registerProblem(rightExpression, PyBundle.message("INSP.format.requires.mapping"));
return;
}
diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
index c0fb3c1d620d..4fd58629c516 100644
--- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
@@ -69,7 +69,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
-import java.util.HashSet;
import static com.jetbrains.python.inspections.quickfix.AddIgnoredIdentifierQuickFix.END_WILDCARD;
@@ -833,6 +832,9 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
else {
actions.add(importFix);
}
+ if (ScopeUtil.getScopeOwner(node) instanceof PyFunction) {
+ actions.add(importFix.forLocalImport());
+ }
}
}
diff --git a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java
index fbbdfa215e9c..2b8591f96d8e 100644
--- a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java
+++ b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java
@@ -239,8 +239,6 @@ public class PyPIPackageUtil {
if (connection instanceof HttpsURLConnection) {
((HttpsURLConnection)connection).setSSLSocketFactory(sslContext.getSocketFactory());
}
- connection.setConnectTimeout(5000);
- connection.setReadTimeout(5000);
InputStream is = connection.getInputStream();
Reader reader = new InputStreamReader(is);
try{
diff --git a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java
index bb0e29f800a7..6356a1f92a0d 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java
@@ -20,6 +20,7 @@ import com.google.common.collect.Queues;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -285,12 +286,6 @@ public class PyElementGeneratorImpl extends PyElementGenerator {
throw new IllegalArgumentException("Invalid call expression text " + functionName);
}
- public PyImportStatement createImportStatementFromText(final LanguageLevel languageLevel,
- final String text) {
- final PsiFile dummyFile = createDummyFile(languageLevel, text);
- return (PyImportStatement)dummyFile.getFirstChild();
- }
-
@Override
public PyImportElement createImportElement(final LanguageLevel languageLevel, String name) {
return createFromText(languageLevel, PyImportElement.class, "from foo import " + name, new int[]{0, 6});
@@ -427,6 +422,23 @@ public class PyElementGeneratorImpl extends PyElementGenerator {
return createFromText(LanguageLevel.getDefault(), PsiWhiteSpace.class, " \n\n ");
}
+ @NotNull
+ @Override
+ public PyFromImportStatement createFromImportStatement(@NotNull LanguageLevel languageLevel, @NotNull String qualifier,
+ @NotNull String name, @Nullable String alias) {
+ final String asClause = StringUtil.isNotEmpty(alias) ? " as " + alias : "";
+ final String statement = "from " + qualifier + " import " + name + asClause;
+ return createFromText(languageLevel, PyFromImportStatement.class, statement);
+ }
+
+ @NotNull
+ @Override
+ public PyImportStatement createImportStatement(@NotNull LanguageLevel languageLevel, @NotNull String name, @Nullable String alias) {
+ final String asClause = StringUtil.isNotEmpty(alias) ? " as " + alias : "";
+ final String statement = "import " + name + asClause;
+ return createFromText(languageLevel, PyImportStatement.class, statement);
+ }
+
private static class CommasOnly extends NotNullPredicate<LeafPsiElement> {
@Override
protected boolean applyNotNull(@NotNull final LeafPsiElement input) {
diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
index 4b3adfd112f8..4bdbae69d83d 100644
--- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
+++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
@@ -18,10 +18,12 @@ package com.jetbrains.python.psi.types;
import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
+import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.psi.resolve.QualifiedResolveResult;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,6 +32,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import static com.jetbrains.python.psi.PyFunction.Modifier.STATICMETHOD;
+import static com.jetbrains.python.psi.PyUtil.as;
+
/**
* Type of a particular function that is represented as a {@link Callable} in the PSI tree.
*
@@ -74,20 +79,79 @@ public class PyFunctionType implements PyCallableType {
@Nullable PyExpression location,
@NotNull AccessDirection direction,
@NotNull PyResolveContext resolveContext) {
- final PyClassTypeImpl functionType = PyBuiltinCache.getInstance(getCallable()).getObjectType(PyNames.FAKE_FUNCTION);
- if (functionType == null) {
+ final PyClassType delegate = selectFakeType(location, resolveContext.getTypeEvalContext());
+ if (delegate == null) {
return Collections.emptyList();
}
- return functionType.resolveMember(name, location, direction, resolveContext);
+ return delegate.resolveMember(name, location, direction, resolveContext);
}
@Override
public Object[] getCompletionVariants(String completionPrefix, PsiElement location, ProcessingContext context) {
- final PyClassTypeImpl functionType = PyBuiltinCache.getInstance(getCallable()).getObjectType(PyNames.FAKE_FUNCTION);
- if (functionType == null) {
+ final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(location.getContainingFile());
+ final PyClassType delegate;
+ if (location instanceof PyReferenceExpression) {
+ delegate = selectFakeType(((PyReferenceExpression)location).getQualifier(), typeEvalContext);
+ }
+ else {
+ delegate = PyBuiltinCache.getInstance(getCallable()).getObjectType(PyNames.FAKE_FUNCTION);
+ }
+ if (delegate == null) {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
- return functionType.getCompletionVariants(completionPrefix, location, context);
+ return delegate.getCompletionVariants(completionPrefix, location, context);
+ }
+
+ /**
+ * Select either {@link PyNames#FAKE_FUNCTION} or {@link PyNames#FAKE_METHOD} fake class depending on concrete reference used and
+ * language level. Will fallback to fake function type.
+ */
+ @Nullable
+ private PyClassTypeImpl selectFakeType(@Nullable PyExpression location, @NotNull TypeEvalContext context) {
+ if (location instanceof PyReferenceExpression && isBoundMethodReference(((PyReferenceExpression)location), context)) {
+ return PyBuiltinCache.getInstance(getCallable()).getObjectType(PyNames.FAKE_METHOD);
+ }
+ return PyBuiltinCache.getInstance(getCallable()).getObjectType(PyNames.FAKE_FUNCTION);
+ }
+
+ private boolean isBoundMethodReference(@NotNull PyReferenceExpression location, @NotNull TypeEvalContext context) {
+ final PyFunction function = as(getCallable(), PyFunction.class);
+ final boolean isNonStaticMethod = function != null && function.getContainingClass() != null && function.getModifier() != STATICMETHOD;
+ if (isNonStaticMethod) {
+ // In Python 2 unbound methods have __method fake type
+ if (LanguageLevel.forElement(location).isOlderThan(LanguageLevel.PYTHON30)) {
+ return true;
+ }
+ final PyExpression qualifier;
+ if (location.isQualified()) {
+ qualifier = location.getQualifier();
+ }
+ else {
+ final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
+ final QualifiedResolveResult resolveResult = location.followAssignmentsChain(resolveContext);
+ final List<PyExpression> qualifiers = resolveResult.getQualifiers();
+ qualifier = ContainerUtil.isEmpty(qualifiers) ? null : qualifiers.get(qualifiers.size() - 1);
+ }
+ if (qualifier != null) {
+ //noinspection ConstantConditions
+ final PyType qualifierType = PyTypeChecker.toNonWeakType(context.getType(qualifier), context);
+ if (isInstanceType(qualifierType)) {
+ return true;
+ }
+ else if (qualifierType instanceof PyUnionType) {
+ for (PyType type : ((PyUnionType)qualifierType).getMembers()) {
+ if (isInstanceType(type)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private static boolean isInstanceType(@Nullable PyType type) {
+ return type instanceof PyClassType && !((PyClassType)type).isDefinition();
}
@Override
diff --git a/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java b/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java
index e4259d8581bb..fa2b4cf1204b 100644
--- a/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java
+++ b/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java
@@ -109,7 +109,7 @@ public class PyRefactoringUtil {
final PyElementGenerator generator = PyElementGenerator.getInstance(project);
final LanguageLevel langLevel = LanguageLevel.forElement(element1);
final PyExpression expression = generator.createFromText(langLevel, PyAssignmentStatement.class, "z=" + selection).getAssignedValue();
- if (PsiUtilCore.hasErrorElementChild(expression) || !(expression instanceof PyBinaryExpression)) {
+ if (!(expression instanceof PyBinaryExpression) || PsiUtilCore.hasErrorElementChild(expression)) {
return null;
}
final String parentText = parent.getText();
diff --git a/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java b/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java
index f4cb9e6a73f3..2cebb3ec2720 100644
--- a/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java
+++ b/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java
@@ -47,6 +47,15 @@ import static com.jetbrains.python.inspections.PyStringFormatParser.parsePercent
* @author Dennis.Ushakov
*/
public class PyReplaceExpressionUtil implements PyElementTypes {
+ /**
+ * This marker is added in cases where valid selection nevertheless breaks existing expression.
+ * It can happen in cases like (here {@code <start> and <end>} represent selection boundaries):
+ * <ul>
+ * <li>Selection conflicts with operator precedence: {@code n = 1 * <start>2 + 3<end>}</li>
+ * <li>Selection conflicts with operator associativity: {@code n = 1 + <start>2 + 3<end>}</li>
+ * <li>Part of string literal is selected: {@code s = 'green <start>eggs<end> and ham'}</li>
+ * </ul>
+ */
public static final Key<Pair<PsiElement, TextRange>> SELECTION_BREAKS_AST_NODE =
new Key<Pair<PsiElement, TextRange>>("python.selection.breaks.ast.node");
diff --git a/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java b/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
index a582b1728d47..575399c61ceb 100644
--- a/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
@@ -134,7 +134,7 @@ public class PyInlineLocalHandler extends InlineActionHandler {
if (editor != null && !ApplicationManager.getApplication().isUnitTestMode()) {
highlightManager.addOccurrenceHighlights(editor, refsToInline, attributes, true, null);
int occurrencesCount = refsToInline.length;
- String occurencesString = RefactoringBundle.message("occurences.string", occurrencesCount);
+ String occurencesString = RefactoringBundle.message("occurrences.string", occurrencesCount);
final String promptKey = "inline.local.variable.prompt";
final String question = RefactoringBundle.message(promptKey, localName) + " " + occurencesString;
RefactoringMessageDialog dialog = new RefactoringMessageDialog(REFACTORING_NAME, question, HELP_ID, "OptionPane.questionIcon", true, project);
diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
index 29fc44105857..00448c8b69bd 100644
--- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
@@ -69,6 +69,11 @@ import static com.jetbrains.python.inspections.PyStringFormatParser.*;
abstract public class IntroduceHandler implements RefactoringActionHandler {
protected static PsiElement findAnchor(List<PsiElement> occurrences) {
PsiElement anchor = occurrences.get(0);
+ final Pair<PsiElement, TextRange> data = anchor.getUserData(PyReplaceExpressionUtil.SELECTION_BREAKS_AST_NODE);
+ // Search anchor in the origin file, not in dummy.py, if selection breaks statement and thus element was generated
+ if (data != null && occurrences.size() == 1) {
+ return PsiTreeUtil.getParentOfType(data.getFirst(), PyStatement.class);
+ }
next:
do {
final PyStatement statement = PsiTreeUtil.getParentOfType(anchor, PyStatement.class);
@@ -192,7 +197,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
String text = expression.getText();
final Pair<PsiElement, TextRange> selection = expression.getUserData(PyReplaceExpressionUtil.SELECTION_BREAKS_AST_NODE);
if (selection != null) {
- text = selection.getSecond().substring(text);
+ text = selection.getSecond().substring(selection.getFirst().getText());
}
if (expression instanceof PyCallExpression) {
final PyExpression callee = ((PyCallExpression)expression).getCallee();
diff --git a/python/src/com/jetbrains/python/refactoring/introduce/constant/PyIntroduceConstantHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/constant/PyIntroduceConstantHandler.java
index af9ff583e3e4..44fdee8abdf7 100644
--- a/python/src/com/jetbrains/python/refactoring/introduce/constant/PyIntroduceConstantHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/introduce/constant/PyIntroduceConstantHandler.java
@@ -24,6 +24,7 @@ import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.imports.AddImportHelper;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyParameterList;
import com.jetbrains.python.refactoring.PyReplaceExpressionUtil;
import com.jetbrains.python.refactoring.introduce.IntroduceHandler;
import com.jetbrains.python.refactoring.introduce.IntroduceOperation;
@@ -66,6 +67,11 @@ public class PyIntroduceConstantHandler extends IntroduceHandler {
}
@Override
+ protected boolean isValidIntroduceContext(PsiElement element) {
+ return super.isValidIntroduceContext(element) || PsiTreeUtil.getParentOfType(element, PyParameterList.class) != null;
+ }
+
+ @Override
protected String getHelpId() {
return "python.reference.introduceConstant";
}
diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
index a4d1718bb006..220939efc274 100644
--- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java
+++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
@@ -87,7 +87,7 @@ public abstract class PythonCommandLineState extends CommandLineState {
private Boolean myMultiprocessDebug = null;
public boolean isDebug() {
- return PyDebugRunner.PY_DEBUG_RUNNER.equals(getEnvironment().getRunnerId());
+ return PyDebugRunner.PY_DEBUG_RUNNER.equals(getEnvironment().getRunner().getRunnerId());
}
public static ServerSocket createServerSocket() throws ExecutionException {
@@ -171,23 +171,13 @@ public abstract class PythonCommandLineState extends CommandLineState {
* @throws ExecutionException
*/
protected ProcessHandler startProcess(CommandLinePatcher... patchers) throws ExecutionException {
-
-
GeneralCommandLine commandLine = generateCommandLine(patchers);
// Extend command line
- RunnerSettings runnerSettings = getRunnerSettings();
- String runnerId = getEnvironment().getRunnerId();
- if (runnerId != null) {
- PythonRunConfigurationExtensionsManager.getInstance().patchCommandLine(myConfig, runnerSettings, commandLine, runnerId);
- }
-
+ PythonRunConfigurationExtensionsManager.getInstance().patchCommandLine(myConfig, getRunnerSettings(), commandLine, getEnvironment().getRunner().getRunnerId());
Sdk sdk = PythonSdkType.findSdkByPath(myConfig.getInterpreterPath());
-
-
final ProcessHandler processHandler;
if (PySdkUtil.isRemote(sdk)) {
- assert sdk != null;
processHandler =
createRemoteProcessStarter().startRemoteProcess(sdk, commandLine, myConfig.getProject(), myConfig.getMappingSettings());
}
diff --git a/python/src/com/jetbrains/python/run/PythonRunner.java b/python/src/com/jetbrains/python/run/PythonRunner.java
index b95da7c62957..3007b0b7a5f9 100644
--- a/python/src/com/jetbrains/python/run/PythonRunner.java
+++ b/python/src/com/jetbrains/python/run/PythonRunner.java
@@ -59,9 +59,6 @@ public class PythonRunner extends DefaultProgramRunner {
else {
executionResult = state.execute(env.getExecutor(), this);
}
- if (executionResult == null) return null;
-
- final RunContentBuilder contentBuilder = new RunContentBuilder(this, executionResult, env);
- return contentBuilder.showRunContent(contentToReuse);
+ return executionResult == null ? null : new RunContentBuilder(executionResult, env).showRunContent(contentToReuse);
}
}
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
index f194f359e1a9..58de09370d37 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
@@ -910,6 +910,16 @@ public class PythonSdkType extends SdkType {
return null;
}
+ @Nullable
+ public static Sdk findPython2Sdk(List<Sdk> sdks) {
+ Collections.sort(sdks, PreferredSdkComparator.INSTANCE);
+ for (Sdk sdk : sdks) {
+ if (!getLanguageLevelForSdk(sdk).isPy3K()) {
+ return sdk;
+ }
+ }
+ return null;
+ }
@Nullable
public static Sdk findLocalCPython(@Nullable Module module) {
@@ -997,7 +1007,7 @@ public class PythonSdkType extends SdkType {
public static boolean isIncompleteRemote(Sdk sdk) {
if (PySdkUtil.isRemote(sdk)) {
//noinspection ConstantConditions
- if (!((PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData()).isInitialized()) {
+ if (!((PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData()).isValid()) {
return true;
}
}
diff --git a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
index 284a125e8736..4e4a43102202 100644
--- a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
+++ b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
@@ -20,7 +20,6 @@ import com.google.common.collect.Lists;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.execution.ExecutionException;
import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
@@ -35,6 +34,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -58,7 +58,6 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.io.*;
import java.util.*;
@@ -164,18 +163,27 @@ public class PySkeletonRefresher {
else {
message = PyBundle.message("sdk.errorlog.$0.mods.fail.in.$1.sdks", module_errors, errors.size());
}
- Notifications.Bus.notify(
- new Notification(
- PythonSdkType.SKELETONS_TOPIC, PyBundle.message("sdk.some.skeletons.failed"), message,
- NotificationType.WARNING,
- new NotificationListener() {
- @Override
- public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
- new SkeletonErrorsDialog(errors, failedSdks).setVisible(true);
- }
- }
- )
- );
+ logErrors(errors, failedSdks, message);
+ }
+ }
+
+ private static void logErrors(@NotNull final Map<String, List<String>> errors, @NotNull final List<String> failedSdks,
+ @NotNull final String message) {
+ LOG.warn(PyBundle.message("sdk.some.skeletons.failed"));
+ LOG.warn(message);
+
+ if (failedSdks.size() > 0) {
+ LOG.warn(PyBundle.message("sdk.error.dialog.failed.sdks"));
+ LOG.warn(StringUtil.join(failedSdks, ", "));
+ }
+
+ if (errors.size() > 0) {
+ LOG.warn(PyBundle.message("sdk.error.dialog.failed.modules"));
+ for (String sdkName : errors.keySet()) {
+ for (String moduleName : errors.get(sdkName)) {
+ LOG.warn(moduleName);
+ }
+ }
}
}
diff --git a/python/src/com/jetbrains/python/sdk/skeletons/SkeletonErrorsDialog.form b/python/src/com/jetbrains/python/sdk/skeletons/SkeletonErrorsDialog.form
deleted file mode 100644
index c82d5fa91b00..000000000000
--- a/python/src/com/jetbrains/python/sdk/skeletons/SkeletonErrorsDialog.form
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.sdk.skeletons.SkeletonErrorsDialog">
- <grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
- <margin top="10" left="10" bottom="10" right="10"/>
- <constraints>
- <xy x="48" y="54" width="436" height="409"/>
- </constraints>
- <properties/>
- <border type="none"/>
- <children>
- <grid id="94766" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
- <margin top="0" left="0" bottom="0" right="0"/>
- <constraints>
- <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties/>
- <border type="none"/>
- <children>
- <grid id="9538f" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
- <margin top="0" left="0" bottom="0" right="0"/>
- <constraints>
- <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties/>
- <border type="none"/>
- <children>
- <component id="e7465" class="javax.swing.JButton" binding="buttonOK">
- <constraints>
- <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties>
- <text value="OK"/>
- </properties>
- </component>
- </children>
- </grid>
- <scrollpane id="d5fbd" class="com.intellij.ui.components.JBScrollPane" binding="myScroller">
- <constraints>
- <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties/>
- <border type="none"/>
- <children>
- <component id="10d56" class="javax.swing.JTextPane" binding="myMessagePane">
- <constraints/>
- <properties>
- <editable value="false"/>
- <enabled value="true"/>
- </properties>
- <clientProperties>
- <JEditorPane.honorDisplayProperties class="java.lang.Boolean" value="true"/>
- <caretAspectRatio class="java.lang.Float" value="0.04"/>
- </clientProperties>
- </component>
- </children>
- </scrollpane>
- </children>
- </grid>
- </children>
- </grid>
-</form>
diff --git a/python/src/com/jetbrains/python/sdk/skeletons/SkeletonErrorsDialog.java b/python/src/com/jetbrains/python/sdk/skeletons/SkeletonErrorsDialog.java
deleted file mode 100644
index f6c6b45ceb44..000000000000
--- a/python/src/com/jetbrains/python/sdk/skeletons/SkeletonErrorsDialog.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.sdk.skeletons;
-
-import com.intellij.ui.components.JBScrollPane;
-import com.jetbrains.python.PyBundle;
-
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.List;
-import java.util.Map;
-
-public class SkeletonErrorsDialog extends JDialog {
- private JPanel contentPane;
- private JButton buttonOK;
- private JBScrollPane myScroller;
- private JTextPane myMessagePane;
-
- public SkeletonErrorsDialog(Map<String, List<String>> errors, List<String> failed_sdks) {
- setContentPane(contentPane);
- setModal(true);
- getRootPane().setDefaultButton(buttonOK);
-
- buttonOK.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- dispose();
- }
- });
-
- // fill data
- myMessagePane.setContentType("text/html");
- myMessagePane.setBorder(new EmptyBorder(0, 0, 0, 0));
- StringBuilder sb = new StringBuilder("<html><body style='margin: 4pt;' ");
- final Color foreground = getParent().getForeground();
- final Color background = getParent().getBackground();
- if (foreground != null && background != null) {
- sb.append("text='").append(getHTMLColor(foreground)).append("' ");
- sb.append("bgcolor='").append(getHTMLColor(background)).append("'");
- }
- sb.append(">");
-
- if (failed_sdks.size() > 0) {
- sb.append("<h1>").append(PyBundle.message("sdk.error.dialog.failed.sdks")).append("</h1>");
- sb.append("<ul>");
- for (String sdk_name : failed_sdks) {
- sb.append("<li>").append(sdk_name).append("</li>");
- }
- sb.append("</ul><br>");
- }
-
- if (errors.size() > 0) {
- sb.append("<h1>").append(PyBundle.message("sdk.error.dialog.failed.modules")).append("</h1>");
- for (String sdk_name : errors.keySet()) {
- sb.append("<b>").append(sdk_name).append("</b><br>");
- sb.append("<ul>");
- for (String module_name : errors.get(sdk_name)) {
- sb.append("<li>").append(module_name).append("</li>");
- }
- sb.append("</ul>");
- }
- sb.append(PyBundle.message("sdk.error.dialog.were.blacklisted"));
- }
-
- sb.append("</body></html>");
- myMessagePane.setText(sb.toString());
-
- setTitle(PyBundle.message("sdk.error.dialog.problems"));
-
- pack();
- setLocationRelativeTo(getParent());
- }
-
- private static String getHTMLColor(Color color) {
- StringBuilder sb = new StringBuilder("#");
- sb.append(Integer.toHexString(color.getRGB() & 0xffffff));
- return sb.toString();
- }
-}
diff --git a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
index cc468c5e40ac..0b922514e52e 100644
--- a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
+++ b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
@@ -72,7 +72,7 @@ public class PyRerunFailedTestsAction extends AbstractRerunFailedTestsAction {
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
final AbstractPythonRunConfiguration configuration = ((AbstractPythonRunConfiguration)getPeer());
return new FailedPythonTestCommandLineStateBase(configuration, env,
- (PythonTestCommandLineStateBase)configuration.getState(executor, env));
+ (PythonTestCommandLineStateBase)configuration.getState(executor, env));
}
}