Snapshot idea/138.1029 from git://git.jetbrains.org/idea/community.git
Update from idea/138.538 to idea/138.1029
Change-Id: I828f829a968439a99ec67640990c18ff7c9b58ce
diff --git a/python/build/pycharm_community_build.gant b/python/build/pycharm_community_build.gant
index 7efb4e3..3b793ec 100644
--- a/python/build/pycharm_community_build.gant
+++ b/python/build/pycharm_community_build.gant
@@ -173,7 +173,7 @@
String tarRoot = isEap() ? "pycharm-community-$buildNumber" : "pycharm-community-${p("component.version.major")}.${p("component.version.minor")}"
buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildNumber}.tar", [paths.distAll, paths.distUnix])
- String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app" : "PyCharm CE.app"
+ String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm CE.app/Contents"
buildMacZip(macAppRoot, "${paths.artifacts}/pycharmPC-${buildNumber}.sit", [paths.distAll], paths.distMac)
}
@@ -181,22 +181,6 @@
dir("plugins") {
layouts.layoutPlugin("rest")
layouts.layoutPlugin("python-rest")
- /*
- layouts.layoutPlugin("pycharm-flask")
- layouts.layoutPlugin("pycharm-numpy")
- layouts.layoutPlugin("textmate") {
- dir("themes") {
- fileset(dir: "${home}/plugins/textmate/lib/themes/", includes: "*.tmTheme")
- }
- fileset(dir: "${home}/plugins/textmate/lib") {
- include(name: "jcodings.jar")
- include(name: "joni.jar")
- }
- }
- layouts.layoutPlugin("puppet")
- layouts.layoutPlugin("fileWatcher")
- layouts.layoutPlugin("ini4idea")
- */
}
layouts.layoutCommunityPlugins(ch)
diff --git a/python/build/python_plugin_build.gant b/python/build/python_plugin_build.gant
index dc37d14..702ab30 100644
--- a/python/build/python_plugin_build.gant
+++ b/python/build/python_plugin_build.gant
@@ -95,6 +95,7 @@
dirset(dir: "${pluginHome}") {
include(name: "resources")
include(name: "src")
+ include(name: "gen")
include(name: "pluginSrc")
include(name: "pydevSrc")
include(name: "openapi/src")
diff --git a/python/gen/icons/PythonIcons.java b/python/gen/icons/PythonIcons.java
index 4e91858..b4c59bd 100644
--- a/python/gen/icons/PythonIcons.java
+++ b/python/gen/icons/PythonIcons.java
@@ -45,6 +45,7 @@
public static final Icon PropertyGetter = load("/icons/com/jetbrains/python/propertyGetter.png"); // 16x16
public static final Icon PropertySetter = load("/icons/com/jetbrains/python/propertySetter.png"); // 16x16
public static final Icon Pypy = load("/icons/com/jetbrains/python/pypy.png"); // 16x16
+ public static final Icon Python_logo = load("/icons/com/jetbrains/python/python-logo.png"); // 32x32
public static final Icon Python = load("/icons/com/jetbrains/python/python.png"); // 16x16
public static final Icon Python_24 = load("/icons/com/jetbrains/python/python_24.png"); // 24x24
public static final Icon PythonClosed = load("/icons/com/jetbrains/python/pythonClosed.png"); // 16x16
diff --git a/python/helpers/packaging_tool.py b/python/helpers/packaging_tool.py
index c66cbcb..9101a16 100644
--- a/python/helpers/packaging_tool.py
+++ b/python/helpers/packaging_tool.py
@@ -21,7 +21,7 @@
def usage():
- sys.stderr.write('Usage: packaging_tool.py <list|install|uninstall|pyvenv>\n')
+ sys.stderr.write('Usage: packaging_tool.py <list|search|install|uninstall|pyvenv>\n')
sys.stderr.flush()
exit(ERROR_WRONG_USAGE)
@@ -58,6 +58,13 @@
error_no_pip()
return pip.main(['install'] + pkgs)
+def do_search(pkgs):
+ try:
+ import pip
+ except ImportError:
+ error_no_pip()
+ return pip.main(['search'] + pkgs)
+
def do_uninstall(pkgs):
try:
@@ -115,6 +122,11 @@
if len(sys.argv) != 2:
usage()
do_list()
+ elif cmd == 'search':
+ if len(sys.argv) < 2:
+ usage()
+ pkgs = sys.argv[2:]
+ do_search(pkgs)
elif cmd == 'install':
if len(sys.argv) < 2:
usage()
diff --git a/python/helpers/pycharm_generator_utils/module_redeclarator.py b/python/helpers/pycharm_generator_utils/module_redeclarator.py
index 0e96b9c..3af1961 100644
--- a/python/helpers/pycharm_generator_utils/module_redeclarator.py
+++ b/python/helpers/pycharm_generator_utils/module_redeclarator.py
@@ -120,7 +120,7 @@
init = None
try:
if self.split_modules:
- mod_path = self.outfile.strip(".py")
+ mod_path = module_to_package_name(self.outfile)
fname = build_output_name(mod_path, "__init__")
init = fopen(fname, "w")
@@ -1093,3 +1093,7 @@
for mod_name in sorted_no_case(self.hidden_imports.keys()):
out(0, 'import ', mod_name, ' as ', self.hidden_imports[mod_name])
out(0, "") # empty line after group
+
+
+def module_to_package_name(module_name):
+ return re.sub(r"(.*)\.py$", r"\1", module_name)
diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py
index 4a509d0..2077903 100644
--- a/python/helpers/pydev/pydevd.py
+++ b/python/helpers/pydev/pydevd.py
@@ -814,7 +814,7 @@
del self.exception_set[exception]
self.always_exception_set.remove(exception)
except:
- pydev_log.debug("Error while removing exception"%sys.exc_info()[0]);
+ pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0]);
update_exception_hook(self)
elif cmd_id == CMD_LOAD_SOURCE:
diff --git a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.form b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.form
index 108b9af..b732b51 100644
--- a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.form
+++ b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.form
@@ -80,7 +80,7 @@
<text value="Pro&ject:"/>
</properties>
</component>
- <component id="195cd" class="javax.swing.JComboBox" binding="myModuleCombo">
+ <component id="195cd" class="com.intellij.application.options.ModulesComboBox" binding="myModuleCombo">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
diff --git a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java
index 94e9912..3b59037 100644
--- a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java
+++ b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java
@@ -26,6 +26,7 @@
import com.intellij.openapi.projectRoots.SdkModel;
import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer;
import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.application.options.ModulesComboBox;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
@@ -40,7 +41,6 @@
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
import com.jetbrains.python.configuration.PyConfigureInterpretersLinkPanel;
import com.jetbrains.python.run.AbstractPyCommonOptionsForm;
-import com.intellij.application.options.ModuleListCellRenderer;
import com.jetbrains.python.run.PyCommonOptionsFormData;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkType;
@@ -64,7 +64,7 @@
private JComboBox myInterpreterComboBox;
private JBLabel myPythonInterpreterJBLabel;
private JLabel myProjectLabel;
- private JComboBox myModuleCombo;
+ private ModulesComboBox myModuleCombo;
private JPanel myConfigureInterpretersPanel;
private String mySelectedSdkHome = null;
private PathMappingsComponent myPathMappingsComponent;
@@ -97,15 +97,15 @@
else {
final List<Module> validModules = data.getValidModules();
Module selection = validModules.size() > 0 ? validModules.get(0) : null;
- myModuleCombo.setModel(new CollectionComboBoxModel(validModules, selection));
- myModuleCombo.setRenderer(new ModuleListCellRenderer());
+ myModuleCombo.setModules(validModules);
+ myModuleCombo.setSelectedModule(selection);
myModuleCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- updateDefaultInterpreter((Module)myModuleCombo.getSelectedItem());
+ updateDefaultInterpreter(myModuleCombo.getSelectedModule());
}
});
- updateDefaultInterpreter((Module)myModuleCombo.getSelectedItem());
+ updateDefaultInterpreter(myModuleCombo.getSelectedModule());
}
setAnchor(myEnvsComponent.getLabel());
@@ -200,7 +200,7 @@
@Nullable
@Override
public Module getModule() {
- final Module selectedItem = (Module)myModuleCombo.getSelectedItem();
+ final Module selectedItem = myModuleCombo.getSelectedModule();
if (selectedItem != null) {
return selectedItem;
}
@@ -213,7 +213,7 @@
@Override
public void setModule(Module module) {
- myModuleCombo.setSelectedItem(module);
+ myModuleCombo.setSelectedModule(module);
updateDefaultInterpreter(module);
}
diff --git a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java
index 2d89427..3010b74 100644
--- a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java
+++ b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java
@@ -19,20 +19,16 @@
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.projectRoots.SdkType;
-import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.ComboboxWithBrowseButton;
import com.intellij.util.NullableConsumer;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
-import com.jetbrains.python.sdk.PyDetectedSdk;
+import com.jetbrains.python.sdk.PySdkListCellRenderer;
import com.jetbrains.python.sdk.PySdkService;
import com.jetbrains.python.sdk.PythonSdkDetailsStep;
-import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -58,14 +54,7 @@
}
final JComboBox comboBox = getComboBox();
comboBox.setModel(new CollectionComboBoxModel(sdks, initialSelection));
- comboBox.setRenderer(new SdkListCellRenderer("<no interpreter>") {
- @Override
- protected Icon getSdkIcon(Sdk sdk) {
- final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk);
- final Icon icon = flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon();
- return sdk instanceof PyDetectedSdk ? IconLoader.getTransparentIcon(icon) : icon;
- }
- });
+ comboBox.setRenderer(new PySdkListCellRenderer(true));
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showOptions(project);
diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java
index b2a7d91..fc165b8 100644
--- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java
+++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java
@@ -188,7 +188,7 @@
}
};
mySdkCombo.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
- mySdkCombo.setRenderer(new PySdkListCellRenderer());
+ mySdkCombo.setRenderer(new PySdkListCellRenderer(false));
final PackagesNotificationPanel notificationsArea = new PackagesNotificationPanel(myProject);
final JComponent notificationsComponent = notificationsArea.getComponent();
@@ -407,7 +407,7 @@
items.add(PySdkListCellRenderer.SEPARATOR);
items.add(SHOW_ALL);
- mySdkCombo.setRenderer(new PySdkListCellRenderer());
+ mySdkCombo.setRenderer(new PySdkListCellRenderer(false));
//noinspection unchecked
mySdkCombo.setModel(new CollectionComboBoxModel(items, selection));
}
diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonPathEditor.java b/python/ide/src/com/jetbrains/python/configuration/PythonPathEditor.java
index 1c1a663..33169a7 100644
--- a/python/ide/src/com/jetbrains/python/configuration/PythonPathEditor.java
+++ b/python/ide/src/com/jetbrains/python/configuration/PythonPathEditor.java
@@ -300,7 +300,7 @@
}
- private static class PythonPathListCellRenderer extends ListCellRendererWrapper<VirtualFile> {
+ private class PythonPathListCellRenderer extends ListCellRendererWrapper<VirtualFile> {
private final PathListModel model;
public PythonPathListCellRenderer(final ListCellRenderer listCellRenderer, PathListModel model) {
@@ -314,7 +314,11 @@
if (suffix.length() > 0) {
suffix = " " + suffix;
}
- setText(value != null ? value.getPresentableUrl() + suffix : "");
+ setText(value != null ? getPresentablePath(value) + suffix : "");
}
}
+
+ protected String getPresentablePath(VirtualFile value) {
+ return value.getPresentableUrl();
+ }
}
diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java
index 6ff0a2e..b0ca6db 100644
--- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java
+++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java
@@ -45,6 +45,7 @@
import com.intellij.util.NullableConsumer;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.FactoryMap;
+import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.sdk.*;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
@@ -286,8 +287,9 @@
myModifiedModificators.add(modificator);
}
final Sdk oldSdk = myProjectSdksModel.findSdk(sdk);
- if (oldSdk == null)
+ if (oldSdk == null) {
myProjectSdksModel.addSdk(sdk);
+ }
refreshSdkList();
mySdkList.setSelectedValue(sdk, true);
mySdkListChanged = true;
@@ -452,15 +454,10 @@
return LocalFileSystem.getInstance().refreshAndFindFileByPath(sdkName);
}
});
- sdk = SdkConfigurationUtil.setupSdk(ProjectJdkTable.getInstance().getAllJdks(), sdkHome, PythonSdkType.getInstance(), true, null, null);
+ sdk =
+ SdkConfigurationUtil.setupSdk(ProjectJdkTable.getInstance().getAllJdks(), sdkHome, PythonSdkType.getInstance(), true, null, null);
}
- final PythonPathEditor pathEditor =
- new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) {
- @Override
- protected void onReloadButtonClicked() {
- reloadSdk();
- }
- };
+ final PythonPathEditor pathEditor = createPathEditor(sdk);
final SdkModificator sdkModificator = myModificators.get(sdk);
PythonPathDialog dialog = new PythonPathDialog(myProject, pathEditor);
@@ -476,4 +473,40 @@
updateOkButton();
}
}
+
+ private PythonPathEditor createPathEditor(final Sdk sdk) {
+ if (PySdkUtil.isRemote(sdk)) {
+ return new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) {
+ private final PyRemoteSdkAdditionalDataBase myRemoteSdkData = (PyRemoteSdkAdditionalDataBase) sdk.getSdkAdditionalData();
+ @Override
+ protected void onReloadButtonClicked() {
+ reloadSdk();
+ }
+
+ @Override
+ protected String getPresentablePath(VirtualFile value) {
+ String path = value.getPath();
+ return myRemoteSdkData.getPathMappings().convertToRemote(path);
+ }
+
+ @Override
+ protected void addToolbarButtons(ToolbarDecorator toolbarDecorator) {
+ toolbarDecorator.setAddActionUpdater(new AnActionButtonUpdater() {
+ @Override
+ public boolean isEnabled(AnActionEvent e) {
+ return false; //TODO: implement adding remote path
+ }
+ });
+ }
+ };
+ }
+ else {
+ return new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) {
+ @Override
+ protected void onReloadButtonClicked() {
+ reloadSdk();
+ }
+ };
+ }
+ }
}
diff --git a/python/ide/src/com/jetbrains/python/newProject/PyCharmNewProjectAction.java b/python/ide/src/com/jetbrains/python/newProject/PyCharmNewProjectAction.java
new file mode 100644
index 0000000..85f649c
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/newProject/PyCharmNewProjectAction.java
@@ -0,0 +1,27 @@
+/*
+ * 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.newProject;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+
+public class PyCharmNewProjectAction extends AnAction {
+
+ public void actionPerformed(final AnActionEvent e) {
+ final PyCharmNewProjectDialog dlg = new PyCharmNewProjectDialog();
+ dlg.show();
+ }
+}
diff --git a/python/ide/src/com/jetbrains/python/newProject/PyCharmNewProjectDialog.java b/python/ide/src/com/jetbrains/python/newProject/PyCharmNewProjectDialog.java
new file mode 100644
index 0000000..d186f33
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/newProject/PyCharmNewProjectDialog.java
@@ -0,0 +1,70 @@
+/*
+ * 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.newProject;
+
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.wm.impl.welcomeScreen.CardActionsPanel;
+import com.jetbrains.python.newProject.actions.PyCharmNewProjectStep;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class PyCharmNewProjectDialog extends DialogWrapper {
+ public PyCharmNewProjectDialog() {
+ super(ProjectManager.getInstance().getDefaultProject());
+ setTitle(" "); // hack to make native fileChooser work on Mac. See MacFileChooserDialogImpl.MAIN_THREAD_RUNNABLE
+ init();
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ final Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ PyCharmNewProjectDialog.this.close(OK_EXIT_CODE);
+ }
+ };
+ final DefaultActionGroup root = new PyCharmNewProjectStep(runnable);
+
+ return new CardActionsPanel(root) {
+
+ @Override
+ public Dimension getPreferredSize() {
+ return getMinimumSize();
+ }
+
+ @Override
+ public Dimension getMinimumSize() {
+ return new Dimension(650, 450);
+ }
+ };
+ }
+
+ @Override
+ protected String getHelpId() {
+ return null;
+ }
+
+ @NotNull
+ protected Action[] createActions() {
+ return new Action[0];
+ }
+}
diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonBaseProjectGenerator.java b/python/ide/src/com/jetbrains/python/newProject/PythonBaseProjectGenerator.java
new file mode 100644
index 0000000..a862956
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/newProject/PythonBaseProjectGenerator.java
@@ -0,0 +1,82 @@
+package com.jetbrains.python.newProject;
+
+import com.intellij.facet.ui.ValidationResult;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootModificationUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.platform.DirectoryProjectGenerator;
+import com.intellij.remote.RemoteSdkCredentials;
+import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
+import com.jetbrains.python.remote.RemoteProjectSettings;
+import icons.PythonIcons;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.io.File;
+
+public class PythonBaseProjectGenerator extends PythonProjectGenerator implements DirectoryProjectGenerator {
+ @NotNull
+ @Nls
+ @Override
+ public String getName() {
+ return "Pure Python";
+ }
+
+ @Nullable
+ @Override
+ public Object showGenerationSettings(VirtualFile baseDir) throws ProcessCanceledException {
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public JComponent getSettingsPanel(File baseDir) throws ProcessCanceledException {
+ return null;
+ }
+
+ @Override
+ public Object getProjectSettings() {
+ return new PyNewProjectSettings();
+ }
+
+ @Nullable
+ @Override
+ public Icon getLogo() {
+ return PythonIcons.Python.Python_logo;
+ }
+
+ @Override
+ public void generateProject(@NotNull final Project project, @NotNull VirtualFile baseDir, final Object settings,
+ @NotNull final Module module) {
+ if (settings instanceof RemoteProjectSettings) {
+ PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
+ assert manager != null;
+ manager.createDeployment(project, baseDir, (RemoteProjectSettings)settings,
+ (RemoteSdkCredentials)((RemoteProjectSettings)settings).getSdk().getSdkAdditionalData());
+ }
+ else if (settings instanceof PyNewProjectSettings) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ ModuleRootModificationUtil.setModuleSdk(module, ((PyNewProjectSettings)settings).getSdk());
+ }
+ });
+ }
+ }
+
+ @NotNull
+ @Override
+ public ValidationResult validate(@NotNull String baseDirPath) {
+ /*if (PythonSdkType.isRemote(myProjectAction.getSdk())) {
+ if (PythonRemoteInterpreterManager.getInstance() == null) {
+ return new ValidationResult(PythonRemoteInterpreterManager.WEB_DEPLOYMENT_PLUGIN_IS_DISABLED);
+ }
+ }*/
+ return ValidationResult.OK;
+ }
+}
diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java
deleted file mode 100644
index a58fdd6..0000000
--- a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java
+++ /dev/null
@@ -1,105 +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.newProject;
-
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.progress.ProcessCanceledException;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.openapi.projectRoots.ProjectJdkTable;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.projectRoots.SdkAdditionalData;
-import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
-import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
-import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.openapi.util.Computable;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.platform.DirectoryProjectGenerator;
-import com.intellij.platform.NewDirectoryProjectAction;
-import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
-import com.jetbrains.python.sdk.PyDetectedSdk;
-import com.jetbrains.python.sdk.PySdkService;
-import com.jetbrains.python.sdk.PythonSdkAdditionalData;
-import com.jetbrains.python.sdk.PythonSdkType;
-
-import java.util.List;
-
-/**
- * User : catherine
- */
-public class PythonNewDirectoryProjectAction extends NewDirectoryProjectAction {
- private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.newProject.PythonNewDirectoryProjectAction");
- private Sdk mySdk;
- private boolean myInstallFramework;
-
- public void actionPerformed(final AnActionEvent e) {
- Project project = e.getData(CommonDataKeys.PROJECT);
- if (project == null) {
- project = ProjectManager.getInstance().getDefaultProject();
- }
- PythonNewDirectoryProjectDialog dlg = new PythonNewDirectoryProjectDialog(project);
- dlg.show();
- if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) return;
- mySdk = dlg.getSdk();
- final ProjectSdksModel model = PyConfigurableInterpreterList.getInstance(project).getModel();
- if (mySdk instanceof PyDetectedSdk) {
- VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
- @Override
- public VirtualFile compute() {
- return LocalFileSystem.getInstance().refreshAndFindFileByPath(mySdk.getName());
- }
- });
- PySdkService.getInstance().solidifySdk(mySdk);
- mySdk = SdkConfigurationUtil.setupSdk(ProjectJdkTable.getInstance().getAllJdks(), sdkHome, PythonSdkType.getInstance(), true, null, null);
- model.addSdk(mySdk);
- try {
- model.apply();
- }
- catch (ConfigurationException exception) {
- LOG.error("Error adding detected python interpreter " + exception.getMessage());
- }
- }
- mySdk = model.findSdk(mySdk);
- myInstallFramework = dlg.installFramework();
- Project newProject = generateProject(project, dlg);
- if (newProject != null) {
- SdkConfigurationUtil.setDirectoryProjectSdk(newProject, mySdk);
- final List<Sdk> sdks = PythonSdkType.getAllSdks();
- for (Sdk sdk : sdks) {
- final SdkAdditionalData additionalData = sdk.getSdkAdditionalData();
- if (additionalData instanceof PythonSdkAdditionalData) {
- ((PythonSdkAdditionalData)additionalData).reassociateWithCreatedProject(newProject);
- }
- }
- }
- }
-
- @Override
- protected Object showSettings(DirectoryProjectGenerator generator, VirtualFile baseDir)
- throws ProcessCanceledException {
- Object settings = super.showSettings(generator, baseDir);
- if (settings instanceof PyNewProjectSettings) {
- ((PyNewProjectSettings)settings).setSdk(mySdk);
- ((PyNewProjectSettings)settings).setInstallFramework(myInstallFramework);
- }
- return settings;
- }
-}
diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java
deleted file mode 100644
index fe497d4..0000000
--- a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java
+++ /dev/null
@@ -1,303 +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.newProject;
-
-import com.intellij.facet.ui.ValidationResult;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.progress.ProcessCanceledException;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.roots.ModuleRootModificationUtil;
-import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.platform.DirectoryProjectGenerator;
-import com.intellij.platform.NewDirectoryProjectDialog;
-import com.intellij.remote.RemoteSdkCredentials;
-import com.intellij.ui.ComboboxWithBrowseButton;
-import com.intellij.ui.components.JBCheckBox;
-import com.intellij.ui.components.JBLabel;
-import com.jetbrains.python.PythonSdkChooserCombo;
-import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
-import com.jetbrains.python.configuration.VirtualEnvProjectFilter;
-import com.jetbrains.python.packaging.PyExternalProcessException;
-import com.jetbrains.python.packaging.PyPackage;
-import com.jetbrains.python.packaging.PyPackageManager;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
-import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
-import com.jetbrains.python.remote.RemoteProjectSettings;
-import com.jetbrains.python.sdk.PythonSdkType;
-import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
-import com.jetbrains.python.sdk.flavors.PyPySdkFlavor;
-import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
-import icons.PythonIcons;
-import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.List;
-
-/**
- * User : catherine
- */
-public class PythonNewDirectoryProjectDialog extends NewDirectoryProjectDialog {
- private ComboboxWithBrowseButton mySdkCombo;
- private final JCheckBox myFrameworkCheckbox;
- private boolean myInstallFrameworkChanged;
- private final Project myProject;
-
- protected PythonNewDirectoryProjectDialog(Project project) {
- super(project);
- myProject = project;
-
- final List<Sdk> sdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks();
- VirtualEnvProjectFilter.removeAllAssociated(sdks);
- final Sdk preferred = sdks.isEmpty() ? null : sdks.iterator().next();
- mySdkCombo = new PythonSdkChooserCombo(project, sdks, new Condition<Sdk>() {
- @Override
- public boolean value(Sdk sdk) {
- return sdk == preferred;
- }
- });
- mySdkCombo.setButtonIcon(PythonIcons.Python.InterpreterGear);
-
- final JLabel label = new JBLabel("Interpreter:", SwingConstants.LEFT) {
- @Override
- public Dimension getMinimumSize() {
- return new JLabel("Project name:").getPreferredSize();
- }
-
- @Override
- public Dimension getPreferredSize() {
- return getMinimumSize();
- }
- };
- label.setLabelFor(mySdkCombo);
- final JPanel placeholder = getPlaceHolder();
- final GridBagConstraints constraints = new GridBagConstraints();
- constraints.gridx = 0;
- constraints.gridy = 0;
- constraints.anchor = GridBagConstraints.WEST;
- constraints.insets = new Insets(0, 0, 0, 10);
- placeholder.add(label, constraints);
-
- constraints.gridx = 1;
- constraints.gridy = 0;
- constraints.fill = GridBagConstraints.BOTH;
- constraints.weightx = 1.0;
- constraints.insets = new Insets(0, 0, 0, 0);
-
- placeholder.add(mySdkCombo, constraints);
-
- final ActionListener listener = new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent event) {
- checkValid();
- }
- };
-
- myFrameworkCheckbox = new JBCheckBox("Install <framework>");
- constraints.gridx = 0;
- constraints.gridy = 1;
- constraints.gridwidth = 2;
- constraints.weightx = 0.0;
- placeholder.add(myFrameworkCheckbox, constraints);
- myFrameworkCheckbox.setVisible(false);
-
- myFrameworkCheckbox.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- myInstallFrameworkChanged = true;
- checkValid();
- }
- });
-
- mySdkCombo.addActionListener(listener);
- mySdkCombo.getComboBox().addActionListener(listener);
- myProjectTypeComboBox.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent event) {
- selectCompatiblePython();
- checkValid();
- }
- });
-
- mySdkCombo.getComboBox().addPropertyChangeListener(new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent event) {
- checkValid();
- }
- });
-
- final Dimension checkBoxSize = myFrameworkCheckbox.getPreferredSize();
- myRootPane.setPreferredSize(new Dimension(myRootPane.getPreferredSize().width,
- myRootPane.getPreferredSize().height + checkBoxSize.height));
-
- checkValid();
- }
-
- @Override
- protected Object getEmptyProjectGenerator() {
- return new DirectoryProjectGenerator() {
-
- @NotNull
- @Nls
- @Override
- public String getName() {
- return "Empty project";
- }
-
- @Nullable
- @Override
- public Object showGenerationSettings(VirtualFile baseDir) throws ProcessCanceledException {
- if (PythonSdkType.isRemote(getSdk())) {
- PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
- assert manager != null;
- return manager.showRemoteProjectSettingsDialog(baseDir, (RemoteSdkCredentials)getSdk().getSdkAdditionalData());
- }
- else {
- return new PyNewProjectSettings();
- }
- }
-
- @Override
- public void generateProject(@NotNull final Project project,
- @NotNull VirtualFile baseDir,
- final Object settings,
- @NotNull final Module module) {
- if (settings instanceof RemoteProjectSettings) {
- PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
- assert manager != null;
- manager.createDeployment(project, baseDir, (RemoteProjectSettings)settings,
- (RemoteSdkCredentials)getSdk().getSdkAdditionalData());
- }
- else if (settings instanceof PyNewProjectSettings) {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- ModuleRootModificationUtil.setModuleSdk(module, ((PyNewProjectSettings)settings).getSdk());
- }
- });
- }
- }
-
- @NotNull
- @Override
- public ValidationResult validate(@NotNull String baseDirPath) {
- if (PythonSdkType.isRemote(getSdk())) {
- if (PythonRemoteInterpreterManager.getInstance() == null) {
- return new ValidationResult(PythonRemoteInterpreterManager.WEB_DEPLOYMENT_PLUGIN_IS_DISABLED);
- }
- }
- return ValidationResult.OK;
- }
- };
- }
-
- @Override
- public void checkValid() {
- super.checkValid();
- Sdk sdk = getSdk();
- if (isOKActionEnabled()) {
- setOKActionEnabled(true);
- setErrorText(null);
- myFrameworkCheckbox.setVisible(false);
-
- DirectoryProjectGenerator generator = getProjectGenerator();
- final boolean isPy3k = sdk != null && PythonSdkType.getLanguageLevelForSdk(sdk).isPy3K();
- if (sdk != null && PythonSdkType.isRemote(sdk) && !acceptsRemoteSdk(generator)) {
- setOKActionEnabled(false);
- setErrorText("Please choose a local interpreter");
- }
- else if (generator instanceof PyFrameworkProjectGenerator) {
- PyFrameworkProjectGenerator frameworkProjectGenerator = (PyFrameworkProjectGenerator)generator;
- String frameworkName = frameworkProjectGenerator.getFrameworkTitle();
- if (sdk != null && !isFrameworkInstalled(sdk)) {
- final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
- final boolean onlyWithCache =
- PythonSdkFlavor.getFlavor(sdk) instanceof JythonSdkFlavor || PythonSdkFlavor.getFlavor(sdk) instanceof PyPySdkFlavor;
- try {
- if (onlyWithCache && packageManager.cacheIsNotNull() || !onlyWithCache) {
- final PyPackage pip = packageManager.findPackage("pip");
- myFrameworkCheckbox.setText("Install " + frameworkName);
- myFrameworkCheckbox.setMnemonic(frameworkName.charAt(0));
- myFrameworkCheckbox.setVisible(pip != null);
- if (!myInstallFrameworkChanged) {
- myFrameworkCheckbox.setSelected(pip != null);
- }
- }
- }
- catch (PyExternalProcessException e) {
- myFrameworkCheckbox.setVisible(false);
- }
- if (!myFrameworkCheckbox.isSelected()) {
- setErrorText("No " + frameworkName + " support installed in selected interpreter");
- setOKActionEnabled(false);
- }
- }
- if (isPy3k && !((PyFrameworkProjectGenerator)generator).supportsPython3()) {
- setErrorText(frameworkName + " is not supported for the selected interpreter");
- setOKActionEnabled(false);
- }
- }
- if (sdk == null) {
- setOKActionEnabled(false);
- setErrorText("No Python interpreter selected");
- }
- }
- }
-
- private void selectCompatiblePython() {
- DirectoryProjectGenerator generator = getProjectGenerator();
- if (generator instanceof PyFrameworkProjectGenerator && !((PyFrameworkProjectGenerator)generator).supportsPython3()) {
- Sdk sdk = getSdk();
- if (sdk != null && PythonSdkType.getLanguageLevelForSdk(sdk).isPy3K()) {
- Sdk python2Sdk = PythonSdkType.findPython2Sdk(null);
- if (python2Sdk != null) {
- mySdkCombo.getComboBox().setSelectedItem(python2Sdk);
- mySdkCombo.getComboBox().repaint();
- }
- }
- }
- }
-
- private boolean isFrameworkInstalled(Sdk sdk) {
- PyFrameworkProjectGenerator projectGenerator = (PyFrameworkProjectGenerator)getProjectGenerator();
-
- return projectGenerator != null && projectGenerator.isFrameworkInstalled(myProject, sdk);
- }
-
- private static boolean acceptsRemoteSdk(DirectoryProjectGenerator generator) {
- if (generator instanceof PyFrameworkProjectGenerator) {
- return ((PyFrameworkProjectGenerator)generator).acceptsRemoteSdk();
- }
- return true;
- }
-
- public boolean installFramework() {
- return myFrameworkCheckbox.isSelected() && myFrameworkCheckbox.isVisible();
- }
-
- public Sdk getSdk() {
- return (Sdk)mySdkCombo.getComboBox().getSelectedItem();
- }
-}
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/AbstractProjectSettingsStep.java b/python/ide/src/com/jetbrains/python/newProject/actions/AbstractProjectSettingsStep.java
new file mode 100644
index 0000000..d9f3cf2
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/AbstractProjectSettingsStep.java
@@ -0,0 +1,408 @@
+package com.jetbrains.python.newProject.actions;
+
+import com.intellij.facet.ui.ValidationResult;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.impl.ProjectUtil;
+import com.intellij.ide.util.projectWizard.WebProjectTemplate;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.actionSystem.impl.ActionButtonWithText;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.ui.MessageType;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.wm.impl.welcomeScreen.AbstractActionWithPanel;
+import com.intellij.platform.DirectoryProjectGenerator;
+import com.intellij.platform.WebProjectGenerator;
+import com.intellij.ui.DocumentAdapter;
+import com.intellij.ui.JBColor;
+import com.intellij.ui.components.JBScrollPane;
+import com.intellij.util.NullableConsumer;
+import com.intellij.util.ui.UIUtil;
+import com.jetbrains.python.PythonSdkChooserCombo;
+import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
+import com.jetbrains.python.configuration.VirtualEnvProjectFilter;
+import com.jetbrains.python.newProject.PyFrameworkProjectGenerator;
+import com.jetbrains.python.newProject.PythonProjectGenerator;
+import com.jetbrains.python.packaging.PyExternalProcessException;
+import com.jetbrains.python.packaging.PyPackage;
+import com.jetbrains.python.packaging.PyPackageManager;
+import com.jetbrains.python.packaging.PyPackageManagerImpl;
+import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
+import com.jetbrains.python.sdk.flavors.PyPySdkFlavor;
+import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
+import icons.PythonIcons;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.event.DocumentEvent;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.util.List;
+
+abstract public class AbstractProjectSettingsStep extends AbstractActionWithPanel implements DumbAware {
+ protected final DirectoryProjectGenerator myProjectGenerator;
+ private final NullableConsumer<AbstractProjectSettingsStep> myCallback;
+ private PythonSdkChooserCombo mySdkCombo;
+ private boolean myInstallFramework;
+ private TextFieldWithBrowseButton myLocationField;
+ protected final File myProjectDirectory;
+ private ActionButtonWithText myCreateButton;
+ private JLabel myErrorLabel;
+ private AnAction myCreateAction;
+
+ public AbstractProjectSettingsStep(DirectoryProjectGenerator projectGenerator, NullableConsumer<AbstractProjectSettingsStep> callback) {
+ super();
+ myProjectGenerator = projectGenerator;
+ myCallback = callback;
+ myProjectDirectory = FileUtil.findSequentNonexistentFile(new File(ProjectUtil.getBaseDir()), "untitled", "");
+ if (myProjectGenerator instanceof WebProjectTemplate) {
+ ((WebProjectTemplate)myProjectGenerator).getPeer().addSettingsStateListener(new WebProjectGenerator.SettingsStateListener() {
+ @Override
+ public void stateChanged(boolean validSettings) {
+ checkValid();
+ }
+ });
+ }
+ else if (myProjectGenerator instanceof PythonProjectGenerator) {
+ ((PythonProjectGenerator)myProjectGenerator).addSettingsStateListener(new PythonProjectGenerator.SettingsListener() {
+ @Override
+ public void stateChanged() {
+ checkValid();
+ }
+ });
+ }
+
+ myCreateAction = new AnAction("Create", "Create Project", getIcon()) {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ boolean isValid = checkValid();
+ if (isValid && myCallback != null)
+ myCallback.consume(AbstractProjectSettingsStep.this);
+ }
+ };
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ }
+
+ @Override
+ public JPanel createPanel() {
+ final JPanel mainPanel = new JPanel(new BorderLayout());
+ final JPanel scrollPanel = new JPanel(new BorderLayout());
+
+ mainPanel.setPreferredSize(new Dimension(mainPanel.getPreferredSize().width, 400));
+ myErrorLabel = new JLabel("");
+ myErrorLabel.setForeground(JBColor.RED);
+ myCreateButton = new Button(myCreateAction, myCreateAction.getTemplatePresentation());
+
+ final JPanel panel = createBasePanel();
+ scrollPanel.add(panel, BorderLayout.NORTH);
+ final JPanel advancedSettings = createAdvancedSettings();
+ if (advancedSettings != null) {
+ scrollPanel.add(advancedSettings, BorderLayout.CENTER);
+ }
+ final JBScrollPane scrollPane = new JBScrollPane(scrollPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+ scrollPane.setBorder(null);
+ mainPanel.add(scrollPane, BorderLayout.CENTER);
+
+ final JPanel bottomPanel = new JPanel(new BorderLayout());
+
+
+ myCreateButton.setPreferredSize(new Dimension(mainPanel.getPreferredSize().width, 40));
+ bottomPanel.add(myErrorLabel, BorderLayout.NORTH);
+ bottomPanel.add(myCreateButton, BorderLayout.EAST);
+ mainPanel.add(bottomPanel, BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ protected Icon getIcon() {
+ return myProjectGenerator.getLogo();
+ }
+
+ private JPanel createBasePanel() {
+ final JPanel panel = new JPanel(new GridBagLayout());
+ final GridBagConstraints c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.weightx = 0;
+ c.insets = new Insets(2, 2, 2, 2);
+ myLocationField = new TextFieldWithBrowseButton();
+ myLocationField.setText(myProjectDirectory.toString());
+
+ final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
+ myLocationField.addBrowseFolderListener("Select base directory", "Select base directory for the Project",
+ null, descriptor);
+
+ final JLabel locationLabel = new JLabel("Location:");
+ c.gridx = 0;
+ c.gridy = 0;
+ panel.add(locationLabel, c);
+
+ c.gridx = 1;
+ c.gridy = 0;
+ c.weightx = 1.;
+ panel.add(myLocationField, c);
+
+ final JLabel interpreterLabel = new JLabel("Interpreter:", SwingConstants.LEFT) {
+ @Override
+ public Dimension getMinimumSize() {
+ return new JLabel("Project name:").getPreferredSize();
+ }
+
+ @Override
+ public Dimension getPreferredSize() {
+ return getMinimumSize();
+ }
+ };
+ c.gridx = 0;
+ c.gridy = 1;
+ c.weightx = 0;
+ panel.add(interpreterLabel, c);
+
+ final Project project = ProjectManager.getInstance().getDefaultProject();
+ final List<Sdk> sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
+ VirtualEnvProjectFilter.removeAllAssociated(sdks);
+ final Sdk preferred = sdks.isEmpty() ? null : sdks.iterator().next();
+ mySdkCombo = new PythonSdkChooserCombo(project, sdks, new Condition<Sdk>() {
+ @Override
+ public boolean value(Sdk sdk) {
+ return sdk == preferred;
+ }
+ });
+ mySdkCombo.setButtonIcon(PythonIcons.Python.InterpreterGear);
+
+ c.gridx = 1;
+ c.gridy = 1;
+ c.weightx = 1.;
+ panel.add(mySdkCombo, c);
+
+ registerValidators();
+ return panel;
+ }
+
+ protected void registerValidators() {
+
+ myLocationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
+ @Override
+ protected void textChanged(DocumentEvent e) {
+ checkValid();
+ }
+ });
+ final ActionListener listener = new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ checkValid();
+ }
+ };
+ mySdkCombo.getComboBox().addPropertyChangeListener(new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ checkValid();
+ }
+ });
+ myLocationField.getTextField().addActionListener(listener);
+ mySdkCombo.getComboBox().addActionListener(listener);
+ mySdkCombo.addActionListener(listener);
+ }
+
+ public boolean checkValid() {
+ final String projectName = myLocationField.getText();
+ setErrorText(null);
+ myInstallFramework = false;
+
+ if (projectName.trim().isEmpty()) {
+ setErrorText("Project name can't be empty");
+ return false;
+ }
+ if (myLocationField.getText().indexOf('$') >= 0) {
+ setErrorText("Project directory name must not contain the $ character");
+ return false;
+ }
+ if (myProjectGenerator != null) {
+ final String baseDirPath = myLocationField.getTextField().getText();
+ ValidationResult validationResult = myProjectGenerator.validate(baseDirPath);
+ if (!validationResult.isOk()) {
+ setErrorText(validationResult.getErrorMessage());
+ return false;
+ }
+ if (myProjectGenerator instanceof PythonProjectGenerator) {
+ final ValidationResult warningResult = ((PythonProjectGenerator)myProjectGenerator).warningValidation(getSdk());
+ if (!warningResult.isOk()) {
+ setWarningText(warningResult.getErrorMessage());
+ }
+ }
+ if (myProjectGenerator instanceof WebProjectTemplate) {
+ final WebProjectGenerator.GeneratorPeer peer = ((WebProjectTemplate)myProjectGenerator).getPeer();
+ final ValidationInfo validationInfo = peer.validate();
+ if (validationInfo != null && !peer.isBackgroundJobRunning()) {
+ setErrorText(validationInfo.message);
+ return false;
+ }
+ }
+ }
+
+ final Sdk sdk = getSdk();
+
+ final boolean isPy3k = sdk != null && PythonSdkType.getLanguageLevelForSdk(sdk).isPy3K();
+ if (sdk != null && PythonSdkType.isRemote(sdk) && !acceptsRemoteSdk(myProjectGenerator)) {
+ setErrorText("Please choose a local interpreter");
+ return false;
+ }
+ else if (myProjectGenerator instanceof PyFrameworkProjectGenerator) {
+ PyFrameworkProjectGenerator frameworkProjectGenerator = (PyFrameworkProjectGenerator)myProjectGenerator;
+ String frameworkName = frameworkProjectGenerator.getFrameworkTitle();
+ if (sdk != null && !isFrameworkInstalled(sdk)) {
+ final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
+ final boolean onlyWithCache =
+ PythonSdkFlavor.getFlavor(sdk) instanceof JythonSdkFlavor || PythonSdkFlavor.getFlavor(sdk) instanceof PyPySdkFlavor;
+ String warningText = frameworkName + " will be installed on selected interpreter";
+ try {
+ if (onlyWithCache && packageManager.cacheIsNotNull() || !onlyWithCache) {
+ final PyPackage pip = packageManager.findInstalledPackage("pip");
+ myInstallFramework = true;
+ if (pip == null) {
+ warningText = "pip and " + warningText;
+ }
+ setWarningText(warningText);
+ }
+ }
+ catch (PyExternalProcessException ignored) {
+ myInstallFramework = true;
+ warningText = "pip and " + warningText;
+ setWarningText(warningText);
+ }
+ if (!myInstallFramework) {
+ setErrorText("No " + frameworkName + " support installed in selected interpreter");
+ return false;
+ }
+ }
+ if (isPy3k && !((PyFrameworkProjectGenerator)myProjectGenerator).supportsPython3()) {
+ setErrorText(frameworkName + " is not supported for the selected interpreter");
+ return false;
+ }
+ }
+ if (sdk == null) {
+ setErrorText("No Python interpreter selected");
+ return false;
+ }
+ return true;
+ }
+
+ public void setErrorText(@Nullable String text) {
+ myErrorLabel.setText(text);
+ myErrorLabel.setForeground(MessageType.ERROR.getTitleForeground());
+ myErrorLabel.setIcon(text == null ? null : AllIcons.Actions.Lightning);
+ myCreateButton.setEnabled(text == null);
+ }
+
+ public void setWarningText(@Nullable String text) {
+ myErrorLabel.setText("Note: " + text + " ");
+ myErrorLabel.setForeground(MessageType.WARNING.getTitleForeground());
+ }
+
+ public void selectCompatiblePython() {
+ DirectoryProjectGenerator generator = getProjectGenerator();
+ if (generator instanceof PyFrameworkProjectGenerator && !((PyFrameworkProjectGenerator)generator).supportsPython3()) {
+ Sdk sdk = getSdk();
+ if (sdk != null && PythonSdkType.getLanguageLevelForSdk(sdk).isPy3K()) {
+ Sdk python2Sdk = PythonSdkType.findPython2Sdk(null);
+ if (python2Sdk != null) {
+ mySdkCombo.getComboBox().setSelectedItem(python2Sdk);
+ mySdkCombo.getComboBox().repaint();
+ }
+ }
+ }
+ }
+
+ private static boolean acceptsRemoteSdk(DirectoryProjectGenerator generator) {
+ if (generator instanceof PyFrameworkProjectGenerator) {
+ return ((PyFrameworkProjectGenerator)generator).acceptsRemoteSdk();
+ }
+ return true;
+ }
+
+ private boolean isFrameworkInstalled(Sdk sdk) {
+ PyFrameworkProjectGenerator projectGenerator = (PyFrameworkProjectGenerator)getProjectGenerator();
+ return projectGenerator != null && projectGenerator.isFrameworkInstalled(sdk);
+ }
+
+ @Nullable
+ protected JPanel createAdvancedSettings() {
+ return null;
+ }
+
+ public DirectoryProjectGenerator getProjectGenerator() {
+ return myProjectGenerator;
+ }
+
+ private static class Button extends ActionButtonWithText {
+ private final Border myBorder;
+
+ public Button(AnAction action, Presentation presentation) {
+ super(action, presentation, "NewProject", new Dimension(70, 50));
+ myBorder = UIUtil.isUnderDarcula() ? UIUtil.getButtonBorder() : BorderFactory.createLineBorder(UIUtil.getBorderColor());
+ setBorder(myBorder);
+ }
+
+ @Override
+ protected int iconTextSpace() {
+ return 8;
+ }
+
+ @Override
+ public Insets getInsets() {
+ return new Insets(5,10,5,5);
+ }
+
+ @Override
+ protected int horizontalTextAlignment() {
+ return SwingConstants.LEFT;
+ }
+
+ @Override
+ public String getToolTipText() {
+ return null;
+ }
+
+ protected void processMouseEvent(MouseEvent e) {
+ super.processMouseEvent(e);
+ if (e.getID() == MouseEvent.MOUSE_ENTERED) {
+ setBorder(null);
+ }
+ else if (e.getID() == MouseEvent.MOUSE_EXITED) {
+ setBorder(myBorder);
+ }
+ }
+ }
+
+ public Sdk getSdk() {
+ return (Sdk)mySdkCombo.getComboBox().getSelectedItem();
+ }
+
+ public String getProjectLocation() {
+ return myLocationField.getText();
+ }
+
+ public boolean installFramework() {
+ return myInstallFramework;
+ }
+
+}
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/PluginSpecificProjectsStep.java b/python/ide/src/com/jetbrains/python/newProject/actions/PluginSpecificProjectsStep.java
new file mode 100644
index 0000000..a0c5f6e
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/PluginSpecificProjectsStep.java
@@ -0,0 +1,37 @@
+/*
+ * 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.newProject.actions;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.platform.DirectoryProjectGenerator;
+import com.intellij.util.NullableConsumer;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class PluginSpecificProjectsStep extends DefaultActionGroup implements DumbAware {
+
+ public PluginSpecificProjectsStep(@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback,
+ @NotNull final List<DirectoryProjectGenerator> projectGenerators) {
+ super("Plugin-specific", true);
+ getTemplatePresentation().setIcon(AllIcons.Nodes.PluginLogo);
+ for (DirectoryProjectGenerator generator : projectGenerators) {
+ add(new ProjectSpecificAction(callback, generator));
+ }
+ }
+}
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificAction.java b/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificAction.java
new file mode 100644
index 0000000..950e11e
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificAction.java
@@ -0,0 +1,47 @@
+/*
+ * 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.newProject.actions;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.platform.DirectoryProjectGenerator;
+import com.intellij.util.NullableConsumer;
+import org.jetbrains.annotations.NotNull;
+
+public class ProjectSpecificAction extends DefaultActionGroup implements DumbAware {
+
+ private final ProjectSpecificSettingsStep mySettings;
+
+ public ProjectSpecificAction(@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback,
+ @NotNull final DirectoryProjectGenerator projectGenerator) {
+ super(projectGenerator.getName(), true);
+ getTemplatePresentation().setIcon(projectGenerator.getLogo());
+ mySettings = new ProjectSpecificSettingsStep(projectGenerator, callback);
+ add(mySettings);
+ }
+
+ public Sdk getSdk() {
+ return mySettings.getSdk();
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ super.actionPerformed(e);
+ mySettings.selectCompatiblePython();
+ }
+}
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java b/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java
new file mode 100644
index 0000000..ebd0658
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/ProjectSpecificSettingsStep.java
@@ -0,0 +1,54 @@
+/*
+ * 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.newProject.actions;
+
+import com.intellij.ide.util.projectWizard.WebProjectTemplate;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.ui.VerticalFlowLayout;
+import com.intellij.platform.DirectoryProjectGenerator;
+import com.intellij.ui.HideableDecorator;
+import com.intellij.util.NullableConsumer;
+import com.jetbrains.python.newProject.PythonProjectGenerator;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class ProjectSpecificSettingsStep extends AbstractProjectSettingsStep implements DumbAware {
+
+ public ProjectSpecificSettingsStep(@NotNull final DirectoryProjectGenerator projectGenerator,
+ @NotNull final NullableConsumer<AbstractProjectSettingsStep> callback) {
+ super(projectGenerator, callback);
+ }
+
+ @Override
+ @Nullable
+ protected JPanel createAdvancedSettings() {
+ JComponent advancedSettings = null;
+ if (myProjectGenerator instanceof PythonProjectGenerator)
+ advancedSettings = ((PythonProjectGenerator)myProjectGenerator).getSettingsPanel(myProjectDirectory);
+ else if (myProjectGenerator instanceof WebProjectTemplate) {
+ advancedSettings = ((WebProjectTemplate)myProjectGenerator).getPeer().getComponent();
+ }
+ if (advancedSettings != null) {
+ final JPanel jPanel = new JPanel(new VerticalFlowLayout());
+ final HideableDecorator deco = new HideableDecorator(jPanel, "Mor&e Settings", false);
+ deco.setContentComponent(advancedSettings);
+ return jPanel;
+ }
+ return null;
+ }
+}
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/PyCharmNewProjectStep.java b/python/ide/src/com/jetbrains/python/newProject/actions/PyCharmNewProjectStep.java
new file mode 100644
index 0000000..b6134ed
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/PyCharmNewProjectStep.java
@@ -0,0 +1,195 @@
+/*
+ * 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.newProject.actions;
+
+import com.google.common.collect.Lists;
+import com.intellij.ide.GeneralSettings;
+import com.intellij.ide.util.projectWizard.WebProjectTemplate;
+import com.intellij.internal.statistic.UsageTrigger;
+import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkAdditionalData;
+import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.platform.DirectoryProjectGenerator;
+import com.intellij.platform.PlatformProjectOpenProcessor;
+import com.intellij.projectImport.ProjectOpenedCallback;
+import com.intellij.util.NullableConsumer;
+import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
+import com.jetbrains.python.newProject.PyFrameworkProjectGenerator;
+import com.jetbrains.python.newProject.PyNewProjectSettings;
+import com.jetbrains.python.newProject.PythonBaseProjectGenerator;
+import com.jetbrains.python.newProject.PythonProjectGenerator;
+import com.jetbrains.python.sdk.PyDetectedSdk;
+import com.jetbrains.python.sdk.PySdkService;
+import com.jetbrains.python.sdk.PythonSdkAdditionalData;
+import com.jetbrains.python.sdk.PythonSdkType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+public class PyCharmNewProjectStep extends DefaultActionGroup implements DumbAware {
+ private static final Logger LOG = Logger.getInstance(PyCharmNewProjectStep.class);
+
+ public PyCharmNewProjectStep(@Nullable final Runnable runnable) {
+ super("Select Project Type", true);
+
+ final NullableConsumer<AbstractProjectSettingsStep> callback = new NullableConsumer<AbstractProjectSettingsStep>() {
+ @Override
+ public void consume(@Nullable AbstractProjectSettingsStep settingsStep) {
+ if (runnable != null)
+ runnable.run();
+ if (settingsStep == null) return;
+
+ Sdk sdk = settingsStep.getSdk();
+ final Project project = ProjectManager.getInstance().getDefaultProject();
+ final ProjectSdksModel model = PyConfigurableInterpreterList.getInstance(project).getModel();
+ if (sdk instanceof PyDetectedSdk) {
+ final String name = sdk.getName();
+ VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
+ @Override
+ public VirtualFile compute() {
+ return LocalFileSystem.getInstance().refreshAndFindFileByPath(name);
+ }
+ });
+ PySdkService.getInstance().solidifySdk(sdk);
+ sdk = SdkConfigurationUtil.setupSdk(ProjectJdkTable.getInstance().getAllJdks(), sdkHome, PythonSdkType.getInstance(), true, null,
+ null);
+ model.addSdk(sdk);
+ try {
+ model.apply();
+ }
+ catch (ConfigurationException exception) {
+ LOG.error("Error adding detected python interpreter " + exception.getMessage());
+ }
+ }
+ Project newProject = generateProject(project, settingsStep);
+ if (newProject != null) {
+ SdkConfigurationUtil.setDirectoryProjectSdk(newProject, sdk);
+ final List<Sdk> sdks = PythonSdkType.getAllSdks();
+ for (Sdk s : sdks) {
+ final SdkAdditionalData additionalData = s.getSdkAdditionalData();
+ if (additionalData instanceof PythonSdkAdditionalData) {
+ ((PythonSdkAdditionalData)additionalData).reassociateWithCreatedProject(newProject);
+ }
+ }
+ }
+ }
+
+ @Nullable
+ private Project generateProject(@NotNull final Project project, @NotNull final AbstractProjectSettingsStep settings) {
+ final DirectoryProjectGenerator generator = settings.getProjectGenerator();
+ final File location = new File(settings.getProjectLocation());
+ if (!location.exists() && !location.mkdirs()) {
+ Messages.showErrorDialog(project, "Cannot create directory '" + location + "'", "Create Project");
+ return null;
+ }
+
+ final VirtualFile baseDir = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
+ public VirtualFile compute() {
+ return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(location);
+ }
+ });
+ LOG.assertTrue(baseDir != null, "Couldn't find '" + location + "' in VFS");
+ baseDir.refresh(false, true);
+
+ if (baseDir.getChildren().length > 0) {
+ int rc = Messages.showYesNoDialog(project,
+ "The directory '" + location +
+ "' is not empty. Would you like to create a project from existing sources instead?",
+ "Create New Project", Messages.getQuestionIcon());
+ if (rc == Messages.YES) {
+ return PlatformProjectOpenProcessor.getInstance().doOpenProject(baseDir, null, false);
+ }
+ }
+
+ String generatorName = generator == null ? "empty" : ConvertUsagesUtil.ensureProperKey(generator.getName());
+ UsageTrigger.trigger("NewDirectoryProjectAction." + generatorName);
+
+ GeneralSettings.getInstance().setLastProjectCreationLocation(location.getParent());
+
+ return PlatformProjectOpenProcessor.doOpenProject(baseDir, null, false, -1, new ProjectOpenedCallback() {
+ @Override
+ public void projectOpened(Project project, Module module) {
+ if (generator != null) {
+ Object projectSettings = null;
+ if (generator instanceof PythonProjectGenerator)
+ projectSettings = ((PythonProjectGenerator)generator).getProjectSettings();
+ else if (generator instanceof WebProjectTemplate) {
+ projectSettings = ((WebProjectTemplate)generator).getPeer().getSettings();
+ }
+ if (projectSettings instanceof PyNewProjectSettings) {
+ ((PyNewProjectSettings)projectSettings).setSdk(settings.getSdk());
+ ((PyNewProjectSettings)projectSettings).setInstallFramework(settings.installFramework());
+ }
+ //noinspection unchecked
+ generator.generateProject(project, baseDir, projectSettings, module);
+ }
+ }
+ }, false);
+ }
+ };
+
+ final ProjectSpecificAction action = new ProjectSpecificAction(callback, new PythonBaseProjectGenerator());
+ add(action);
+
+ final DirectoryProjectGenerator[] generators = Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME);
+ Arrays.sort(generators, new Comparator<DirectoryProjectGenerator>() {
+ @Override
+ public int compare(DirectoryProjectGenerator o1, DirectoryProjectGenerator o2) {
+ if (o1 instanceof PyFrameworkProjectGenerator && !(o2 instanceof PyFrameworkProjectGenerator)) return -1;
+ if (!(o1 instanceof PyFrameworkProjectGenerator) && o2 instanceof PyFrameworkProjectGenerator) return 1;
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
+
+ List<DirectoryProjectGenerator> pluginSpecificGenerators = Lists.newArrayList();
+ for (DirectoryProjectGenerator generator : generators) {
+ if (generator instanceof PythonProjectGenerator)
+ add(new ProjectSpecificAction(callback, generator));
+ else
+ pluginSpecificGenerators.add(generator);
+ }
+
+ if (!pluginSpecificGenerators.isEmpty()) {
+ add(new PluginSpecificProjectsStep(callback, pluginSpecificGenerators));
+ }
+ }
+
+ public PyCharmNewProjectStep() {
+ this(null);
+
+ }
+
+}
diff --git a/python/openapi/src/com/jetbrains/python/newProject/PyFrameworkProjectGenerator.java b/python/openapi/src/com/jetbrains/python/newProject/PyFrameworkProjectGenerator.java
index f9dc7a6..08e3402 100644
--- a/python/openapi/src/com/jetbrains/python/newProject/PyFrameworkProjectGenerator.java
+++ b/python/openapi/src/com/jetbrains/python/newProject/PyFrameworkProjectGenerator.java
@@ -15,7 +15,6 @@
*/
package com.jetbrains.python.newProject;
-import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.platform.DirectoryProjectGenerator;
@@ -25,7 +24,7 @@
public interface PyFrameworkProjectGenerator<T> extends DirectoryProjectGenerator<T> {
String getFrameworkTitle();
- boolean isFrameworkInstalled(Project project, Sdk sdk);
+ boolean isFrameworkInstalled(Sdk sdk);
boolean acceptsRemoteSdk();
diff --git a/python/openapi/src/com/jetbrains/python/newProject/PythonProjectGenerator.java b/python/openapi/src/com/jetbrains/python/newProject/PythonProjectGenerator.java
new file mode 100644
index 0000000..5577959
--- /dev/null
+++ b/python/openapi/src/com/jetbrains/python/newProject/PythonProjectGenerator.java
@@ -0,0 +1,43 @@
+package com.jetbrains.python.newProject;
+
+import com.intellij.facet.ui.ValidationResult;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.io.File;
+import java.util.List;
+
+public abstract class PythonProjectGenerator {
+ private final List<SettingsListener> myListeners = ContainerUtil.newArrayList();
+
+ @Nullable
+ public JComponent getSettingsPanel(File baseDir) throws ProcessCanceledException {
+ return null;
+ }
+
+ public Object getProjectSettings() {
+ return new PyNewProjectSettings();
+ }
+
+ public ValidationResult warningValidation(@Nullable final Sdk sdk) {
+ return ValidationResult.OK;
+ }
+
+ public void addSettingsStateListener(@NotNull SettingsListener listener) {
+ myListeners.add(listener);
+ }
+
+ public interface SettingsListener {
+ void stateChanged();
+ }
+
+ public void fireStateChanged() {
+ for (SettingsListener listener : myListeners) {
+ listener.stateChanged();
+ }
+ }
+}
diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java
index 588efa6..3b2080b 100644
--- a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java
+++ b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java
@@ -17,6 +17,8 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.awt.*;
@@ -39,4 +41,9 @@
public abstract void showInstallationError(Project project, String title, String description);
public abstract void showInstallationError(Component owner, String title, String description);
public abstract void refresh();
+ @Nullable
+ public abstract PyPackage findInstalledPackage(String name) throws PyExternalProcessException;
+
+ public abstract boolean findPackage(@NotNull final String name);
+
}
diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java
index 796bc47..9f59874 100644
--- a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java
+++ b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java
@@ -18,6 +18,7 @@
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -26,10 +27,13 @@
* @author yole
*/
public abstract class PyPackageManagers {
+
+ @NotNull
public static PyPackageManagers getInstance() {
return ServiceManager.getService(PyPackageManagers.class);
}
+ @NotNull
public abstract PyPackageManager forSdk(Sdk sdk);
/**
diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java b/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java
new file mode 100644
index 0000000..e660029
--- /dev/null
+++ b/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java
@@ -0,0 +1,65 @@
+/*
+ * 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.templateLanguages;
+
+import com.intellij.facet.ui.ValidationResult;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.jetbrains.python.packaging.PyExternalProcessException;
+import com.jetbrains.python.packaging.PyPackage;
+import com.jetbrains.python.packaging.PyPackageManager;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class PyTemplatesUtil {
+ private PyTemplatesUtil(){}
+
+ public static ValidationResult checkInstalled(@Nullable final Sdk sdk, @NotNull final TemplateLanguagePanel templatesPanel,
+ @NotNull final String prefix) {
+ if (sdk == null) return ValidationResult.OK;
+ String templateBinding = null;
+ @NonNls String language = templatesPanel.getTemplateLanguage();
+ if (language != null) {
+ if (language.equals(TemplatesService.JINJA2)) language = "jinja";
+ templateBinding = prefix + language.toLowerCase();
+ }
+ final PyPackageManager packageManager = PyPackageManager.getInstance(sdk);
+ if (templateBinding != null) {
+ if (TemplatesService.ALL_TEMPLATE_BINDINGS.contains(templateBinding)) {
+ try {
+ final PyPackage installedPackage = packageManager.findInstalledPackage(templateBinding);
+ if (installedPackage == null)
+ return new ValidationResult(templateBinding + " will be installed on selected interpreter");
+ }
+ catch (PyExternalProcessException ignored) {
+ }
+ }
+ }
+ if (language != null) {
+ try {
+ final PyPackage installedPackage = packageManager.findInstalledPackage(language);
+ if (installedPackage == null) {
+ return new ValidationResult(language + " will be installed on selected interpreter");
+ }
+ }
+ catch (PyExternalProcessException ignored) {
+ }
+ }
+ return null;
+ }
+
+}
+
diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateLanguagePanel.form b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateLanguagePanel.form
new file mode 100644
index 0000000..1ac79c6
--- /dev/null
+++ b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateLanguagePanel.form
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.templateLanguages.TemplateLanguagePanel">
+ <grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <xy x="20" y="20" width="617" height="171"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <vspacer id="73c47">
+ <constraints>
+ <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </vspacer>
+ <component id="37bbe" class="javax.swing.JComboBox" binding="myTemplateLanguage" default-binding="true">
+ <constraints>
+ <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ </component>
+ <component id="e231b" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text value="Template language:"/>
+ </properties>
+ </component>
+ <component id="d243b" class="javax.swing.JLabel" binding="myTemplatesFolderLabel">
+ <constraints>
+ <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text value="Templates folder:"/>
+ </properties>
+ </component>
+ <component id="37ce3" class="javax.swing.JTextField" binding="myTemplatesFolder">
+ <constraints>
+ <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+ <preferred-size width="150" height="-1"/>
+ </grid>
+ </constraints>
+ <properties/>
+ </component>
+ </children>
+ </grid>
+</form>
diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateLanguagePanel.java b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateLanguagePanel.java
new file mode 100644
index 0000000..d2c453e
--- /dev/null
+++ b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateLanguagePanel.java
@@ -0,0 +1,73 @@
+package com.jetbrains.python.templateLanguages;
+
+import com.intellij.facet.ui.FacetValidatorsManager;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.ui.components.JBLabel;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+public class TemplateLanguagePanel extends JPanel {
+ private JTextField myTemplatesFolder;
+ private JPanel myMainPanel;
+ private JLabel myTemplatesFolderLabel;
+ private JComboBox myTemplateLanguage;
+
+ private static final String DEFAULT_TEMPLATES_FOLDER = "templates";
+
+ public TemplateLanguagePanel() {
+ super(new BorderLayout());
+ add(myMainPanel, BorderLayout.CENTER);
+ myTemplatesFolderLabel.setLabelFor(myTemplatesFolder);
+ FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
+ descriptor.withTreeRootVisible(true);
+ descriptor.setShowFileSystemRoots(true);
+ List<String> templateConfigurations = TemplatesService.getAllTemplateLanguages();
+ for (String configuration : templateConfigurations) {
+ if (!configuration.equals(TemplatesService.WEB2PY))
+ myTemplateLanguage.addItem(configuration);
+ }
+ myTemplatesFolder.setText(DEFAULT_TEMPLATES_FOLDER);
+ }
+
+ public String getTemplatesFolder() {
+ return myTemplatesFolder.getText();
+ }
+
+ public String getTemplateLanguage() {
+ final Object selectedItem = myTemplateLanguage.getSelectedItem();
+ return selectedItem != null ? (String)selectedItem : null;
+ }
+
+ public void setTemplateLanguage(String language) {
+ myTemplateLanguage.setSelectedItem(language);
+ }
+
+ public void saveSettings(TemplateSettingsHolder holder) {
+ holder.setTemplatesFolder(getTemplatesFolder());
+ final Object templateLanguage = getTemplateLanguage();
+ holder.setTemplateLanguage((String)templateLanguage);
+ }
+
+ public void setTemplatesFolder(@NotNull final String folder) {
+ myTemplatesFolder.setText(folder);
+ }
+
+ public Dimension getLabelSize() {
+ return new JBLabel("Template language:").getPreferredSize();
+ }
+
+ public void registerValidators(final FacetValidatorsManager validatorsManager) {
+ myTemplateLanguage.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ validatorsManager.validate();
+ }
+ });
+ }
+}
diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateSettingsHolder.java b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateSettingsHolder.java
new file mode 100644
index 0000000..e6ab03b
--- /dev/null
+++ b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateSettingsHolder.java
@@ -0,0 +1,26 @@
+package com.jetbrains.python.templateLanguages;
+
+import com.jetbrains.python.newProject.PyNewProjectSettings;
+import org.jetbrains.annotations.Nullable;
+
+public class TemplateSettingsHolder extends PyNewProjectSettings {
+ private String myTemplatesFolder;
+ private String myTemplateLanguage;
+
+ public String getTemplatesFolder() {
+ return myTemplatesFolder;
+ }
+
+ public void setTemplatesFolder(String templatesFolder) {
+ myTemplatesFolder = templatesFolder;
+ }
+
+ @Nullable
+ public String getTemplateLanguage() {
+ return myTemplateLanguage;
+ }
+
+ public void setTemplateLanguage(@Nullable String templateLanguage) {
+ myTemplateLanguage = templateLanguage;
+ }
+}
diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java
index eff10e1..73603e4 100644
--- a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java
+++ b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java
@@ -18,8 +18,10 @@
import com.intellij.lang.Language;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleServiceManager;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
+import com.jetbrains.python.packaging.PyPackageManager;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -42,6 +44,9 @@
WEB2PY,
CHAMELEON);
+ public static List<String> ALL_TEMPLATE_BINDINGS = ContainerUtil.immutableList("django-mako", "django-jinja", "django-chameleon",
+ "flask-mako", "pyramid_jinja2");
+
public abstract Language getSelectedTemplateLanguage();
public static TemplatesService getInstance(Module module) {
@@ -65,5 +70,9 @@
public abstract List<String> getTemplateFileTypes();
public abstract void setTemplateFileTypes(List<String> fileTypes);
+
+ public abstract void generateTemplates(@NotNull final TemplateSettingsHolder settings, VirtualFile baseDir);
+ public abstract void installTemplateEngine(@NotNull final TemplateSettingsHolder settings, @NotNull final PyPackageManager packageManager,
+ @NotNull final Project project, @NotNull final String prefix);
}
diff --git a/python/pluginResources/META-INF/plugin.xml b/python/pluginResources/META-INF/plugin.xml
index 6ec30aa..31f714c 100644
--- a/python/pluginResources/META-INF/plugin.xml
+++ b/python/pluginResources/META-INF/plugin.xml
@@ -4,13 +4,22 @@
<id>PythonCore</id>
<name>Python Community Edition</name>
- <idea-version since-build="135.406" until-build="138.*"/>
- <description>Smart editing for Python scripts</description>
- <version>3.4.Beta.135.@@BUILD_NUMBER@@</version>
+ <idea-version since-build="138.0" until-build="138.*"/>
+
+ <description><![CDATA[
+The Python plug-in provides smart editing for Python scripts. The feature set of the plugin
+ corresponds to PyCharm IDE Community Edition.
+<br>
+<a href="http://blog.jetbrains.com/pycharm">PyCharm blog</a><br>
+<a href="http://forum.jetbrains.com/forum/PyCharm">Discussion forum</a><br>
+<a href="http://youtrack.jetbrains.com/issues/PY">Issue tracker</a><br>
+]]></description>
+
+ <version>4.0.@@BUILD_NUMBER@@</version>
<depends>com.intellij.modules.java</depends>
- <vendor url="http://www.jetbrains.com/pycharm/" logo="/com/jetbrains/python/python.png">JetBrains, Keith Lea</vendor>
+ <vendor url="http://www.jetbrains.com/pycharm/" logo="/com/jetbrains/python/python.png">JetBrains</vendor>
<xi:include href="/META-INF/python-core.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/python-plugin-core.xml" xpointer="xpointer(/idea-plugin/*)"/>
</idea-plugin>
diff --git a/python/pluginSrc/com/jetbrains/python/packaging/PyManagePackagesDialog.java b/python/pluginSrc/com/jetbrains/python/packaging/PyManagePackagesDialog.java
index 4a663c3..4a9df08 100644
--- a/python/pluginSrc/com/jetbrains/python/packaging/PyManagePackagesDialog.java
+++ b/python/pluginSrc/com/jetbrains/python/packaging/PyManagePackagesDialog.java
@@ -48,7 +48,7 @@
List<Sdk> sdks = PythonSdkType.getAllSdks();
Collections.sort(sdks, new PreferredSdkComparator());
final JComboBox sdkComboBox = new JComboBox(new CollectionComboBoxModel(sdks, sdk));
- sdkComboBox.setRenderer(new PySdkListCellRenderer());
+ sdkComboBox.setRenderer(new PySdkListCellRenderer(false));
PackagesNotificationPanel notificationPanel = new PackagesNotificationPanel(project);
final PyInstalledPackagesPanel packagesPanel = new PyInstalledPackagesPanel(project, notificationPanel);
diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java
index a667bb6..e9014b3 100644
--- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java
+++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java
@@ -18,8 +18,8 @@
import com.intellij.psi.*;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.psi.AccessDirection;
+import com.jetbrains.python.psi.PyCallSiteExpression;
import com.jetbrains.python.psi.PyExpression;
-import com.jetbrains.python.psi.PyQualifiedExpression;
import com.jetbrains.python.psi.resolve.CompletionVariantsProcessor;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
@@ -113,7 +113,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
+ public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
return getReturnType(context);
}
diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java
index 6f0fd48..cb5d94e 100644
--- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java
+++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java
@@ -21,8 +21,8 @@
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.psi.AccessDirection;
+import com.jetbrains.python.psi.PyCallSiteExpression;
import com.jetbrains.python.psi.PyExpression;
-import com.jetbrains.python.psi.PyQualifiedExpression;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.types.PyCallableParameter;
@@ -58,7 +58,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
+ public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
return getReturnType(context);
}
diff --git a/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.form b/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.form
index edec809..0332fda 100644
--- a/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.form
+++ b/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.form
@@ -75,7 +75,7 @@
<text value="Use SDK of module:"/>
</properties>
</component>
- <component id="5f300" class="javax.swing.JComboBox" binding="myModuleComboBox">
+ <component id="5f300" class="com.intellij.application.options.ModulesComboBox" binding="myModuleComboBox">
<constraints>
<grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
diff --git a/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.java b/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.java
index 4a1957e..cf0e440 100644
--- a/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.java
+++ b/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.java
@@ -15,7 +15,6 @@
*/
package com.jetbrains.python.run;
-import com.intellij.application.options.ModuleListCellRenderer;
import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.util.PathMappingsComponent;
import com.intellij.ide.util.PropertiesComponent;
@@ -27,6 +26,7 @@
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.ui.configuration.ModulesAlphaComparator;
+import com.intellij.application.options.ModulesComboBox;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.ui.CollectionComboBoxModel;
@@ -58,7 +58,7 @@
private RawCommandLineEditor myInterpreterOptionsTextField;
private JComboBox myInterpreterComboBox;
private JRadioButton myUseModuleSdkRadioButton;
- private JComboBox myModuleComboBox;
+ private ModulesComboBox myModuleComboBox;
private JPanel myMainPanel;
private JRadioButton myUseSpecifiedSdkRadioButton;
private JBLabel myPythonInterpreterJBLabel;
@@ -77,8 +77,8 @@
final List<Module> validModules = data.getValidModules();
Collections.sort(validModules, new ModulesAlphaComparator());
Module selection = validModules.size() > 0 ? validModules.get(0) : null;
- myModuleComboBox.setModel(new CollectionComboBoxModel(validModules, selection));
- myModuleComboBox.setRenderer(new ModuleListCellRenderer());
+ myModuleComboBox.setModules(validModules);
+ myModuleComboBox.setSelectedModule(selection);
myInterpreterComboBox.setRenderer(new SdkListCellRenderer("<Project Default>"));
myWorkingDirectoryTextField.addBrowseFolderListener("Select Working Directory", "", data.getProject(),
@@ -181,11 +181,11 @@
}
public Module getModule() {
- return (Module)myModuleComboBox.getSelectedItem();
+ return myModuleComboBox.getSelectedModule();
}
public void setModule(Module module) {
- myModuleComboBox.setSelectedItem(module);
+ myModuleComboBox.setSelectedModule(module);
}
public boolean isUseModuleSdk() {
diff --git a/python/psi-api/src/com/jetbrains/python/psi/Callable.java b/python/psi-api/src/com/jetbrains/python/psi/Callable.java
index a31197e..59e190e 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java
@@ -45,7 +45,7 @@
* Returns the type of the call to the callable.
*/
@Nullable
- PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite);
+ PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite);
/**
* Returns the type of the call to the callable where the call site is specified by the optional receiver and the arguments to parameters
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyBinaryExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyBinaryExpression.java
index 0461318..9ca5a30 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyBinaryExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyBinaryExpression.java
@@ -21,7 +21,7 @@
/**
* @author yole
*/
-public interface PyBinaryExpression extends PyQualifiedExpression, PyReferenceOwner {
+public interface PyBinaryExpression extends PyQualifiedExpression, PyCallSiteExpression, PyReferenceOwner {
PyExpression getLeftExpression();
@Nullable PyExpression getRightExpression();
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java
index 581c425..ae429f0 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java
@@ -25,7 +25,7 @@
/**
* Represents an entire call expression, like <tt>foo()</tt> or <tt>foo.bar[1]('x')</tt>.
*/
-public interface PyCallExpression extends PyExpression {
+public interface PyCallExpression extends PyCallSiteExpression {
/**
* @return the expression representing the object being called (reference to a function).
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyCallSiteExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyCallSiteExpression.java
new file mode 100644
index 0000000..a2c49cb
--- /dev/null
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyCallSiteExpression.java
@@ -0,0 +1,24 @@
+/*
+ * 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.psi;
+
+/**
+ * Marker interface for Python expressions that are call sites for explicit or implicit function calls.
+ *
+ * @author vlan
+ */
+public interface PyCallSiteExpression extends PyExpression {
+}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyFile.java b/python/psi-api/src/com/jetbrains/python/psi/PyFile.java
index 1786b93..48d1b50 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyFile.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyFile.java
@@ -27,6 +27,7 @@
List<PyClass> getTopLevelClasses();
+ @NotNull
List<PyFunction> getTopLevelFunctions();
List<PyTargetExpression> getTopLevelAttributes();
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceOwner.java b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceOwner.java
index d9fab3f..d034347 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceOwner.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceOwner.java
@@ -17,12 +17,12 @@
import com.intellij.psi.PsiPolyVariantReference;
import com.jetbrains.python.psi.resolve.PyResolveContext;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public interface PyReferenceOwner extends PyElement {
- @Nullable
+ @NotNull
PsiPolyVariantReference getReference(PyResolveContext context);
}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java
index dc3f28d..cc1bba0 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java
@@ -21,7 +21,7 @@
/**
* @author yole
*/
-public interface PySubscriptionExpression extends PyQualifiedExpression, PyReferenceOwner {
+public interface PySubscriptionExpression extends PyQualifiedExpression, PyCallSiteExpression, PyReferenceOwner {
/**
* @return For <code>spam[x][y][n]</code> will return <code>spam</code> regardless number of its dimensions
diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java
index b3a1134..f4f3a74 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java
@@ -236,6 +236,7 @@
}
}
+ @NotNull
static <T, U extends PsiElement> List<T> collectStubChildren(U e,
final StubElement<U> stub, final IElementType elementType,
final Class<T> itemClass) {
diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java
index 5707005..be76db2 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java
@@ -42,7 +42,7 @@
PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context);
@Nullable
- PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context);
+ PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context);
@Nullable
PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context);
diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java
index 66fb827..d2c36ba 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java
@@ -15,7 +15,7 @@
*/
package com.jetbrains.python.psi.types;
-import com.jetbrains.python.psi.PyQualifiedExpression;
+import com.jetbrains.python.psi.PyCallSiteExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,7 +46,7 @@
* Returns the type which is the result of calling an instance of this type.
*/
@Nullable
- PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite);
+ PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite);
/**
* Returns the list of parameter types.
diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java
index c27dc4b..0c60e65 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java
@@ -35,7 +35,7 @@
protected interface ReturnTypeCallback {
@Nullable
- PyType getType(@Nullable PyQualifiedExpression callSite, @Nullable PyType qualifierType, TypeEvalContext context);
+ PyType getType(@Nullable PyCallSiteExpression callSite, @Nullable PyType qualifierType, TypeEvalContext context);
}
private static class ReturnTypeDescriptor {
@@ -46,12 +46,13 @@
}
@Nullable
- public PyType get(PyFunction function, @Nullable PyQualifiedExpression callSite, TypeEvalContext context) {
+ public PyType get(PyFunction function, @Nullable PyCallSiteExpression callSite, TypeEvalContext context) {
PyClass containingClass = function.getContainingClass();
if (containingClass != null) {
final ReturnTypeCallback typeCallback = myStringToReturnTypeMap.get(containingClass.getQualifiedName());
if (typeCallback != null) {
- final PyExpression qualifier = callSite != null ? callSite.getQualifier() : null;
+ final PyExpression callee = callSite instanceof PyCallExpression ? ((PyCallExpression)callSite).getCallee() : null;
+ final PyExpression qualifier = callee instanceof PyQualifiedExpression ? ((PyQualifiedExpression)callee).getQualifier() : null;
PyType qualifierType = qualifier != null ? context.getType(qualifier) : null;
return typeCallback.getType(callSite, qualifierType, context);
}
@@ -62,7 +63,7 @@
private final ReturnTypeCallback mySelfTypeCallback = new ReturnTypeCallback() {
@Override
- public PyType getType(@Nullable PyQualifiedExpression callSite, @Nullable PyType qualifierType, TypeEvalContext context) {
+ public PyType getType(@Nullable PyCallSiteExpression callSite, @Nullable PyType qualifierType, TypeEvalContext context) {
if (qualifierType instanceof PyClassType) {
PyClass aClass = ((PyClassType)qualifierType).getPyClass();
return PyPsiFacade.getInstance(aClass.getProject()).createClassType(aClass, false);
@@ -101,7 +102,7 @@
}
@Override
- public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) {
+ public PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) {
ReturnTypeDescriptor descriptor;
synchronized (myMethodToReturnTypeMap) {
descriptor = myMethodToReturnTypeMap.get(function.getName());
diff --git a/python/python-community.iml b/python/python-community.iml
index 831f4bd..e0aca64 100644
--- a/python/python-community.iml
+++ b/python/python-community.iml
@@ -14,7 +14,7 @@
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="module" module-name="python-pydev" />
- <orderEntry type="library" name="XmlRPC" level="project" />
+ <orderEntry type="library" exported="" name="XmlRPC" level="project" />
<orderEntry type="module" module-name="xdebugger-api" />
<orderEntry type="library" name="http-client-3.1" level="project" />
<orderEntry type="module" module-name="RegExpSupport" exported="" />
diff --git a/python/python-rest/src/com/jetbrains/rest/RestFileProviderFactory.java b/python/python-rest/src/com/jetbrains/rest/RestFileProviderFactory.java
index 5c61251..ae15df0 100644
--- a/python/python-rest/src/com/jetbrains/rest/RestFileProviderFactory.java
+++ b/python/python-rest/src/com/jetbrains/rest/RestFileProviderFactory.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.
@@ -27,6 +27,7 @@
*/
public class RestFileProviderFactory implements FileViewProviderFactory {
+ @NotNull
public FileViewProvider createFileViewProvider(@NotNull VirtualFile virtualFile, Language language, @NotNull PsiManager psiManager, boolean eventSystemEnabled) {
return new RestFileViewProvider(psiManager, virtualFile, eventSystemEnabled);
}
diff --git a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
index 52b8de6..f32fce8 100644
--- a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
+++ b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
@@ -50,7 +50,7 @@
if (sdk != null) {
PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
try {
- final PyPackage sphinx = manager.findPackage("Sphinx");
+ final PyPackage sphinx = manager.findInstalledPackage("Sphinx");
presentation.setEnabled(sphinx != null);
}
catch (PyExternalProcessException ignored) {
diff --git a/python/python-rest/src/com/jetbrains/rest/inspections/RestInspection.java b/python/python-rest/src/com/jetbrains/rest/inspections/RestInspection.java
index 0369198..a22819d 100644
--- a/python/python-rest/src/com/jetbrains/rest/inspections/RestInspection.java
+++ b/python/python-rest/src/com/jetbrains/rest/inspections/RestInspection.java
@@ -15,9 +15,7 @@
*/
package com.jetbrains.rest.inspections;
-import com.intellij.codeInspection.CustomSuppressableInspectionTool;
-import com.intellij.codeInspection.LocalInspectionTool;
-import com.intellij.codeInspection.SuppressIntentionAction;
+import com.intellij.codeInspection.*;
import com.intellij.psi.PsiElement;
import com.jetbrains.rest.RestBundle;
import org.jetbrains.annotations.Nls;
@@ -27,7 +25,7 @@
/**
* User : catherine
*/
-public abstract class RestInspection extends LocalInspectionTool implements CustomSuppressableInspectionTool {
+public abstract class RestInspection extends LocalInspectionTool {
@Nls
@NotNull
@Override
@@ -46,9 +44,10 @@
return true;
}
+ @NotNull
@Override
- public SuppressIntentionAction[] getSuppressActions(@Nullable PsiElement element) {
- return null;
+ public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
+ return SuppressQuickFix.EMPTY_ARRAY;
}
@Override
diff --git a/python/resources/icons/com/jetbrains/python/python-logo.png b/python/resources/icons/com/jetbrains/python/python-logo.png
new file mode 100644
index 0000000..87fff4d
--- /dev/null
+++ b/python/resources/icons/com/jetbrains/python/python-logo.png
Binary files differ
diff --git a/python/src/META-INF/pycharm-core.xml b/python/src/META-INF/pycharm-core.xml
index fdec83a..775d912 100644
--- a/python/src/META-INF/pycharm-core.xml
+++ b/python/src/META-INF/pycharm-core.xml
@@ -79,7 +79,7 @@
<actions>
<group id="PlatformOpenProjectGroup">
- <action id="NewDirectoryProject" class="com.jetbrains.python.newProject.PythonNewDirectoryProjectAction"/>
+ <action id="NewDirectoryProject" class="com.jetbrains.python.newProject.PyCharmNewProjectAction"/>
<add-to-group group-id="FileOpenGroup" anchor="first"/>
</group>
@@ -95,7 +95,7 @@
icon="AllIcons.RunConfigurations.RerunFailedTests"/>
<group id="WelcomeScreen.Platform.NewProject">
- <action id="WelcomeScreen.CreateDirectoryProject" class="com.jetbrains.python.newProject.PythonNewDirectoryProjectAction" icon="AllIcons.General.CreateNewProject"/>
+ <action id="WelcomeScreen.CreateDirectoryProject" class="com.jetbrains.python.newProject.actions.PyCharmNewProjectStep" icon="AllIcons.General.CreateNewProject"/>
<action id="WelcomeScreen.OpenDirectoryProject" class="com.intellij.ide.actions.OpenFileAction" icon="AllIcons.General.OpenProject"/>
<add-to-group group-id="WelcomeScreen.QuickStart" anchor="first"/>
diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml
index 411fa6c..54491eb 100644
--- a/python/src/META-INF/python-core.xml
+++ b/python/src/META-INF/python-core.xml
@@ -69,6 +69,8 @@
implementationClass="com.jetbrains.python.codeInsight.completion.PyParameterCompletionContributor"/>
<completion.contributor language="Python"
implementationClass="com.jetbrains.python.codeInsight.completion.PyDocstringCompletionContributor"/>
+ <completion.contributor language="Python"
+ implementationClass="com.jetbrains.python.codeInsight.completion.PyMetaClassCompletionContributor"/>
<lang.tokenSeparatorGenerator language="Python" implementationClass="com.jetbrains.python.PyTokenSeparatorGenerator"/>
<lang.elementManipulator forClass="com.jetbrains.python.psi.PyReferenceExpression"
implementationClass="com.jetbrains.python.psi.impl.PyReferenceExpressionManipulator"/>
@@ -91,6 +93,7 @@
<stubIndex implementation="com.jetbrains.python.psi.stubs.PySuperClassIndex"/>
<stubIndex implementation="com.jetbrains.python.psi.stubs.PyVariableNameIndex"/>
<stubIndex implementation="com.jetbrains.python.psi.stubs.PyInstanceAttributeIndex"/>
+ <stubIndex implementation="com.jetbrains.python.psi.stubs.PyDecoratorStubIndex"/>
<fileBasedIndex implementation="com.jetbrains.python.psi.stubs.PyModuleNameIndex"/>
<declarationRangeHandler key="com.jetbrains.python.psi.PyClass"
diff --git a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java
index 27207ab..18786ed 100644
--- a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java
+++ b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java
@@ -20,10 +20,7 @@
import com.intellij.psi.PsiFile;
import com.jetbrains.numpy.documentation.NumPyDocString;
import com.jetbrains.numpy.documentation.NumPyDocStringParameter;
-import com.jetbrains.python.psi.PyFunction;
-import com.jetbrains.python.psi.PyNamedParameter;
-import com.jetbrains.python.psi.PyPsiFacade;
-import com.jetbrains.python.psi.PyQualifiedExpression;
+import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.PyTypeProviderBase;
import com.jetbrains.python.psi.types.TypeEvalContext;
@@ -67,9 +64,10 @@
@Nullable
@Override
- public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) {
+ public PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) {
if (isInsideNumPy(function)) {
- final NumPyDocString docString = NumPyDocString.forFunction(function, callSite);
+ final PyExpression callee = callSite instanceof PyCallExpression ? ((PyCallExpression)callSite).getCallee() : null;
+ final NumPyDocString docString = NumPyDocString.forFunction(function, callee);
if (docString != null) {
final List<NumPyDocStringParameter> returns = docString.getReturns();
final PyPsiFacade facade = getPsiFacade(function);
diff --git a/python/src/com/jetbrains/python/PyBundle.java b/python/src/com/jetbrains/python/PyBundle.java
index 28b853e..c6f17d1 100644
--- a/python/src/com/jetbrains/python/PyBundle.java
+++ b/python/src/com/jetbrains/python/PyBundle.java
@@ -27,6 +27,7 @@
// A copy of Ruby's.
/**
+ * TODO: Copy/paste with Django and PyBDD bundles
* Resource bundle access.
* Date: Nov 25, 2008 2:36:10 AM
*/
diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties
index f87f2c2..5d29d3f 100644
--- a/python/src/com/jetbrains/python/PyBundle.properties
+++ b/python/src/com/jetbrains/python/PyBundle.properties
@@ -774,8 +774,7 @@
# Consoles messages
python.console=Python Console
-django.console=Django Console
-django.console.and.manage.py=Django Console and manage.py options
+
# UI messages
MSG.title.bad.sdk=Invalid Python SDK
@@ -790,6 +789,7 @@
runcfg.unittest.dlg.keywords=Keywords:
run.configuration.remote.debug.name=Python Remote Debug
run.configuration.type.description=Starts server for remote debug
+run.configuration.show.command.line.action.name=Show Python Prompt
unable.to.stop=Currently running process can't be stopped. Kill it manually first.
diff --git a/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java b/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java
index 15b29c1..dd9d3ef 100644
--- a/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java
+++ b/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java
@@ -82,7 +82,7 @@
if (caretOffset == chars.length() || chars.charAt(caretOffset) != ':') {
textToType += ':';
}
- EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, textToType, true, 1 + pname.length()); // right after param name
+ EditorModificationUtil.insertStringAtCaret(editor, textToType, true, 1 + pname.length()); // right after param name
return Result.STOP;
}
}
diff --git a/python/src/com/jetbrains/python/codeInsight/PyStdReferenceContributor.java b/python/src/com/jetbrains/python/codeInsight/PyStdReferenceContributor.java
index 3be84bf..5b0221d 100644
--- a/python/src/com/jetbrains/python/codeInsight/PyStdReferenceContributor.java
+++ b/python/src/com/jetbrains/python/codeInsight/PyStdReferenceContributor.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.
@@ -31,7 +31,7 @@
*/
public class PyStdReferenceContributor extends PsiReferenceContributor {
@Override
- public void registerReferenceProviders(PsiReferenceRegistrar registrar) {
+ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registerClassAttributeReference(registrar, PyNames.ALL, new PsiReferenceProvider() {
@NotNull
@Override
diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java
index 24318f8..3b2e828 100644
--- a/python/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java
+++ b/python/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java
@@ -41,6 +41,7 @@
import com.jetbrains.python.psi.stubs.PyFunctionNameIndex;
import com.jetbrains.python.psi.stubs.PyVariableNameIndex;
import com.jetbrains.python.psi.types.PyModuleType;
+import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -50,7 +51,7 @@
public class PyClassNameCompletionContributor extends CompletionContributor {
@Override
- public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) {
+ public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
if (parameters.isExtendedCompletion()) {
final PsiElement element = parameters.getPosition();
final PsiElement parent = element.getParent();
diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyMetaClassCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyMetaClassCompletionContributor.java
new file mode 100644
index 0000000..bac2708
--- /dev/null
+++ b/python/src/com/jetbrains/python/codeInsight/completion/PyMetaClassCompletionContributor.java
@@ -0,0 +1,92 @@
+/*
+ * 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.codeInsight.completion;
+
+import com.intellij.codeInsight.completion.*;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.filters.ElementFilter;
+import com.intellij.psi.filters.position.FilterPattern;
+import com.intellij.util.ProcessingContext;
+import com.intellij.util.Processor;
+import com.jetbrains.python.PythonLanguage;
+import com.jetbrains.python.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author vlan
+ */
+public class PyMetaClassCompletionContributor extends CompletionContributor {
+ public PyMetaClassCompletionContributor() {
+ extend(CompletionType.BASIC,
+ PlatformPatterns
+ .psiElement()
+ .withLanguage(PythonLanguage.getInstance())
+ .withParents(PyReferenceExpression.class, PyExpressionStatement.class, PyStatementList.class, PyClass.class)
+ .and(hasLanguageLevel(new Processor<LanguageLevel>() {
+ @Override
+ public boolean process(LanguageLevel level) {
+ return level.isOlderThan(LanguageLevel.PYTHON30);
+ }
+ })),
+ new CompletionProvider<CompletionParameters>() {
+ @Override
+ protected void addCompletions(@NotNull CompletionParameters parameters,
+ ProcessingContext context,
+ @NotNull CompletionResultSet result) {
+ result.addElement(LookupElementBuilder.create("__metaclass__ = "));
+ }
+ });
+ extend(CompletionType.BASIC,
+ PlatformPatterns
+ .psiElement()
+ .withLanguage(PythonLanguage.getInstance())
+ .withParents(PyReferenceExpression.class, PyArgumentList.class, PyClass.class)
+ .and(hasLanguageLevel(new Processor<LanguageLevel>() {
+ @Override
+ public boolean process(LanguageLevel level) {
+ return level.isAtLeast(LanguageLevel.PYTHON30);
+ }
+ })),
+ new CompletionProvider<CompletionParameters>() {
+ @Override
+ protected void addCompletions(@NotNull CompletionParameters parameters,
+ ProcessingContext context,
+ @NotNull CompletionResultSet result) {
+ result.addElement(LookupElementBuilder.create("metaclass="));
+ }
+ });
+ }
+
+ public static FilterPattern hasLanguageLevel(@NotNull final Processor<LanguageLevel> processor) {
+ return new FilterPattern(new ElementFilter() {
+ @Override
+ public boolean isAcceptable(Object element, @Nullable PsiElement context) {
+ if (element instanceof PsiElement) {
+ return processor.process(LanguageLevel.forElement((PsiElement)element));
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isClassAcceptable(Class hintClass) {
+ return true;
+ }
+ });
+ }
+}
diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PySpecialMethodNamesCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PySpecialMethodNamesCompletionContributor.java
index db0e453..bc3de2d 100644
--- a/python/src/com/jetbrains/python/codeInsight/completion/PySpecialMethodNamesCompletionContributor.java
+++ b/python/src/com/jetbrains/python/codeInsight/completion/PySpecialMethodNamesCompletionContributor.java
@@ -40,7 +40,7 @@
*/
public class PySpecialMethodNamesCompletionContributor extends CompletionContributor {
@Override
- public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
+ public AutoCompletionDecision handleAutoCompletionPossibility(@NotNull AutoCompletionContext context) {
// auto-insert the obvious only case; else show other cases.
final LookupElement[] items = context.getItems();
if (items.length == 1) {
diff --git a/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java b/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java
index 168a3fe..1cdba26 100644
--- a/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java
+++ b/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java
@@ -84,7 +84,7 @@
@Override
public PyType getType(TypeEvalContext context, PsiElement anchor) {
final List<PyType> types = new ArrayList<PyType>();
- types.add(PyTypeParser.getTypeByName(target, PyNames.CALLABLE));
+ types.add(PyTypeParser.getTypeByName(target, "collections." + PyNames.CALLABLE));
return createAssertionType(context.getType(target), types, positive, context);
}
});
diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java
index ad1d6a2..bcad2c1 100644
--- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java
+++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java
@@ -95,7 +95,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
+ public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
if (myDefinitionLevel > 0) {
return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, myDefinitionLevel-1);
}
diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibCanonicalPathProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibCanonicalPathProvider.java
index 1a09726..8a0b9eb 100644
--- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibCanonicalPathProvider.java
+++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibCanonicalPathProvider.java
@@ -73,6 +73,10 @@
components.set(0, "sqlite3");
return QualifiedName.fromComponents(components);
}
+ else if (head.equals("_pickle")) {
+ components.set(0, "pickle");
+ return QualifiedName.fromComponents(components);
+ }
}
return null;
}
diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
index d7678c2..346d40f 100644
--- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
+++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
@@ -120,7 +120,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) {
+ public PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) {
final String qname = getQualifiedName(function, callSite);
if (qname != null) {
if (OPEN_FUNCTIONS.contains(qname) && callSite != null) {
diff --git a/python/src/com/jetbrains/python/console/PyOpenDebugConsoleAction.java b/python/src/com/jetbrains/python/console/PyOpenDebugConsoleAction.java
index 45906d5..6b6edde 100644
--- a/python/src/com/jetbrains/python/console/PyOpenDebugConsoleAction.java
+++ b/python/src/com/jetbrains/python/console/PyOpenDebugConsoleAction.java
@@ -59,7 +59,7 @@
selectRunningProcess(e.getDataContext(), project, new Consumer<PythonDebugLanguageConsoleView>() {
@Override
public void consume(PythonDebugLanguageConsoleView view) {
- view.showDebugConsole(true);
+ view.enableConsole(false);
IdeFocusManager.getInstance(project).requestFocus(view.getPydevConsoleView().getComponent(), true);
}
});
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
index 2213375..ba2f137 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
@@ -131,6 +131,7 @@
public static Key<Sdk> CONSOLE_SDK = new Key<Sdk>("PYDEV_CONSOLE_SDK_KEY");
private static final long APPROPRIATE_TO_WAIT = 60000;
+ private PyRemoteSdkCredentials myRemoteCredentials;
protected PydevConsoleRunner(@NotNull final Project project,
@NotNull Sdk sdk, @NotNull final PyConsoleType consoleType,
@@ -352,16 +353,16 @@
myCommandLine = commandLine.getCommandLineString();
try {
- PyRemoteSdkCredentials remoteCredentials = data.getRemoteSdkCredentials();
+ myRemoteCredentials = data.getRemoteSdkCredentials(true);
PathMappingSettings mappings = manager.setupMappings(getProject(), data, null);
RemoteSshProcess remoteProcess =
- manager.createRemoteProcess(getProject(), remoteCredentials, mappings, commandLine, true);
+ manager.createRemoteProcess(getProject(), myRemoteCredentials, mappings, commandLine, true);
Pair<Integer, Integer> remotePorts = getRemotePortsFromProcess(remoteProcess);
- remoteProcess.addLocalTunnel(myPorts[0], remoteCredentials.getHost(), remotePorts.first);
+ remoteProcess.addLocalTunnel(myPorts[0], myRemoteCredentials.getHost(), remotePorts.first);
remoteProcess.addRemoteTunnel(remotePorts.second, "localhost", myPorts[1]);
@@ -425,15 +426,10 @@
if (manager != null) {
PyRemoteSdkAdditionalDataBase data = (PyRemoteSdkAdditionalDataBase)mySdk.getSdkAdditionalData();
assert data != null;
- try {
- myProcessHandler =
- manager.createConsoleProcessHandler(process, data.getRemoteSdkCredentials(), getConsoleView(), myPydevConsoleCommunication,
- myCommandLine, CharsetToolkit.UTF8_CHARSET,
- manager.setupMappings(getProject(), data, null));
- }
- catch (InterruptedException e) {
- LOG.error("Error getting remote credentials");
- }
+ myProcessHandler =
+ manager.createConsoleProcessHandler(process, myRemoteCredentials, getConsoleView(), myPydevConsoleCommunication,
+ myCommandLine, CharsetToolkit.UTF8_CHARSET,
+ manager.setupMappings(getProject(), data, null));
}
else {
LOG.error("Can't create remote console process handler");
diff --git a/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java b/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java
index 495c26d..961f703 100644
--- a/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java
+++ b/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java
@@ -15,64 +15,32 @@
*/
package com.jetbrains.python.console;
-import com.google.common.collect.Lists;
-import com.intellij.execution.ExecutionBundle;
-import com.intellij.execution.filters.Filter;
-import com.intellij.execution.filters.HyperlinkInfo;
+import com.intellij.execution.console.DuplexConsoleView;
+import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.impl.ConsoleViewImpl;
-import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ConsoleView;
-import com.intellij.execution.ui.ConsoleViewContentType;
-import com.intellij.execution.ui.ObservableConsoleView;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.actionSystem.ToggleAction;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.ScrollType;
-import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.jetbrains.python.PyBundle;
import icons.PythonIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.util.List;
-
/**
* @author traff
*/
-public class PythonDebugLanguageConsoleView extends JPanel implements ConsoleView, ObservableConsoleView, PyCodeExecutor {
-
- private final static String TEXT_CONSOLE_PANEL = "TEXT_CONSOLE_PANEL";
- private final static String PYDEV_CONSOLE_PANEL = "PYDEV_CONSOLE_PANEL";
-
- private final PythonConsoleView myPydevConsoleView;
-
- private final ConsoleView myTextConsole;
-
- public boolean myIsDebugConsole = false;
-
- private ProcessHandler myProcessHandler;
+public class PythonDebugLanguageConsoleView extends DuplexConsoleView<ConsoleView, PythonConsoleView> implements PyCodeExecutor {
public PythonDebugLanguageConsoleView(final Project project, Sdk sdk, ConsoleView consoleView) {
- super(new CardLayout());
- myPydevConsoleView = new PythonConsoleView(project, "Python Console", sdk);
- myTextConsole = consoleView;
+ super(consoleView, new PythonConsoleView(project, "Python Console", sdk));
- add(myTextConsole.getComponent(), TEXT_CONSOLE_PANEL);
- add(myPydevConsoleView.getComponent(), PYDEV_CONSOLE_PANEL);
+ enableConsole(!PyConsoleOptions.getInstance(project).isShowDebugConsoleByDefault());
- showDebugConsole(PyConsoleOptions.getInstance(project).isShowDebugConsoleByDefault());
-
- Disposer.register(this, myPydevConsoleView);
- Disposer.register(this, myTextConsole);
+ getSwitchConsoleActionPresentation().setIcon(PythonIcons.Python.Debug.CommandLine);
+ getSwitchConsoleActionPresentation().setText(PyBundle.message("run.configuration.show.command.line.action.name"));
}
public PythonDebugLanguageConsoleView(final Project project, Sdk sdk) {
@@ -81,192 +49,33 @@
@Override
public void executeCode(@NotNull String code, @Nullable Editor e) {
- showDebugConsole(true);
+ enableConsole(false);
getPydevConsoleView().executeCode(code, e);
}
- private void doShowConsole(String type) {
- CardLayout cl = (CardLayout)(getLayout());
- cl.show(this, type);
- }
-
-
- public boolean isDebugConsole() {
- return myIsDebugConsole;
- }
-
- public void showDebugConsole(boolean flag) {
- if (flag) {
- doShowConsole(PYDEV_CONSOLE_PANEL);
- myPydevConsoleView.requestFocus();
- }
- else {
- doShowConsole(TEXT_CONSOLE_PANEL);
- }
- myIsDebugConsole = flag;
- }
-
public PythonConsoleView getPydevConsoleView() {
- return myPydevConsoleView;
+ return getSecondaryConsoleView();
}
public ConsoleViewImpl getTextConsole() {
- if (myTextConsole instanceof ConsoleViewImpl) {
- return (ConsoleViewImpl)myTextConsole;
+ ConsoleView consoleView = getPrimaryConsoleView();
+ if (consoleView instanceof ConsoleViewImpl) {
+ return (ConsoleViewImpl)consoleView;
}
return null;
}
@Override
- public void allowHeavyFilters() {
- myTextConsole.allowHeavyFilters();
- }
+ public void enableConsole(boolean primary) {
+ super.enableConsole(primary);
- @Override
- public JComponent getComponent() {
- return this;
- }
+ if (!primary && !isPrimaryConsoleEnabled()) {
+ PythonConsoleView pydevConsoleView = getPydevConsoleView();
+ LanguageConsoleImpl languageConsole = pydevConsoleView.getConsole();
- @Override
- public JComponent getPreferredFocusableComponent() {
- return this;
- }
-
- @Override
- public void dispose() {
- }
-
- @Override
- public void print(@NotNull String s, @NotNull ConsoleViewContentType contentType) {
- myPydevConsoleView.print(s, contentType);
- myTextConsole.print(s, contentType);
- }
-
- @Override
- public void clear() {
- myPydevConsoleView.clear();
- myTextConsole.clear();
- }
-
- @Override
- public void scrollTo(int offset) {
- myPydevConsoleView.getLanguageConsole().getHistoryViewer().getCaretModel().moveToOffset(offset);
- myPydevConsoleView.getLanguageConsole().getHistoryViewer().getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
- myTextConsole.scrollTo(offset);
- }
-
- @Override
- public void attachToProcess(ProcessHandler processHandler) {
- myProcessHandler = processHandler;
- myPydevConsoleView.attachToProcess(processHandler);
- myTextConsole.attachToProcess(processHandler);
- }
-
- @Override
- public void setOutputPaused(boolean value) {
- myPydevConsoleView.setOutputPaused(value);
- myTextConsole.setOutputPaused(value);
- }
-
- @Override
- public boolean isOutputPaused() {
- return false;
- }
-
- @Override
- public boolean hasDeferredOutput() {
- return myPydevConsoleView.hasDeferredOutput() && myTextConsole.hasDeferredOutput();
- }
-
- @Override
- public void performWhenNoDeferredOutput(Runnable runnable) {
-
- }
-
- @Override
- public void setHelpId(String helpId) {
- myPydevConsoleView.setHelpId(helpId);
- myTextConsole.setHelpId(helpId);
- }
-
- @Override
- public void addMessageFilter(Filter filter) {
- myPydevConsoleView.addMessageFilter(filter);
- myTextConsole.addMessageFilter(filter);
- }
-
- @Override
- public void printHyperlink(String hyperlinkText, HyperlinkInfo info) {
- myPydevConsoleView.printHyperlink(hyperlinkText, info);
- myTextConsole.printHyperlink(hyperlinkText, info);
- }
-
- @Override
- public int getContentSize() {
- return myTextConsole.getContentSize();
- }
-
- @Override
- public boolean canPause() {
- return false;
- }
-
- @NotNull
- @Override
- public AnAction[] createConsoleActions() {
- List<AnAction> actions = Lists.newArrayList(myTextConsole.createConsoleActions());
- actions.add(new ShowDebugConsoleAction(this));
-
- return actions.toArray(new AnAction[actions.size()]);
- }
-
- @Override
- public void addChangeListener(@NotNull ChangeListener listener, @NotNull Disposable parent) {
- myPydevConsoleView.addChangeListener(listener, parent);
- if (myTextConsole instanceof ObservableConsoleView) {
- ((ObservableConsoleView)myTextConsole).addChangeListener(listener, parent);
- }
- }
-
- private static class ShowDebugConsoleAction extends ToggleAction implements DumbAware {
- private final PythonDebugLanguageConsoleView myConsole;
-
-
- public ShowDebugConsoleAction(final PythonDebugLanguageConsoleView console) {
- super(ExecutionBundle.message("run.configuration.show.command.line.action.name"), null,
- PythonIcons.Python.Debug.CommandLine);
- myConsole = console;
- }
-
- @Override
- public boolean isSelected(final AnActionEvent event) {
- return myConsole.isDebugConsole();
- }
-
- @Override
- public void setSelected(final AnActionEvent event, final boolean flag) {
- myConsole.showDebugConsole(flag);
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- update(event);
- }
- });
- }
-
- @Override
- public void update(final AnActionEvent event) {
- super.update(event);
- final Presentation presentation = event.getPresentation();
- final boolean isRunning = myConsole.myProcessHandler != null && !myConsole.myProcessHandler.isProcessTerminated();
- if (isRunning) {
- presentation.setEnabled(true);
- }
- else {
- myConsole.showDebugConsole(false);
- presentation.putClientProperty(SELECTED_PROPERTY, false);
- presentation.setEnabled(false);
- }
+ IdeFocusManager.findInstance().requestFocus(languageConsole.getConsoleEditor().getContentComponent(), true);
+ pydevConsoleView.updateUI();
+ languageConsole.getHistoryViewer().getComponent().updateUI();
}
}
}
diff --git a/python/src/com/jetbrains/python/documentation/DocStringReferenceContributor.java b/python/src/com/jetbrains/python/documentation/DocStringReferenceContributor.java
index 0867c29..192a70b 100644
--- a/python/src/com/jetbrains/python/documentation/DocStringReferenceContributor.java
+++ b/python/src/com/jetbrains/python/documentation/DocStringReferenceContributor.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.
@@ -17,13 +17,14 @@
import com.intellij.psi.PsiReferenceContributor;
import com.intellij.psi.PsiReferenceRegistrar;
+import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class DocStringReferenceContributor extends PsiReferenceContributor {
@Override
- public void registerReferenceProviders(PsiReferenceRegistrar registrar) {
+ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(DocStringTagCompletionContributor.DOCSTRING_PATTERN,
new DocStringReferenceProvider());
}
diff --git a/python/src/com/jetbrains/python/documentation/doctest/PyDocReferenceExpression.java b/python/src/com/jetbrains/python/documentation/doctest/PyDocReferenceExpression.java
index 62356d2..46e4709 100644
--- a/python/src/com/jetbrains/python/documentation/doctest/PyDocReferenceExpression.java
+++ b/python/src/com/jetbrains/python/documentation/doctest/PyDocReferenceExpression.java
@@ -38,6 +38,7 @@
}
@NotNull
+ @Override
public PsiPolyVariantReference getReference(PyResolveContext context) {
if (isQualified()) {
return new PyQualifiedReference(this, context);
diff --git a/python/src/com/jetbrains/python/findUsages/PyClassFindUsagesHandler.java b/python/src/com/jetbrains/python/findUsages/PyClassFindUsagesHandler.java
index 1185c27..10ddcea 100644
--- a/python/src/com/jetbrains/python/findUsages/PyClassFindUsagesHandler.java
+++ b/python/src/com/jetbrains/python/findUsages/PyClassFindUsagesHandler.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.
@@ -52,7 +52,7 @@
}
@Override
- protected Collection<String> getStringsToSearch(PsiElement element) {
+ protected Collection<String> getStringsToSearch(@NotNull PsiElement element) {
if (element instanceof PyFunction && PyNames.INIT.equals(((PyFunction) element).getName())) {
return Collections.emptyList();
}
diff --git a/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java b/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java
index 6588d2d..fd0eef0 100644
--- a/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java
+++ b/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.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.
@@ -72,6 +72,7 @@
};
}
+ @NotNull
@Override
public Collection<PsiReference> findReferencesToHighlight(@NotNull PsiElement target, @NotNull SearchScope searchScope) {
if (target instanceof PyImportedModule) {
diff --git a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java
index 9e7f97d..32ad8a3 100644
--- a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java
+++ b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.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.
@@ -123,6 +123,11 @@
return PlatformUtils.isPyCharm() ? DisplayPriority.KEY_LANGUAGE_SETTINGS : DisplayPriority.LANGUAGE_SETTINGS;
}
+ @Override
+ public boolean isIndentBasedLanguageSemantics() {
+ return true;
+ }
+
@SuppressWarnings("FieldCanBeLocal")
private static String SPACING_SETTINGS_PREVIEW = "def settings_preview(argument, key=value):\n" +
" dict = {1:'a', 2:'b', 3:'c'}\n" +
diff --git a/python/src/com/jetbrains/python/formatter/PyPreFormatProcessor.java b/python/src/com/jetbrains/python/formatter/PyPreFormatProcessor.java
index af07fe8..ee2c4ab 100644
--- a/python/src/com/jetbrains/python/formatter/PyPreFormatProcessor.java
+++ b/python/src/com/jetbrains/python/formatter/PyPreFormatProcessor.java
@@ -84,9 +84,13 @@
String text = element.getText();
int commentStart = text.indexOf('#');
if (commentStart != -1 && (commentStart + 1) < text.length()) {
- if (text.charAt(commentStart+1) == '!') {
+ char charAfterDash = text.charAt(commentStart + 1);
+ if (charAfterDash == '!' && element.getTextRange().getStartOffset() == 0) {
return; //shebang
}
+ if (charAfterDash == '#' || charAfterDash == ':') {
+ return;
+ }
String commentText = StringUtil.trimLeading(text.substring(commentStart + 1));
String newText = "# " + commentText;
diff --git a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java
index 04477b1..e793de3 100644
--- a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java
@@ -78,15 +78,17 @@
}
if (!callable) {
final PyType calleeType = callee != null ? myTypeEvalContext.getType(callee) : type;
+ String message = "Expression is not callable";
if (calleeType instanceof PyClassType) {
- registerProblem(node, String.format("'%s' object is not callable", calleeType.getName()), new PyRemoveCallQuickFix());
+ message = String.format("'%s' object is not callable", calleeType.getName());
}
else if (callee != null) {
- registerProblem(node, String.format("'%s' is not callable", callee.getName()), new PyRemoveCallQuickFix());
+ final String name = callee.getName();
+ if (name != null) {
+ message = String.format("'%s' is not callable", name);
+ }
}
- else {
- registerProblem(node, "Expression is not callable", new PyRemoveCallQuickFix());
- }
+ registerProblem(node, message, new PyRemoveCallQuickFix());
}
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java b/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java
index 5a7ac6f..ae47dbb 100644
--- a/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java
@@ -21,7 +21,7 @@
import com.google.common.collect.Sets;
import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.ProblemsHolder;
-import com.intellij.codeInspection.SuppressIntentionAction;
+import com.intellij.codeInspection.SuppressQuickFix;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.TextRange;
@@ -230,9 +230,10 @@
}
}
+ @NotNull
@Override
- public SuppressIntentionAction[] getSuppressActions(@Nullable PsiElement element) {
- List<SuppressIntentionAction> result = new ArrayList<SuppressIntentionAction>();
+ public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
+ List<SuppressQuickFix> result = new ArrayList<SuppressQuickFix>();
if (element != null) {
if (PsiTreeUtil.getParentOfType(element, PyFunction.class) != null) {
result.add(new PySuppressInspectionFix(getShortName().replace("Inspection", ""), "Suppress for function", PyFunction.class));
@@ -241,6 +242,6 @@
result.add(new PySuppressInspectionFix(getShortName().replace("Inspection", ""), "Suppress for class", PyClass.class));
}
}
- return result.toArray(new SuppressIntentionAction[result.size()]);
+ return result.toArray(new SuppressQuickFix[result.size()]);
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyInspection.java b/python/src/com/jetbrains/python/inspections/PyInspection.java
index 9227f1c..a35e2c7 100644
--- a/python/src/com/jetbrains/python/inspections/PyInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyInspection.java
@@ -15,10 +15,7 @@
*/
package com.jetbrains.python.inspections;
-import com.intellij.codeInspection.CustomSuppressableInspectionTool;
-import com.intellij.codeInspection.LocalInspectionTool;
-import com.intellij.codeInspection.SuppressIntentionAction;
-import com.intellij.codeInspection.SuppressionUtil;
+import com.intellij.codeInspection.*;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -41,7 +38,7 @@
/**
* @author yole
*/
-public abstract class PyInspection extends LocalInspectionTool implements CustomSuppressableInspectionTool {
+public abstract class PyInspection extends LocalInspectionTool {
@Nls
@NotNull
@Override
@@ -60,12 +57,13 @@
return true;
}
+ @NotNull
@Override
- public SuppressIntentionAction[] getSuppressActions(@Nullable final PsiElement element) {
- List<SuppressIntentionAction> result = new ArrayList<SuppressIntentionAction>();
+ public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
+ List<SuppressQuickFix> result = new ArrayList<SuppressQuickFix>();
result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for statement", PyStatement.class) {
@Override
- protected PsiElement getContainer(PsiElement context) {
+ public PsiElement getContainer(PsiElement context) {
if (PsiTreeUtil.getParentOfType(context, PyStatementList.class, false, ScopeOwner.class) != null ||
PsiTreeUtil.getParentOfType(context, PyFunction.class, PyClass.class) == null) {
return super.getContainer(context);
@@ -75,7 +73,7 @@
});
result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for function", PyFunction.class));
result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for class", PyClass.class));
- return result.toArray(new SuppressIntentionAction[result.size()]);
+ return result.toArray(new SuppressQuickFix[result.size()]);
}
@Override
@@ -131,7 +129,7 @@
return m.matches() && SuppressionUtil.isInspectionToolIdMentioned(m.group(1), getSuppressId());
}
- private String getSuppressId() {
+ protected String getSuppressId() {
return getShortName().replace("Inspection", "");
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java
index 149ff2c..f4b9b77 100644
--- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java
@@ -303,9 +303,7 @@
hasReturns = returnStatements.length > 0;
}
else {
- PyReferenceExpression callSite = being_checked instanceof PyReferenceExpression ? (PyReferenceExpression) being_checked : null;
- final PyType type = callSite != null ? callable.getCallType(myTypeEvalContext, callSite)
- : myTypeEvalContext.getReturnType(callable);
+ final PyType type = myTypeEvalContext.getReturnType(callable);
hasReturns = !(type instanceof PyNoneType);
}
if (allowed ^ hasReturns) {
diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
index d31d19e..bb0c83e 100644
--- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
@@ -56,10 +56,7 @@
// TODO: Visit decorators with arguments
@Override
public void visitPyCallExpression(PyCallExpression node) {
- final PyExpression callee = node.getCallee();
- if (callee instanceof PyQualifiedExpression) {
- checkCallSite((PyQualifiedExpression)callee);
- }
+ checkCallSite(node);
}
@Override
@@ -85,7 +82,7 @@
}
}
- private void checkCallSite(@Nullable PyQualifiedExpression callSite) {
+ private void checkCallSite(@Nullable PyCallSiteExpression callSite) {
final Map<PyGenericType, PyType> substitutions = new LinkedHashMap<PyGenericType, PyType>();
final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, myTypeEvalContext);
if (results != null) {
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java
index a138555..9924292 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java
@@ -138,7 +138,7 @@
method = (PyFunction)PyUtil.addElementToStatementList(method, clsStmtList, PyNames.INIT.equals(method.getName()));
if (myReplaceUsage) {
- showTemplateBuilder(method, problemElement.getContainingFile());
+ showTemplateBuilder(method);
}
}
catch (IncorrectOperationException ignored) {
@@ -158,9 +158,10 @@
return pyClass != null ? new PyClassTypeImpl(pyClass, false) : null;
}
- private static void showTemplateBuilder(PyFunction method, PsiFile file) {
+ private static void showTemplateBuilder(@NotNull PyFunction method) {
method = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(method);
-
+ final PsiFile file = method.getContainingFile();
+ if (file == null) return;
final TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(method);
ParamHelper.walkDownParamArray(
method.getParameterList().getParameters(),
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PySuppressInspectionFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PySuppressInspectionFix.java
index 9addabf..0e6a7d9 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/PySuppressInspectionFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/PySuppressInspectionFix.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.inspections.quickfix;
+import com.intellij.codeInsight.daemon.impl.actions.AbstractBatchSuppressByNoInspectionCommentFix;
import com.intellij.codeInsight.daemon.impl.actions.AbstractSuppressByNoInspectionCommentFix;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
@@ -23,7 +24,7 @@
/**
* @author yole
*/
-public class PySuppressInspectionFix extends AbstractSuppressByNoInspectionCommentFix {
+public class PySuppressInspectionFix extends AbstractBatchSuppressByNoInspectionCommentFix {
private final Class<? extends PyElement> myContainerClass;
public PySuppressInspectionFix(final String ID, final String text, final Class<? extends PyElement> containerClass) {
@@ -33,7 +34,7 @@
}
@Override
- protected PsiElement getContainer(PsiElement context) {
+ public PsiElement getContainer(PsiElement context) {
return PsiTreeUtil.getParentOfType(context, myContainerClass);
}
}
diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
index fbe2680..fac391a 100644
--- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
@@ -997,7 +997,12 @@
if (element == null) {
if (importElement.getImportedQName() != null) {
//Mark import as unused even if it can't be resolved
- result.add(importElement.getParent());
+ if (areAllImportsUnused(importStatement, unusedImports)) {
+ result.add(importStatement);
+ }
+ else {
+ result.add(importElement);
+ }
}
continue;
}
diff --git a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralFindUsagesHandlerFactory.java b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralFindUsagesHandlerFactory.java
index 006f4f3..52091ed 100644
--- a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralFindUsagesHandlerFactory.java
+++ b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralFindUsagesHandlerFactory.java
@@ -1,3 +1,18 @@
+/*
+ * 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.magicLiteral;
import com.intellij.find.findUsages.FindUsagesHandler;
@@ -34,7 +49,7 @@
@Nullable
@Override
- protected Collection<String> getStringsToSearch(final PsiElement element) {
+ protected Collection<String> getStringsToSearch(@NotNull final PsiElement element) {
return Collections.singleton(((StringLiteralExpression)element).getStringValue());
}
}
diff --git a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralRenameHandler.java b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralRenameHandler.java
index 0a801b1..b7fdf46 100644
--- a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralRenameHandler.java
+++ b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralRenameHandler.java
@@ -34,7 +34,7 @@
*/
public class PyMagicLiteralRenameHandler implements RenameHandler {
@Override
- public boolean isAvailableOnDataContext(DataContext dataContext) {
+ public boolean isAvailableOnDataContext(final DataContext dataContext) {
final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
if (editor == null) {
return false;
@@ -47,11 +47,7 @@
final PsiElement element = getElement(file, editor);
- if (element == null || !PyMagicLiteralTools.isMagicLiteral(element)) {
- return false;
- }
-
- return true;
+ return !((element == null) || !PyMagicLiteralTools.isMagicLiteral(element));
}
@Nullable
diff --git a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java
index c184794..fbbdfa2 100644
--- a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java
+++ b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java
@@ -239,6 +239,8 @@
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{
@@ -257,8 +259,8 @@
return packages;
}
- public Collection<String> getPackageNames() throws IOException {
- Map<String, String> pyPIPackages = loadAndGetPackages();
+ public Collection<String> getPackageNames() {
+ Map<String, String> pyPIPackages = getPyPIPackages();
ArrayList<String> list = Lists.newArrayList(pyPIPackages.keySet());
Collections.sort(list);
return list;
diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
index 4a4f016..359e497 100644
--- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
+++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
@@ -425,6 +425,21 @@
@Override
public void install(String requirementString) throws PyExternalProcessException {
+ boolean hasSetuptools = false;
+ boolean hasPip = false;
+ try {
+ hasSetuptools = findInstalledPackage(SETUPTOOLS) != null;
+ }
+ catch (PyExternalProcessException ignored) {
+ }
+ try {
+ hasPip = findInstalledPackage(PIP) != null;
+ }
+ catch (PyExternalProcessException ignored) {
+ }
+
+ if (!hasSetuptools) installManagement(SETUPTOOLS);
+ if (!hasPip) installManagement(PIP);
install(Collections.singletonList(PyRequirement.fromString(requirementString)), Collections.<String>emptyList());
}
@@ -591,17 +606,31 @@
}
}
+ @Override
@Nullable
- public PyPackage findPackage(String name) throws PyExternalProcessException {
+ public PyPackage findInstalledPackage(String name) throws PyExternalProcessException {
return findPackageByName(name, getPackages());
}
+ @Override
+ public boolean findPackage(@NotNull final String name) {
+ try {
+ final String output = runPythonHelper(PACKAGING_TOOL, list("search", name));
+ return StringUtil.containsIgnoreCase(output, name + " ");
+ }
+ catch (PyExternalProcessException e) {
+ LOG.error(e.getMessage());
+ return false;
+ }
+ }
+
@Nullable
public PyPackage findPackageFast(String name) throws PyExternalProcessException {
final List<PyPackage> packages = getPackagesFast();
return packages != null ? findPackageByName(name, packages) : null;
}
+ @Nullable
private static PyPackage findPackageByName(String name, List<PyPackage> packages) {
for (PyPackage pkg : packages) {
if (name.equalsIgnoreCase(pkg.getName())) {
diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java
index 714bf82..054e9e0 100644
--- a/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java
+++ b/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java
@@ -17,6 +17,7 @@
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
@@ -29,6 +30,7 @@
public class PyPackageManagersImpl extends PyPackageManagers {
private final Map<String, PyPackageManagerImpl> myInstances = new HashMap<String, PyPackageManagerImpl>();
+ @NotNull
@Override
public synchronized PyPackageManager forSdk(Sdk sdk) {
final String name = sdk.getName();
diff --git a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
index e0c0e30..348d281 100644
--- a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
+++ b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
@@ -88,11 +88,11 @@
PyExternalProcessException exc = null;
try {
PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(selectedSdk);
- myHasSetuptools = packageManager.findPackage(PyPackageManagerImpl.PACKAGE_SETUPTOOLS) != null;
+ myHasSetuptools = packageManager.findInstalledPackage(PyPackageManagerImpl.PACKAGE_SETUPTOOLS) != null;
if (!myHasSetuptools) {
- myHasSetuptools = packageManager.findPackage(PyPackageManagerImpl.PACKAGE_DISTRIBUTE) != null;
+ myHasSetuptools = packageManager.findInstalledPackage(PyPackageManagerImpl.PACKAGE_DISTRIBUTE) != null;
}
- myHasPip = packageManager.findPackage(PyPackageManagerImpl.PACKAGE_PIP) != null;
+ myHasPip = packageManager.findInstalledPackage(PyPackageManagerImpl.PACKAGE_PIP) != null;
}
catch (PyExternalProcessException e) {
exc = e;
diff --git a/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java b/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java
index 2fd5694..62de7ea 100644
--- a/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java
+++ b/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java
@@ -15,25 +15,41 @@
*/
package com.jetbrains.python.projectView;
+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.ide.projectView.PresentationData;
import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
+import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.util.PlatformIcons;
+import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
import com.jetbrains.python.sdk.PySdkUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.Collection;
+
/**
* @author traff
*/
public class PyRemoteLibrariesNode extends PsiDirectoryNode {
- private PyRemoteLibrariesNode(Project project, PsiDirectory value, ViewSettings viewSettings) {
+ private final Sdk mySdk;
+ private final PyRemoteSdkAdditionalDataBase myRemoteSdkData;
+
+ private PyRemoteLibrariesNode(Sdk sdk, Project project, PsiDirectory value, ViewSettings viewSettings) {
super(project, value, viewSettings);
+ mySdk = sdk;
+ assert mySdk.getSdkAdditionalData() instanceof PyRemoteSdkAdditionalDataBase;
+
+ myRemoteSdkData = (PyRemoteSdkAdditionalDataBase)mySdk.getSdkAdditionalData();
}
@Override
@@ -44,11 +60,47 @@
@Nullable
public static PyRemoteLibrariesNode create(@NotNull Project project, @NotNull Sdk sdk, ViewSettings settings) {
- final VirtualFile remoteLibraries = PySdkUtil.findRemoteLibrariesDir(sdk);
- if (remoteLibraries != null) {
+ final VirtualFile remoteLibrary = PySdkUtil.findAnyRemoteLibrary(sdk);
+ if (remoteLibrary != null) {
+ final VirtualFile remoteLibraries = remoteLibrary.getParent();
final PsiDirectory remoteLibrariesDirectory = PsiManager.getInstance(project).findDirectory(remoteLibraries);
- return new PyRemoteLibrariesNode(project, remoteLibrariesDirectory, settings);
+ return new PyRemoteLibrariesNode(sdk, project, remoteLibrariesDirectory, settings);
}
return null;
}
+
+ @Override
+ public Collection<AbstractTreeNode> getChildrenImpl() {
+
+ return FluentIterable.from(Lists.newArrayList(getValue().getChildren())).transform(new Function<PsiElement, AbstractTreeNode>() {
+ @Override
+ public AbstractTreeNode apply(PsiElement input) {
+ if (input instanceof PsiDirectory) {
+ PsiDirectory directory = (PsiDirectory)input;
+ if (myRemoteSdkData.getPathMappings().canReplaceLocal((directory.getVirtualFile().getPath()))) {
+ return new PyRemoteRootNode(myRemoteSdkData.getPathMappings().convertToRemote(directory.getVirtualFile().getPath()),
+ getProject(), directory, getSettings());
+ }
+ }
+
+ return null;
+ }
+ }).filter(Predicates.notNull()).toList();
+ }
+
+ public static class PyRemoteRootNode extends PsiDirectoryNode {
+
+ private String myRemotePath;
+
+ public PyRemoteRootNode(String remotePath, Project project, PsiDirectory value, ViewSettings viewSettings) {
+ super(project, value, viewSettings);
+ myRemotePath = remotePath;
+ }
+
+ @Override
+ protected void updateImpl(PresentationData data) {
+ data.setPresentableText(myRemotePath);
+ data.setIcon(PlatformIcons.FOLDER_ICON);
+ }
+ }
}
diff --git a/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java b/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
index dedc82e..6153bc6 100644
--- a/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
+++ b/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
@@ -36,7 +36,6 @@
import com.jetbrains.python.psi.PyDocStringOwner;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
-import com.jetbrains.python.remote.PyRemoteSdkCredentials;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -116,6 +115,17 @@
if (dirParent != null && dirParent.getName().equals(PythonSdkType.SKELETON_DIR_NAME)) {
continue;
}
+
+ if (dirParent != null && dirParent.getName().equals(PythonSdkType.REMOTE_SOURCES_DIR_NAME)) {
+ continue;
+ }
+ if (dirParent != null) {
+ PsiDirectory grandParent = dirParent.getParent();
+
+ if (grandParent != null && grandParent.getName().equals(PythonSdkType.REMOTE_SOURCES_DIR_NAME)) {
+ continue;
+ }
+ }
}
newChildren.add(child);
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java
deleted file mode 100644
index 36e67a1..0000000
--- a/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java
+++ /dev/null
@@ -1,277 +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.psi.impl;
-
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.util.QualifiedName;
-import com.jetbrains.python.PyNames;
-import com.jetbrains.python.psi.*;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.*;
-
-/**
- *
- * @author yole
- */
-public class PyBlockEvaluator {
- private final Map<String, Object> myNamespace = new HashMap<String, Object>();
- private final Map<String, List<PyExpression>> myDeclarations = new HashMap<String, List<PyExpression>>();
- private final Set<PyFile> myVisitedFiles;
- private final Set<String> myDeclarationsToTrack = new HashSet<String>();
- private String myCurrentFilePath;
- private Object myReturnValue;
- private boolean myEvaluateCollectionItems = true;
-
- public PyBlockEvaluator() {
- myVisitedFiles = new HashSet<PyFile>();
- }
-
- public PyBlockEvaluator(Set<PyFile> visitedFiles) {
- myVisitedFiles = visitedFiles;
- }
-
- public void trackDeclarations(String attrName) {
- myDeclarationsToTrack.add(attrName);
- }
-
- public void evaluate(PyElement element) {
- VirtualFile vFile = element.getContainingFile().getVirtualFile();
- myCurrentFilePath = vFile != null ? vFile.getPath() : null;
- if (myVisitedFiles.contains(element)) {
- return;
- }
- myVisitedFiles.add((PyFile)element.getContainingFile());
- PyElement statementContainer = element instanceof PyFunction ? ((PyFunction) element).getStatementList() : element;
- if (statementContainer == null) {
- return;
- }
- statementContainer.acceptChildren(new PyElementVisitor() {
- @Override
- public void visitPyAssignmentStatement(PyAssignmentStatement node) {
- PyExpression expression = node.getLeftHandSideExpression();
- if (expression instanceof PyTargetExpression) {
- String name = expression.getName();
- PyExpression value = ((PyTargetExpression)expression).findAssignedValue();
- myNamespace.put(name, prepareEvaluator().evaluate(value));
- if (myDeclarationsToTrack.contains(name)) {
- List<PyExpression> declarations = new ArrayList<PyExpression>();
- PyPsiUtils.sequenceToList(declarations, value);
- myDeclarations.put(name, declarations);
- }
- }
- else if (expression instanceof PySubscriptionExpression) {
- PyExpression operand = ((PySubscriptionExpression)expression).getOperand();
- PyExpression indexExpression = ((PySubscriptionExpression)expression).getIndexExpression();
- if (operand instanceof PyReferenceExpression && ((PyReferenceExpression)operand).getQualifier() == null) {
- Object currentValue = myNamespace.get(((PyReferenceExpression)operand).getReferencedName());
- if (currentValue instanceof Map) {
- Object mapKey = prepareEvaluator().evaluate(indexExpression);
- if (mapKey != null) {
- Object value = myEvaluateCollectionItems ? prepareEvaluator().evaluate(node.getAssignedValue()) : node.getAssignedValue();
- ((Map)currentValue).put(mapKey, value);
- }
- }
- }
- }
- }
-
- @Override
- public void visitPyAugAssignmentStatement(PyAugAssignmentStatement node) {
- PyExpression target = node.getTarget();
- String name = target.getName();
- if (target instanceof PyReferenceExpression && !((PyReferenceExpression)target).isQualified() && name != null) {
- Object currentValue = myNamespace.get(name);
- if (currentValue != null) {
- Object rhs = prepareEvaluator().evaluate(node.getValue());
- myNamespace.put(name, prepareEvaluator().concatenate(currentValue, rhs));
- }
- if (myDeclarationsToTrack.contains(name)) {
- List<PyExpression> declarations = myDeclarations.get(name);
- if (declarations != null) {
- PyPsiUtils.sequenceToList(declarations, node.getValue());
- }
- }
- }
- }
-
- @Override
- public void visitPyExpressionStatement(PyExpressionStatement node) {
- node.getExpression().accept(this);
- }
-
- @Override
- public void visitPyCallExpression(PyCallExpression node) {
- PyExpression callee = node.getCallee();
- if (callee instanceof PyReferenceExpression) {
- PyReferenceExpression calleeRef = (PyReferenceExpression)callee;
- PyExpression qualifier = calleeRef.getQualifier();
- if (qualifier instanceof PyReferenceExpression) {
- PyReferenceExpression qualifierRef = (PyReferenceExpression)qualifier;
- if (!qualifierRef.isQualified()) {
- if (PyNames.EXTEND.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
- processExtendCall(node, qualifierRef.getReferencedName());
- }
- else if (PyNames.UPDATE.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
- processUpdateCall(node, qualifierRef.getReferencedName());
- }
- }
- }
- }
- }
-
- @Override
- public void visitPyFromImportStatement(PyFromImportStatement node) {
- if (node.isFromFuture()) return;
- PsiElement source = PyUtil.turnDirIntoInit(node.resolveImportSource());
- if (source instanceof PyFile) {
- PyBlockEvaluator importEvaluator = new PyBlockEvaluator(myVisitedFiles);
- importEvaluator.myDeclarationsToTrack.addAll(myDeclarationsToTrack);
- importEvaluator.evaluate((PyFile)source);
- if (node.isStarImport()) {
- // TODO honor __all__ here
- myNamespace.putAll(importEvaluator.myNamespace);
- myDeclarations.putAll(importEvaluator.myDeclarations);
- }
- else {
- for (final PyImportElement element : node.getImportElements()) {
- final String nameOfVarInOurModule = element.getVisibleName();
- final QualifiedName nameOfVarInExternalModule = element.getImportedQName();
- if ((nameOfVarInOurModule == null) || (nameOfVarInExternalModule == null)) {
- continue;
- }
-
- final Object value = importEvaluator.myNamespace.get(nameOfVarInExternalModule.toString());
- myNamespace.put(nameOfVarInOurModule, value);
- final List<PyExpression> declarations = importEvaluator.getDeclarations(nameOfVarInOurModule);
- if (myDeclarations.containsKey(nameOfVarInOurModule)) {
- myDeclarations.get(nameOfVarInOurModule).addAll(declarations);
- }
- else {
- myDeclarations.put(nameOfVarInOurModule, declarations);
- }
- }
- }
- }
- }
-
- @Override
- public void visitPyIfStatement(PyIfStatement node) {
- PyStatementList list = node.getIfPart().getStatementList();
- if (list != null) {
- list.acceptChildren(this);
- }
- }
-
- @Override
- public void visitPyReturnStatement(PyReturnStatement node) {
- myReturnValue = prepareEvaluator().evaluate(node.getExpression());
- }
- });
- }
-
- private void processExtendCall(PyCallExpression node, String nameBeingExtended) {
- PyExpression arg = node.getArguments()[0];
-
- Object value = myNamespace.get(nameBeingExtended);
- if (value instanceof List) {
- Object argValue = prepareEvaluator().evaluate(arg);
- myNamespace.put(nameBeingExtended, prepareEvaluator().concatenate(value, argValue));
- }
-
- if (myDeclarationsToTrack.contains(nameBeingExtended)) {
- List<PyExpression> declarations = myDeclarations.get(nameBeingExtended);
- if (declarations != null) {
- PyPsiUtils.sequenceToList(declarations, arg);
- }
- }
- }
-
- private void processUpdateCall(PyCallExpression node, String name) {
- Object value = myNamespace.get(name);
- if (value instanceof Map) {
- Object argValue = prepareEvaluator().evaluate(node.getArguments()[0]);
- if (argValue instanceof Map) {
- ((Map)value).putAll((Map)argValue);
- }
- }
- }
-
- private PyEvaluator prepareEvaluator() {
- PyEvaluator evaluator = createEvaluator();
- evaluator.setNamespace(myNamespace);
- evaluator.setEvaluateCollectionItems(myEvaluateCollectionItems);
- return evaluator;
- }
-
- protected PyEvaluator createEvaluator() {
- return new PyPathEvaluator(myCurrentFilePath);
- }
-
- public Object getValue(String name) {
- return myNamespace.get(name);
- }
-
- @Nullable
- public String getValueAsString(String name) {
- Object value = myNamespace.get(name);
- return value instanceof String ? (String) value : null;
- }
-
- @Nullable
- public List getValueAsList(String name) {
- Object value = myNamespace.get(name);
- return value instanceof List ? (List) value : null;
- }
-
- @NotNull
- public List<String> getValueAsStringList(String name) {
- Object value = myNamespace.get(name);
- if (value instanceof List) {
- List valueList = (List) value;
- for (Object o : valueList) {
- if (o != null && !(o instanceof String)) {
- return Collections.emptyList();
- }
- }
- return (List<String>) value;
- }
- if (value instanceof String) {
- return Collections.singletonList((String) value);
- }
- return Collections.emptyList();
- }
-
- public Set<PyFile> getVisitedFiles() {
- return myVisitedFiles;
- }
-
- @NotNull
- public List<PyExpression> getDeclarations(String name) {
- List<PyExpression> expressions = myDeclarations.get(name);
- return expressions != null ? expressions : Collections.<PyExpression>emptyList();
- }
-
- public Object getReturnValue() {
- return myReturnValue;
- }
-
- public void setEvaluateCollectionItems(boolean evaluateCollectionItems) {
- myEvaluateCollectionItems = evaluateCollectionItems;
- }
-}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java
index 0f4b081..1f03945 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.psi.impl;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
@@ -24,6 +25,7 @@
import com.intellij.openapi.roots.OrderEntry;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.impl.ModuleLibraryOrderEntryImpl;
+import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -126,7 +128,7 @@
}
@Nullable
- public static PyFile getSkeletonFile(@NotNull Project project, @NotNull Sdk sdk, @NotNull String name) {
+ public static PyFile getSkeletonFile(final @NotNull Project project, @NotNull Sdk sdk, @NotNull String name) {
SdkTypeId sdkType = sdk.getSdkType();
if (sdkType instanceof PythonSdkType) {
// dig out the builtins file, create an instance based on it
@@ -136,12 +138,20 @@
final String builtins_url = url + "/" + name;
File builtins = new File(VfsUtilCore.urlToPath(builtins_url));
if (builtins.isFile() && builtins.canRead()) {
- VirtualFile builtins_vfile = LocalFileSystem.getInstance().findFileByIoFile(builtins);
+ final VirtualFile builtins_vfile = LocalFileSystem.getInstance().findFileByIoFile(builtins);
if (builtins_vfile != null) {
- PsiFile file = PsiManager.getInstance(project).findFile(builtins_vfile);
- if (file instanceof PyFile) {
- return (PyFile)file;
- }
+ final Ref<PyFile> result = Ref.create();
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ PsiFile file = PsiManager.getInstance(project).findFile(builtins_vfile);
+ if (file instanceof PyFile) {
+ result.set((PyFile)file);
+ }
+ }
+ });
+ return result.get();
+
}
}
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
index b9fe8c3..d44c848 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
@@ -365,14 +365,14 @@
/**
* Returns argument if it exists and has appropriate type
- * @param parameter argument
- * @param argClass expected class
+ * @param parameter argument
+ * @param argClass expected class
* @param expression call expression
- * @param <T> expected class
+ * @param <T> expected class
* @return argument expression or null if has wrong type of does not exist
*/
@Nullable
- public static <T extends PsiElement> T getArgument(
+ public static <T extends PsiElement> T getArgument(
@NotNull final FunctionParameter parameter,
@NotNull final Class<T> argClass,
@NotNull final PyCallExpression expression) {
@@ -449,7 +449,7 @@
}
}
if (init != null) {
- final PyType t = init.getCallType(context, (PyReferenceExpression)callee);
+ final PyType t = init.getCallType(context, call);
if (cls != null) {
if (init.getContainingClass() != cls) {
if (t instanceof PyCollectionType) {
@@ -474,11 +474,11 @@
}
final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, call);
if (providedType instanceof PyCallableType) {
- return ((PyCallableType)providedType).getCallType(context, (PyReferenceExpression)callee);
+ return ((PyCallableType)providedType).getCallType(context, call);
}
if (target instanceof Callable) {
final Callable callable = (Callable)target;
- return callable.getCallType(context, (PyReferenceExpression)callee);
+ return callable.getCallType(context, call);
}
}
}
@@ -489,13 +489,7 @@
final PyType type = context.getType(callee);
if (type instanceof PyCallableType) {
final PyCallableType callableType = (PyCallableType)type;
- final PyQualifiedExpression callSite = callee instanceof PyQualifiedExpression ? (PyQualifiedExpression)callee : null;
- if (callSite != null) {
- return callableType.getCallType(context, callSite);
- }
- else {
- return callableType.getReturnType(context);
- }
+ return callableType.getCallType(context, call);
}
return null;
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
index c723aed..030fcfe 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
@@ -419,6 +419,7 @@
return PyPsiUtils.collectStubChildren(this, this.getStub(), PyElementTypes.CLASS_DECLARATION, PyClass.class);
}
+ @NotNull
@Override
public List<PyFunction> getTopLevelFunctions() {
return PyPsiUtils.collectStubChildren(this, this.getStub(), PyElementTypes.FUNCTION_DECLARATION, PyFunction.class);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java
index 53dea09..e0cdf87 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java
@@ -24,13 +24,9 @@
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.psi.*;
-
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
import java.util.regex.Pattern;
/**
@@ -45,10 +41,13 @@
private final List<String> myDecorators = new ArrayList<String>();
private String myAnnotation = null;
private String[] myDocStringLines = null;
+ @NotNull
+ private final Map<String, String> myDecoratorValues = new HashMap<String, String>();
/**
* Creates builder copying signature and doc from another one.
- * @param source what to copy
+ *
+ * @param source what to copy
* @param decoratorsToCopyIfExist list of decorator names to be copied to new function.
* @return builder configured by this function
*/
@@ -82,6 +81,7 @@
/**
* Adds docstring to function. Provide doc with out of comment blocks.
+ *
* @param docString doc
*/
public void docString(@NotNull final String docString) {
@@ -127,15 +127,21 @@
}
public PyFunction buildFunction(Project project, final LanguageLevel languageLevel) {
- String text = buildText(project);
PyElementGenerator generator = PyElementGenerator.getInstance(project);
+ String text = buildText(project, generator, languageLevel);
return generator.createFromText(languageLevel, PyFunction.class, text);
}
- private String buildText(Project project) {
+ private String buildText(Project project, PyElementGenerator generator, LanguageLevel languageLevel) {
StringBuilder builder = new StringBuilder();
for (String decorator : myDecorators) {
- builder.append(decorator).append("\n");
+ final StringBuilder decoratorAppender = builder.append('@' + decorator);
+ if (myDecoratorValues.containsKey(decorator)) {
+ final PyCallExpression fakeCall = generator.createCallExpression(languageLevel, "fakeFunction");
+ fakeCall.getArgumentList().addArgument(generator.createStringLiteralFromString(myDecoratorValues.get(decorator)));
+ decoratorAppender.append(fakeCall.getArgumentList().getText());
+ }
+ decoratorAppender.append("\n");
}
builder.append("def ");
builder.append(myName).append("(");
@@ -165,8 +171,18 @@
return builder.toString();
}
+ /**
+ * Adds decorator with argument
+ * @param decoratorName decorator name
+ * @param value its argument
+ */
+ public void decorate(@NotNull final String decoratorName, @NotNull final String value) {
+ decorate(decoratorName);
+ myDecoratorValues.put(decoratorName, value);
+ }
+
public void decorate(String decoratorName) {
- myDecorators.add("@" + decoratorName);
+ myDecorators.add(decoratorName);
}
@NotNull
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
index acc225b..2531b37 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
@@ -209,7 +209,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
+ public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
PyType type = null;
for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
type = typeProvider.getCallType(this, callSite, context);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java
index 0dd7591..3dd9f78 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java
@@ -70,7 +70,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
+ public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
return context.getReturnType(this);
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java
index 79535f2..6aeb16e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java
@@ -70,13 +70,10 @@
return getReference(PyResolveContext.noImplicits());
}
+ @NotNull
@Override
public PsiPolyVariantReference getReference(PyResolveContext context) {
- final PyElementType t = getOperator();
- if (t.getSpecialMethodName() != null) {
- return new PyOperatorReference(this, context);
- }
- return null;
+ return new PyOperatorReference(this, context);
}
@Override
@@ -85,11 +82,10 @@
return PyBuiltinCache.getInstance(this).getBoolType();
}
final PsiReference ref = getReference(PyResolveContext.noImplicits().withTypeEvalContext(context));
- if (ref != null) {
- final PsiElement resolved = ref.resolve();
- if (resolved instanceof Callable) {
- return ((Callable)resolved).getCallType(context, this);
- }
+ final PsiElement resolved = ref.resolve();
+ if (resolved instanceof Callable) {
+ // TODO: Make PyPrefixExpression a PyCallSiteExpression, use getCallType() here and analyze it in PyTypeChecker.analyzeCallSite()
+ return ((Callable)resolved).getReturnType(context, key);
}
return null;
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
index 47ae589..126ed26 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
@@ -57,13 +57,14 @@
super(astNode);
}
- @Override
@NotNull
+ @Override
public PsiPolyVariantReference getReference() {
return getReference(PyResolveContext.defaultContext());
}
@NotNull
+ @Override
public PsiPolyVariantReference getReference(PyResolveContext context) {
final PsiFile file = getContainingFile();
final PyExpression qualifier = getQualifier();
diff --git a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java
index 2b21e17..9cceec4 100644
--- a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java
@@ -68,11 +68,9 @@
public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
PyType res = null;
final PsiReference ref = getReference(PyResolveContext.noImplicits().withTypeEvalContext(context));
- if (ref != null) {
- final PsiElement resolved = ref.resolve();
- if (resolved instanceof Callable) {
- res = ((Callable)resolved).getCallType(context, this);
- }
+ final PsiElement resolved = ref.resolve();
+ if (resolved instanceof Callable) {
+ res = ((Callable)resolved).getCallType(context, this);
}
if (PyTypeChecker.isUnknown(res) || res instanceof PyNoneType) {
final PyExpression indexExpression = getIndexExpression();
@@ -98,6 +96,7 @@
return getReference(PyResolveContext.noImplicits());
}
+ @NotNull
@Override
public PsiPolyVariantReference getReference(PyResolveContext context) {
return new PyOperatorReference(this, context);
diff --git a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
index c3fd23b..136a707 100644
--- a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
+++ b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
@@ -15,11 +15,14 @@
*/
package com.jetbrains.python.psi.impl;
+import com.intellij.facet.Facet;
+import com.intellij.facet.FacetManager;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
@@ -37,6 +40,8 @@
import com.intellij.util.io.DataInputOutputUtil;
import com.intellij.util.messages.MessageBus;
import com.jetbrains.python.PythonFileType;
+import com.jetbrains.python.PythonModuleTypeBase;
+import com.jetbrains.python.facet.PythonFacetSettings;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
@@ -61,11 +66,13 @@
final Module[] modules = ModuleManager.getInstance(project).getModules();
Set<Sdk> usedSdks = new HashSet<Sdk>();
for (Module module : modules) {
- final Sdk sdk = PythonSdkType.findPythonSdk(module);
- myModuleSdks.put(module, sdk);
- if (sdk != null && !usedSdks.contains(sdk)) {
- usedSdks.add(sdk);
- updateSdkLanguageLevel(project, sdk);
+ if (isPythonModule(module)) {
+ final Sdk sdk = PythonSdkType.findPythonSdk(module);
+ myModuleSdks.put(module, sdk);
+ if (sdk != null && !usedSdks.contains(sdk)) {
+ usedSdks.add(sdk);
+ updateSdkLanguageLevel(project, sdk);
+ }
}
}
}
@@ -167,17 +174,19 @@
final Module[] modules = ModuleManager.getInstance(project).getModules();
boolean needReparseOpenFiles = false;
for (Module module : modules) {
- Sdk newSdk = PythonSdkType.findPythonSdk(module);
- if (myModuleSdks.containsKey(module)) {
- Sdk oldSdk = myModuleSdks.get(module);
- if ((newSdk != null || oldSdk != null) && newSdk != oldSdk) {
- needReparseOpenFiles = true;
+ if (isPythonModule(module)) {
+ Sdk newSdk = PythonSdkType.findPythonSdk(module);
+ if (myModuleSdks.containsKey(module)) {
+ Sdk oldSdk = myModuleSdks.get(module);
+ if ((newSdk != null || oldSdk != null) && newSdk != oldSdk) {
+ needReparseOpenFiles = true;
+ }
}
- }
- myModuleSdks.put(module, newSdk);
- if (newSdk != null && !updatedSdks.contains(newSdk)) {
- updatedSdks.add(newSdk);
- updateSdkLanguageLevel(project, newSdk);
+ myModuleSdks.put(module, newSdk);
+ if (newSdk != null && !updatedSdks.contains(newSdk)) {
+ updatedSdks.add(newSdk);
+ updateSdkLanguageLevel(project, newSdk);
+ }
}
}
if (needReparseOpenFiles) {
@@ -185,6 +194,18 @@
}
}
+ private static boolean isPythonModule(@NotNull final Module module) {
+ final ModuleType moduleType = ModuleType.get(module);
+ if (moduleType instanceof PythonModuleTypeBase) return true;
+ final Facet[] allFacets = FacetManager.getInstance(module).getAllFacets();
+ for (Facet facet : allFacets) {
+ if (facet.getConfiguration() instanceof PythonFacetSettings) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void updateSdkLanguageLevel(final Project project, final Sdk sdk) {
final LanguageLevel languageLevel = PythonSdkType.getLanguageLevelForSdk(sdk);
final VirtualFile[] files = sdk.getRootProvider().getFiles(OrderRootType.CLASSES);
@@ -240,4 +261,8 @@
LanguageLevel.FORCE_LANGUAGE_LEVEL = languageLevel;
pushLanguageLevel(project);
}
+
+ public void flushLanguageLevelCache() {
+ myModuleSdks.clear();
+ }
}
diff --git a/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyBlockEvaluator.java b/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyBlockEvaluator.java
new file mode 100644
index 0000000..b1fca28
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyBlockEvaluator.java
@@ -0,0 +1,314 @@
+/*
+ * 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.psi.impl.blockEvaluator;
+
+import com.google.common.collect.Sets;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.impl.PyEvaluator;
+import com.jetbrains.python.psi.impl.PyPathEvaluator;
+import com.jetbrains.python.psi.impl.PyPsiUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+/**
+ * @author yole
+ */
+public class PyBlockEvaluator {
+ @NotNull
+ private final PyEvaluationResult myEvaluationResult = new PyEvaluationResult();
+ @NotNull
+ private final PyEvaluationContext myContext;
+ private final Set<PyFile> myVisitedFiles;
+ private final Set<String> myDeclarationsToTrack = new HashSet<String>();
+ private String myCurrentFilePath;
+ private Object myReturnValue;
+ private boolean myEvaluateCollectionItems = true;
+
+ /**
+ * @param evaluationContext context, obtained via {@link #getContext()}. Pass it here to enable cache. See {@link com.jetbrains.python.psi.impl.blockEvaluator.PyEvaluationContext}
+ * for more info
+ * @see com.jetbrains.python.psi.impl.blockEvaluator.PyEvaluationContext
+ */
+ public PyBlockEvaluator(@NotNull final PyEvaluationContext evaluationContext) {
+ this(Sets.<PyFile>newHashSet(), evaluationContext);
+ }
+
+ /**
+ * Create evaluator with out of cache context
+ */
+ public PyBlockEvaluator() {
+ this(new PyEvaluationContext());
+ }
+
+ private PyBlockEvaluator(@NotNull final Set<PyFile> visitedFiles, @NotNull final PyEvaluationContext evaluationContext) {
+ myVisitedFiles = visitedFiles;
+ myContext = evaluationContext;
+ }
+
+ public void trackDeclarations(String attrName) {
+ myDeclarationsToTrack.add(attrName);
+ }
+
+ public void evaluate(PyElement element) {
+ VirtualFile vFile = element.getContainingFile().getVirtualFile();
+ myCurrentFilePath = vFile != null ? vFile.getPath() : null;
+ if (myVisitedFiles.contains(element)) {
+ return;
+ }
+ myVisitedFiles.add((PyFile)element.getContainingFile());
+ PyElement statementContainer = element instanceof PyFunction ? ((PyFunction)element).getStatementList() : element;
+ if (statementContainer == null) {
+ return;
+ }
+ statementContainer.acceptChildren(new MyPyElementVisitor());
+ }
+
+ private void processExtendCall(PyCallExpression node, String nameBeingExtended) {
+ PyExpression arg = node.getArguments()[0];
+
+ Object value = myEvaluationResult.myNamespace.get(nameBeingExtended);
+ if (value instanceof List) {
+ Object argValue = prepareEvaluator().evaluate(arg);
+ myEvaluationResult.myNamespace.put(nameBeingExtended, prepareEvaluator().concatenate(value, argValue));
+ }
+
+ if (myDeclarationsToTrack.contains(nameBeingExtended)) {
+ List<PyExpression> declarations = myEvaluationResult.myDeclarations.get(nameBeingExtended);
+ if (declarations != null) {
+ PyPsiUtils.sequenceToList(declarations, arg);
+ }
+ }
+ }
+
+ private void processUpdateCall(PyCallExpression node, String name) {
+ Object value = myEvaluationResult.myNamespace.get(name);
+ if (value instanceof Map) {
+ Object argValue = prepareEvaluator().evaluate(node.getArguments()[0]);
+ if (argValue instanceof Map) {
+ ((Map)value).putAll((Map)argValue);
+ }
+ }
+ }
+
+ private PyEvaluator prepareEvaluator() {
+ PyEvaluator evaluator = createEvaluator();
+ evaluator.setNamespace(myEvaluationResult.myNamespace);
+ evaluator.setEvaluateCollectionItems(myEvaluateCollectionItems);
+ return evaluator;
+ }
+
+ protected PyEvaluator createEvaluator() {
+ return new PyPathEvaluator(myCurrentFilePath);
+ }
+
+ public Object getValue(String name) {
+ return myEvaluationResult.myNamespace.get(name);
+ }
+
+ @Nullable
+ public String getValueAsString(String name) {
+ Object value = myEvaluationResult.myNamespace.get(name);
+ return value instanceof String ? (String)value : null;
+ }
+
+ @Nullable
+ public List getValueAsList(String name) {
+ Object value = myEvaluationResult.myNamespace.get(name);
+ return value instanceof List ? (List)value : null;
+ }
+
+ @NotNull
+ public List<String> getValueAsStringList(String name) {
+ Object value = myEvaluationResult.myNamespace.get(name);
+ if (value instanceof List) {
+ List valueList = (List)value;
+ for (Object o : valueList) {
+ if (o != null && !(o instanceof String)) {
+ return Collections.emptyList();
+ }
+ }
+ return (List<String>)value;
+ }
+ if (value instanceof String) {
+ return Collections.singletonList((String)value);
+ }
+ return Collections.emptyList();
+ }
+
+ public Set<PyFile> getVisitedFiles() {
+ return myVisitedFiles;
+ }
+
+
+ public Object getReturnValue() {
+ return myReturnValue;
+ }
+
+ public void setEvaluateCollectionItems(boolean evaluateCollectionItems) {
+ myEvaluateCollectionItems = evaluateCollectionItems;
+ }
+
+ @NotNull
+ public List<PyExpression> getDeclarations(@NotNull final String name) {
+ return myEvaluationResult.getDeclarations(name);
+ }
+
+ /**
+ * @return so-called context. You may pass it to any instance of {@link com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator}
+ * to make instances share their cache
+ */
+ @NotNull
+ public PyEvaluationContext getContext() {
+ return myContext;
+ }
+
+ private class MyPyElementVisitor extends PyElementVisitor {
+ @Override
+ public void visitPyAssignmentStatement(PyAssignmentStatement node) {
+ PyExpression expression = node.getLeftHandSideExpression();
+ if (expression instanceof PyTargetExpression) {
+ String name = expression.getName();
+ PyExpression value = ((PyTargetExpression)expression).findAssignedValue();
+ myEvaluationResult.myNamespace.put(name, prepareEvaluator().evaluate(value));
+ if (myDeclarationsToTrack.contains(name)) {
+ List<PyExpression> declarations = new ArrayList<PyExpression>();
+ PyPsiUtils.sequenceToList(declarations, value);
+ myEvaluationResult.myDeclarations.put(name, declarations);
+ }
+ }
+ else if (expression instanceof PySubscriptionExpression) {
+ PyExpression operand = ((PySubscriptionExpression)expression).getOperand();
+ PyExpression indexExpression = ((PySubscriptionExpression)expression).getIndexExpression();
+ if (operand instanceof PyReferenceExpression && ((PyReferenceExpression)operand).getQualifier() == null) {
+ Object currentValue = myEvaluationResult.myNamespace.get(((PyReferenceExpression)operand).getReferencedName());
+ if (currentValue instanceof Map) {
+ Object mapKey = prepareEvaluator().evaluate(indexExpression);
+ if (mapKey != null) {
+ Object value = myEvaluateCollectionItems ? prepareEvaluator().evaluate(node.getAssignedValue()) : node.getAssignedValue();
+ ((Map)currentValue).put(mapKey, value);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visitPyAugAssignmentStatement(PyAugAssignmentStatement node) {
+ PyExpression target = node.getTarget();
+ String name = target.getName();
+ if (target instanceof PyReferenceExpression && !((PyReferenceExpression)target).isQualified() && name != null) {
+ Object currentValue = myEvaluationResult.myNamespace.get(name);
+ if (currentValue != null) {
+ Object rhs = prepareEvaluator().evaluate(node.getValue());
+ myEvaluationResult.myNamespace.put(name, prepareEvaluator().concatenate(currentValue, rhs));
+ }
+ if (myDeclarationsToTrack.contains(name)) {
+ List<PyExpression> declarations = myEvaluationResult.myDeclarations.get(name);
+ if (declarations != null) {
+ PyPsiUtils.sequenceToList(declarations, node.getValue());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visitPyExpressionStatement(PyExpressionStatement node) {
+ node.getExpression().accept(this);
+ }
+
+ @Override
+ public void visitPyCallExpression(PyCallExpression node) {
+ PyExpression callee = node.getCallee();
+ if (callee instanceof PyReferenceExpression) {
+ PyReferenceExpression calleeRef = (PyReferenceExpression)callee;
+ PyExpression qualifier = calleeRef.getQualifier();
+ if (qualifier instanceof PyReferenceExpression) {
+ PyReferenceExpression qualifierRef = (PyReferenceExpression)qualifier;
+ if (!qualifierRef.isQualified()) {
+ if (PyNames.EXTEND.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
+ processExtendCall(node, qualifierRef.getReferencedName());
+ }
+ else if (PyNames.UPDATE.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
+ processUpdateCall(node, qualifierRef.getReferencedName());
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visitPyFromImportStatement(final PyFromImportStatement node) {
+ if (node.isFromFuture()) return;
+ final PsiElement source = PyUtil.turnDirIntoInit(node.resolveImportSource());
+ if (source instanceof PyFile) {
+ final PyFile pyFile = (PyFile)source;
+ PyEvaluationResult newlyEvaluatedResult = myContext.getCachedResult(pyFile);
+
+ if (newlyEvaluatedResult == null) {
+ final PyBlockEvaluator importEvaluator = new PyBlockEvaluator(myVisitedFiles, myContext);
+ importEvaluator.myDeclarationsToTrack.addAll(myDeclarationsToTrack);
+ importEvaluator.evaluate(pyFile);
+ newlyEvaluatedResult = importEvaluator.myEvaluationResult;
+ myContext.cache(pyFile, newlyEvaluatedResult);
+ }
+
+ if (node.isStarImport()) {
+ // TODO honor __all__ here
+ myEvaluationResult.myNamespace.putAll(newlyEvaluatedResult.myNamespace);
+ myEvaluationResult.myDeclarations.putAll(newlyEvaluatedResult.myDeclarations);
+ }
+ else {
+ for (final PyImportElement element : node.getImportElements()) {
+ final String nameOfVarInOurModule = element.getVisibleName();
+ final QualifiedName nameOfVarInExternalModule = element.getImportedQName();
+ if ((nameOfVarInOurModule == null) || (nameOfVarInExternalModule == null)) {
+ continue;
+ }
+
+ final Object value = newlyEvaluatedResult.myNamespace.get(nameOfVarInExternalModule.toString());
+ myEvaluationResult.myNamespace.put(nameOfVarInOurModule, value);
+ final List<PyExpression> declarations = newlyEvaluatedResult.getDeclarations(nameOfVarInOurModule);
+ if (myEvaluationResult.myDeclarations.containsKey(nameOfVarInOurModule)) {
+ myEvaluationResult.myDeclarations.get(nameOfVarInOurModule).addAll(declarations);
+ }
+ else {
+ myEvaluationResult.myDeclarations.put(nameOfVarInOurModule, declarations);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visitPyIfStatement(PyIfStatement node) {
+ PyStatementList list = node.getIfPart().getStatementList();
+ if (list != null) {
+ list.acceptChildren(this);
+ }
+ }
+
+ @Override
+ public void visitPyReturnStatement(PyReturnStatement node) {
+ myReturnValue = prepareEvaluator().evaluate(node.getExpression());
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyEvaluationContext.java b/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyEvaluationContext.java
new file mode 100644
index 0000000..ababfd5
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyEvaluationContext.java
@@ -0,0 +1,42 @@
+package com.jetbrains.python.psi.impl.blockEvaluator;
+
+import com.jetbrains.python.psi.PyFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Cache for {@link com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator}.
+ * You may obtain one via {@link PyBlockEvaluator#getContext()} and pass to ctor:
+ * {@link com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator#PyBlockEvaluator(PyEvaluationContext)} to enable cache
+ *
+ * @author Ilya.Kazakevich
+ */
+public class PyEvaluationContext {
+ @NotNull
+ private final Map<PyFile, PyEvaluationResult> myResultMap = new HashMap<PyFile, PyEvaluationResult>();
+
+ PyEvaluationContext() {
+ }
+
+ /**
+ * Get evaluation result by file
+ * @param file file
+ * @return eval result
+ */
+ @Nullable
+ PyEvaluationResult getCachedResult(@NotNull final PyFile file) {
+ return myResultMap.get(file);
+ }
+
+ /**
+ * Store evaluation result by file
+ * @param file file
+ * @param result evaluation result
+ */
+ void cache(@NotNull final PyFile file, @NotNull final PyEvaluationResult result) {
+ myResultMap.put(file, result);
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyEvaluationResult.java b/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyEvaluationResult.java
new file mode 100644
index 0000000..c28baf5
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/impl/blockEvaluator/PyEvaluationResult.java
@@ -0,0 +1,26 @@
+package com.jetbrains.python.psi.impl.blockEvaluator;
+
+import com.jetbrains.python.psi.PyExpression;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Ilya.Kazakevich
+ */
+@SuppressWarnings("PackageVisibleField") // Package-only class
+class PyEvaluationResult {
+ @NotNull
+ final Map<String, Object> myNamespace = new HashMap<String, Object>();
+ @NotNull
+ final Map<String, List<PyExpression>> myDeclarations = new HashMap<String, List<PyExpression>>();
+
+ @NotNull
+ List<PyExpression> getDeclarations(@NotNull final String name) {
+ final List<PyExpression> expressions = myDeclarations.get(name);
+ return (expressions != null) ? expressions : Collections.<PyExpression>emptyList();
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/impl/blockEvaluator/package-info.java b/python/src/com/jetbrains/python/psi/impl/blockEvaluator/package-info.java
new file mode 100644
index 0000000..c44fd5d
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/impl/blockEvaluator/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Engine to evaluate block of python text.
+ * Use {@link com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator} as entry point.
+ *
+ * @author Ilya.Kazakevich
+ */
+package com.jetbrains.python.psi.impl.blockEvaluator;
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/psi/impl/stubs/PyDecoratorCallElementType.java b/python/src/com/jetbrains/python/psi/impl/stubs/PyDecoratorCallElementType.java
index 388d797..9ad2fe3 100644
--- a/python/src/com/jetbrains/python/psi/impl/stubs/PyDecoratorCallElementType.java
+++ b/python/src/com/jetbrains/python/psi/impl/stubs/PyDecoratorCallElementType.java
@@ -17,14 +17,16 @@
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.stubs.IndexSink;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubInputStream;
import com.intellij.psi.stubs.StubOutputStream;
-import com.jetbrains.python.psi.PyStubElementType;
-import com.jetbrains.python.psi.PyDecorator;
-import com.jetbrains.python.psi.impl.PyDecoratorImpl;
import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.psi.PyDecorator;
+import com.jetbrains.python.psi.PyStubElementType;
+import com.jetbrains.python.psi.impl.PyDecoratorImpl;
import com.jetbrains.python.psi.stubs.PyDecoratorStub;
+import com.jetbrains.python.psi.stubs.PyDecoratorStubIndex;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -34,7 +36,7 @@
* User: dcheryasov
* Date: Dec 18, 2008 9:09:57 PM
*/
-public class PyDecoratorCallElementType extends PyStubElementType<PyDecoratorStub, PyDecorator> {
+public class PyDecoratorCallElementType extends PyStubElementType<PyDecoratorStub, PyDecorator> {
public PyDecoratorCallElementType() {
super("DECORATOR_CALL");
}
@@ -55,10 +57,18 @@
QualifiedName.serialize(stub.getQualifiedName(), dataStream);
}
+ @Override
+ public void indexStub(@NotNull final PyDecoratorStub stub, @NotNull final IndexSink sink) {
+ // Index decorators stub by name (todo: index by FQDN as well!)
+ final QualifiedName qualifiedName = stub.getQualifiedName();
+ if (qualifiedName != null) {
+ sink.occurrence(PyDecoratorStubIndex.KEY, qualifiedName.toString());
+ }
+ }
+
@NotNull
public PyDecoratorStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
QualifiedName q_name = QualifiedName.deserialize(dataStream);
return new PyDecoratorStubImpl(q_name, parentStub);
}
-
}
diff --git a/python/src/com/jetbrains/python/psi/stubs/PyDecoratorStubIndex.java b/python/src/com/jetbrains/python/psi/stubs/PyDecoratorStubIndex.java
new file mode 100644
index 0000000..0e7ea41
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/stubs/PyDecoratorStubIndex.java
@@ -0,0 +1,24 @@
+package com.jetbrains.python.psi.stubs;
+
+import com.intellij.psi.stubs.StringStubIndexExtension;
+import com.intellij.psi.stubs.StubIndexKey;
+import com.jetbrains.python.psi.PyDecorator;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Python Decorator stub index.
+ * Decorators are indexed by name
+ * @author Ilya.Kazakevich
+ */
+public class PyDecoratorStubIndex extends StringStubIndexExtension<PyDecorator> {
+ /**
+ * Key to search for python decorators
+ */
+ public static final StubIndexKey<String, PyDecorator> KEY = StubIndexKey.createIndexKey("Python.Decorator");
+
+ @NotNull
+ @Override
+ public StubIndexKey<String, PyDecorator> getKey() {
+ return KEY;
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java
index dc63784..520c9b5 100644
--- a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java
+++ b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java
@@ -21,8 +21,8 @@
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.AccessDirection;
+import com.jetbrains.python.psi.PyCallSiteExpression;
import com.jetbrains.python.psi.PyExpression;
-import com.jetbrains.python.psi.PyQualifiedExpression;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import org.jetbrains.annotations.NotNull;
@@ -55,7 +55,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
+ public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
return myReturnType;
}
diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
index 778b838..34a92e1 100644
--- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
+++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
@@ -316,7 +316,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
+ public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
return getReturnType(context);
}
diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
index 229fe26..bb58b68 100644
--- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
+++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
@@ -52,7 +52,7 @@
@Nullable
@Override
- public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
+ public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
return myCallable.getCallType(context, callSite);
}
diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java
index f4a5236..9881d6c 100644
--- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java
+++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java
@@ -496,16 +496,9 @@
}
@Nullable
- public static AnalyzeCallResults analyzeCallSite(@Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) {
- if (callSite == null) {
- return null;
- }
- PsiElement parent = callSite.getParent();
- while (parent instanceof PyParenthesizedExpression) {
- parent = ((PyParenthesizedExpression)parent).getContainedExpression();
- }
- if (parent instanceof PyCallExpression) {
- return analyzeCall((PyCallExpression)parent, context);
+ public static AnalyzeCallResults analyzeCallSite(@Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) {
+ if (callSite instanceof PyCallExpression) {
+ return analyzeCall((PyCallExpression)callSite, context);
}
else if (callSite instanceof PyBinaryExpression) {
return analyzeCall((PyBinaryExpression)callSite, context);
diff --git a/python/src/com/jetbrains/python/remote/PySkeletonsPathAware.java b/python/src/com/jetbrains/python/remote/PySkeletonsPathAware.java
index 789d1ba..4cc21ed 100644
--- a/python/src/com/jetbrains/python/remote/PySkeletonsPathAware.java
+++ b/python/src/com/jetbrains/python/remote/PySkeletonsPathAware.java
@@ -2,9 +2,22 @@
/**
* @author traff
+ * @deprecated
*/
public interface PySkeletonsPathAware {
+ /**
+ * Use RemoteSdkProperties.getPathMappings() instead
+ * To be removed in IDEA 15
+ * @deprecated
+ */
+ @Deprecated
String getSkeletonsPath();
+ /**
+ * Use RemoteSdkProperties.getPathMappings() instead
+ * To be removed in IDEA 15
+ * @deprecated
+ */
+ @Deprecated
void setSkeletonsPath(String path);
}
diff --git a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
index b904b55..429be6c 100644
--- a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
+++ b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.remote;
+import com.google.common.base.Function;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.ParamsGroup;
@@ -40,7 +41,6 @@
import org.jetbrains.annotations.Nullable;
import java.awt.*;
-import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.List;
@@ -145,14 +145,16 @@
public abstract SdkAdditionalData loadRemoteSdkData(Sdk sdk, Element additional);
- public abstract boolean testConnection(RemoteCredentials credentials);
-
public abstract PyConsoleProcessHandler createConsoleProcessHandler(Process process,
PyRemoteSdkCredentials data,
PythonConsoleView view,
PydevConsoleCommunication consoleCommunication,
String commandLine, Charset charset, PathMappingSettings settings);
+ @NotNull
+ public abstract RemoteSdkCredentialsProducer<PyRemoteSdkCredentials> getRemoteSdkCredentialsProducer(Function<RemoteCredentials, PyRemoteSdkCredentials> credentialsTransformer,
+ RemoteConnectionCredentialsWrapper connectionWrapper);
+
public static class PyRemoteInterpreterExecutionException extends ExecutionException {
public PyRemoteInterpreterExecutionException() {
@@ -167,15 +169,6 @@
}
}
- @Nullable
- public abstract RemoteCredentials getVagrantRemoteCredentials(VagrantBasedCredentialsHolder data) throws IOException;
-
- public abstract boolean checkVagrantStatus(String vagrantFolder, boolean runIfDown);
-
public abstract void runVagrant(String vagrantFolder) throws ExecutionException;
-
- public abstract void checkVagrantStatus(VagrantBasedCredentialsHolder data);
-
- public abstract RemoteCredentials getCredentialsBySftpServerId(String id);
}
diff --git a/python/src/com/jetbrains/python/remote/RemoteProjectSettings.java b/python/src/com/jetbrains/python/remote/RemoteProjectSettings.java
index 424ea52..80d8697 100644
--- a/python/src/com/jetbrains/python/remote/RemoteProjectSettings.java
+++ b/python/src/com/jetbrains/python/remote/RemoteProjectSettings.java
@@ -15,10 +15,12 @@
*/
package com.jetbrains.python.remote;
+import com.jetbrains.python.newProject.PyNewProjectSettings;
+
/**
* @author traff
*/
-public class RemoteProjectSettings {
+public class RemoteProjectSettings extends PyNewProjectSettings {
private String myDeploymentName;
private String myRemoteRoot;
diff --git a/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java b/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java
index d5ba031..168e801 100644
--- a/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java
+++ b/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java
@@ -74,7 +74,7 @@
try {
settings = manager.setupMappings(project, pyRemoteSdkAdditionalDataBase, settings);
- return manager.startRemoteProcess(project, pyRemoteSdkAdditionalDataBase.getRemoteSdkCredentials(), commandLine,
+ return manager.startRemoteProcess(project, pyRemoteSdkAdditionalDataBase.getRemoteSdkCredentials(true), commandLine,
settings);
}
catch (InterruptedException e) {
diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
index c3516dc..39fc2c9 100644
--- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
+++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
@@ -362,7 +362,7 @@
}
private void updateSdkList(final List<Sdk> allSdks, @Nullable Sdk initialSelection) {
- mySdkCombo.setRenderer(new PySdkListCellRenderer());
+ mySdkCombo.setRenderer(new PySdkListCellRenderer(false));
mySdkCombo.setModel(new CollectionComboBoxModel(allSdks, initialSelection));
checkValid();
}
diff --git a/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java b/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java
index 9886224..1a42621 100644
--- a/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java
+++ b/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java
@@ -23,17 +23,25 @@
import com.intellij.ui.LayeredIcon;
import com.intellij.ui.ListCellRendererWrapper;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import java.io.File;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class PySdkListCellRenderer extends ListCellRendererWrapper<Object> {
private final String myNullText;
private final Map<Sdk, SdkModificator> mySdkModifiers;
public static final String SEPARATOR = "separator";
- public PySdkListCellRenderer() {
+ final Pattern PYTHON_PATTERN = Pattern.compile("(\\d\\.?\\d\\.?\\d?)[ ]*\\(([^\\(\\)]*)\\)|(\\d\\.?\\d\\.?\\d?)[ ]*([^\\(\\)]*)");
+ private boolean isShortVersion;
+
+ public PySdkListCellRenderer(boolean shortVersion) {
+ isShortVersion = shortVersion;
myNullText = "";
mySdkModifiers = null;
}
@@ -50,13 +58,21 @@
final PythonSdkFlavor flavor = PythonSdkFlavor.getPlatformIndependentFlavor(sdk.getHomePath());
final Icon icon = flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon();
- final String name;
+ String name;
if (mySdkModifiers != null && mySdkModifiers.containsKey(sdk)) {
name = mySdkModifiers.get(sdk).getName();
}
else {
name = sdk.getName();
}
+ if (name.startsWith("Remote")) name = name.substring(7);
+ final String flavorName = flavor == null ? "Python" : flavor.getName();
+ if (name.startsWith(flavorName)) name = name.substring(flavorName.length() + 1);
+
+ if (isShortVersion){
+ name = shortenName(name);
+ }
+
if (PythonSdkType.isInvalid(sdk)) {
setText("[invalid] " + name);
setIcon(wrapIconWithWarningDecorator(icon));
@@ -80,6 +96,28 @@
setText(myNullText);
}
+ private String shortenName(@NotNull String name) {
+ final Matcher matcher = PYTHON_PATTERN.matcher(name);
+ if (matcher.matches()) {
+ String path = matcher.group(2);
+ if (path != null) {
+ name = matcher.group(1) + " at " + path;
+ }
+ else {
+ path = matcher.group(4);
+ final int index = path.lastIndexOf(File.separator);
+ if (index > 0) {
+ path = path.substring(index);
+ }
+ name = matcher.group(3) + " at ..." + path;
+ }
+ }
+ else if (new File(name).exists()) {
+ name = "..." + File.separator + new File(name).getParentFile().getParentFile().getName();
+ }
+ return name;
+ }
+
private static LayeredIcon wrapIconWithWarningDecorator(Icon icon) {
final LayeredIcon layered = new LayeredIcon(2);
layered.setIcon(icon, 0);
diff --git a/python/src/com/jetbrains/python/sdk/PySdkUtil.java b/python/src/com/jetbrains/python/sdk/PySdkUtil.java
index 60a4c5b..8f2b62b 100644
--- a/python/src/com/jetbrains/python/sdk/PySdkUtil.java
+++ b/python/src/com/jetbrains/python/sdk/PySdkUtil.java
@@ -57,8 +57,6 @@
// Windows EOF marker, Ctrl+Z
public static final int SUBSTITUTE = 26;
- private static final String REMOTE_SOURCES_DIR_NAME = "remote_sources";
-
private PySdkUtil() {
// explicitly none
}
@@ -243,7 +241,7 @@
String basePath = PathManager.getSystemPath();
return basePath +
File.separator +
- REMOTE_SOURCES_DIR_NAME +
+ PythonSdkType.REMOTE_SOURCES_DIR_NAME +
sep +
FileUtil.toSystemIndependentName(sdkHome).hashCode() +
sep;
@@ -255,8 +253,8 @@
}
@Nullable
- public static VirtualFile findRemoteLibrariesDir(@NotNull final Sdk sdk) {
- return findLibraryDir(sdk, REMOTE_SOURCES_DIR_NAME, OrderRootType.CLASSES);
+ public static VirtualFile findAnyRemoteLibrary(@NotNull final Sdk sdk) {
+ return findLibraryDir(sdk, PythonSdkType.REMOTE_SOURCES_DIR_NAME, OrderRootType.CLASSES);
}
private static VirtualFile findLibraryDir(Sdk sdk, String dirName, OrderRootType rootType) {
diff --git a/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java b/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java
index ad860f7..0f44888 100644
--- a/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java
+++ b/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java
@@ -86,9 +86,4 @@
public static void addToPythonPath(@NotNull Map<String, String> env, String value) {
addPathToEnv(env, PYTHONPATH, value);
}
-
- public static List<String> getPathListFromEnv(@NotNull Map<String, String> env, String envKey) {
- String pythonPath = env.get(envKey);
- return pythonPath != null ? Lists.newArrayList(pythonPath.split(File.pathSeparator)) : null;
- }
}
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
index a51d8e2..5e3506b 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
@@ -56,9 +56,7 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.reference.SoftReference;
-import com.intellij.remote.RemoteSdkCredentials;
-import com.intellij.remote.RemoteSdkCredentialsHolder;
-import com.intellij.remote.VagrantNotStartedException;
+import com.intellij.remote.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Consumer;
import com.intellij.util.NullableConsumer;
@@ -71,10 +69,10 @@
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.search.PyProjectScopeBuilder;
+import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.sdk.flavors.CPythonSdkFlavor;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
-import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher;
import icons.PythonIcons;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -96,6 +94,7 @@
* @author yole
*/
public class PythonSdkType extends SdkType {
+ public static final String REMOTE_SOURCES_DIR_NAME = "remote_sources";
private static final Logger LOG = Logger.getInstance("#" + PythonSdkType.class.getName());
private static final String[] WINDOWS_EXECUTABLE_SUFFIXES = new String[]{"cmd", "exe", "bat", "com"};
@@ -143,12 +142,9 @@
*/
@NotNull
@NonNls
- public static String getBuiltinsFileName(Sdk sdk) {
- final String version = sdk.getVersionString();
- if (version != null && version.startsWith("Python 3")) {
- return PyBuiltinCache.BUILTIN_FILE_3K;
- }
- return PyBuiltinCache.BUILTIN_FILE;
+ public static String getBuiltinsFileName(@NotNull Sdk sdk) {
+ final LanguageLevel level = getLanguageLevelForSdk(sdk);
+ return level.isOlderThan(LanguageLevel.PYTHON30) ? PyBuiltinCache.BUILTIN_FILE : PyBuiltinCache.BUILTIN_FILE_3K;
}
@NonNls
@@ -241,6 +237,15 @@
return PySdkUtil.isRemote(sdk);
}
+ public static boolean isVagrant(@Nullable Sdk sdk) {
+ if (sdk != null && sdk.getSdkAdditionalData() instanceof PyRemoteSdkAdditionalDataBase) {
+ PyRemoteSdkAdditionalDataBase data = (PyRemoteSdkAdditionalDataBase) sdk.getSdkAdditionalData();
+
+ return data.getRemoteConnectionType() == CredentialsType.VAGRANT;
+ }
+ return false;
+ }
+
public static boolean isRemote(@Nullable String sdkPath) {
return isRemote(findSdkByPath(sdkPath));
}
@@ -554,11 +559,11 @@
public void run(@NotNull ProgressIndicator indicator) {
try {
final String skeletonsPath = getSkeletonsPath(PathManager.getSystemPath(), sdk.getHomePath());
- PySkeletonRefresher.refreshSkeletonsOfSdk(project, ownerComponent, skeletonsPath, null, sdk);
+ PythonSdkUpdater.updateSdk(project, ownerComponent, sdk, skeletonsPath);
}
catch (InvalidSdkException e) {
// If the SDK is invalid, the user should worry about the SDK itself, not about skeletons generation errors
- if (isRemote(sdk)) {
+ if (isVagrant(sdk)) {
notifyRemoteSdkSkeletonsFail(e, new Runnable() {
@Override
public void run() {
@@ -647,9 +652,6 @@
}
}
}
- else {
- addRemoteLibrariesRoot(sdkModificator, sdkHome);
- }
PyUserSkeletonsUtil.addUserSkeletonsRoot(sdkModificator);
addSkeletonsRoot(sdkModificator, sdkHome);
@@ -699,14 +701,6 @@
sdkModificator.addRoot(builtins_root, BUILTIN_ROOT_TYPE);
}
- private static void addRemoteLibrariesRoot(@NotNull SdkModificator sdkModificator, String sdkHome) {
- @NonNls final String librariesRoot = PySdkUtil.getRemoteSourcesLocalPath(sdkHome);
- new File(librariesRoot).mkdirs();
- final VirtualFile remoteLibraries = LocalFileSystem.getInstance().refreshAndFindFileByPath(librariesRoot);
- assert remoteLibraries != null : "Cannot find remote libraries path " + librariesRoot + " in VFS";
- sdkModificator.addRoot(remoteLibraries, OrderRootType.CLASSES);
- }
-
protected static void addHardcodedPaths(SdkModificator sdkModificator) {
// Add python-django installed as package in Linux
// NOTE: fragile and arbitrary
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
index f583ebb..b4b968f 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
@@ -15,6 +15,8 @@
*/
package com.jetbrains.python.sdk;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -30,16 +32,22 @@
import com.intellij.openapi.projectRoots.SdkTypeId;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.startup.StartupActivity;
+import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.PathMappingSettings;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil;
+import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import java.awt.*;
import java.io.File;
import java.util.*;
+import java.util.List;
/**
* A component that initiates a refresh of all project's Python SDKs.
@@ -91,56 +99,75 @@
// NOTE: everything is run later on the AWT thread
if (!sdksToUpdate.isEmpty()) {
- ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
- public void run() {
- if (delay > 0) {
- try {
- Thread.sleep(delay); // wait until all short-term disk-hitting activity ceases
- }
- catch (InterruptedException ignore) {
- }
- }
- // update skeletons
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- ProgressManager.getInstance().run(new Task.Backgroundable(project, PyBundle.message("sdk.gen.updating.skels"), false) {
- @Override
- public void run(@NotNull ProgressIndicator indicator) {
- for (final Sdk sdk : sdksToUpdate) {
- try {
- LOG.info("Performing background update of skeletons for SDK " + sdk.getHomePath());
- updateSdk(project, sdk);
- }
- catch (InvalidSdkException e) {
- if (PythonSdkType.isRemote(sdk)) {
- PythonSdkType.notifyRemoteSdkSkeletonsFail(e, new Runnable() {
- @Override
- public void run() {
- updateActiveSdks(project, delay);
- }
- });
- }
- else if (!PythonSdkType.isInvalid(sdk)) {
- LOG.error(e);
- }
- }
- myAlreadyUpdated.add(sdk.getHomePath());
- }
- }
- });
- }
- });
- }
- });
+ updateSdks(project, delay, sdksToUpdate);
}
}
- private static void updateSdk(@NotNull Project project, @NotNull final Sdk sdk) throws InvalidSdkException {
- PySkeletonRefresher.refreshSkeletonsOfSdk(project, sdk); // NOTE: whole thing would need a rename
+ private void updateSdks(final Project project, final int delay, final Set<Sdk> sdksToUpdate) {
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ public void run() {
+ if (delay > 0) {
+ try {
+ Thread.sleep(delay); // wait until all short-term disk-hitting activity ceases
+ }
+ catch (InterruptedException ignore) {
+ }
+ }
+ // update skeletons
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ ProgressManager.getInstance().run(new Task.Backgroundable(project, PyBundle.message("sdk.gen.updating.skels"), false) {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ for (final Sdk sdk : sdksToUpdate) {
+ try {
+ LOG.info("Performing background update of skeletons for SDK " + sdk.getHomePath());
+ updateSdk(project, null, sdk, PythonSdkType.findSkeletonsPath(sdk));
+ }
+ catch (InvalidSdkException e) {
+ if (PythonSdkType.isVagrant(sdk)) {
+ PythonSdkType.notifyRemoteSdkSkeletonsFail(e, new Runnable() {
+ @Override
+ public void run() {
+ updateSdks(project, delay, Sets.newHashSet(sdk));
+ }
+ });
+ }
+ else if (!PythonSdkType.isInvalid(sdk)) {
+ LOG.error(e);
+ }
+ }
+ myAlreadyUpdated.add(sdk.getHomePath());
+ }
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+ public static void updateSdk(@Nullable Project project, @Nullable Component ownerComponent, @NotNull final Sdk sdk, String skeletonsPath) throws InvalidSdkException {
+ PySkeletonRefresher.refreshSkeletonsOfSdk(project, ownerComponent, skeletonsPath, new Ref<Boolean>(false), sdk); // NOTE: whole thing would need a rename
if (!PySdkUtil.isRemote(sdk)) {
updateSysPath(sdk);
}
+ else {
+ PyRemoteSdkAdditionalDataBase remoteSdkData = (PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData();
+ assert remoteSdkData != null;
+ final List<String> paths = Lists.newArrayList();
+ for (PathMappingSettings.PathMapping mapping : remoteSdkData.getPathMappings().getPathMappings()) {
+ paths.add(mapping.getLocalRoot());
+ }
+
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ updateSdkPath(sdk, paths);
+ }
+ });
+ }
}
private static void updateSysPath(@NotNull final Sdk sdk) throws InvalidSdkException {
diff --git a/python/src/com/jetbrains/python/sdk/flavors/IronPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/IronPythonSdkFlavor.java
index 450dff4..51b9ffd 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/IronPythonSdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/IronPythonSdkFlavor.java
@@ -17,17 +17,22 @@
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.PatternUtil;
import icons.PythonIcons;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.util.*;
+import java.util.regex.Pattern;
/**
* @author yole
*/
public class IronPythonSdkFlavor extends PythonSdkFlavor {
+ public static final Pattern VERSION_RE = Pattern.compile("\\w+ ([0-9\\.]+).*");
+
private IronPythonSdkFlavor() {
}
@@ -64,13 +69,11 @@
return name.equals("ipy.exe") || name.equals("ipy64.exe");
}
- public String getVersionStringFromOutput(String version) {
- return getName() + " " + version;
- }
-
+ @Nullable
@Override
- public String getVersionRegexp() {
- return "\\w+ ([0-9\\.]+).*";
+ public String getVersionStringFromOutput(@NotNull String output) {
+ final String match = PatternUtil.getFirstMatch(Arrays.asList(StringUtil.splitByLines(output)), VERSION_RE);
+ return match != null ? getName() + " " + match : null;
}
@Override
diff --git a/python/src/com/jetbrains/python/sdk/flavors/JythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/JythonSdkFlavor.java
index 882d82b..4b0fa93 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/JythonSdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/JythonSdkFlavor.java
@@ -19,19 +19,24 @@
import com.intellij.execution.configurations.ParamsGroup;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.PatternUtil;
import com.jetbrains.python.run.PythonCommandLineState;
import icons.PythonIcons;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
+import java.util.regex.Pattern;
/**
* @author yole
*/
public class JythonSdkFlavor extends PythonSdkFlavor {
+ private static final Pattern VERSION_RE = Pattern.compile("(Jython \\S+)( on .*)?");
private static final String JYTHONPATH = "JYTHONPATH";
private static final String PYTHON_PATH_PREFIX = "-Dpython.path=";
@@ -44,9 +49,10 @@
return FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("jython");
}
+ @Nullable
@Override
- public String getVersionRegexp() {
- return "(Jython \\S+)( on .*)?";
+ public String getVersionStringFromOutput(@NotNull String output) {
+ return PatternUtil.getFirstMatch(Arrays.asList(StringUtil.splitByLines(output)), VERSION_RE);
}
@Override
diff --git a/python/src/com/jetbrains/python/sdk/flavors/PyPySdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PyPySdkFlavor.java
index d857e45..eb35d3f 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/PyPySdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/PyPySdkFlavor.java
@@ -18,29 +18,53 @@
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.PatternUtil;
import com.jetbrains.python.psi.LanguageLevel;
import icons.PythonIcons;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
+import java.util.Arrays;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* @author traff
*/
public class PyPySdkFlavor extends PythonSdkFlavor {
+ public static PyPySdkFlavor INSTANCE = new PyPySdkFlavor();
+
+ private static final Pattern VERSION_RE = Pattern.compile("\\[(PyPy \\S+).*\\]");
+ private static final Pattern PYTHON_VERSION_RE = Pattern.compile("(Python \\S+).*");
+ private static final Pattern VERSION_STRING_RE = Pattern.compile("PyPy (\\S+)( \\[Python (\\S+)\\])?");
+
private PyPySdkFlavor() {
}
- public static PyPySdkFlavor INSTANCE = new PyPySdkFlavor();
-
public boolean isValidSdkPath(@NotNull File file) {
return FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("pypy");
}
- public String getVersionRegexp() {
- return "\\[(PyPy \\S+).*\\]";
+ @Nullable
+ @Override
+ public String getVersionStringFromOutput(@NotNull String output) {
+ final List<String> lines = Arrays.asList(StringUtil.splitByLines(output));
+ final String version = PatternUtil.getFirstMatch(lines, VERSION_RE);
+ final String pythonVersion = PatternUtil.getFirstMatch(lines, PYTHON_VERSION_RE);
+ if (version != null) {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(version);
+ if (pythonVersion != null) {
+ builder.append(" [");
+ builder.append(pythonVersion);
+ builder.append("]");
+ }
+ return builder.toString();
+ }
+ return null;
}
public String getVersionOption() {
@@ -55,11 +79,19 @@
@Override
public LanguageLevel getLanguageLevel(Sdk sdk) {
- final String version = sdk.getVersionString();
- final String prefix = getName() + " ";
- if (version != null && version.startsWith(prefix)) {
- String pypyVersion = version.substring(prefix.length());
- return LanguageLevel.fromPythonVersion(getPythonVersion(pypyVersion));
+ final String versionString = sdk.getVersionString();
+ if (versionString != null) {
+ final Matcher matcher = VERSION_STRING_RE.matcher(versionString);
+ if (matcher.matches()) {
+ final String version = matcher.group(1);
+ final String pythonVersion = matcher.group(3);
+ if (pythonVersion != null) {
+ return LanguageLevel.fromPythonVersion(pythonVersion);
+ }
+ else if (version != null) {
+ return LanguageLevel.fromPythonVersion(getPythonVersion(version));
+ }
+ }
}
return LanguageLevel.getDefault();
}
diff --git a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java
index ec255b5..4edac44 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java
@@ -45,6 +45,7 @@
* @author yole
*/
public abstract class PythonSdkFlavor {
+ private static final Pattern VERSION_RE = Pattern.compile("(Python \\S+).*");
private static final Logger LOG = Logger.getInstance(PythonSdkFlavor.class);
public static Collection<String> appendSystemPythonPath(@NotNull Collection<String> pythonPath) {
@@ -158,55 +159,42 @@
return FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("python");
}
- public String getVersionString(String sdkHome) {
- return getVersionStringFromOutput(getVersionFromOutput(sdkHome, getVersionOption(), getVersionRegexp()));
+ @Nullable
+ public String getVersionString(@Nullable String sdkHome) {
+ if (sdkHome == null) {
+ return null;
+ }
+ final String runDirectory = new File(sdkHome).getParent();
+ final ProcessOutput processOutput = PySdkUtil.getProcessOutput(runDirectory, new String[]{sdkHome, getVersionOption()}, 10000);
+ return getVersionStringFromOutput(processOutput);
}
- public String getVersionStringFromOutput(String version) {
- return version;
+ @Nullable
+ public String getVersionStringFromOutput(@NotNull ProcessOutput processOutput) {
+ if (processOutput.getExitCode() != 0) {
+ String errors = processOutput.getStderr();
+ if (StringUtil.isEmpty(errors)) {
+ errors = processOutput.getStdout();
+ }
+ LOG.warn("Couldn't get interpreter version: process exited with code " + processOutput.getExitCode() + "\n" + errors);
+ return null;
+ }
+ final String result = getVersionStringFromOutput(processOutput.getStderr());
+ if (result != null) {
+ return result;
+ }
+ return getVersionStringFromOutput(processOutput.getStdout());
}
-
- public String getVersionRegexp() {
- return "(Python \\S+).*";
+ @Nullable
+ public String getVersionStringFromOutput(@NotNull String output) {
+ return PatternUtil.getFirstMatch(Arrays.asList(StringUtil.splitByLines(output)), VERSION_RE);
}
public String getVersionOption() {
return "-V";
}
- @Nullable
- public String getVersionFromOutput(ProcessOutput processOutput) {
- return getVersionFromOutput(getVersionRegexp(), processOutput);
- }
-
- @Nullable
- protected static String getVersionFromOutput(String sdkHome, String versionOpt, String versionRegexp) {
- String runDirectory = new File(sdkHome).getParent();
- final ProcessOutput processOutput = PySdkUtil.getProcessOutput(runDirectory, new String[]{sdkHome, versionOpt}, 10000);
-
- return getVersionFromOutput(versionRegexp, processOutput);
- }
-
- @Nullable
- private static String getVersionFromOutput(String version_regexp, ProcessOutput process_output) {
- if (process_output.getExitCode() != 0) {
- String err = process_output.getStderr();
- if (StringUtil.isEmpty(err)) {
- err = process_output.getStdout();
- }
- LOG.warn("Couldn't get interpreter version: process exited with code " + process_output.getExitCode() + "\n" + err
- );
- return null;
- }
- Pattern pattern = Pattern.compile(version_regexp);
- final String result = PatternUtil.getFirstMatch(process_output.getStderrLines(), pattern);
- if (result != null) {
- return result;
- }
- return PatternUtil.getFirstMatch(process_output.getStdoutLines(), pattern);
- }
-
public Collection<String> getExtraDebugOptions() {
return Collections.emptyList();
}
diff --git a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
index 13202d7..284a125 100644
--- a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
+++ b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
@@ -237,7 +237,7 @@
final VirtualFile userSkeletonsDir = PyUserSkeletonsUtil.getUserSkeletonsDirectory();
final File userSkeletons = userSkeletonsDir != null ? new File(userSkeletonsDir.getPath()) : null;
- final VirtualFile remoteSourcesDir = PySdkUtil.findRemoteLibrariesDir(sdk);
+ final VirtualFile remoteSourcesDir = PySdkUtil.findAnyRemoteLibrary(sdk);
final File remoteSources = remoteSourcesDir != null ? new File(remoteSourcesDir.getPath()) : null;
final VirtualFile[] classDirs = sdk.getRootProvider().getFiles(OrderRootType.CLASSES);
diff --git a/python/src/com/jetbrains/python/spellchecker/python.dic b/python/src/com/jetbrains/python/spellchecker/python.dic
index edcc8d6..d486a4f 100644
--- a/python/src/com/jetbrains/python/spellchecker/python.dic
+++ b/python/src/com/jetbrains/python/spellchecker/python.dic
@@ -1072,6 +1072,7 @@
itemconfigure
itemgetter
itemre
+iter
iterable
iterdecode
iterdump
@@ -1264,6 +1265,7 @@
memset
menubutton
menudefs
+metaclass
metas
metastrings
metavar
diff --git a/python/src/com/jetbrains/python/spellchecker/pythonExtras.dic b/python/src/com/jetbrains/python/spellchecker/pythonExtras.dic
index 18bb40e..6db6fb3 100644
--- a/python/src/com/jetbrains/python/spellchecker/pythonExtras.dic
+++ b/python/src/com/jetbrains/python/spellchecker/pythonExtras.dic
@@ -1,3 +1,4 @@
+cinit
rtype
tuple
tuples
diff --git a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java
index f070293..f8b4add 100644
--- a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java
+++ b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java
@@ -30,8 +30,10 @@
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
-import java.io.IOException;
-import java.util.*;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
/**
* @author yole
@@ -51,13 +53,7 @@
public void run() {
List<PyRequirement> requirements = PyPackageManagerImpl.getRequirements(m);
if (requirements != null) {
- Collection<String> packages;
- try {
- packages = new HashSet<String>(PyPIPackageUtil.INSTANCE.getPackageNames());
- }
- catch (IOException e) {
- return;
- }
+ Collection<String> packages = new HashSet<String>(PyPIPackageUtil.INSTANCE.getPackageNames());
for (PyRequirement requirement : requirements) {
String name = requirement.getName();
if (packages.contains(name)) {
diff --git a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
index 2e92a0e..cc468c5 100644
--- a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
+++ b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
@@ -23,14 +23,11 @@
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.testframework.AbstractTestProxy;
-import com.intellij.execution.testframework.Filter;
import com.intellij.execution.testframework.TestFrameworkRunningModel;
import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction;
-import com.intellij.execution.testframework.sm.runner.states.TestStateInfo;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComponentContainer;
-import com.intellij.psi.search.GlobalSearchScope;
import com.jetbrains.python.run.AbstractPythonRunConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -131,15 +128,4 @@
passParentEnvs);
}
}
-
- @NotNull
- @Override
- protected Filter getFilter(Project project, GlobalSearchScope searchScope) {
- return new Filter() {
- public boolean shouldAccept(final AbstractTestProxy test) {
- boolean ignored = (test.getMagnitude() == TestStateInfo.Magnitude.IGNORED_INDEX.getValue());
- return !ignored && (test.isInterrupted() || test.isDefect());
- }
- };
- }
}
diff --git a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java
index 69d1ce0..9d763e2 100644
--- a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java
+++ b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java
@@ -133,7 +133,7 @@
}
final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
try {
- return packageManager.findPackage(testPackageName) != null;
+ return packageManager.findInstalledPackage(testPackageName) != null;
}
catch (PyExternalProcessException e) {
LOG.info("Can't load package list " + e.getMessage());
diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java
index 51a28ee..f988dbd 100644
--- a/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java
+++ b/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java
@@ -99,7 +99,7 @@
if (pyClass != null) {
final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
try {
- final PyPackage pytestPackage = packageManager.findPackage("pytest");
+ final PyPackage pytestPackage = packageManager.findInstalledPackage("pytest");
if (pytestPackage != null && PackageVersionComparator.VERSION_COMPARATOR.compare(pytestPackage.getVersion(), "2.3.3") >= 0) {
keywords = pyClass.getName() + " and " + keywords;
}
diff --git a/python/testData/inspections/PyCallingNonCallableInspection/callDictSubscriptionExpression.py b/python/testData/inspections/PyCallingNonCallableInspection/callDictSubscriptionExpression.py
new file mode 100644
index 0000000..4c6d765
--- /dev/null
+++ b/python/testData/inspections/PyCallingNonCallableInspection/callDictSubscriptionExpression.py
@@ -0,0 +1,4 @@
+ops = {'and': all, 'or': any}
+op = ops['or']
+ops['and']()
+op()
diff --git a/python/testData/inspections/PyCallingNonCallableInspection/localCallableClass.py b/python/testData/inspections/PyCallingNonCallableInspection/localCallableClass.py
new file mode 100644
index 0000000..de03229
--- /dev/null
+++ b/python/testData/inspections/PyCallingNonCallableInspection/localCallableClass.py
@@ -0,0 +1,7 @@
+class Callable(object):
+ pass
+
+
+def f(g):
+ if callable(g):
+ g()
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/OneUnsedOneMarked/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/OneUnsedOneMarked/a.py
new file mode 100644
index 0000000..baae7fc
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/OneUnsedOneMarked/a.py
@@ -0,0 +1,4 @@
+from library import foo,<error descr="Unresolved reference 'bar'">bar</error>
+
+
+print(foo)
\ No newline at end of file
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/OneUnsedOneMarked/library.py b/python/testData/inspections/PyUnresolvedReferencesInspection/OneUnsedOneMarked/library.py
new file mode 100644
index 0000000..048ea67
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/OneUnsedOneMarked/library.py
@@ -0,0 +1 @@
+foo = 0
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java
index 646f17c..1409ff4 100644
--- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java
+++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java
@@ -52,6 +52,14 @@
doTest();
}
+ // PY-13157
+ public void testMetaClass() {
+ doTestByText("class C(meta<caret>):\n" +
+ " pass\n");
+ myFixture.checkResult("class C(metaclass=):\n" +
+ " pass\n");
+ }
+
private void doTest() {
CamelHumpMatcher.forceStartMatching(getTestRootDisposable());
final String testName = "completion/" + getTestName(true);
@@ -59,4 +67,10 @@
myFixture.completeBasic();
myFixture.checkResultByFile(testName + ".after.py");
}
+
+ private List<String> doTestByText(String text) {
+ myFixture.configureByText(PythonFileType.INSTANCE, text);
+ myFixture.completeBasic();
+ return myFixture.getLookupElementStrings();
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/PyBlockEvaluatorTest.java b/python/testSrc/com/jetbrains/python/PyBlockEvaluatorTest.java
index 368c055..75665ac 100644
--- a/python/testSrc/com/jetbrains/python/PyBlockEvaluatorTest.java
+++ b/python/testSrc/com/jetbrains/python/PyBlockEvaluatorTest.java
@@ -21,7 +21,7 @@
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyStringLiteralExpression;
import com.jetbrains.python.psi.PyUtil;
-import com.jetbrains.python.psi.impl.PyBlockEvaluator;
+import com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator;
import org.junit.Assert;
import java.util.ArrayList;
diff --git a/python/testSrc/com/jetbrains/python/PySdkFlavorTest.java b/python/testSrc/com/jetbrains/python/PySdkFlavorTest.java
new file mode 100644
index 0000000..e934eb9
--- /dev/null
+++ b/python/testSrc/com/jetbrains/python/PySdkFlavorTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
+import com.jetbrains.python.fixtures.PyTestCase;
+import com.jetbrains.python.psi.LanguageLevel;
+import com.jetbrains.python.sdk.PythonSdkAdditionalData;
+import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
+import com.jetbrains.python.sdk.flavors.PyPySdkFlavor;
+import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
+import com.jetbrains.python.sdk.flavors.UnixPythonSdkFlavor;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author vlan
+ */
+public class PySdkFlavorTest extends PyTestCase {
+ public void testPython27VersionString() {
+ final PythonSdkFlavor flavor = UnixPythonSdkFlavor.INSTANCE;
+ final String versionOutput = "Python 2.7.6\n";
+ final Sdk mockSdk = createMockSdk(flavor, versionOutput);
+ assertEquals("Python 2.7.6", mockSdk.getVersionString());
+ assertEquals(LanguageLevel.PYTHON27, flavor.getLanguageLevel(mockSdk));
+ }
+
+ public void testPython34VersionString() {
+ final PythonSdkFlavor flavor = UnixPythonSdkFlavor.INSTANCE;
+ final String versionOutput = "Python 3.4.0\n";
+ final Sdk mockSdk = createMockSdk(flavor, versionOutput);
+ assertEquals("Python 3.4.0", mockSdk.getVersionString());
+ assertEquals(LanguageLevel.PYTHON34, flavor.getLanguageLevel(mockSdk));
+ }
+
+ public void testJython25VersionString() {
+ final PythonSdkFlavor flavor = JythonSdkFlavor.INSTANCE;
+ final String versionOutput = "Jython 2.5.3\n";
+ final Sdk mockSdk = createMockSdk(flavor, versionOutput);
+ assertEquals("Jython 2.5.3", mockSdk.getVersionString());
+ assertEquals(LanguageLevel.PYTHON25, flavor.getLanguageLevel(mockSdk));
+ }
+
+ public void testJython25WithWarningsVersionString() {
+ final PythonSdkFlavor flavor = JythonSdkFlavor.INSTANCE;
+ final String versionOutput = "\"my\" variable $jythonHome masks earlier declaration in same scope at /usr/bin/jython line 15.\n" +
+ "Jython 2.5.3\n";
+ final Sdk mockSdk = createMockSdk(flavor, versionOutput);
+ assertEquals("Jython 2.5.3", mockSdk.getVersionString());
+ assertEquals(LanguageLevel.PYTHON25, flavor.getLanguageLevel(mockSdk));
+ }
+
+ public void testPyPy23VersionString() {
+ final PythonSdkFlavor flavor = PyPySdkFlavor.INSTANCE;
+ final String versionOutput = "Python 2.7.6 (32f35069a16d819b58c1b6efb17c44e3e53397b2, Jun 10 2014, 00:42:27)\n" +
+ "[PyPy 2.3.1 with GCC 4.8.2]\n";
+ final Sdk mockSdk = createMockSdk(flavor, versionOutput);
+ assertEquals("PyPy 2.3.1 [Python 2.7.6]", mockSdk.getVersionString());
+ assertEquals(LanguageLevel.PYTHON27, flavor.getLanguageLevel(mockSdk));
+ assertEquals("__builtin__.py", PythonSdkType.getBuiltinsFileName(mockSdk));
+ }
+
+ public void testPyPy323VersionString() {
+ final PythonSdkFlavor flavor = PyPySdkFlavor.INSTANCE;
+ final String versionOutput = "Python 3.2.5 (986752d005bb6c65ce418113e4c3cd115f61a9b4, Jun 23 2014, 00:23:34)\n" +
+ "[PyPy 2.3.1 with GCC 4.8.2]\n";
+ final Sdk mockSdk = createMockSdk(flavor, versionOutput);
+ assertEquals("PyPy 2.3.1 [Python 3.2.5]", mockSdk.getVersionString());
+ assertEquals(LanguageLevel.PYTHON32, flavor.getLanguageLevel(mockSdk));
+ assertEquals("builtins.py", PythonSdkType.getBuiltinsFileName(mockSdk));
+ }
+
+ // TODO: Add tests for MayaPy and IronPython SDK flavors
+
+ @NotNull
+ private static Sdk createMockSdk(@NotNull PythonSdkFlavor flavor, @NotNull String versionOutput) {
+ final String versionString = flavor.getVersionStringFromOutput(versionOutput);
+ final ProjectJdkImpl sdk = new ProjectJdkImpl("Test", PythonSdkType.getInstance(), "/path/to/sdk", versionString);
+ sdk.setSdkAdditionalData(new PythonSdkAdditionalData(flavor));
+ return sdk;
+ }
+}
diff --git a/python/testSrc/com/jetbrains/python/PythonAutoPopupTest.java b/python/testSrc/com/jetbrains/python/PythonAutoPopupTest.java
index 6daf6de..0df52f8 100644
--- a/python/testSrc/com/jetbrains/python/PythonAutoPopupTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonAutoPopupTest.java
@@ -18,6 +18,7 @@
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.testFramework.fixtures.CompletionAutoPopupTester;
import com.jetbrains.python.fixtures.PyTestCase;
+import org.jetbrains.annotations.NotNull;
/**
* @author peter
@@ -39,7 +40,7 @@
}
@Override
- protected void invokeTestRunnable(Runnable runnable) throws Exception {
+ protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
myTester.runWithAutoPopupEnabled(runnable);
}
diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java
index da7888e..b57ae35 100644
--- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java
@@ -606,4 +606,13 @@
myFixture.checkResult("bar = {'a': '1'}\n" +
"print bar<caret>['a']");
}
+
+ // PY-1860
+ public void testDunderMetaClass() {
+ doTestByText("class C(object):\n" +
+ " __meta<caret>\n");
+ myFixture.checkResult("class C(object):\n" +
+ " __metaclass__ = \n");
+
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
index 3404194..6850c3b 100644
--- a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
+++ b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
@@ -16,13 +16,14 @@
package com.jetbrains.python.fixtures;
import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.module.EmptyModuleType;
+import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.impl.FilePropertyPusher;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -39,6 +40,7 @@
import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.PythonMockSdk;
+import com.jetbrains.python.PythonModuleTypeBase;
import com.jetbrains.python.PythonTestUtil;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyClass;
@@ -92,6 +94,8 @@
setLanguageLevel(null);
myFixture.tearDown();
myFixture = null;
+ final PythonLanguageLevelPusher levelPusher = Extensions.findExtension(FilePropertyPusher.EP_NAME, PythonLanguageLevelPusher.class);
+ levelPusher.flushLanguageLevelCache();
super.tearDown();
}
@@ -149,7 +153,7 @@
@Override
public ModuleType getModuleType() {
- return EmptyModuleType.getInstance();
+ return PythonModuleTypeBase.getInstance();
}
@Override
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java
index 22743ac..b4ae36c 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java
@@ -89,6 +89,16 @@
doTest();
}
+ // PY-13051
+ public void testCallDictSubscriptionExpression() {
+ doTest();
+ }
+
+ // PY-12004
+ public void testLocalCallableClass() {
+ doTest();
+ }
+
private void doTest() {
setLanguageLevel(LanguageLevel.PYTHON27);
try {
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
index 2141736..e614edd 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
@@ -361,6 +361,11 @@
doTest();
}
+ // PY-13418
+ public void testOneUnsedOneMarked() {
+ doMultiFileTest();
+ }
+
@NotNull
@Override
protected Class<? extends PyInspection> getInspectionClass() {