From 9ac5a475dc2da33f697734639fd85ce80d0c4fb1 Mon Sep 17 00:00:00 2001 From: Oleg Sukhodolsky Date: Fri, 30 Aug 2013 07:45:11 +0400 Subject: [PATCH 01/10] Fix tests: we should declare resource bundle only once --- python/src/META-INF/python-plugin-common.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 528183691f29..75fe8c3eb215 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -3,8 +3,6 @@ - com.jetbrains.python.PyBundle - Date: Fri, 30 Aug 2013 17:19:22 +0200 Subject: [PATCH 02/10] extract community part out of python-ide module --- python/build/pycharm_build.gant | 4 +- python/ide/python-ide-community.iml | 18 + .../python/PlatformPythonModuleType.java | 21 + .../python/PyCharmInitialConfigurator.java | 79 +++ .../python/PyIdeCommonOptionsForm.form | 128 ++++ .../python/PyIdeCommonOptionsForm.java | 352 +++++++++++ .../python/PyIdeCommonOptionsFormFactory.java | 15 + .../jetbrains/python/PyModuleListener.java | 36 ++ .../python/PyOptionsApplicabilityFilter.java | 14 + .../python/PythonFileTypeFactory.java | 21 + .../python/PythonModuleTypeManager.java | 14 + .../python/PythonSdkChooserCombo.java | 74 +++ .../python/PythonSdkConfigurator.java | 79 +++ .../python/PythonSourceRootConfigurator.java | 104 ++++ .../python/buildout/BuildoutConfigurable.form | 35 ++ .../python/buildout/BuildoutConfigurable.java | 171 ++++++ .../buildout/BuildoutFacetConfigurator.java | 63 ++ .../buildout/BuildoutModulesConfigurable.java | 23 + .../configuration/AddVEnvOptionsDialog.form | 35 ++ .../configuration/AddVEnvOptionsDialog.java | 35 ++ .../python/configuration/EditSdkDialog.form | 69 +++ .../python/configuration/EditSdkDialog.java | 106 ++++ .../PyActiveSdkConfigurable.form | 40 ++ .../PyActiveSdkConfigurable.java | 203 +++++++ .../PyActiveSdkModuleConfigurable.java | 60 ++ .../PyConfigurableInterpreterList.java | 68 +++ .../PyConfigureInterpretersLinkPanel.java | 41 ++ .../PyDependenciesConfigurable.java | 32 + .../configuration/PyDiffPreviewProvider.java | 59 ++ .../PyModuleDependenciesConfigurable.form | 29 + .../PyModuleDependenciesConfigurable.java | 118 ++++ .../PythonContentEntriesConfigurable.java | 42 ++ .../configuration/PythonPathEditor.java | 316 ++++++++++ .../configuration/PythonSdkConfigurable.form | 32 + .../configuration/PythonSdkConfigurable.java | 571 ++++++++++++++++++ .../VirtualEnvProjectFilter.java | 50 ++ .../PythonNewDirectoryProjectAction.java | 75 +++ .../PythonNewDirectoryProjectDialog.java | 292 +++++++++ python/python-ide.iml | 1 + python/src/META-INF/python-plugin-common.xml | 1 + 40 files changed, 3524 insertions(+), 2 deletions(-) create mode 100644 python/ide/python-ide-community.iml create mode 100644 python/ide/src/com/jetbrains/python/PlatformPythonModuleType.java create mode 100644 python/ide/src/com/jetbrains/python/PyCharmInitialConfigurator.java create mode 100644 python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.form create mode 100644 python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java create mode 100644 python/ide/src/com/jetbrains/python/PyIdeCommonOptionsFormFactory.java create mode 100644 python/ide/src/com/jetbrains/python/PyModuleListener.java create mode 100644 python/ide/src/com/jetbrains/python/PyOptionsApplicabilityFilter.java create mode 100644 python/ide/src/com/jetbrains/python/PythonFileTypeFactory.java create mode 100644 python/ide/src/com/jetbrains/python/PythonModuleTypeManager.java create mode 100644 python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java create mode 100644 python/ide/src/com/jetbrains/python/PythonSdkConfigurator.java create mode 100644 python/ide/src/com/jetbrains/python/PythonSourceRootConfigurator.java create mode 100644 python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.form create mode 100644 python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.java create mode 100644 python/ide/src/com/jetbrains/python/buildout/BuildoutFacetConfigurator.java create mode 100644 python/ide/src/com/jetbrains/python/buildout/BuildoutModulesConfigurable.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.form create mode 100644 python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/EditSdkDialog.form create mode 100644 python/ide/src/com/jetbrains/python/configuration/EditSdkDialog.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.form create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyConfigureInterpretersLinkPanel.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyDependenciesConfigurable.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyDiffPreviewProvider.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyModuleDependenciesConfigurable.form create mode 100644 python/ide/src/com/jetbrains/python/configuration/PyModuleDependenciesConfigurable.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PythonContentEntriesConfigurable.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PythonPathEditor.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.form create mode 100644 python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java create mode 100644 python/ide/src/com/jetbrains/python/configuration/VirtualEnvProjectFilter.java create mode 100644 python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java create mode 100644 python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index 6ca80732d84d..73910d56afaf 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -26,8 +26,8 @@ private List pycharmPlatformApiModules() { private List pycharmImplementationModules() { //modules to put into pycharm.jar - return ["yaml", "graph", "coverage-common", "python-community", "python", "python-ide", "python-openapi", "python-psi-api", - "duplicates", "duplicates-xml"] + return ["yaml", "graph", "coverage-common", "python-community", "python", "python-ide", "python-ide-community", + "python-openapi", "python-psi-api", "duplicates", "duplicates-xml"] } class Paths { diff --git a/python/ide/python-ide-community.iml b/python/ide/python-ide-community.iml new file mode 100644 index 000000000000..9cfa2aa868d5 --- /dev/null +++ b/python/ide/python-ide-community.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/python/ide/src/com/jetbrains/python/PlatformPythonModuleType.java b/python/ide/src/com/jetbrains/python/PlatformPythonModuleType.java new file mode 100644 index 000000000000..130e3e0ad974 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PlatformPythonModuleType.java @@ -0,0 +1,21 @@ +package com.jetbrains.python; + +import com.intellij.ide.util.projectWizard.EmptyModuleBuilder; +import com.intellij.openapi.module.ModuleType; +import org.jetbrains.annotations.NotNull; + +/** + * @author yole + */ +public class PlatformPythonModuleType extends PythonModuleTypeBase { + @NotNull + @Override + public EmptyModuleBuilder createModuleBuilder() { + return new EmptyModuleBuilder() { + @Override + public ModuleType getModuleType() { + return getInstance(); + } + }; + } +} diff --git a/python/ide/src/com/jetbrains/python/PyCharmInitialConfigurator.java b/python/ide/src/com/jetbrains/python/PyCharmInitialConfigurator.java new file mode 100644 index 000000000000..2d18eb67e6dd --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PyCharmInitialConfigurator.java @@ -0,0 +1,79 @@ +package com.jetbrains.python; + +import com.intellij.application.options.InitialConfigurationDialog; +import com.intellij.codeInsight.CodeInsightSettings; +import com.intellij.ide.AppLifecycleListener; +import com.intellij.ide.OpenJdkNotifier; +import com.intellij.ide.ui.UISettings; +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.util.messages.MessageBus; +import com.jetbrains.python.codeInsight.PyCodeInsightSettings; +import org.jetbrains.annotations.NonNls; + +import javax.swing.*; + +/** + * @author yole + */ +@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "UtilityClassWithPublicConstructor"}) +public class PyCharmInitialConfigurator { + @NonNls private static final String DISPLAYED_PROPERTY = "PyCharm.initialConfigurationShown"; + + public PyCharmInitialConfigurator(MessageBus bus, final PropertiesComponent propertiesComponent, final FileTypeManager fileTypeManager) { + OpenJdkNotifier.checkJdk(bus); + if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration", false)) { + propertiesComponent.setValue("PyCharm.InitialConfiguration", "true"); + EditorSettingsExternalizable.getInstance().setVirtualSpace(false); + } + if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration.V2", false)) { + propertiesComponent.setValue("PyCharm.InitialConfiguration.V2", "true"); + final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance().getCurrentSettings(); + settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; + settings.getCommonSettings(PythonLanguage.getInstance()).ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; + UISettings.getInstance().SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true; + } + if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration.V3", false)) { + propertiesComponent.setValue("PyCharm.InitialConfiguration.V3", "true"); + UISettings.getInstance().SHOW_MEMORY_INDICATOR = false; + final String ignoredFilesList = fileTypeManager.getIgnoredFilesList(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + FileTypeManager.getInstance().setIgnoredFilesList(ignoredFilesList + ";*$py.class"); + } + }); + } + if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration.V4", false)) { + propertiesComponent.setValue("PyCharm.InitialConfiguration.V4", "true"); + PyCodeInsightSettings.getInstance().SHOW_IMPORT_POPUP = false; + } + if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration.V5", false)) { + propertiesComponent.setValue("PyCharm.InitialConfiguration.V5", "true"); + CodeInsightSettings.getInstance().REFORMAT_ON_PASTE = CodeInsightSettings.NO_REFORMAT; + } + if (!propertiesComponent.isValueSet(DISPLAYED_PROPERTY)) { + bus.connect().subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() { + @Override + public void welcomeScreenDisplayed() { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + propertiesComponent.setValue(DISPLAYED_PROPERTY, "true"); + showInitialConfigurationDialog(); + } + }); + } + }); + } + } + + private static void showInitialConfigurationDialog() { + final JFrame frame = WindowManager.getInstance().findVisibleFrame(); + new InitialConfigurationDialog(frame, "Python").show(); + } +} diff --git a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.form b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.form new file mode 100644 index 000000000000..108b9af1902f --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.form @@ -0,0 +1,128 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java new file mode 100644 index 000000000000..0ee44d57b756 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsForm.java @@ -0,0 +1,352 @@ +package com.jetbrains.python; + +import com.intellij.execution.configuration.EnvironmentVariablesComponent; +import com.intellij.execution.util.PathMappingsComponent; +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkModel; +import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; +import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.ui.HideableDecorator; +import com.intellij.ui.RawCommandLineEditor; +import com.intellij.ui.components.JBCheckBox; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.PathMappingSettings; +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; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author yole + */ +public class PyIdeCommonOptionsForm implements AbstractPyCommonOptionsForm { + private JPanel myMainPanel; + private EnvironmentVariablesComponent myEnvsComponent; + private RawCommandLineEditor myInterpreterOptionsTextField; + private TextFieldWithBrowseButton myWorkingDirectoryTextField; + private JComboBox myInterpreterComboBox; + private JBLabel myPythonInterpreterJBLabel; + private JLabel myProjectLabel; + private JComboBox myModuleCombo; + private JPanel myConfigureInterpretersPanel; + private String mySelectedSdkHome = null; + private PathMappingsComponent myPathMappingsComponent; + private JPanel myHideablePanel; + private JBCheckBox myAddContentRootsCheckbox; + private JBCheckBox myAddSourceRootsCheckbox; + + private JComponent labelAnchor; + private final Project myProject; + private List myPythonSdks; + private boolean myInterpreterRemote; + private final HideableDecorator myDecorator; + + public PyIdeCommonOptionsForm(PyCommonOptionsFormData data) { + myProject = data.getProject(); + myWorkingDirectoryTextField.addBrowseFolderListener("Select Working Directory", "", data.getProject(), + FileChooserDescriptorFactory.createSingleFolderDescriptor()); + + myPythonSdks = new ArrayList(PythonSdkType.getAllSdks()); + myPythonSdks.add(0, null); + + myInterpreterComboBox.setModel(new CollectionComboBoxModel(myPythonSdks, null)); + + final Module[] modules = ModuleManager.getInstance(data.getProject()).getModules(); + if (modules.length == 1) { + setModule(modules[0]); + myProjectLabel.setVisible(false); + myModuleCombo.setVisible(false); + } + else { + final List validModules = data.getValidModules(); + Module selection = validModules.size() > 0 ? validModules.get(0) : null; + myModuleCombo.setModel(new CollectionComboBoxModel(validModules, selection)); + myModuleCombo.setRenderer(new ModuleListCellRenderer()); + myModuleCombo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + updateDefaultInterpreter((Module)myModuleCombo.getSelectedItem()); + } + }); + updateDefaultInterpreter((Module)myModuleCombo.getSelectedItem()); + } + + setAnchor(myEnvsComponent.getLabel()); + myPathMappingsComponent.setAnchor(myEnvsComponent.getLabel()); + + if (data.showConfigureInterpretersLink()) { + myConfigureInterpretersPanel.add(new PyConfigureInterpretersLinkPanel(myMainPanel)); + } + + addInterpreterComboBoxActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent event) { + updateRemoteInterpreterMode(); + } + } + ); + + updateRemoteInterpreterMode(); + + myDecorator = new HideableDecorator(myHideablePanel, "Environment", false) { + @Override + protected void on() { + super.on(); + storeState(); + } + + @Override + protected void off() { + super.off(); + storeState(); + } + private void storeState() { + PropertiesComponent.getInstance().setValue(EXPAND_PROPERTY_KEY, String.valueOf(isExpanded())); + } + }; + myDecorator.setOn(PropertiesComponent.getInstance().getBoolean(EXPAND_PROPERTY_KEY, true)); + myDecorator.setContentComponent(myMainPanel); + } + + @Override + public JComponent getMainPanel() { + return myHideablePanel; + } + + @Override + public void subscribe() { + PyConfigurableInterpreterList myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); + ProjectSdksModel myProjectSdksModel = myInterpreterList.getModel(); + myProjectSdksModel.addListener(new MyListener(this, myInterpreterList)); + updateSdkList(true, myInterpreterList); + } + + @Override + public JComponent getAnchor() { + return labelAnchor; + } + + @Override + public void setAnchor(JComponent anchor) { + labelAnchor = anchor; + myEnvsComponent.setAnchor(anchor); + myPythonInterpreterJBLabel.setAnchor(anchor); + } + + public String getInterpreterOptions() { + return myInterpreterOptionsTextField.getText().trim(); + } + + public void setInterpreterOptions(String interpreterOptions) { + myInterpreterOptionsTextField.setText(interpreterOptions); + } + + public String getWorkingDirectory() { + return FileUtil.toSystemIndependentName(myWorkingDirectoryTextField.getText().trim()); + } + + public void setWorkingDirectory(String workingDirectory) { + myWorkingDirectoryTextField.setText(workingDirectory == null ? "" : FileUtil.toSystemDependentName(workingDirectory)); + } + + @Override + public String getSdkHome() { + final Sdk selectedSdk = (Sdk)myInterpreterComboBox.getSelectedItem(); + return selectedSdk == null ? null : selectedSdk.getHomePath(); + } + + @Override + public void setSdkHome(String sdkHome) { + mySelectedSdkHome = sdkHome; + } + + @Nullable + @Override + public Module getModule() { + final Module selectedItem = (Module)myModuleCombo.getSelectedItem(); + if (selectedItem != null) { + return selectedItem; + } + final Module[] modules = ModuleManager.getInstance(myProject).getModules(); + if (modules.length == 1) { + return modules[0]; + } + return null; + } + + @Override + public void setModule(Module module) { + myModuleCombo.setSelectedItem(module); + updateDefaultInterpreter(module); + } + + private void updateDefaultInterpreter(Module module) { + final Sdk sdk = module == null ? null : ModuleRootManager.getInstance(module).getSdk(); + String projectSdkName = sdk == null ? "none" : sdk.getName(); + myInterpreterComboBox.setRenderer(new SdkListCellRenderer("Project Default (" + projectSdkName + ")")); + } + + public void updateSdkList(boolean preserveSelection, PyConfigurableInterpreterList myInterpreterList) { + myPythonSdks = myInterpreterList.getAllPythonSdks(); + Sdk selection = preserveSelection ? (Sdk)myInterpreterComboBox.getSelectedItem() : null; + if (!myPythonSdks.contains(selection)) { + selection = null; + } + myPythonSdks.add(0, null); + myInterpreterComboBox.setModel(new CollectionComboBoxModel(myPythonSdks, selection)); + } + + @Override + public boolean isUseModuleSdk() { + return myInterpreterComboBox.getSelectedItem() == null; + } + + @Override + public void setUseModuleSdk(boolean useModuleSdk) { + myInterpreterComboBox.setSelectedItem(useModuleSdk ? null : PythonSdkType.findSdkByPath(myPythonSdks, mySelectedSdkHome)); + } + + public boolean isPassParentEnvs() { + return myEnvsComponent.isPassParentEnvs(); + } + + public void setPassParentEnvs(boolean passParentEnvs) { + myEnvsComponent.setPassParentEnvs(passParentEnvs); + } + + public Map getEnvs() { + return myEnvsComponent.getEnvs(); + } + + public void setEnvs(Map envs) { + myEnvsComponent.setEnvs(envs); + } + + @Override + @Nullable + public PathMappingSettings getMappingSettings() { + if (myInterpreterRemote) { + return myPathMappingsComponent.getMappingSettings(); + } + else { + return null; + } + } + + @Override + public void setMappingSettings(@Nullable PathMappingSettings mappingSettings) { + myPathMappingsComponent.setMappingSettings(mappingSettings); + } + + @Override + public boolean addContentRoots() { + return myAddContentRootsCheckbox.isSelected(); + } + + @Override + public boolean addSourceRoots() { + return myAddSourceRootsCheckbox.isSelected(); + } + + @Override + public void addContentRoots(boolean add) { + myAddContentRootsCheckbox.setSelected(add); + } + + @Override + public void addSourceRoots(boolean add) { + myAddSourceRootsCheckbox.setSelected(add); + } + + private void createUIComponents() { + myInterpreterComboBox = new ComboBox(100); + } + + private void setRemoteInterpreterMode(boolean isInterpreterRemote) { + myInterpreterRemote = isInterpreterRemote; + myPathMappingsComponent.setVisible(isInterpreterRemote); + } + + private void updateRemoteInterpreterMode() { + setRemoteInterpreterMode(PySdkUtil.isRemote(getSdkSelected())); + } + + @Nullable + private Sdk getSdkSelected() { + String sdkHome = getSdkHome(); + if (StringUtil.isEmptyOrSpaces(sdkHome)) { + final Sdk projectJdk = PythonSdkType.findPythonSdk(getModule()); + if (projectJdk != null) { + sdkHome = projectJdk.getHomePath(); + } + } + + return PythonSdkType.findSdkByPath(sdkHome); + } + + @Override + public void addInterpreterComboBoxActionListener(ActionListener listener) { + myInterpreterComboBox.addActionListener(listener); + } + + @Override + public void removeInterpreterComboBoxActionListener(ActionListener listener) { + myInterpreterComboBox.removeActionListener(listener); + } + + private static class MyListener implements SdkModel.Listener { + private final PyIdeCommonOptionsForm myForm; + private PyConfigurableInterpreterList myInterpreterList; + + public MyListener(PyIdeCommonOptionsForm form, PyConfigurableInterpreterList interpreterList) { + myForm = form; + myInterpreterList = interpreterList; + } + + + private void update() { + myForm.updateSdkList(true, myInterpreterList); + } + + @Override + public void sdkAdded(Sdk sdk) { + update(); + } + + @Override + public void beforeSdkRemove(Sdk sdk) { + update(); + } + + @Override + public void sdkChanged(Sdk sdk, String previousName) { + update(); + } + + @Override + public void sdkHomeSelected(Sdk sdk, String newSdkHome) { + } + } +} diff --git a/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsFormFactory.java b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsFormFactory.java new file mode 100644 index 000000000000..fee2954acc4b --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PyIdeCommonOptionsFormFactory.java @@ -0,0 +1,15 @@ +package com.jetbrains.python; + +import com.jetbrains.python.run.AbstractPyCommonOptionsForm; +import com.jetbrains.python.run.PyCommonOptionsFormData; +import com.jetbrains.python.run.PyCommonOptionsFormFactory; + +/** + * @author yole + */ +public class PyIdeCommonOptionsFormFactory extends PyCommonOptionsFormFactory { + @Override + public PyIdeCommonOptionsForm createForm(PyCommonOptionsFormData data) { + return new PyIdeCommonOptionsForm(data); + } +} diff --git a/python/ide/src/com/jetbrains/python/PyModuleListener.java b/python/ide/src/com/jetbrains/python/PyModuleListener.java new file mode 100644 index 000000000000..22edad8278e0 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PyModuleListener.java @@ -0,0 +1,36 @@ +package com.jetbrains.python; + +import com.intellij.ProjectTopics; +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.ModuleAdapter; +import com.intellij.openapi.project.Project; +import com.intellij.util.messages.MessageBus; +import com.jetbrains.python.run.AbstractPythonRunConfiguration; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author yole + */ +public class PyModuleListener { + public PyModuleListener(MessageBus messageBus) { + messageBus.connect().subscribe(ProjectTopics.MODULES, new ModuleAdapter() { + @Override + public void beforeModuleRemoved(Project project, Module module) { + final RunManagerEx runManager = RunManagerEx.getInstanceEx(project); + final Collection configurations = new ArrayList(runManager.getSortedConfigurations()); + for (RunnerAndConfigurationSettings configuration : configurations) { + if (configuration.getConfiguration() instanceof AbstractPythonRunConfiguration) { + final Module configModule = ((AbstractPythonRunConfiguration)configuration.getConfiguration()).getModule(); + if (configModule == module) { + runManager.removeConfiguration(configuration); + } + } + } + } + }); + } +} diff --git a/python/ide/src/com/jetbrains/python/PyOptionsApplicabilityFilter.java b/python/ide/src/com/jetbrains/python/PyOptionsApplicabilityFilter.java new file mode 100644 index 000000000000..7e27275e8e0e --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PyOptionsApplicabilityFilter.java @@ -0,0 +1,14 @@ +package com.jetbrains.python; + +import com.intellij.application.options.OptionId; +import com.intellij.application.options.OptionsApplicabilityFilter; + +/** + * @author yole + */ +public class PyOptionsApplicabilityFilter extends OptionsApplicabilityFilter { + @Override + public boolean isOptionApplicable(OptionId optionId) { + return optionId == OptionId.RENAME_IN_PLACE; + } +} diff --git a/python/ide/src/com/jetbrains/python/PythonFileTypeFactory.java b/python/ide/src/com/jetbrains/python/PythonFileTypeFactory.java new file mode 100644 index 000000000000..25a2ecc42ad4 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PythonFileTypeFactory.java @@ -0,0 +1,21 @@ +package com.jetbrains.python; + +import com.intellij.ide.highlighter.XmlFileType; +import com.intellij.openapi.fileTypes.FileTypeConsumer; +import com.intellij.openapi.fileTypes.FileTypeFactory; +import com.jetbrains.pyqt.QtUIFileType; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +/** + * IDE version of file type factory - does not use UltimateVerifier. + * + * @author yole + */ +public class PythonFileTypeFactory extends FileTypeFactory { + public void createFileTypes(@NonNls @NotNull final FileTypeConsumer consumer) { + consumer.consume(PythonFileType.INSTANCE, "py;pyw;"); + consumer.consume(QtUIFileType.INSTANCE, "ui"); + consumer.consume(XmlFileType.INSTANCE, "qrc"); + } +} \ No newline at end of file diff --git a/python/ide/src/com/jetbrains/python/PythonModuleTypeManager.java b/python/ide/src/com/jetbrains/python/PythonModuleTypeManager.java new file mode 100644 index 000000000000..89b682894aae --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PythonModuleTypeManager.java @@ -0,0 +1,14 @@ +package com.jetbrains.python; + +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.impl.ModuleTypeManagerImpl; + +/** + * @author yole + */ +public class PythonModuleTypeManager extends ModuleTypeManagerImpl { + @Override + public ModuleType getDefaultModuleType() { + return new PlatformPythonModuleType(); + } +} diff --git a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java new file mode 100644 index 000000000000..a295070cfb3d --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java @@ -0,0 +1,74 @@ +package com.jetbrains.python; + +import com.intellij.openapi.options.ShowSettingsUtil; +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.util.Condition; +import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.ui.ComboboxWithBrowseButton; +import com.intellij.util.containers.ContainerUtil; +import com.jetbrains.python.configuration.PythonSdkConfigurable; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import com.jetbrains.python.sdk.PythonSdkType; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +/** + * @author yole + */ +public class PythonSdkChooserCombo extends ComboboxWithBrowseButton { + private final List myChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList(); + + //public PythonSdkChooserCombo(final Condition acceptableSdkCondition) { + // this(PythonSdkType.getAllSdks(), acceptableSdkCondition); + //} + + public PythonSdkChooserCombo(final Project project, List sdks, final Condition acceptableSdkCondition) { + Sdk initialSelection = null; + for (Sdk sdk : sdks) { + if (acceptableSdkCondition.value(sdk)) { + initialSelection = sdk; + break; + } + } + getComboBox().setModel(new CollectionComboBoxModel(sdks, initialSelection)); + getComboBox().setRenderer(new SdkListCellRenderer("") { + @Override + protected Icon getSdkIcon(Sdk sdk) { + final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk); + return flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon(); + } + }); + addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + final PythonSdkConfigurable configurable = new PythonSdkConfigurable(project); + configurable.setNewProject(true); + ShowSettingsUtil.getInstance().editConfigurable(PythonSdkChooserCombo.this, configurable); + Sdk selection = configurable.getRealSelectedSdk(); + final List sdks = PythonSdkType.getAllSdks(); + getComboBox().setModel(new CollectionComboBoxModel(sdks, selection)); + notifyChanged(e); + } + }); + getComboBox().addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + notifyChanged(e); + } + }); + } + + private void notifyChanged(ActionEvent e) { + for (ActionListener changedListener : myChangedListeners) { + changedListener.actionPerformed(e); + } + } + + public void addChangedListener(ActionListener listener) { + myChangedListeners.add(listener); + } +} diff --git a/python/ide/src/com/jetbrains/python/PythonSdkConfigurator.java b/python/ide/src/com/jetbrains/python/PythonSdkConfigurator.java new file mode 100644 index 000000000000..8a5397dfb044 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PythonSdkConfigurator.java @@ -0,0 +1,79 @@ +package com.jetbrains.python; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkAdditionalData; +import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.platform.DirectoryProjectConfigurator; +import com.intellij.util.SystemProperties; +import com.jetbrains.python.sdk.PreferredSdkComparator; +import com.jetbrains.python.sdk.PythonSdkAdditionalData; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import com.jetbrains.python.sdk.PythonSdkType; +import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * @author dcheryasov + */ +public class PythonSdkConfigurator implements DirectoryProjectConfigurator { + + public void configureProject(final Project project, @NotNull final VirtualFile baseDir, Ref moduleRef) { + // it it a virtualenv? + final PythonSdkType py_sdk_type = PythonSdkType.getInstance(); + //find virtualEnv in project directory + final List candidates = new ArrayList(); + if (project != null) { + final VirtualFile rootDir = project.getBaseDir(); + if (rootDir != null) + candidates.addAll(VirtualEnvSdkFlavor.findInDirectory(rootDir)); + if (!candidates.isEmpty()) { + String filePath = candidates.get(0); + if (StringUtil.startsWithChar(filePath, '~')) { + final String home = SystemProperties.getUserHome(); + filePath = home + filePath.substring(1); + } + final Sdk virtualEnvSdk = SdkConfigurationUtil.createAndAddSDK(filePath, py_sdk_type); + if (virtualEnvSdk != null) { + SdkConfigurationUtil.setDirectoryProjectSdk(project, virtualEnvSdk); + SdkAdditionalData additionalData = virtualEnvSdk.getSdkAdditionalData(); + if (additionalData == null) { + additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(virtualEnvSdk.getHomePath())); + ((ProjectJdkImpl)virtualEnvSdk).setSdkAdditionalData(additionalData); + } + ((PythonSdkAdditionalData) additionalData).associateWithProject(project); + return; + } + return; + } + } + + + final Sdk existing_sdk = ProjectRootManager.getInstance(project).getProjectSdk(); + if (existing_sdk != null && existing_sdk.getSdkType() == py_sdk_type) return; // SdkConfigurationUtil does the same + final File py_exe = PythonSdkType.findExecutableFile(new File(project.getBasePath(), "bin"), "python"); + if (py_exe != null) { + final File env_root = PythonSdkType.getVirtualEnvRoot(py_exe.getPath()); + if (env_root != null) { + // yes, an unknown virtualenv; set it up as SDK + final Sdk an_sdk = SdkConfigurationUtil.createAndAddSDK(py_exe.getPath(), py_sdk_type); + if (an_sdk != null) { + SdkConfigurationUtil.setDirectoryProjectSdk(project, an_sdk); + return; + } + } + } + // default + SdkConfigurationUtil.configureDirectoryProjectSdk(project, new PreferredSdkComparator(), py_sdk_type); + } +} diff --git a/python/ide/src/com/jetbrains/python/PythonSourceRootConfigurator.java b/python/ide/src/com/jetbrains/python/PythonSourceRootConfigurator.java new file mode 100644 index 000000000000..fd6d1615d12a --- /dev/null +++ b/python/ide/src/com/jetbrains/python/PythonSourceRootConfigurator.java @@ -0,0 +1,104 @@ +package com.jetbrains.python; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.impl.LoadTextUtil; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ContentEntry; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.SourceFolder; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.platform.DirectoryProjectConfigurator; +import com.intellij.psi.PsiFileFactory; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +/** + * @author yole + */ +public class PythonSourceRootConfigurator implements DirectoryProjectConfigurator { + @NonNls private static final String SETUP_PY = "setup.py"; + + @Override + public void configureProject(Project project, @NotNull final VirtualFile baseDir, Ref moduleRef) { + VirtualFile setupPy = baseDir.findChild(SETUP_PY); + if (setupPy != null) { + final CharSequence content = LoadTextUtil.loadText(setupPy); + PyFile setupPyFile = (PyFile) PsiFileFactory.getInstance(project).createFileFromText(SETUP_PY, content.toString()); + final SetupCallVisitor visitor = new SetupCallVisitor(); + setupPyFile.accept(visitor); + String dir = visitor.getRootPackageDir(); + if (dir != null) { + final VirtualFile rootPackageVFile = baseDir.findFileByRelativePath(dir); + addSourceRoot(project, baseDir, rootPackageVFile, true); + } + } + + VirtualFile web2Py = baseDir.findChild("web2py"); + if (web2Py != null) { + addSourceRoot(project, baseDir, web2Py, false); + } + } + + private static void addSourceRoot(Project project, final VirtualFile baseDir, final VirtualFile root, final boolean unique) { + final Module[] modules = ModuleManager.getInstance(project).getModules(); + if (modules.length > 0 && root != null) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + final ModifiableRootModel model = ModuleRootManager.getInstance(modules[0]).getModifiableModel(); + final ContentEntry[] contentEntries = model.getContentEntries(); + for (ContentEntry contentEntry : contentEntries) { + if (Comparing.equal(contentEntry.getFile(), baseDir)) { + final SourceFolder[] sourceFolders = contentEntry.getSourceFolders(); + if (!unique || sourceFolders.length == 0) { + contentEntry.addSourceFolder(root, false); + } + } + } + model.commit(); + } + }); + } + } + + private static class SetupCallVisitor extends PyRecursiveElementVisitor { + private String myRootPackageDir = null; + + @Override + public void visitPyCallExpression(PyCallExpression node) { + final PyArgumentList argList = node.getArgumentList(); + if (node.isCalleeText("setup") && argList != null) { + final PyKeywordArgument packageDirArg = argList.getKeywordArgument("package_dir"); + if (packageDirArg != null) { + final PyExpression valueExpression = packageDirArg.getValueExpression(); + if (valueExpression instanceof PyDictLiteralExpression) { + PyDictLiteralExpression packageDirDict = (PyDictLiteralExpression)valueExpression; + for (PyKeyValueExpression keyValue : packageDirDict.getElements()) { + final PyExpression keyExpr = keyValue.getKey(); + final PyExpression valueExpr = keyValue.getValue(); + if (keyExpr instanceof PyStringLiteralExpression && valueExpr instanceof PyStringLiteralExpression) { + String key = ((PyStringLiteralExpression) keyExpr).getStringValue(); + String value = ((PyStringLiteralExpression)valueExpr).getStringValue(); + if (key.length() == 0) { + myRootPackageDir = value; + } + } + } + } + } + } + else { + super.visitPyCallExpression(node); + } + } + + public String getRootPackageDir() { + return myRootPackageDir; + } + } +} diff --git a/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.form b/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.form new file mode 100644 index 000000000000..8da1065e40e0 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.form @@ -0,0 +1,35 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.java b/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.java new file mode 100644 index 000000000000..d8f48ee3dfff --- /dev/null +++ b/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.java @@ -0,0 +1,171 @@ +package com.jetbrains.python.buildout; + +import com.intellij.facet.FacetManager; +import com.intellij.facet.ModifiableFacetModel; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.NonDefaultProjectConfigurable; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.List; + +/** + * A silly configurable to add buildout facet configurator to PyCharm + * User: dcheryasov + * Date: Jul 28, 2010 4:34:58 PM + */ +public class BuildoutConfigurable implements Configurable, NonDefaultProjectConfigurable { + + private JCheckBox myEnabledCheckbox; + private JPanel myPlaceholder; + private JPanel myMainPanel; + private BuildoutConfigPanel mySettingsPanel; + private final Module myModule; + + public BuildoutConfigurable(@NotNull Module module) { + myModule = module; + BuildoutFacetConfiguration config = null; + BuildoutFacet facet = BuildoutFacet.getInstance(myModule); + if (facet != null) config = facet.getConfiguration(); + if (config == null) config = new BuildoutFacetConfiguration(null); + mySettingsPanel = new BuildoutConfigPanel(myModule, config); + myPlaceholder.add(mySettingsPanel, BorderLayout.CENTER); + final boolean isEnabled = !StringUtil.isEmptyOrSpaces(config.getScriptName()); + myEnabledCheckbox.setSelected(isEnabled); + updateFacetEnabled(isEnabled); + myEnabledCheckbox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + final boolean enabled = myEnabledCheckbox.isSelected(); + updateFacetEnabled(enabled); + } + }); + mySettingsPanel.addFocusListener( + new FocusListener() { + @Override + public void focusGained(FocusEvent focusEvent) { + switchNoticeText(); + } + + @Override + public void focusLost(FocusEvent focusEvent) { } + } + ); + } + + private void updateFacetEnabled(boolean enabled) { + mySettingsPanel.setFacetEnabled(enabled); + UIUtil.setEnabled(mySettingsPanel, enabled, true); + } + + @Nls + @Override + public String getDisplayName() { + return "Buildout Support"; + } + + @Override + public String getHelpTopic() { + return "reference-python-buildout"; + } + + @Override + public JComponent createComponent() { + switchNoticeText(); + return myMainPanel; + } + + @Override + public boolean isModified() { + if (! myEnabledCheckbox.isEnabled()) return false; + final BuildoutFacet facet = myModule != null? BuildoutFacet.getInstance(myModule) : null; + final boolean got_facet = facet != null; + if (myEnabledCheckbox.isSelected() != got_facet) return true; + if (got_facet && myEnabledCheckbox.isSelected()) { + return mySettingsPanel.isModified(facet.getConfiguration()); + } + return false; + } + + @Override + public void apply() throws ConfigurationException { + final BuildoutFacet facet = myModule != null? BuildoutFacet.getInstance(myModule) : null; + final boolean got_facet = facet != null; + boolean facet_is_desired = myEnabledCheckbox.isSelected(); + + mySettingsPanel.apply(); + List paths_from_script = null; + if (facet_is_desired) { + String script_name = mySettingsPanel.getScriptName(); + VirtualFile script_file = BuildoutConfigPanel.getScriptFile(script_name); + paths_from_script = BuildoutFacet.extractBuildoutPaths(script_file); + if (paths_from_script == null) { + throw new ConfigurationException("Failed to extract paths from '" + script_file.getPresentableName() + "'"); + } + mySettingsPanel.getConfiguration().setPaths(paths_from_script); + + } + if (facet_is_desired && ! got_facet) addFacet(mySettingsPanel.getConfiguration()); + if (! facet_is_desired && got_facet) removeFacet(facet); + if (facet_is_desired) BuildoutFacet.attachLibrary(myModule); + else BuildoutFacet.detachLibrary(myModule); + } + + private void addFacet(BuildoutFacetConfiguration config) { + BuildoutFacetConfigurator.setupFacet(myModule, config); + } + + private void removeFacet(BuildoutFacet facet) { + final ModifiableFacetModel model = FacetManager.getInstance(myModule).createModifiableModel(); + model.removeFacet(facet); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + model.commit(); + } + }); + } + + @Override + public void reset() { + // TODO: refactor, see AppEngineConfigurable + if (myModule == null) { + myEnabledCheckbox.setSelected(false); + myEnabledCheckbox.setEnabled(false); + } + else { + myEnabledCheckbox.setEnabled(true); + switchNoticeText(); + final BuildoutFacet instance = BuildoutFacet.getInstance(myModule); + if (instance != null) { + boolean selected = ! StringUtil.isEmptyOrSpaces(instance.getConfiguration().getScriptName()); + myEnabledCheckbox.setSelected(selected); + mySettingsPanel.setEnabled(selected); + mySettingsPanel.reset(); + } + else { + myEnabledCheckbox.setSelected(false); + mySettingsPanel.setEnabled(false); + } + } + } + + private void switchNoticeText() { + mySettingsPanel.showNoticeText(/*DjangoFacet.getInstance(myModule) != null*/ false); + } + + @Override + public void disposeUIResources() { + } + +} diff --git a/python/ide/src/com/jetbrains/python/buildout/BuildoutFacetConfigurator.java b/python/ide/src/com/jetbrains/python/buildout/BuildoutFacetConfigurator.java new file mode 100644 index 000000000000..4eca76e939b0 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/buildout/BuildoutFacetConfigurator.java @@ -0,0 +1,63 @@ +package com.jetbrains.python.buildout; + +import com.intellij.facet.FacetManager; +import com.intellij.facet.ModifiableFacetModel; +import com.intellij.facet.ProjectFacetManager; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.platform.DirectoryProjectConfigurator; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * Detects and configures a buildout facet. + * User: dcheryasov + * Date: Jul 26, 2010 6:10:39 PM + */ +public class BuildoutFacetConfigurator implements DirectoryProjectConfigurator { + @Override + public void configureProject(Project project, @NotNull VirtualFile baseDir, Ref moduleRef) { + final Module[] modules = ModuleManager.getInstance(project).getModules(); + if (modules.length > 0) { + final Module module = modules[0]; + if (BuildoutFacet.getInstance(module) == null) { + baseDir.refresh(false, false); + final VirtualFile runner = BuildoutFacet.getRunner(baseDir); + if (runner != null) { + // TODO parse buildout.cfg and find out the part to use for the default script + final File script = BuildoutFacet.findScript(null, "buildout", project.getBaseDir()); + if (script != null) { + final ProjectFacetManager facetManager = ProjectFacetManager.getInstance(module.getProject()); + final BuildoutFacetConfiguration config = facetManager.createDefaultConfiguration(BuildoutFacetType.getInstance()); + config.setScriptName(script.getPath()); + setupFacet(module, config); + } + } + } + } + } + + + static void setupFacet(Module module, @NotNull BuildoutFacetConfiguration config) { + //TODO: refactor, see other python facets + FacetManager facetManager = FacetManager.getInstance(module); + final ModifiableFacetModel model = facetManager.createModifiableModel(); + BuildoutFacetType facetType = BuildoutFacetType.getInstance(); + BuildoutFacet facet = facetManager.createFacet(facetType, facetType.getDefaultFacetName(), config, null); + model.addFacet(facet); + + new WriteAction() { + protected void run(final Result result) throws Throwable { + model.commit(); + } + }.execute(); + facet.updatePaths(); + BuildoutFacet.attachLibrary(module); + } +} diff --git a/python/ide/src/com/jetbrains/python/buildout/BuildoutModulesConfigurable.java b/python/ide/src/com/jetbrains/python/buildout/BuildoutModulesConfigurable.java new file mode 100644 index 000000000000..2e2805eb9745 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/buildout/BuildoutModulesConfigurable.java @@ -0,0 +1,23 @@ +package com.jetbrains.python.buildout; + +import com.intellij.application.options.ModuleAwareProjectConfigurable; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.NonDefaultProjectConfigurable; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author yole + */ +public class BuildoutModulesConfigurable extends ModuleAwareProjectConfigurable implements NonDefaultProjectConfigurable { + public BuildoutModulesConfigurable(Project project) { + super(project, "Buildout Support", "reference-python-buildout"); + } + + @NotNull + @Override + protected Configurable createModuleConfigurable(Module module) { + return new BuildoutConfigurable(module); + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.form b/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.form new file mode 100644 index 000000000000..78c5657ecc11 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.form @@ -0,0 +1,35 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.java b/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.java new file mode 100644 index 000000000000..43bc66f58513 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/AddVEnvOptionsDialog.java @@ -0,0 +1,35 @@ +package com.jetbrains.python.configuration; + +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.components.JBCheckBox; + +import javax.swing.*; +import java.awt.*; + +/** + * @author yole + */ +public class AddVEnvOptionsDialog extends DialogWrapper { + private JBCheckBox myUseForThisProjectJBCheckBox; + private JBCheckBox myMakeAvailableToAllJBCheckBox; + private JPanel myMainPanel; + + public AddVEnvOptionsDialog(Component parent) { + super(parent, false); + init(); + setTitle("Add Virtualenv"); + } + + @Override + protected JComponent createCenterPanel() { + return myMainPanel; + } + + public boolean useForThisProject() { + return myUseForThisProjectJBCheckBox.isSelected(); + } + + public boolean makeAvailableToAll() { + return myMakeAvailableToAllJBCheckBox.isSelected(); + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/EditSdkDialog.form b/python/ide/src/com/jetbrains/python/configuration/EditSdkDialog.form new file mode 100644 index 000000000000..a5f3036f09dc --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/EditSdkDialog.form @@ -0,0 +1,69 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/ide/src/com/jetbrains/python/configuration/EditSdkDialog.java b/python/ide/src/com/jetbrains/python/configuration/EditSdkDialog.java new file mode 100644 index 000000000000..8843c2e6635a --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/EditSdkDialog.java @@ -0,0 +1,106 @@ +package com.jetbrains.python.configuration; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.SdkModificator; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.ui.ClickListener; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.components.JBCheckBox; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.NullableFunction; +import com.jetbrains.python.sdk.PythonSdkAdditionalData; +import com.jetbrains.python.sdk.PythonSdkType; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.event.MouseEvent; + +/** + * @author yole + */ +public class EditSdkDialog extends DialogWrapper { + private JPanel myMainPanel; + private JTextField myNameTextField; + private TextFieldWithBrowseButton myInterpreterPathTextField; + private JBCheckBox myAssociateCheckbox; + private JBLabel myRemoveAssociationLabel; + private final boolean myWasAssociated; + private boolean myAssociationRemoved = false; + + protected EditSdkDialog(Project project, SdkModificator sdk, final NullableFunction nameValidator) { + super(project, true); + setTitle("Edit Python Interpreter"); + myNameTextField.setText(sdk.getName()); + myNameTextField.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + String nameError = nameValidator.fun(getName()); + setErrorText(nameError); + setOKActionEnabled(nameError == null); + } + }); + myInterpreterPathTextField.setText(sdk.getHomePath()); + myInterpreterPathTextField.addBrowseFolderListener("Specify Interpreter Path", null, project, + PythonSdkType.getInstance().getHomeChooserDescriptor()); + myRemoveAssociationLabel.setVisible(false); + if (PythonSdkType.getVirtualEnvRoot(sdk.getHomePath()) == null) { + myAssociateCheckbox.setVisible(false); + } + else { + PythonSdkAdditionalData data = (PythonSdkAdditionalData) sdk.getSdkAdditionalData(); + if (data != null) { + final String path = data.getAssociatedProjectPath(); + if (path != null) { + myAssociateCheckbox.setSelected(true); + final String basePath = project.getBasePath(); + if (basePath != null && !path.equals(FileUtil.toSystemIndependentName(basePath))) { + myAssociateCheckbox.setEnabled(false); + myAssociateCheckbox.setText("Associate this virtual environment with " + FileUtil.toSystemDependentName(path)); + myRemoveAssociationLabel.setVisible(true); + } + } + } + } + myWasAssociated = myAssociateCheckbox.isSelected(); + init(); + new ClickListener() { + @Override + public boolean onClick(MouseEvent e, int clickCount) { + myAssociateCheckbox.setSelected(false); + myAssociateCheckbox.setEnabled(true); + myAssociateCheckbox.setText("Associate this environment with current project"); + myRemoveAssociationLabel.setVisible(false); + myAssociationRemoved = true; + return true; + } + }.installOn(myRemoveAssociationLabel); + } + + @Override + protected JComponent createCenterPanel() { + return myMainPanel; + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myNameTextField; + } + + public String getName() { + return myNameTextField.getText(); + } + + public String getHomePath() { + return myInterpreterPathTextField.getText(); + } + + public boolean associateWithProject() { + return myAssociateCheckbox.isSelected(); + } + + public boolean isAssociateChanged() { + return myWasAssociated != associateWithProject() || myAssociationRemoved; + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.form b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.form new file mode 100644 index 000000000000..79a648b213a2 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.form @@ -0,0 +1,40 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java new file mode 100644 index 000000000000..98364d29bb28 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -0,0 +1,203 @@ +package com.jetbrains.python.configuration; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkModel; +import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ModuleRootModificationUtil; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.CollectionComboBoxModel; +import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.sdk.PySdkListCellRenderer; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/** + * @author yole + */ +public class PyActiveSdkConfigurable implements UnnamedConfigurable { + private JPanel myPanel; + private final Project myProject; + @Nullable private final Module myModule; + private JComboBox mySdkCombo; + private JPanel myConfigureInterpretersPanel; + private PyConfigurableInterpreterList myInterpreterList; + private ProjectSdksModel myProjectSdksModel; + private MyListener myListener; + + public PyActiveSdkConfigurable(Project project) { + myModule = null; + myProject = project; + init(); + } + + public PyActiveSdkConfigurable(@NotNull Module module) { + myModule = module; + myProject = module.getProject(); + init(); + } + + private void init() { + mySdkCombo.setRenderer(new SdkListCellRenderer("")); + + myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); + myProjectSdksModel = myInterpreterList.getModel(); + myListener = new MyListener(this); + myProjectSdksModel.addListener(myListener); + myConfigureInterpretersPanel.add(new PyConfigureInterpretersLinkPanel(myPanel), BorderLayout.CENTER); + myInterpreterList.setSdkCombo(mySdkCombo); + } + + @Override + public JComponent createComponent() { + return myPanel; + } + + @Override + public boolean isModified() { + final Sdk sdk = getSdk(); + return sdk != myProjectSdksModel.findSdk((Sdk)mySdkCombo.getSelectedItem()); + } + + @Nullable + private Sdk getSdk() { + if (myModule == null) { + return ProjectRootManager.getInstance(myProject).getProjectSdk(); + } + final ModuleRootManager rootManager = ModuleRootManager.getInstance(myModule); + return rootManager.getSdk(); + } + + @Override + public void apply() throws ConfigurationException { + final Sdk selectedSdk = myProjectSdksModel.findSdk((Sdk)mySdkCombo.getSelectedItem()); + if (myModule == null) { + final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + rootManager.setProjectSdk(selectedSdk); + } + }); + } + else { + ModuleRootModificationUtil.setModuleSdk(myModule, selectedSdk); + } + final Sdk prevSdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + ProjectRootManager.getInstance(myProject).setProjectSdk(selectedSdk); + } + }); + + myProjectSdksModel.setProjectSdk(selectedSdk); + + // update string literals if different LanguageLevel was selected + if (prevSdk != null && selectedSdk != null) { + final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(selectedSdk); + final PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(prevSdk); + if (flavor1 != null && flavor2 != null) { + final LanguageLevel languageLevel1 = flavor1.getLanguageLevel(selectedSdk); + final LanguageLevel languageLevel2 = flavor2.getLanguageLevel(prevSdk); + if ((languageLevel1.isPy3K() && languageLevel2.isPy3K()) || + (!languageLevel1.isPy3K()) && !languageLevel2.isPy3K()) { + return; + } + } + } + rehighlightStrings(myProject); + } + + public static void rehighlightStrings(final @NotNull Project project) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + + for (Editor editor : EditorFactory.getInstance().getAllEditors()) { + if (editor instanceof EditorEx && editor.getProject() == project) { + final VirtualFile vFile = ((EditorEx)editor).getVirtualFile(); + if (vFile != null) { + final EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(project, vFile); + ((EditorEx)editor).setHighlighter(highlighter); + } + } + } + } + }); + } + + @Override + public void reset() { + updateSdkList(false); + + final Sdk sdk = getSdk(); + mySdkCombo.setSelectedItem(myProjectSdksModel.getProjectSdks().get(sdk)); + } + + private void updateSdkList(boolean preserveSelection) { + final List sdkList = myInterpreterList.getAllPythonSdks(); + Sdk selection = preserveSelection ? (Sdk)mySdkCombo.getSelectedItem() : null; + if (!sdkList.contains(selection)) { + selection = null; + } + VirtualEnvProjectFilter.removeNotMatching(myProject, sdkList); + // if the selection is a non-matching virtualenv, show it anyway + if (selection != null && !sdkList.contains(selection)) { + sdkList.add(0, selection); + } + sdkList.add(0, null); + mySdkCombo.setRenderer(new PySdkListCellRenderer()); + mySdkCombo.setModel(new CollectionComboBoxModel(sdkList, selection)); + } + + @Override + public void disposeUIResources() { + myProjectSdksModel.removeListener(myListener); + myInterpreterList.disposeModel(); + } + + private static class MyListener implements SdkModel.Listener { + private final PyActiveSdkConfigurable myConfigurable; + + public MyListener(PyActiveSdkConfigurable configurable) { + myConfigurable = configurable; + } + + @Override + public void sdkAdded(Sdk sdk) { + myConfigurable.reset(); + } + + @Override + public void beforeSdkRemove(Sdk sdk) { + myConfigurable.updateSdkList(true); + } + + @Override + public void sdkChanged(Sdk sdk, String previousName) { + myConfigurable.updateSdkList(true); + } + + @Override + public void sdkHomeSelected(Sdk sdk, String newSdkHome) { + } + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java new file mode 100644 index 000000000000..2fd855c40551 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java @@ -0,0 +1,60 @@ +package com.jetbrains.python.configuration; + +import com.intellij.application.options.ModuleAwareProjectConfigurable; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ModuleRootManager; +import com.jetbrains.python.sdk.PythonSdkUpdater; +import com.jetbrains.python.testing.VFSTestFrameworkListener; +import org.jetbrains.annotations.NotNull; + +/** + * @author yole + */ +public class PyActiveSdkModuleConfigurable extends ModuleAwareProjectConfigurable implements Configurable.Composite { + private final Project myProject; + private final Configurable mySdkConfigurable; + + public PyActiveSdkModuleConfigurable(Project project) { + super(project, "Project Interpreter", "reference.settings.project.interpreter"); + myProject = project; + mySdkConfigurable = new PythonSdkConfigurable(project); + } + + @NotNull + @Override + protected UnnamedConfigurable createModuleConfigurable(Module module) { + return new PyActiveSdkConfigurable(module); + } + + @Override + protected UnnamedConfigurable createDefaultProjectConfigurable() { + return new PyActiveSdkConfigurable(myProject); + } + + @Override + public void apply() throws ConfigurationException { + super.apply(); + + // TODO[catherine] proper per-module caching of framework installed state + for (Module module : ModuleManager.getInstance(myProject).getModules()) { + final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); + if (sdk != null) { + VFSTestFrameworkListener.getInstance().updateAllTestFrameworks(sdk); + break; + } + + } + PythonSdkUpdater.getInstance().updateActiveSdks(myProject, 0); + } + + @Override + public Configurable[] getConfigurables() { + return new Configurable[] { mySdkConfigurable }; + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java new file mode 100644 index 000000000000..b6a080e29072 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java @@ -0,0 +1,68 @@ +package com.jetbrains.python.configuration; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; +import com.intellij.openapi.util.Comparing; +import com.jetbrains.python.sdk.PythonSdkType; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * Manages the SDK model shared between PythonSdkConfigurable and PyActiveSdkConfigurable. + * + * @author yole + */ +public class PyConfigurableInterpreterList { + private ProjectSdksModel myModel; + private JComboBox mySdkCombo; + + public void setSdkCombo(final JComboBox sdkCombo) { + mySdkCombo = sdkCombo; + } + + public void setSelectedSdk(final Sdk selectedSdk) { + if (mySdkCombo != null) + mySdkCombo.setSelectedItem(selectedSdk); + } + + public static PyConfigurableInterpreterList getInstance(Project project) { + return ServiceManager.getService(project, PyConfigurableInterpreterList.class); + } + + public ProjectSdksModel getModel() { + if (myModel == null) { + myModel = new ProjectSdksModel(); + myModel.reset(null); + } + return myModel; + } + + public void disposeModel() { + if (myModel != null) { + myModel.disposeUIResources(); + myModel = null; + } + } + + public List getAllPythonSdks() { + List result = new ArrayList(); + for (Sdk sdk : getModel().getSdks()) { + if (sdk.getSdkType() instanceof PythonSdkType) { + result.add(sdk); + } + } + Collections.sort(result, new Comparator() { + @Override + public int compare(Sdk o1, Sdk o2) { + return Comparing.compare(o1.getName(), o2.getName()); + } + }); + return result; + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PyConfigureInterpretersLinkPanel.java b/python/ide/src/com/jetbrains/python/configuration/PyConfigureInterpretersLinkPanel.java new file mode 100644 index 000000000000..0db63b1619be --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyConfigureInterpretersLinkPanel.java @@ -0,0 +1,41 @@ +package com.jetbrains.python.configuration; + +import com.intellij.ide.DataManager; +import com.intellij.openapi.options.newEditor.OptionsEditor; +import com.intellij.ui.ClickListener; +import com.intellij.ui.components.JBLabel; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseEvent; + +/** + * @author traff + */ +public class PyConfigureInterpretersLinkPanel extends JPanel { + private final JBLabel myConfigureLabel; + + public PyConfigureInterpretersLinkPanel(final JPanel parentPanel) { + super(new BorderLayout()); + myConfigureLabel = new JBLabel("Configure Interpreters"); + myConfigureLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + new ClickListener() { + @Override + public boolean onClick(MouseEvent e, int clickCount) { + if (clickCount == 1) { + final OptionsEditor optionsEditor = OptionsEditor.KEY.getData(DataManager.getInstance().getDataContext(parentPanel)); + if (optionsEditor != null) { + PythonSdkConfigurable configurable = optionsEditor.findConfigurable(PythonSdkConfigurable.class); + if (configurable != null) { + optionsEditor.clearSearchAndSelect(configurable); + } + return true; + } + } + return false; + } + }.installOn(myConfigureLabel); + + add(myConfigureLabel, BorderLayout.CENTER); + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PyDependenciesConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyDependenciesConfigurable.java new file mode 100644 index 000000000000..b1269b9f1c5f --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyDependenciesConfigurable.java @@ -0,0 +1,32 @@ +package com.jetbrains.python.configuration; + +import com.intellij.application.options.ModuleAwareProjectConfigurable; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.OptionalConfigurable; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author yole + */ +public class PyDependenciesConfigurable extends ModuleAwareProjectConfigurable implements OptionalConfigurable { + private final Project myProject; + + public PyDependenciesConfigurable(Project project) { + super(project, "Project Dependencies", "reference.settingsdialog.project.dependencies"); + myProject = project; + } + + @NotNull + @Override + protected UnnamedConfigurable createModuleConfigurable(Module module) { + return new PyModuleDependenciesConfigurable(module); + } + + @Override + public boolean needDisplay() { + return ModuleManager.getInstance(myProject).getModules().length > 1; + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PyDiffPreviewProvider.java b/python/ide/src/com/jetbrains/python/configuration/PyDiffPreviewProvider.java new file mode 100644 index 000000000000..63afbd83e537 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyDiffPreviewProvider.java @@ -0,0 +1,59 @@ +package com.jetbrains.python.configuration; + +import com.intellij.openapi.diff.DiffContent; +import com.intellij.openapi.diff.SimpleContent; +import com.intellij.openapi.diff.impl.settings.DiffPreviewProvider; +import com.jetbrains.python.PythonFileType; +import org.jetbrains.annotations.NonNls; + +/** + * @author oleg + */ +public class PyDiffPreviewProvider extends DiffPreviewProvider { + @Override + public DiffContent[] createContents() { + return new DiffContent[]{createContent(LEFT_TEXT), createContent(CENTER_TEXT), createContent(RIGHT_TEXT)}; + } + + private static SimpleContent createContent(final String text) { + return new SimpleContent(text, PythonFileType.INSTANCE); + } + + @NonNls private static final String LEFT_TEXT = "class MyClass\n" + + " value = 123\n" + + "\n" + + " def left_only(self):\n" + + " bar(123)\n" + + "\n" + + " def bar(self, a)\n" + + " print a\n"+ + "\n"+ + " def foo(self):\n" + + " pass # Left changes\n"+ + "\n"+ + "\n"; + @NonNls private static final String CENTER_TEXT = "class MyClass\n" + + " value = 123\n" + + "\n" + + " def bar(self, a)\n" + + " print a\n"+ + "\n"+ + " def foo(self):\n" + + " pass\n" + + "\n" + + "\n" + + " def removed_from_left(self):\n" + + " bar('PyCharmRulezzz')"; + @NonNls private static final String RIGHT_TEXT = "class MyClass\n" + + " value = -123\n" + + "\n" + + " def bar(self, a)\n" + + " print a\n"+ + "\n"+ + " def foo(self):\n" + + " pass # Right changes\n" + + "\n" + + "\n" + + " def removed_from_left(self):\n" + + " bar('PyCharmRulezzz')"; +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PyModuleDependenciesConfigurable.form b/python/ide/src/com/jetbrains/python/configuration/PyModuleDependenciesConfigurable.form new file mode 100644 index 000000000000..d5b0c6bb33c2 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyModuleDependenciesConfigurable.form @@ -0,0 +1,29 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/ide/src/com/jetbrains/python/configuration/PyModuleDependenciesConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyModuleDependenciesConfigurable.java new file mode 100644 index 000000000000..56045c23266b --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PyModuleDependenciesConfigurable.java @@ -0,0 +1,118 @@ +package com.jetbrains.python.configuration; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ModuleOrderEntry; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.ui.CheckBoxList; +import com.intellij.ui.ToolbarDecorator; +import com.intellij.util.Function; +import com.intellij.util.ui.EditableListModelDecorator; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author yole + */ +public class PyModuleDependenciesConfigurable implements UnnamedConfigurable { + private final Module myModule; + private List myInitialDependencies; + private JPanel myMainPanel; + private JPanel myListHolderPanel; + private CheckBoxList myDependenciesList; + + public PyModuleDependenciesConfigurable(Module module) { + myModule = module; + myDependenciesList = new CheckBoxList(); + resetModel(); + ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myDependenciesList, + new EditableListModelDecorator((DefaultListModel) myDependenciesList.getModel())); + decorator.disableRemoveAction(); + myListHolderPanel.add(decorator.createPanel(), BorderLayout.CENTER); + } + + private void resetModel() { + List possibleDependencies = new ArrayList(); + myInitialDependencies = Arrays.asList(ModuleRootManager.getInstance(myModule).getDependencies()); + possibleDependencies.addAll(myInitialDependencies); + for (Module otherModule : ModuleManager.getInstance(myModule.getProject()).getModules()) { + if (!possibleDependencies.contains(otherModule) && otherModule != myModule) { + possibleDependencies.add(otherModule); + } + } + myDependenciesList.setItems(possibleDependencies, new Function() { + @Override + public String fun(Module module) { + return module.getName(); + } + }); + myDependenciesList.setBorder(null); + for (Module dependency : myInitialDependencies) { + myDependenciesList.setItemSelected(dependency, true); + } + } + + @Nullable + @Override + public JComponent createComponent() { + return myMainPanel; + } + + @Override + public boolean isModified() { + return collectDependencies().equals(myInitialDependencies); + } + + private List collectDependencies() { + List result = new ArrayList(); + for (int i = 0; i < myDependenciesList.getItemsCount(); i++) { + Module module = (Module)myDependenciesList.getItemAt(i); + if (myDependenciesList.isItemSelected(module)) { + result.add(module); + } + } + return result; + } + + @Override + public void apply() throws ConfigurationException { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + ModifiableRootModel model = ModuleRootManager.getInstance(myModule).getModifiableModel(); + List entries = new ArrayList(); + for (OrderEntry entry : model.getOrderEntries()) { + if (entry instanceof ModuleOrderEntry) { + entries.add((ModuleOrderEntry) entry); + } + } + for (ModuleOrderEntry entry : entries) { + model.removeOrderEntry(entry); + } + for (Module module : collectDependencies()) { + model.addModuleOrderEntry(module); + } + model.commit(); + } + }); + } + + @Override + public void reset() { + resetModel(); + } + + @Override + public void disposeUIResources() { + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonContentEntriesConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonContentEntriesConfigurable.java new file mode 100644 index 000000000000..f7a3e2f03a8a --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PythonContentEntriesConfigurable.java @@ -0,0 +1,42 @@ +package com.jetbrains.python.configuration; + +import com.intellij.application.options.ModuleAwareProjectConfigurable; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.NonDefaultProjectConfigurable; +import com.intellij.openapi.options.OptionalConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.PlatformContentEntriesConfigurable; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.java.JavaSourceRootType; + +/** + * @author yole + */ +public class PythonContentEntriesConfigurable extends ModuleAwareProjectConfigurable implements NonDefaultProjectConfigurable, OptionalConfigurable { + private final Project myProject; + + public PythonContentEntriesConfigurable(final Project project) { + super(project, "Project Structure", "reference.settingsdialog.project.structure"); + myProject = project; + } + + @Nullable + private static Module getSingleModule(Project project) { + return ArrayUtil.getFirstElement(ModuleManager.getInstance(project).getModules()); + } + + @Override + public boolean needDisplay() { + return getSingleModule(myProject) != null; + } + + @NotNull + @Override + protected Configurable createModuleConfigurable(Module module) { + return new PlatformContentEntriesConfigurable(module, JavaSourceRootType.SOURCE); + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonPathEditor.java b/python/ide/src/com/jetbrains/python/configuration/PythonPathEditor.java new file mode 100644 index 000000000000..97d1c9703138 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PythonPathEditor.java @@ -0,0 +1,316 @@ +/* + * Copyright 2000-2009 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.configuration; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.projectRoots.SdkAdditionalData; +import com.intellij.openapi.projectRoots.SdkModificator; +import com.intellij.openapi.projectRoots.ui.SdkPathEditor; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.AnActionButton; +import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.ui.ListUtil; +import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.components.JBList; +import com.intellij.util.ArrayUtil; +import com.jetbrains.python.sdk.PythonSdkAdditionalData; +import com.jetbrains.python.sdk.PythonSdkType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.List; +import java.util.Set; + +/** + * @author traff + */ +public class PythonPathEditor extends SdkPathEditor { + private final PathListModel myPathListModel; + + public PythonPathEditor(final String displayName, + final OrderRootType orderRootType, + final FileChooserDescriptor descriptor) { + super(displayName, orderRootType, descriptor); + myPathListModel = new PathListModel(orderRootType, getListModel()); + } + + public void reset(@Nullable SdkModificator modificator) { + if (modificator != null) { + List list = Lists.newArrayList(modificator.getRoots(getOrderRootType())); + resetPath(myPathListModel.reset(list, modificator)); + } + else { + setEnabled(false); + } + } + + public void reload(@Nullable SdkModificator sdkModificator) { + if (sdkModificator != null) { + List list = Lists.newArrayList(sdkModificator.getRoots(getOrderRootType())); + resetPath(myPathListModel.reload(list)); + setModified(true); + } + else { + setEnabled(false); + } + } + + @Override + public void apply(SdkModificator sdkModificator) { + sdkModificator.removeRoots(getOrderRootType()); + // add all items + for (int i = 0; i < myPathListModel.getRowCount(); i++) { + VirtualFile path = myPathListModel.getValueAt(i); + if (!myPathListModel.isExcluded(path)) { + sdkModificator.addRoot(path, getOrderRootType()); + } + } + setModified(false); + myPathListModel.apply(sdkModificator); + } + + @Override + protected VirtualFile[] adjustAddedFileSet(Component component, VirtualFile[] files) { + for (int i = 0, filesLength = files.length; i < filesLength; i++) { + if (files[i].getFileType() == FileTypes.ARCHIVE) { + files[i] = JarFileSystem.getInstance().getJarRootForLocalFile(files[i]); + } + } + if (myPathListModel.add(Lists.newArrayList(files))) { + setModified(true); + } + return files; + } + + @Override + protected void doRemoveItems(int[] idxs, JList list) { + List> removed = Lists.newArrayList(); + for (int i : idxs) { + removed.add(Pair.create((VirtualFile)getListModel().get(i), i)); + } + ListUtil.removeIndices(list, myPathListModel.remove(removed)); + list.updateUI(); + setModified(true); + } + + @Override + protected ListCellRenderer createListCellRenderer(JBList list) { + return new PythonPathListCellRenderer(super.createListCellRenderer(list), myPathListModel); + } + + @Override + protected void addToolbarButtons(ToolbarDecorator toolbarDecorator) { + AnActionButton reloadButton = new AnActionButton("Reload List of Paths", AllIcons.Actions.Refresh) { + @Override + public void actionPerformed(AnActionEvent e) { + onReloadButtonClicked(); + } + }; + toolbarDecorator.addExtraAction(reloadButton); + } + + protected void onReloadButtonClicked() { + } + + private static class PathListModel { + private Set myAdded = Sets.newHashSet(); + private Set myExcluded = Sets.newHashSet(); + private Set myFoundFiles = Sets.newHashSet(); + private List myFilteredOut = Lists.newArrayList(); + private final DefaultListModel myListModel; + private final OrderRootType myOrderRootType; + private Set myUserAddedToRemove = Sets.newHashSet(); + + public PathListModel(OrderRootType orderRootType, DefaultListModel listModel) { + myOrderRootType = orderRootType; + myListModel = listModel; + } + + private int getRowCount() { + return myListModel.getSize(); + } + + private VirtualFile getValueAt(int row) { + return (VirtualFile)myListModel.get(row); + } + + public boolean add(List files) { + for (VirtualFile file : files) { + if (!myFoundFiles.contains(file)) { + if (!myExcluded.remove(file)) { //if it was excluded we only delete exclusion mark + myAdded.add(file); + myUserAddedToRemove.remove(file); + } + else { + myFoundFiles.add(file); + return true; + } + } else { + myExcluded.remove(file); + } + } + return false; + } + + public int[] remove(List> files) { + List toRemove = Lists.newArrayList(); + for (Pair e : files) { + if (myAdded.contains(e.first)) { + toRemove.add(e.second); + myAdded.remove(e.first); + myUserAddedToRemove.add(e.first); + } + else if (myExcluded.contains(e.first)) { + myExcluded.remove(e.first); + } + else { + myExcluded.add(e.first); + } + } + return ArrayUtil.toIntArray(toRemove); + } + + public void apply(SdkModificator sdkModificator) { + sdkModificator.setSdkAdditionalData(collectSdkAdditionalData(sdkModificator)); + addFilteredOutRoots(sdkModificator); + } + + private void addFilteredOutRoots(SdkModificator sdkModificator) { + for (VirtualFile file : myFilteredOut) { + sdkModificator.addRoot(file, myOrderRootType); + } + } + + private SdkAdditionalData collectSdkAdditionalData(SdkModificator sdkModificator) { + PythonSdkAdditionalData data = (PythonSdkAdditionalData)sdkModificator.getSdkAdditionalData(); + if (data == null) { + data = new PythonSdkAdditionalData(null); + } + data.setAddedPathsFromVirtualFiles(myAdded); + data.setExcludedPathsFromVirtualFiles(myExcluded); + return data; + } + + public void setAdded(Set added) { + myAdded = Sets.newHashSet(added); + } + + public void setExcluded(Set excluded) { + myExcluded = Sets.newHashSet(excluded); + } + + public String getPresentationSuffix(VirtualFile file) { + if (myAdded.contains(file)) { + return "(added by user)"; + } + if (myExcluded.contains(file)) { + return "(removed by user)"; + } + return ""; + } + + public List reload(List list) { + myFoundFiles.clear(); + myFoundFiles.addAll(list); + List result = filterOutStubs(list, myFilteredOut); + result.removeAll(myUserAddedToRemove); + result.addAll(myAdded); + + return result; + } + + public List reset(List list, SdkModificator modificator) { + myFilteredOut.clear(); + List result = filterOutStubs(list, myFilteredOut); + + myFoundFiles.clear(); + myFoundFiles.addAll(list); + myUserAddedToRemove.clear(); + + if (modificator.getSdkAdditionalData() instanceof PythonSdkAdditionalData) { + PythonSdkAdditionalData data = (PythonSdkAdditionalData)modificator.getSdkAdditionalData(); + setAdded(data.getAddedPathFiles()); + setExcluded(data.getExcludedPathFiles()); + result.addAll(myExcluded); + } + else if (modificator.getSdkAdditionalData() == null) { + myAdded.clear(); + myExcluded.clear(); + } + return result; + } + + private static List filterOutStubs(List list, List filteredOut) { + List result = Lists.newArrayList(); + filteredOut.clear(); + for (VirtualFile file : list) { + if (!isStubPath(file)) { + result.add(file); + } + else { + filteredOut.add(file); + } + } + return result; + } + + private static boolean isStubPath(@NotNull VirtualFile file) { + final String path = PythonSdkType.getSkeletonsRootPath(PathManager.getSystemPath()); + final VirtualFile skeletonRoot = LocalFileSystem.getInstance().findFileByPath(path); + if (skeletonRoot != null) { + return file.getPath().startsWith(skeletonRoot.getPath()); + } + else { + return false; + } + } + + public boolean isExcluded(VirtualFile path) { + return myExcluded.contains(path); + } + } + + + private static class PythonPathListCellRenderer extends ListCellRendererWrapper { + private final PathListModel model; + + public PythonPathListCellRenderer(final ListCellRenderer listCellRenderer, PathListModel model) { + super(); + this.model = model; + } + + @Override + public void customize(JList list, VirtualFile value, int index, boolean selected, boolean hasFocus) { + String suffix = model.getPresentationSuffix(value); + if (suffix.length() > 0) { + suffix = " " + suffix; + } + setText(value != null ? value.getPresentableUrl() + suffix : ""); + } + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.form b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.form new file mode 100644 index 000000000000..b1a81e8c2a8a --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.form @@ -0,0 +1,32 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java new file mode 100644 index 000000000000..3365ac8bbf24 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java @@ -0,0 +1,571 @@ +package com.jetbrains.python.configuration; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.intellij.CommonBundle; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.*; +import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.Splitter; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.remotesdk.RemoteCredentials; +import com.intellij.ui.*; +import com.intellij.ui.components.JBList; +import com.intellij.ui.components.JBTabbedPane; +import com.intellij.util.Consumer; +import com.intellij.util.NullableConsumer; +import com.intellij.util.NullableFunction; +import com.intellij.util.containers.FactoryMap; +import com.intellij.webcore.packaging.PackagesNotificationPanel; +import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel; +import com.jetbrains.python.packaging.ui.PyPackageManagementService; +import com.jetbrains.python.remote.PythonRemoteInterpreterManager; +import com.jetbrains.python.sdk.*; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import icons.PythonIcons; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.util.*; +import java.util.List; + +public class PythonSdkConfigurable implements Configurable, Configurable.NoScroll { + private JPanel myPanel; + private JList mySdkList; + private JPanel mySplitterHolder; + private PackagesNotificationPanel myNotificationsArea; + private JPanel myNotificationsPlaceholder; + private PythonPathEditor myPathEditor; + private boolean mySdkListChanged = false; + private final PyConfigurableInterpreterList myInterpreterList; + private final ProjectSdksModel myProjectSdksModel; + private final PyInstalledPackagesPanel myPackagesPanel; + + private Map myModificators = new FactoryMap() { + @Override + protected SdkModificator create(Sdk sdk) { + return sdk.getSdkModificator(); + } + }; + private Set myModifiedModificators = new HashSet(); + private Sdk myPreviousSelection; + private boolean myFirstReset; + private final Project myProject; + + private boolean myNewProject = false; + private boolean myShowOtherProjectVirtualenvs = false; + + public void setNewProject(final boolean newProject) { + myNewProject = newProject; + } + + public PythonSdkConfigurable(Project project) { + myProject = project; + myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject); + myProjectSdksModel = myInterpreterList.getModel(); + myFirstReset = true; + + + mySdkList = new JBList(); + mySdkList.setCellRenderer(new PySdkListCellRenderer("", myModificators)); + mySdkList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + ToolbarDecorator decorator = ToolbarDecorator.createDecorator(mySdkList).disableUpDownActions() + .setAddAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + addSdk(button); + } + }) + .setEditAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + editSdk(); + } + }) + .setRemoveAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + removeSdk(); + } + }) + .addExtraAction(new CreateVirtualEnvButton()) + .addExtraAction(new ToggleVirtualEnvFilterButton()); + + + final Splitter splitter = new Splitter(true); + /* + final JScrollPane sdkListPane = ScrollPaneFactory.createScrollPane(mySdkList, + ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + sdkListPane.setPreferredSize(new Dimension(10, 10)); + */ + splitter.setFirstComponent(decorator.createPanel()); + + myPathEditor = + new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) { + @Override + protected void onReloadButtonClicked() { + reloadSdk(); + } + }; + + myNotificationsArea = new PackagesNotificationPanel(project); + myNotificationsPlaceholder.add(myNotificationsArea.getComponent(), BorderLayout.CENTER); + + final JBTabbedPane tabbedPane = new JBTabbedPane(SwingConstants.TOP); + myPackagesPanel = new PyInstalledPackagesPanel(project, myNotificationsArea); + tabbedPane.addTab("Packages", myPackagesPanel); + + JPanel panel1 = new JPanel(new GridBagLayout()); + Insets anInsets1 = new Insets(2, 2, 2, 2); + JScrollPane scrollPane1 = ScrollPaneFactory.createScrollPane(myPathEditor.createComponent(), + ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane1.setPreferredSize(new Dimension(500, 500)); + panel1.add(scrollPane1, new GridBagConstraints(0, 0, 1, 8, 1.0, 1.0, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + anInsets1, 0, 0)); + + tabbedPane.addTab("Paths", panel1); + + splitter.setSecondComponent(tabbedPane); + mySplitterHolder.add(splitter, BorderLayout.CENTER); + + addListeners(); + } + + private void addListeners() { + myProjectSdksModel.addListener(new SdkModel.Listener() { + @Override + public void sdkAdded(Sdk sdk) { + } + + @Override + public void beforeSdkRemove(Sdk sdk) { + } + + @Override + public void sdkChanged(Sdk sdk, String previousName) { + refreshSdkList(); + } + + @Override + public void sdkHomeSelected(Sdk sdk, String newSdkHome) { + } + }); + myPackagesPanel.addPathChangedListener(new Consumer() { + @Override + public void consume(Sdk sdk) { + updateSdkPaths(sdk); + } + }); + + myNotificationsArea.addLinkHandler(PyInstalledPackagesPanel.CREATE_VENV, new Runnable() { + @Override + public void run() { + createVirtualEnv(getSelectedSdk()); + } + }); + mySdkList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent event) { + updateUI(getSelectedSdk()); + } + }); + } + + private void updateUI(final Sdk selectedSdk) { + if (myPreviousSelection != null) { + saveSdkPaths(myPreviousSelection); + } + myProjectSdksModel.setProjectSdk(selectedSdk); + updateSdkPaths(selectedSdk); + myPreviousSelection = selectedSdk; + myPackagesPanel.updatePackages(selectedSdk == null ? null : new PyPackageManagementService(myProject, selectedSdk)); + + if (selectedSdk != null) { + myPackagesPanel.updateNotifications(selectedSdk); + } + } + + private void createVirtualEnv(Sdk sdk) { + CreateVirtualEnvDialog.VirtualEnvCallback callback = new CreateVirtualEnvDialog.VirtualEnvCallback() { + @Override + public void virtualEnvCreated(Sdk sdk, boolean associateWithProject, boolean setAsProjectInterpreter) { + PythonSdkType.setupSdkPaths(sdk, myProject, null); + if (associateWithProject) { + SdkAdditionalData additionalData = sdk.getSdkAdditionalData(); + if (additionalData == null) { + additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath())); + ((ProjectJdkImpl)sdk).setSdkAdditionalData(additionalData); + } + if (myNewProject) { + ((PythonSdkAdditionalData)additionalData).associateWithNewProject(); + } + else { + ((PythonSdkAdditionalData)additionalData).associateWithProject(myProject); + } + } + addCreatedSdk(sdk, true, setAsProjectInterpreter); + } + }; + final List allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks(); + final CreateVirtualEnvDialog dialog = new CreateVirtualEnvDialog(myProject, myNewProject, allSdks, sdk); + dialog.show(); + if (dialog.isOK()) { + dialog.createVirtualEnv(allSdks, callback); + } + } + + public String getDisplayName() { + return "Python Interpreters"; + } + + public String getHelpTopic() { + return "python_interpreter"; + } + + public JComponent createComponent() { + return myPanel; + } + + public boolean isModified() { + return mySdkListChanged || + myProjectSdksModel.isModified() || + myPathEditor.isModified() || + !myModifiedModificators.isEmpty(); + } + + @Nullable + private String getSelectedSdkName() { + final Sdk selectedSdk = (Sdk)mySdkList.getSelectedValue(); + return selectedSdk == null ? null : selectedSdk.getName(); + } + + public void apply() throws ConfigurationException { + if (myPreviousSelection != null) { + saveSdkPaths(myPreviousSelection); + } + for (SdkModificator modificator : myModifiedModificators) { + modificator.commitChanges(); + } + myModificators.clear(); + myModifiedModificators.clear(); + myProjectSdksModel.apply(); + mySdkListChanged = false; + } + + /** + * Returns the stable copy of the SDK currently selected in the SDK table. + * + * @return the selected SDK, or null if there's no selection + */ + @Nullable + public Sdk getRealSelectedSdk() { + return ProjectJdkTable.getInstance().findJdk(getSelectedSdkName()); + } + + @Nullable + public Sdk getSelectedSdk() { + return (Sdk)mySdkList.getSelectedValue(); + } + + public void reset() { + clearModificators(); + if (myFirstReset) { + myFirstReset = false; + } + else { + myProjectSdksModel.reset(null); + } + refreshSdkList(); + final Sdk selectedSdk = getRealSelectedSdk(); + if (selectedSdk != null) { + myPackagesPanel.updateNotifications(selectedSdk); + } + } + + private void clearModificators() { + myModificators.clear(); + myModifiedModificators.clear(); + myPreviousSelection = null; + } + + private void refreshSdkList() { + final List pythonSdks = myInterpreterList.getAllPythonSdks(); + Sdk projectSdk = myProjectSdksModel.getProjectSdk(); + if (!myShowOtherProjectVirtualenvs) { + VirtualEnvProjectFilter.removeNotMatching(myProject, pythonSdks); + } + Collections.sort(pythonSdks, new PreferredSdkComparator()); + mySdkList.setModel(new CollectionListModel(pythonSdks)); + + mySdkListChanged = false; + if (projectSdk == null) projectSdk = getSdk(); + if (projectSdk != null) { + projectSdk = myProjectSdksModel.findSdk(projectSdk.getName()); + mySdkList.clearSelection(); + mySdkList.setSelectedValue(projectSdk, true); + mySdkList.updateUI(); + } + } + + @Nullable + private Sdk getSdk() { + final Module[] modules = ModuleManager.getInstance(myProject).getModules(); + if (modules.length > 0) { + final Module module = modules[0]; + final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); + return rootManager.getSdk(); + } + return ProjectRootManager.getInstance(myProject).getProjectSdk(); + } + + private void addSdk(AnActionButton button) { + InterpreterPathChooser + .show(myProject, myProjectSdksModel.getSdks(), button.getPreferredPopupPoint(), false, new NullableConsumer() { + @Override + public void consume(Sdk sdk) { + addCreatedSdk(sdk, false, false); + } + }); + } + + private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv, boolean makeActive) { + if (sdk != null) { + boolean isVirtualEnv = PythonSdkType.isVirtualEnv(sdk); + boolean askSetAsProjectInterpreter = !myProject.isDefault() && !myNewProject; + if (askSetAsProjectInterpreter && isVirtualEnv && !newVirtualEnv) { + AddVEnvOptionsDialog dialog = new AddVEnvOptionsDialog(myPanel); + dialog.show(); + if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { + return; + } + SdkModificator modificator = myModificators.get(sdk); + setSdkAssociated(modificator, !dialog.makeAvailableToAll()); + myModifiedModificators.add(modificator); + makeActive = dialog.useForThisProject(); + } + myProjectSdksModel.addSdk(sdk); + refreshSdkList(); + mySdkList.setSelectedValue(sdk, true); + mySdkListChanged = true; + if (askSetAsProjectInterpreter && !isVirtualEnv && !PythonSdkType.isInvalid(sdk) && !PythonSdkType.isIncompleteRemote(sdk)) { + //TODO: make native mac dialog work + makeActive = Messages.showIdeaMessageDialog(myProject, "Do you want to set this interpreter as Project Interpreter?", + "Project Interpreter", + new String[]{CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText()}, 0, null, + null + ) == Messages.YES; + } + if (makeActive) { + SdkConfigurationUtil.setDirectoryProjectSdk(myProject, sdk); + myProjectSdksModel.setProjectSdk(sdk); + myInterpreterList.setSelectedSdk(sdk); + } + } + } + + private void editSdk() { + final Sdk currentSdk = getSelectedSdk(); + if (currentSdk != null) { + if (currentSdk.getSdkAdditionalData() instanceof RemoteCredentials) { + editRemoteSdk(currentSdk); + } + else { + editSdk(currentSdk); + } + updateUI(currentSdk); + } + } + + private void editRemoteSdk(Sdk currentSdk) { + PythonRemoteInterpreterManager remoteInterpreterManager = PythonRemoteInterpreterManager.getInstance(); + if (remoteInterpreterManager != null) { + final SdkModificator modificator = myModificators.get(currentSdk); + Set existingSdks = Sets.newHashSet(myProjectSdksModel.getSdks()); + existingSdks.remove(currentSdk); + if (remoteInterpreterManager.editSdk(myProject, modificator, existingSdks)) { + myModifiedModificators.add(modificator); + } + } + } + + private void editSdk(final Sdk currentSdk) { + final SdkModificator modificator = myModificators.get(currentSdk); + final EditSdkDialog dialog = new EditSdkDialog(myProject, modificator, new NullableFunction() { + @Override + public String fun(String s) { + if (isDuplicateSdkName(s, currentSdk)) { + return "Please specify a unique name for the interpreter"; + } + return null; + } + }); + dialog.show(); + if (dialog.isOK()) { + final boolean pathChanged = !Comparing.equal(currentSdk.getHomePath(), dialog.getHomePath()); + if (!currentSdk.getName().equals(dialog.getName()) || pathChanged || dialog.isAssociateChanged()) { + myModifiedModificators.add(modificator); + modificator.setName(dialog.getName()); + modificator.setHomePath(dialog.getHomePath()); + + if (dialog.isAssociateChanged()) { + setSdkAssociated(modificator, dialog.associateWithProject()); + } + if (pathChanged) { + reloadSdk(currentSdk); + } + } + } + } + + private void setSdkAssociated(SdkModificator modificator, boolean isAssociated) { + PythonSdkAdditionalData additionalData = (PythonSdkAdditionalData)modificator.getSdkAdditionalData(); + if (additionalData == null) { + additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(modificator.getHomePath())); + modificator.setSdkAdditionalData(additionalData); + } + if (isAssociated) { + additionalData.associateWithProject(myProject); + } + else { + additionalData.setAssociatedProjectPath(null); + } + } + + private boolean isDuplicateSdkName(String s, Sdk sdk) { + for (Sdk existingSdk : myProjectSdksModel.getSdks()) { + if (existingSdk == sdk) { + continue; + } + String existingName; + if (myModificators.containsKey(existingSdk)) { + existingName = myModificators.get(existingSdk).getName(); + } + else { + existingName = existingSdk.getName(); + } + if (existingName.equals(s)) { + return true; + } + } + return false; + } + + private void removeSdk() { + final Sdk current_sdk = getSelectedSdk(); + if (current_sdk != null) { + myProjectSdksModel.removeSdk(current_sdk); + if (myModificators.containsKey(current_sdk)) { + SdkModificator modificator = myModificators.get(current_sdk); + myModifiedModificators.remove(modificator); + myModificators.remove(current_sdk); + } + refreshSdkList(); + mySdkListChanged = true; + // TODO select initially selected SDK + if (mySdkList.getSelectedIndex() < 0) { + mySdkList.setSelectedIndex(0); + } + } + } + + private void reloadSdk() { + final Sdk currentSdk = getSelectedSdk(); + if (currentSdk != null) { + myModifiedModificators.add(myModificators.get(currentSdk)); + reloadSdk(currentSdk); + } + } + + private void reloadSdk(Sdk currentSdk) { + PythonSdkType.setupSdkPaths(myProject, null, currentSdk, myModificators.get(currentSdk)); // or must it be a RunWriteAction? + reloadSdkPaths(currentSdk); + } + + public void disposeUIResources() { + myInterpreterList.disposeModel(); + clearModificators(); + myFirstReset = true; + } + + private void saveSdkPaths(Sdk selection) { + SdkModificator modificator = myModificators.get(selection); + if (myPathEditor.isModified()) { + myPathEditor.apply(modificator); + myModifiedModificators.add(modificator); + } + } + + private void reloadSdkPaths(Sdk selection) { + List rootPaths = Lists.newArrayList(); + if (selection != null) { + Collections.addAll(rootPaths, selection.getRootProvider().getFiles(OrderRootType.CLASSES)); + myPathEditor.reload(myModificators.get(selection)); + } + else { + myPathEditor.reload(null); + } + } + + private void updateSdkPaths(final Sdk selection) { + final List rootPaths = Lists.newArrayList(); + if (selection != null) { + Collections.addAll(rootPaths, selection.getRootProvider().getFiles(OrderRootType.CLASSES)); + myPathEditor.reset(myModificators.get(selection)); + } + else { + myPathEditor.reset(null); + } + } + + private class CreateVirtualEnvButton extends AnActionButton implements DumbAware { + public CreateVirtualEnvButton() { + super("Create Virtual Environment", PythonIcons.Python.Virtualenv); + } + + @Override + public void actionPerformed(AnActionEvent e) { + Sdk selectedSdk = getSelectedSdk(); + createVirtualEnv(selectedSdk); + } + } + + private class ToggleVirtualEnvFilterButton extends ToggleActionButton implements DumbAware { + public ToggleVirtualEnvFilterButton() { + super("Show virtual environments associated with other projects", AllIcons.General.Filter); + } + + @Override + public boolean isSelected(AnActionEvent e) { + return myShowOtherProjectVirtualenvs; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + myShowOtherProjectVirtualenvs = state; + refreshSdkList(); + } + } +} diff --git a/python/ide/src/com/jetbrains/python/configuration/VirtualEnvProjectFilter.java b/python/ide/src/com/jetbrains/python/configuration/VirtualEnvProjectFilter.java new file mode 100644 index 000000000000..50b2b7436a3f --- /dev/null +++ b/python/ide/src/com/jetbrains/python/configuration/VirtualEnvProjectFilter.java @@ -0,0 +1,50 @@ +package com.jetbrains.python.configuration; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.util.io.FileUtil; +import com.jetbrains.python.sdk.PythonSdkAdditionalData; +import com.jetbrains.python.sdk.PythonSdkType; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** +* @author yole +*/ +public class VirtualEnvProjectFilter implements Predicate { + private final String myBasePath; + + public VirtualEnvProjectFilter(@Nullable final String basePath) { + myBasePath = basePath; + } + + @Override + public boolean apply(@Nullable final Sdk input) { + if (input != null && PythonSdkType.isVirtualEnv(input)) { + PythonSdkAdditionalData data = (PythonSdkAdditionalData) input.getSdkAdditionalData(); + if (data != null) { + final String path = data.getAssociatedProjectPath(); + if (path != null && (myBasePath == null || !path.equals(myBasePath))) { + return true; + } + } + } + return false; + } + + public static void removeNotMatching(Project project, List sdks) { + if (project != null) { + final String basePath = project.getBasePath(); + if (basePath != null) { + Iterables.removeIf(sdks, new VirtualEnvProjectFilter(FileUtil.toSystemIndependentName(basePath))); + } + } + } + + public static void removeAllAssociated(List sdks) { + Iterables.removeIf(sdks, new VirtualEnvProjectFilter(null)); + } +} diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java new file mode 100644 index 000000000000..1919be622ea3 --- /dev/null +++ b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2009 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.PlatformDataKeys; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkAdditionalData; +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.platform.DirectoryProjectGenerator; +import com.intellij.platform.NewDirectoryProjectAction; +import com.jetbrains.python.sdk.PythonSdkAdditionalData; +import com.jetbrains.python.sdk.PythonSdkType; + +import java.util.List; + +/** + * User : catherine + */ +public class PythonNewDirectoryProjectAction extends NewDirectoryProjectAction { + private Sdk mySdk; + private boolean myInstallFramework; + + public void actionPerformed(final AnActionEvent e) { + Project project = e.getData(PlatformDataKeys.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(); + myInstallFramework = dlg.installFramework(); + Project newProject = generateProject(project, dlg); + if (newProject != null) { + SdkConfigurationUtil.setDirectoryProjectSdk(newProject, mySdk); + final List 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 new file mode 100644 index 000000000000..1b959844722e --- /dev/null +++ b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectDialog.java @@ -0,0 +1,292 @@ +/* + * Copyright 2000-2009 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.module.Module; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +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.remotesdk.RemoteSdkData; +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.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.PreferredSdkComparator; +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 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.Collections; +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 sdks = PythonSdkType.getAllSdks(); + VirtualEnvProjectFilter.removeAllAssociated(sdks); + Collections.sort(sdks, PreferredSdkComparator.INSTANCE); + final Sdk preferred = sdks.isEmpty() ? null : sdks.iterator().next(); + mySdkCombo = new PythonSdkChooserCombo(project, sdks, new Condition() { + @Override + public boolean value(Sdk sdk) { + return sdk == preferred; + } + }); + 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 "); + 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, (RemoteSdkData)getSdk().getSdkAdditionalData()); + } + else { + return null; + } + } + + @Override + public void generateProject(@NotNull Project project, + @NotNull VirtualFile baseDir, + Object settings, + @NotNull Module module) { + if (settings instanceof RemoteProjectSettings) { + PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance(); + assert manager != null; + manager.createDeployment(project, baseDir, (RemoteProjectSettings)settings, + (RemoteSdkData)getSdk().getSdkAdditionalData()); + } + } + + @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/python-ide.iml b/python/python-ide.iml index 0a9c7f9fc149..b1c3c129ab68 100644 --- a/python/python-ide.iml +++ b/python/python-ide.iml @@ -22,6 +22,7 @@ +
diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 75fe8c3eb215..0d6326a88198 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -423,6 +423,7 @@ + From 6cd63be7563c21f943235613cdba3c8113a0c4ff Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Aug 2013 17:19:56 +0200 Subject: [PATCH 03/10] we're using separate file type factory for Cython, no need to use it here --- .../pluginSrc/com/jetbrains/python/PythonFileTypeFactory.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/pluginSrc/com/jetbrains/python/PythonFileTypeFactory.java b/python/pluginSrc/com/jetbrains/python/PythonFileTypeFactory.java index 2e7c07c2a340..0075ce121406 100644 --- a/python/pluginSrc/com/jetbrains/python/PythonFileTypeFactory.java +++ b/python/pluginSrc/com/jetbrains/python/PythonFileTypeFactory.java @@ -5,7 +5,6 @@ import com.intellij.openapi.fileTypes.FileTypeConsumer; import com.intellij.openapi.fileTypes.FileTypeFactory; import com.intellij.ultimate.PluginVerifier; import com.intellij.ultimate.UltimateVerifier; -import com.jetbrains.cython.CythonFileType; import com.jetbrains.pyqt.QtUIFileType; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -22,7 +21,6 @@ public class PythonFileTypeFactory extends FileTypeFactory { public void createFileTypes(@NonNls @NotNull final FileTypeConsumer consumer) { consumer.consume(PythonFileType.INSTANCE, "py;pyw;"); - consumer.consume(CythonFileType.INSTANCE, "pyx;pxd;pxi;"); consumer.consume(QtUIFileType.INSTANCE, "ui"); consumer.consume(XmlFileType.INSTANCE, "qrc"); } From 0c74a245415b67bca6f263834fdae75f8f5f6e04 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Aug 2013 17:30:42 +0200 Subject: [PATCH 04/10] tweaking dependencies to allow running pycharm ce --- python/ide/python-ide-community.iml | 3 +++ python/main_pycharm_ce.iml | 4 ++-- python/python-ide.iml | 3 --- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/ide/python-ide-community.iml b/python/ide/python-ide-community.iml index 9cfa2aa868d5..0ec9c8325478 100644 --- a/python/ide/python-ide-community.iml +++ b/python/ide/python-ide-community.iml @@ -5,6 +5,9 @@ + + + diff --git a/python/main_pycharm_ce.iml b/python/main_pycharm_ce.iml index b546319d222c..279ba247051e 100644 --- a/python/main_pycharm_ce.iml +++ b/python/main_pycharm_ce.iml @@ -5,7 +5,6 @@ - @@ -14,11 +13,12 @@ - + +
diff --git a/python/python-ide.iml b/python/python-ide.iml index b1c3c129ab68..08f4987ff1c8 100644 --- a/python/python-ide.iml +++ b/python/python-ide.iml @@ -5,9 +5,6 @@ - - - From 957000559aacf52c00aaf94eedb08bca3bb39486 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Aug 2013 17:52:14 +0200 Subject: [PATCH 05/10] extract pycharm community resources --- python/build/pycharm_build.gant | 7 +- python/build/python_plugin_build.gant | 4 ++ python/python-community.iml | 1 + .../resources/colorSchemes/PythonDarcula.xml | 68 ++++++++++++++++++ .../resources/colorSchemes/PythonDefault.xml | 62 ++++++++++++++++ .../internal/Python Script.py.ft | 1 + .../internal/Python Unit Test.py.ft | 10 +++ .../fileTemplates/internal/Setup Script.py.ft | 12 ++++ .../icons/com/jetbrains/pyqt/tsFile.png | Bin 0 -> 386 bytes .../icons/com/jetbrains/pyqt/tsFile@2x.png | Bin 0 -> 1007 bytes .../icons/com/jetbrains/pyqt/uiForm.png | Bin 0 -> 324 bytes .../icons/com/jetbrains/pyqt/uiForm@2x.png | Bin 0 -> 866 bytes .../jetbrains/python/buildout/buildout.png | Bin 0 -> 197 bytes .../jetbrains/python/buildout/buildout@2x.png | Bin 0 -> 224 bytes .../jetbrains/python/debug/commandLine.png | Bin 0 -> 303 bytes .../jetbrains/python/debug/commandLine@2x.png | Bin 0 -> 534 bytes .../icons/com/jetbrains/python/dotnet.png | Bin 0 -> 499 bytes .../icons/com/jetbrains/python/dotnet@2x.png | Bin 0 -> 1377 bytes .../icons/com/jetbrains/python/jython.png | Bin 0 -> 469 bytes .../icons/com/jetbrains/python/jython@2x.png | Bin 0 -> 880 bytes .../com/jetbrains/python/nodes/cyan-dot.png | Bin 0 -> 209 bytes .../jetbrains/python/nodes/cyan-dot@2x.png | Bin 0 -> 342 bytes .../icons/com/jetbrains/python/nodes/lock.png | Bin 0 -> 204 bytes .../com/jetbrains/python/nodes/lock@2x.png | Bin 0 -> 318 bytes .../python/nodes/red-inv-triangle.png | Bin 0 -> 191 bytes .../python/nodes/red-inv-triangle@2x.png | Bin 0 -> 265 bytes .../com/jetbrains/python/propertyDeleter.png | Bin 0 -> 694 bytes .../jetbrains/python/propertyDeleter@2x.png | Bin 0 -> 1465 bytes .../python/propertyDeleter@2x_dark.png | Bin 0 -> 1458 bytes .../jetbrains/python/propertyDeleter_dark.png | Bin 0 -> 700 bytes .../com/jetbrains/python/propertyGetter.png | Bin 0 -> 682 bytes .../jetbrains/python/propertyGetter@2x.png | Bin 0 -> 1375 bytes .../python/propertyGetter@2x_dark.png | Bin 0 -> 1376 bytes .../jetbrains/python/propertyGetter_dark.png | Bin 0 -> 682 bytes .../com/jetbrains/python/propertySetter.png | Bin 0 -> 687 bytes .../jetbrains/python/propertySetter@2x.png | Bin 0 -> 1447 bytes .../python/propertySetter@2x_dark.png | Bin 0 -> 1428 bytes .../jetbrains/python/propertySetter_dark.png | Bin 0 -> 668 bytes .../icons/com/jetbrains/python/pypy.png | Bin 0 -> 697 bytes .../icons/com/jetbrains/python/pypy@2x.png | Bin 0 -> 1680 bytes .../icons/com/jetbrains/python/python.png | Bin 0 -> 628 bytes .../icons/com/jetbrains/python/python@2x.png | Bin 0 -> 1253 bytes .../com/jetbrains/python/pythonClosed.png | Bin 0 -> 393 bytes .../com/jetbrains/python/pythonClosed@2x.png | Bin 0 -> 981 bytes .../com/jetbrains/python/pythonTests.png | Bin 0 -> 715 bytes .../com/jetbrains/python/pythonTests@2x.png | Bin 0 -> 1528 bytes .../icons/com/jetbrains/python/python_24.png | Bin 0 -> 1020 bytes .../com/jetbrains/python/python_24@2x.png | Bin 0 -> 2033 bytes .../icons/com/jetbrains/python/virtualenv.png | Bin 0 -> 715 bytes .../com/jetbrains/python/virtualenv@2x.png | Bin 0 -> 1513 bytes .../BuildoutUnresolvedPartInspection.html | 5 ++ .../PyAbstractClassInspection.html | 7 ++ .../PyArgumentEqualDefaultInspection.html | 7 ++ .../PyArgumentListInspection.html | 8 +++ .../PyAttributeOutsideInitInspection.html | 7 ++ .../PyAugmentAssignmentInspection.html | 7 ++ .../PyBroadExceptionInspection.html | 8 +++ .../PyByteLiteralInspection.html | 7 ++ .../PyCallByClassInspection.html | 15 ++++ .../PyCallingNonCallableInspection.html | 7 ++ .../PyChainedComparisonsInspection.html | 7 ++ .../PyClassHasNoInitInspection.html | 7 ++ .../PyClassicStyleClassInspection.html | 5 ++ .../PyComparisonWithNoneInspection.html | 8 +++ .../PyCompatibilityInspection.html | 8 +++ .../PyDecoratorInspection.html | 7 ++ .../PyDefaultArgumentInspection.html | 9 +++ .../PyDeprecatedModulesInspection.html | 7 ++ .../PyDeprecationInspection.html | 8 +++ .../PyDictCreationInspection.html | 6 ++ .../PyDictDuplicateKeysInspection.html | 7 ++ .../PyDocstringInspection.html | 7 ++ .../PyDocstringTypesInspection.html | 5 ++ .../PyExceptClausesOrderInspection.html | 9 +++ .../PyExceptionInheritInspection.html | 7 ++ .../PyFromFutureImportInspection.html | 7 ++ .../PyGlobalUndefinedInspection.html | 7 ++ .../PyInconsistentIndentationInspection.html | 7 ++ .../PyInitNewSignatureInspection.html | 7 ++ .../PyInterpreterInspection.html | 5 ++ .../PyListCreationInspection.html | 8 +++ .../PyMandatoryEncodingInspection.html | 7 ++ .../PyMethodFirstArgAssignmentInspection.html | 6 ++ .../PyMethodMayBeStaticInspection.html | 7 ++ .../PyMethodOverridingInspection.html | 6 ++ .../PyMethodParametersInspection.html | 5 ++ .../PyMissingConstructorInspection.html | 7 ++ .../PyNestedDecoratorsInspection.html | 7 ++ .../PyNonAsciiCharInspection.html | 7 ++ .../PyNoneFunctionAssignmentInspection.html | 6 ++ .../PyOldStyleClassesInspection.html | 7 ++ .../PyPackageRequirementsInspection.html | 5 ++ .../PyPep8Inspection.html | 5 ++ .../PyPropertyAccessInspection.html | 8 +++ .../PyPropertyDefinitionInspection.html | 8 +++ .../PyProtectedMemberInspection.html | 7 ++ .../PyRaisingNewStyleClassInspection.html | 9 +++ .../PyRedeclarationInspection.html | 10 +++ .../PyRedundantParenthesesInspection.html | 7 ++ .../PyReturnFromInitInspection.html | 6 ++ .../PySetFunctionToLiteralInspection.html | 8 +++ .../PyShadowingBuiltinsInspection.html | 5 ++ .../PySimplifyBooleanCheckInspection.html | 7 ++ .../PySingleQuotedDocstringInspection.html | 7 ++ .../PyStatementEffectInspection.html | 7 ++ .../PyStringExceptionInspection.html | 7 ++ .../PyStringFormatInspection.html | 7 ++ .../PySuperArgumentsInspection.html | 7 ++ .../PyTrailingSemicolonInspection.html | 5 ++ .../PyTupleAssignmentBalanceInspection.html | 6 ++ .../PyTupleItemAssignmentInspection.html | 7 ++ .../PyTypeCheckerInspection.html | 8 +++ .../PyUnboundLocalVariableInspection.html | 5 ++ .../PyUnnecessaryBackslashInspection.html | 7 ++ .../PyUnreachableCodeInspection.html | 3 + .../PyUnresolvedReferencesInspection.html | 7 ++ .../PyUnsupportedFeaturesInspection.html | 7 ++ .../PyUnusedLocalInspection.html | 3 + .../RestRoleInspection.html | 7 ++ .../after.py.template | 1 + .../before.py.template | 1 + .../description.html | 7 ++ .../after.py.template | 2 + .../before.py.template | 2 + .../description.html | 7 ++ .../after.py.template | 2 + .../before.py.template | 2 + .../description.html | 8 +++ .../after.py.template | 2 + .../before.py.template | 2 + .../description.html | 8 +++ .../after.py.template | 2 + .../before.py.template | 2 + .../description.html | 8 +++ .../after.py.template | 7 ++ .../before.py.template | 4 ++ .../description.html | 7 ++ .../after.py.template | 13 ++++ .../before.py.template | 12 ++++ .../description.html | 5 ++ .../after.py.template | 14 ++++ .../before.py.template | 15 ++++ .../description.html | 5 ++ .../after.py.template | 3 + .../before.py.template | 3 + .../description.html | 7 ++ .../PyDemorganIntention/after.py.template | 2 + .../PyDemorganIntention/before.py.template | 2 + .../PyDemorganIntention/description.html | 14 ++++ .../after.py.template | 1 + .../before.py.template | 1 + .../description.html | 7 ++ .../after.py.template | 1 + .../before.py.template | 1 + .../description.html | 7 ++ .../after.py.template | 2 + .../before.py.template | 2 + .../description.html | 7 ++ .../after.py.template | 7 ++ .../before.py.template | 2 + .../description.html | 7 ++ .../PyJoinIfIntention/after.py.template | 2 + .../PyJoinIfIntention/before.py.template | 3 + .../PyJoinIfIntention/description.html | 7 ++ .../after.py.template | 2 + .../before.py.template | 2 + .../description.html | 8 +++ .../PyQuotedStringIntention/after.py.template | 1 + .../before.py.template | 1 + .../PyQuotedStringIntention/description.html | 7 ++ .../PySplitIfIntention/after.py.template | 3 + .../PySplitIfIntention/before.py.template | 2 + .../PySplitIfIntention/description.html | 7 ++ .../after.py.template | 1 + .../before.py.template | 1 + .../description.html | 8 +++ .../after.py.template | 4 ++ .../before.py.template | 1 + .../description.html | 7 ++ .../PyYieldFromIntention/after.py.template | 1 + .../PyYieldFromIntention/before.py.template | 2 + .../PyYieldFromIntention/description.html | 5 ++ .../after.py.template | 3 + .../before.py.template | 1 + .../description.html | 7 ++ .../after.html.template | 5 ++ .../before.html.template | 2 + .../description.html | 7 ++ .../after.html.template | 2 + .../before.html.template | 2 + .../description.html | 7 ++ .../after.html.template | 3 + .../before.html.template | 2 + .../TypeAssertionIntention/description.html | 7 ++ .../WrapTransTagIntention/after.html.template | 1 + .../before.html.template | 1 + .../WrapTransTagIntention/description.html | 7 ++ python/resources/liveTemplates/Python.xml | 24 +++++++ 198 files changed, 1009 insertions(+), 2 deletions(-) create mode 100644 python/resources/colorSchemes/PythonDarcula.xml create mode 100644 python/resources/colorSchemes/PythonDefault.xml create mode 100644 python/resources/fileTemplates/internal/Python Script.py.ft create mode 100644 python/resources/fileTemplates/internal/Python Unit Test.py.ft create mode 100644 python/resources/fileTemplates/internal/Setup Script.py.ft create mode 100644 python/resources/icons/com/jetbrains/pyqt/tsFile.png create mode 100644 python/resources/icons/com/jetbrains/pyqt/tsFile@2x.png create mode 100644 python/resources/icons/com/jetbrains/pyqt/uiForm.png create mode 100644 python/resources/icons/com/jetbrains/pyqt/uiForm@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/buildout/buildout.png create mode 100644 python/resources/icons/com/jetbrains/python/buildout/buildout@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/debug/commandLine.png create mode 100644 python/resources/icons/com/jetbrains/python/debug/commandLine@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/dotnet.png create mode 100644 python/resources/icons/com/jetbrains/python/dotnet@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/jython.png create mode 100644 python/resources/icons/com/jetbrains/python/jython@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/nodes/cyan-dot.png create mode 100644 python/resources/icons/com/jetbrains/python/nodes/cyan-dot@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/nodes/lock.png create mode 100644 python/resources/icons/com/jetbrains/python/nodes/lock@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/nodes/red-inv-triangle.png create mode 100644 python/resources/icons/com/jetbrains/python/nodes/red-inv-triangle@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/propertyDeleter.png create mode 100644 python/resources/icons/com/jetbrains/python/propertyDeleter@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/propertyDeleter@2x_dark.png create mode 100644 python/resources/icons/com/jetbrains/python/propertyDeleter_dark.png create mode 100644 python/resources/icons/com/jetbrains/python/propertyGetter.png create mode 100644 python/resources/icons/com/jetbrains/python/propertyGetter@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/propertyGetter@2x_dark.png create mode 100644 python/resources/icons/com/jetbrains/python/propertyGetter_dark.png create mode 100644 python/resources/icons/com/jetbrains/python/propertySetter.png create mode 100644 python/resources/icons/com/jetbrains/python/propertySetter@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/propertySetter@2x_dark.png create mode 100644 python/resources/icons/com/jetbrains/python/propertySetter_dark.png create mode 100644 python/resources/icons/com/jetbrains/python/pypy.png create mode 100644 python/resources/icons/com/jetbrains/python/pypy@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/python.png create mode 100644 python/resources/icons/com/jetbrains/python/python@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/pythonClosed.png create mode 100644 python/resources/icons/com/jetbrains/python/pythonClosed@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/pythonTests.png create mode 100644 python/resources/icons/com/jetbrains/python/pythonTests@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/python_24.png create mode 100644 python/resources/icons/com/jetbrains/python/python_24@2x.png create mode 100644 python/resources/icons/com/jetbrains/python/virtualenv.png create mode 100644 python/resources/icons/com/jetbrains/python/virtualenv@2x.png create mode 100644 python/resources/inspectionDescriptions/BuildoutUnresolvedPartInspection.html create mode 100644 python/resources/inspectionDescriptions/PyAbstractClassInspection.html create mode 100644 python/resources/inspectionDescriptions/PyArgumentEqualDefaultInspection.html create mode 100644 python/resources/inspectionDescriptions/PyArgumentListInspection.html create mode 100644 python/resources/inspectionDescriptions/PyAttributeOutsideInitInspection.html create mode 100644 python/resources/inspectionDescriptions/PyAugmentAssignmentInspection.html create mode 100644 python/resources/inspectionDescriptions/PyBroadExceptionInspection.html create mode 100644 python/resources/inspectionDescriptions/PyByteLiteralInspection.html create mode 100644 python/resources/inspectionDescriptions/PyCallByClassInspection.html create mode 100644 python/resources/inspectionDescriptions/PyCallingNonCallableInspection.html create mode 100644 python/resources/inspectionDescriptions/PyChainedComparisonsInspection.html create mode 100644 python/resources/inspectionDescriptions/PyClassHasNoInitInspection.html create mode 100644 python/resources/inspectionDescriptions/PyClassicStyleClassInspection.html create mode 100644 python/resources/inspectionDescriptions/PyComparisonWithNoneInspection.html create mode 100644 python/resources/inspectionDescriptions/PyCompatibilityInspection.html create mode 100644 python/resources/inspectionDescriptions/PyDecoratorInspection.html create mode 100644 python/resources/inspectionDescriptions/PyDefaultArgumentInspection.html create mode 100644 python/resources/inspectionDescriptions/PyDeprecatedModulesInspection.html create mode 100644 python/resources/inspectionDescriptions/PyDeprecationInspection.html create mode 100644 python/resources/inspectionDescriptions/PyDictCreationInspection.html create mode 100644 python/resources/inspectionDescriptions/PyDictDuplicateKeysInspection.html create mode 100644 python/resources/inspectionDescriptions/PyDocstringInspection.html create mode 100644 python/resources/inspectionDescriptions/PyDocstringTypesInspection.html create mode 100644 python/resources/inspectionDescriptions/PyExceptClausesOrderInspection.html create mode 100644 python/resources/inspectionDescriptions/PyExceptionInheritInspection.html create mode 100644 python/resources/inspectionDescriptions/PyFromFutureImportInspection.html create mode 100644 python/resources/inspectionDescriptions/PyGlobalUndefinedInspection.html create mode 100644 python/resources/inspectionDescriptions/PyInconsistentIndentationInspection.html create mode 100644 python/resources/inspectionDescriptions/PyInitNewSignatureInspection.html create mode 100644 python/resources/inspectionDescriptions/PyInterpreterInspection.html create mode 100644 python/resources/inspectionDescriptions/PyListCreationInspection.html create mode 100644 python/resources/inspectionDescriptions/PyMandatoryEncodingInspection.html create mode 100644 python/resources/inspectionDescriptions/PyMethodFirstArgAssignmentInspection.html create mode 100644 python/resources/inspectionDescriptions/PyMethodMayBeStaticInspection.html create mode 100644 python/resources/inspectionDescriptions/PyMethodOverridingInspection.html create mode 100644 python/resources/inspectionDescriptions/PyMethodParametersInspection.html create mode 100644 python/resources/inspectionDescriptions/PyMissingConstructorInspection.html create mode 100644 python/resources/inspectionDescriptions/PyNestedDecoratorsInspection.html create mode 100644 python/resources/inspectionDescriptions/PyNonAsciiCharInspection.html create mode 100644 python/resources/inspectionDescriptions/PyNoneFunctionAssignmentInspection.html create mode 100644 python/resources/inspectionDescriptions/PyOldStyleClassesInspection.html create mode 100644 python/resources/inspectionDescriptions/PyPackageRequirementsInspection.html create mode 100644 python/resources/inspectionDescriptions/PyPep8Inspection.html create mode 100644 python/resources/inspectionDescriptions/PyPropertyAccessInspection.html create mode 100644 python/resources/inspectionDescriptions/PyPropertyDefinitionInspection.html create mode 100644 python/resources/inspectionDescriptions/PyProtectedMemberInspection.html create mode 100644 python/resources/inspectionDescriptions/PyRaisingNewStyleClassInspection.html create mode 100644 python/resources/inspectionDescriptions/PyRedeclarationInspection.html create mode 100644 python/resources/inspectionDescriptions/PyRedundantParenthesesInspection.html create mode 100644 python/resources/inspectionDescriptions/PyReturnFromInitInspection.html create mode 100644 python/resources/inspectionDescriptions/PySetFunctionToLiteralInspection.html create mode 100644 python/resources/inspectionDescriptions/PyShadowingBuiltinsInspection.html create mode 100644 python/resources/inspectionDescriptions/PySimplifyBooleanCheckInspection.html create mode 100644 python/resources/inspectionDescriptions/PySingleQuotedDocstringInspection.html create mode 100644 python/resources/inspectionDescriptions/PyStatementEffectInspection.html create mode 100644 python/resources/inspectionDescriptions/PyStringExceptionInspection.html create mode 100644 python/resources/inspectionDescriptions/PyStringFormatInspection.html create mode 100644 python/resources/inspectionDescriptions/PySuperArgumentsInspection.html create mode 100644 python/resources/inspectionDescriptions/PyTrailingSemicolonInspection.html create mode 100644 python/resources/inspectionDescriptions/PyTupleAssignmentBalanceInspection.html create mode 100644 python/resources/inspectionDescriptions/PyTupleItemAssignmentInspection.html create mode 100644 python/resources/inspectionDescriptions/PyTypeCheckerInspection.html create mode 100644 python/resources/inspectionDescriptions/PyUnboundLocalVariableInspection.html create mode 100644 python/resources/inspectionDescriptions/PyUnnecessaryBackslashInspection.html create mode 100644 python/resources/inspectionDescriptions/PyUnreachableCodeInspection.html create mode 100644 python/resources/inspectionDescriptions/PyUnresolvedReferencesInspection.html create mode 100644 python/resources/inspectionDescriptions/PyUnsupportedFeaturesInspection.html create mode 100644 python/resources/inspectionDescriptions/PyUnusedLocalInspection.html create mode 100644 python/resources/inspectionDescriptions/RestRoleInspection.html create mode 100644 python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/description.html create mode 100644 python/resources/intentionDescriptions/ConvertVariadicParamIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/ConvertVariadicParamIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/ConvertVariadicParamIntention/description.html create mode 100644 python/resources/intentionDescriptions/ImportFromToImportIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/ImportFromToImportIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/ImportFromToImportIntention/description.html create mode 100644 python/resources/intentionDescriptions/ImportToImportFromIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/ImportToImportFromIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/ImportToImportFromIntention/description.html create mode 100644 python/resources/intentionDescriptions/ImportToggleAliasIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/ImportToggleAliasIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/ImportToggleAliasIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyDemorganIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyDemorganIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyDemorganIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyFlipComparisonIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyFlipComparisonIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyFlipComparisonIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyGenerateDocstringIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyGenerateDocstringIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyGenerateDocstringIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyJoinIfIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyJoinIfIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyJoinIfIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyNegateComparisonIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyNegateComparisonIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyNegateComparisonIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyQuotedStringIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyQuotedStringIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyQuotedStringIntention/description.html create mode 100644 python/resources/intentionDescriptions/PySplitIfIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PySplitIfIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PySplitIfIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/description.html create mode 100644 python/resources/intentionDescriptions/PyYieldFromIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/PyYieldFromIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/PyYieldFromIntention/description.html create mode 100644 python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/after.py.template create mode 100644 python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/before.py.template create mode 100644 python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/description.html create mode 100644 python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/after.html.template create mode 100644 python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/before.html.template create mode 100644 python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/description.html create mode 100644 python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/after.html.template create mode 100644 python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/before.html.template create mode 100644 python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/description.html create mode 100644 python/resources/intentionDescriptions/TypeAssertionIntention/after.html.template create mode 100644 python/resources/intentionDescriptions/TypeAssertionIntention/before.html.template create mode 100644 python/resources/intentionDescriptions/TypeAssertionIntention/description.html create mode 100644 python/resources/intentionDescriptions/WrapTransTagIntention/after.html.template create mode 100644 python/resources/intentionDescriptions/WrapTransTagIntention/before.html.template create mode 100644 python/resources/intentionDescriptions/WrapTransTagIntention/description.html create mode 100644 python/resources/liveTemplates/Python.xml diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index 73910d56afaf..c023154a5458 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -137,7 +137,8 @@ target('default': "Build artifacts") { def launcher = "${paths.distWin}/bin/pycharm.exe" List resourcePaths = ["$home/community/community-resources/src", "$home/community/platform/icons/src", - "$home/python/resources"] + "$home/python/resources", + "$home/python/community/resources"] buildWinLauncher("$home/community", "$home/community/bin/WinLauncher/WinLauncher.exe", launcher, appInfoFile(), "$home/python/build/pycharm_launcher.properties", system_selector, resourcePaths) signExe(launcher) @@ -267,13 +268,15 @@ private layoutFull(Map args, String target, Set usedJars) { fileset(dir: "$home/python/resources") { include(name: "**/tips/**") } + fileset(dir: "$home/python/community/resources") { + include(name: "**/tips/**") + } module("platform-resources-en") { ant.patternset { exclude(name: "tips/images/switcher.png") exclude(name: "tips/images/navigateToFilePath.gif") } } - zipfileset(dir: "$home/python/resources/tips", prefix: "tips") } jar("icons.jar") { module("icons") } diff --git a/python/build/python_plugin_build.gant b/python/build/python_plugin_build.gant index d7bee89e7ca8..6b8aa89a481b 100644 --- a/python/build/python_plugin_build.gant +++ b/python/build/python_plugin_build.gant @@ -333,6 +333,10 @@ target(name: "compile", description: "Compile module python") { patternset(refid: "resources.pt") type(type: "file") } + fileset(dir: "${pluginHome}/community/resources") { + patternset(refid: "resources.pt") + type(type: "file") + } connectorPlugins.each { fileset(dir: "${pluginHome}/${it}/resources") { patternset(refid: "resources.pt") diff --git a/python/python-community.iml b/python/python-community.iml index c068a3c62842..676b4956e068 100644 --- a/python/python-community.iml +++ b/python/python-community.iml @@ -4,6 +4,7 @@ + diff --git a/python/resources/colorSchemes/PythonDarcula.xml b/python/resources/colorSchemes/PythonDarcula.xml new file mode 100644 index 000000000000..97d59dde6c58 --- /dev/null +++ b/python/resources/colorSchemes/PythonDarcula.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + diff --git a/python/resources/colorSchemes/PythonDefault.xml b/python/resources/colorSchemes/PythonDefault.xml new file mode 100644 index 000000000000..058ac3c402f1 --- /dev/null +++ b/python/resources/colorSchemes/PythonDefault.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + diff --git a/python/resources/fileTemplates/internal/Python Script.py.ft b/python/resources/fileTemplates/internal/Python Script.py.ft new file mode 100644 index 000000000000..edba329d3074 --- /dev/null +++ b/python/resources/fileTemplates/internal/Python Script.py.ft @@ -0,0 +1 @@ +__author__ = '$USER' diff --git a/python/resources/fileTemplates/internal/Python Unit Test.py.ft b/python/resources/fileTemplates/internal/Python Unit Test.py.ft new file mode 100644 index 000000000000..bc5c1af456cb --- /dev/null +++ b/python/resources/fileTemplates/internal/Python Unit Test.py.ft @@ -0,0 +1,10 @@ +__author__ = '$USER' + +import unittest + +class MyTestCase(unittest.TestCase): + def test_something(self): + self.assertEqual(True, False) + +if __name__ == '__main__': + unittest.main() diff --git a/python/resources/fileTemplates/internal/Setup Script.py.ft b/python/resources/fileTemplates/internal/Setup Script.py.ft new file mode 100644 index 000000000000..cb9cb9b36e0b --- /dev/null +++ b/python/resources/fileTemplates/internal/Setup Script.py.ft @@ -0,0 +1,12 @@ +from distutils.core import setup + +setup( + name='$Package_name', + version='$Version', + packages=$PackageList,$PackageDirs + url='$URL', + license='$License', + author='$Author', + author_email='$Author_Email', + description='$Description' +) diff --git a/python/resources/icons/com/jetbrains/pyqt/tsFile.png b/python/resources/icons/com/jetbrains/pyqt/tsFile.png new file mode 100644 index 0000000000000000000000000000000000000000..4f962a2bdae2a0c36441192253383fd980d600b0 GIT binary patch literal 386 zcmV-|0e$|7P)F35|fZ%z!gLQ!vf3!c@wJvOpHvxIQ);- z5S%WUcxf8LEc?ljd~mKCOmBLy4Qv~(#Ks8nFHrI~x?wmp{eh(ym=|DyI29@h2RJlO g#_9q}06>5N00~BCCjnVoi2wiq07*qoM6N<$f{PrOpa1{> literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/pyqt/tsFile@2x.png b/python/resources/icons/com/jetbrains/pyqt/tsFile@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..628e5af168b1987f806146c18c577233fd4ce944 GIT binary patch literal 1007 zcmV86`bO>?@O zIn5NoGR#7h%F2qO9x5WDKTr{2Ne{gg>p>-r(1$Fvhw7mo3dDjQg6NNqRvHqPVo4!c zIOjAsbGqr=pWAot=Ja0w-Q7+44y`MQ{po5B%osxILgDx3QMB3oyWXU#1%Gy2p*1dkiaif>gWqcxYLM_V`_=I0<$EZY!<-W1&W3xdTB1K1n zIexsF*oPS5QU`pt2?-E;gNwEfwt>+$2n{_?q2FqtqmdK0j=o=*m=8s(w$S~uJPq6_ ztYNH=;(Uqi53YsCXUP#Ny6rN5oAHK!U(MZgUlox=x4A1f;J!UOAF=<1;YssMo+-z5 zV+xzzpGxR6x!6;S%ywqv$RhOpP|y9^&U!FT40-!?Q2wdP_hig!i-@$G-vw+D5_3^* z#&s9v$+8gPlG$4@-NABAxA(WzagTu2VfF5mS(_rgzpYMN(B6jg5*R?y5lfS&GOnk} z)pTpL8JCy9wD^iu+kGjQ8Iu87F`2X&J4{`3-%3JJVCR9^rZwnbXHpTwg~dYE=5iF@ z2q?niK_C!7`)~*7$NOj0ZXczK)S1jvFzK>GReN>d5g;14g{mH&G=W4Uh6JgCUVP9t z1dqNyW{hn%yaP9il~h7??ZnNHNjJd6AF2&{_@eA3eh zqf-`or^nZFKD$``5g|D!oLJBk>f&1$ literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/pyqt/uiForm.png b/python/resources/icons/com/jetbrains/pyqt/uiForm.png new file mode 100644 index 0000000000000000000000000000000000000000..048cc19dc1c2d963fccddf185bdb4eabbe8eb031 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xo_V@BhE&{2`t$$4Ju}Cdxz^%`4)97f><~QW>F39G*@x#y zvxdStckz^iizWzmOPna}bJ!z(s(p8hh`0@F67Py|2@lf-!S>SzdkbQI%J>EAyqDT~ z_==2uL0@9u;gB_n49vC;bJ&lpiQv&^eWd9S({Y}g^~9`1h7|29Pc2&xHAH#`Ft1^3 z>2={vm^G32pnQkxubn)a?3)f+cw3A5G&A(5nM!SBx+P`s`xjG%gwGxuUY%_(51Lg( zGzfF_ow>r-v#BVB+hNv(zkDq94M}S(Vii90zSo)Xi~aH9Y_>-yHS`q38CWD3wjTAB U=ASLN3Fu=6Pgg&ebxsLQ0MfE{8UO$Q literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/pyqt/uiForm@2x.png b/python/resources/icons/com/jetbrains/pyqt/uiForm@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a4b359a8a4fa2674bde26d9b88c70ab1a23af93b GIT binary patch literal 866 zcmV-o1D*VdP)`>7WjX zo3TkGCnsZwF)>gdGy!ofv5INofd8a8f))S0Og3m!kg z3?X(whEU}|25lit1|~)(hC3hcF|4_}p5e*YXN1h~rX︠(4u%qgdO$U9QP zaQWR;1|Fb=o^oz*b%rAP;Lri7mF1D4UN$rk(F4<49&Ts&@be?Xw?E$*R^3^LA_wwy zlqw{~B2+>c$_xsqR}xBaih=3dAMe1$o_~A6@bm9420?ZK26kq4Ap0l7vv1ECV*I|D>s<_^7|`__}AZG;PN*=+-A7<=>eF3^u-B=O%JwG&jEk_{Q=Xg zOspv4F#a!KNYJz>e*g0Wm=@(kltpaJY+#@N{`Z^V>z}W*b-1N7E5)vMz}&yFxyikmTb$hrdaIxoYof4>-PC9J@5hhH3rtNZrn8<@71uw;{Rcn@_#;P%J63>)rmVPIrrWU!UAVsMsr07t=5pyj7to`I{o_~tUOVep^9SkwSq zYErd90xAQ}zq!buC8*9|B5K5-%&!E_hX0Y;B6mOCXXv>wkwKAHp5ev!S7bThKeT!U zQSIop+*4q=55i}G4rwy2W^k0YW4QY6I>W`cm*Hwa*%5@Pk_Z|9GycIQ{_e*+hSk7| zh!F@AHDbYq5gzb`>?q*Z0QnL7jj}iHRsaA107*qoM6N<$f;{7e)c^nh literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/buildout/buildout.png b/python/resources/icons/com/jetbrains/python/buildout/buildout.png new file mode 100644 index 0000000000000000000000000000000000000000..d3133dd0b0a89bdad7cd1f63c4aa75851a8c53ef GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X(mh=qLn>}1{rUgjo>{e_v(f1QlhUfyt2r&31!pH@XKNp6 zaJsCX(D?7NQGppx!;y^ltSQk2H-5-Z4-eSWki)StZs9(0kFQ*JxOdF)J)wQ&E0bm1 s!4B4-y-u?u6b@?h^h`-hZ(v|%IQ-4>_==j?D4>-Lp00i_>zopr0D}}qKmY&$ literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/buildout/buildout@2x.png b/python/resources/icons/com/jetbrains/python/buildout/buildout@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e0bcb6e6593374a7b50eeefeb1e6c9b80f7ab302 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1GO`a}}Ar-fh{`~)Mf7pRZt&NdwF<(NX;i}cEHGO${mT2VV z=E|lh24wtVab5I(3r|>K2}7{?EROa%y#u1tRgQeDFDg3v;4JG7r>0vwlS~Bp{>3=F zjxqdE#JF2tDnm{r-UW|?wwDz literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/debug/commandLine.png b/python/resources/icons/com/jetbrains/python/debug/commandLine.png new file mode 100644 index 0000000000000000000000000000000000000000..e064d3f7fec8c9eda55125af1adf31c0b449caf9 GIT binary patch literal 303 zcmV+~0nq-5P)RCwBA{Qv(y10{e3M1)S;O_nLE zvs@XO7$^iRFh-??@L5tcwx4)wjA8&IBO@zCE|`7sy(&cpr0NUaCPic0@i%%P8YK{y zFJG?s>eVX_QVc>dKwVw^-Fo`9J6Q7RwpS8 zK;Y7)O9H1(of6~X;`-z7@Bffw11?^?DD3R){8Uj<@hgbGfB$~*GiT0-!{kd#OE2Ly zAT~DkE;8TI(eWh+6XgO}w2%rIDb0-(XC{CE0{|JFMwv&Kh(7=T002ovPDHLkV1gUp BdY}LR literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/debug/commandLine@2x.png b/python/resources/icons/com/jetbrains/python/debug/commandLine@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a70992337f1ebefc4bed3a0a90e6210236ff79db GIT binary patch literal 534 zcmV+x0_pvUP)UI600z=j8PaKK;jG&XGx0hA1Ox>It7u{Q`}gnLM$-VnG_d#{ zLlqDECrMgZ_T?u-)!+|-SS5xwK|wy6B|`LEFnAN;%9Sg{A3uJ~K41=b`t&Ks>eZ_y zfLQF=vuA8{cYuY3#Rm=!j=#WA;9Rj{h2+|`YsFr^e91=hL`R#qQPO-(sHN=i!KtgWp-h>D8-rl|u!fR&Z?znPiYCnF=H&lfLV?pmyZ#+qb!C9s(eX?%uu235o_#S^$YL zGc*5JQ&anDVq)@%rVcoB<_s?|*m*yG{KyL8v$M1R)6voSY;0`&nTLnxFU=F-p+kp+ zKr}Be?;k@$!%zD9`d>h40$I)B!-oYRCou7S($v)a#>mKs zRgJB!?FSHz&k!=q%HMR z=;)xEgB>K3E;@*cItvbhgMuJ9xGIQrQCu7xTm^A(a&WCqE-rOb>Xf!h(>C9xi8mz= zx_5B#LEznc&O7Jk-uIXw2w<4S!jS9l1$cG$zQ0j7R0aYlX`kA5CZ7pR-DJJ4XXXmI zwens0nI0%E70>F``VPY|Vtyk3K3Kt?(J~JBI4=vLph#Isvf9>I;0M=~fF=u$;T-n7 zo}3;{3n+5MM!-0_AL}(8@L&~FGhB@GkpPb6Od&oUX{=xjXaGqi*}(XQR&a#wGB5BU zc!DLrVy+U4$DnI>Lwr8s&AFBfN=^y)7s#_%RF^T>YJazZWJq`^9wPEfU%=@LsK_gL zt~VLp8&MK}Fn39(u!=4OK}e891y!|3;7LdbRA3RmbE9bhNfW?dJ4K#O1(t2o29b!s zu*~g1Qy)>lc5N4Y-%sL1);rA(kSuu%#Rl)eELPA=$*FLjB?^QN*pGeeORM%#gT_|_ plo3Vacy1FhkMfxRw*bEa3;;2DqnY7@1~>o!002ovPDHLkV1h^G(s2L) literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/dotnet@2x.png b/python/resources/icons/com/jetbrains/python/dotnet@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1c08889f8a000f2e6e8ff604d8614c7d1d291025 GIT binary patch literal 1377 zcmV-n1)lneP)64>(2 zw+}ME<7mCG0?Rk7F5qjg%H(rtGpWinb#ZM&G0%1#E9@!N9nT%bnz#PA^2_A?G62WM z*DHt@(^kAPX|$>;Qx-o9E7477p%!41hx?;Ry)lwDVzRNkSPH0E?j@}?HKuDMYqc<_ zmS479cm2xY)sJ7h{Bvso9B%PfLgYJJ*rU?SV7Z<}m4OPOfP?o_V4q6U5!s9>ELb$S zxI&e_B8hg_C@DE~>*fqm+M?cSI8Gw zymCKX+w>T2{^``Ai!)j&;&mKX&tAHoruuidko2qq2@;vZuJNFLr_sPO5e#e(1APAs3xfQq%nTMhng`ZzieuH_T+l z9x6Jvr4YNgdSMQGc&Uwds~A}Bf70Mb;n3z!@7NodvQ%SaTM%cNPdp1XU6k5)^7{j$xA&YL*k!5C+YTNjc)xl zMbkH?poB|{mJOmv@%1+cFC6I@`Ccp#Nbb~EHfQd{1<$SxF6+PQ`tC<~wEpz|bJxt9 zGN%RO(y_4FRDzGtEFkJRrc@oNvciPsTarh(nlU@I-Y$L-rJM$*zt7C$HAZO jzhqqkT>@PK{|PVvEF!%_FLP~s00000NkvXXu0mjfwN0C@ literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/jython.png b/python/resources/icons/com/jetbrains/python/jython.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8826310828d86d5719587abb06edd51e58169c GIT binary patch literal 469 zcmV;`0V@89P)}V^HiqW1<%1I(ASFx>c$4w}KO3A9x?9y}14%NMU^-I0+_uT>^1o44eZazy=%TBCn}Xm0Ukd zu!8Pubg`#mrh26x1FpJ^sA*uMY1xYXM1dPw4{m_&%De60i60Mi$hs-fLEO<3!Dx^Q zddeyKvo*BvOil6)*jra1DKn*uF%@F#6#AUwR6&>#aS2 zhH~`o0$;#<3{Y)hc%h=aqnjw_^CR#H?2s`q-eHUpbL@fBb(wFN1(&1aS&Kf&JZ}3b zp*F)biA5+bf+!~`9=pe!aZB}pRTQKvCz+KLD9RH!Q?sP9G&Vvn?j=dz`<+I?9?V2y z`3OAGro3OKJl9C7S7t5~Dl#dN5FH2BGJ3XfnJ&az0`nEAfq9?;hP;duF+)(yrSc5* z8~SK$GakhQPP!ILkn89iU>ZIsV31~>`OW;6#7x-7!8j3yaW)w1_#m>_fLVU7fPoyv zG5rrNC69Z-2vtuWa4lH2RVXr1($Mt9cb0%rc+Ha++}^13&mn*1%nU9lY}Ocih?1F2DdFz1s-6Sivp;0000}1mE71cosr{E!w$ZV(8eET0_Kb#SN;9x$J4^V zEzr*J(M!cJSLL6U6Pp2JAv51jD>fwt;VU<9G-z#PyK_vje0Bu0RN)Cz;p_uh3VjTZ zUOW7e_Htjqs^fRy$N&HJY+ek)%&iGm8WIy392yuIwA@8pmEJsD4z!-Z)78&qol`;+ E04cde&j0`b literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/nodes/cyan-dot@2x.png b/python/resources/icons/com/jetbrains/python/nodes/cyan-dot@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6b4f5766e5ce7f40d254de089bffe776ab5384be GIT binary patch literal 342 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1GKRjI=Ln>}1mE71cosqMHq0mm?H`7M8kT+ri`HYY36zZ6R zcig|<*(lY(+9}I*q_}a0xNonXNIFxYl0bgK0;PneONkD9gu0)eaA4@T&RA%%RaSxZ ztEIBwE61!fr^Q`ad>RZ%azbA|Fc+Gc%0BRIv$M~#a_Hr$opq(;fPNbzivs%{W#{{) zSyl>7)@Kv69q#ZQ(Yml`#;S&o|NsBzVV=wDE^F|rA&|YtD&Y#_ lVm^t|11p%>L>O2k7*1+v1iH0(l>ozl!PC{xWt~$(695ELclQ7Q literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/nodes/lock.png b/python/resources/icons/com/jetbrains/python/nodes/lock.png new file mode 100644 index 0000000000000000000000000000000000000000..7ce8afc104ce5258821e9509d247bf44f1f3f286 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X@;qG}Ln>}1**wiSz`(NBA?6SRqpd?s?ymPX%!Un|UelR3 zN{CE1n7|ORz{FUfzGc%*51{a?8i61DM|nJwTqFbfT=%qyFefY!>XP)}ZT4Hy`!-_d==w literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/nodes/lock@2x.png b/python/resources/icons/com/jetbrains/python/nodes/lock@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..84c278689df8bf268245da8c51c3162ed6d391d5 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1G4?JBQLn>}1**wiSz`&a0aEJHEMh6`Z(Q5u9-Hkg$I_hV> zvp(;Td!Xq^9@`@ulS;=GH|!PkQWh{KI3+E2%#>D0Ye|Y;5h26e%dm-=Wx%EGe9po7K+}|8j+qV29oidL{AN6IXTu$bT=oR-zb_h^!*(`u zYJOF2&J5_`dz3MegViHI-(D|2Hge3}o-IO1Q$fm`|egzzSwJS%X&%jI0cdYz#+Yl|;5$8~XwM O%HZkh=d#Wzp$Pz;J$OC< literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/nodes/red-inv-triangle.png b/python/resources/icons/com/jetbrains/python/nodes/red-inv-triangle.png new file mode 100644 index 0000000000000000000000000000000000000000..0e9ad023fd5ece57067aedbd2a87702d833ed425 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X5}1**wiKnBCZ@*ve=q_$$5_ZAVDBtc&nNoZwTF=>;H&}f4W1*M5f|pnVNR7#RuD4y_y7O=Mxg^o l926x?6Rt3V0dmN>N!v24Ij`l22WQ%mvv4FO#s^qJg@)& literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/nodes/red-inv-triangle@2x.png b/python/resources/icons/com/jetbrains/python/nodes/red-inv-triangle@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1c7c45e603327e6da58a8ea8ee421d19e38dc6d1 GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1Gt36#DLn>}1**wiKnBUl_*w|RI;Y7*(pA~FejKTux%pXmK zzQ(dY(qYqLn83V`v5;em8e7AaR;G{PS(XgX7W*iDeZufDlue6K?TH2JBi5EjvK`Nj z0|X5ge*CzUebrHGJN5@&{2{&NHGBuA%B_%k-y+j6Pi}?W`x6bU{W2Q1A1*1~o5=Y1 z|NsAzY(fTxJO&b_2Uak<$r`+B2xRZEO1Q$fm=7$(z{JClwM|izeRFXu(Af;0u6{1- HoD!Mxi7 zuEg>f9OG^H1aUptQ!CM{W>*J60~FN`4e?_7oDF&A*LW;mZeL`9Q^E6cXyt+JMO zguf9yhvzD~G~|mHn>&diqaQ*vny1)S46H7X6&LkmAQs`3f` c$Nma106O13QrOiXBme*a07*qoM6N<$f{lJX6#xJL literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/propertyDeleter@2x.png b/python/resources/icons/com/jetbrains/python/propertyDeleter@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5e022744fb003c04e9d0daeb8328d9383d0fb13d GIT binary patch literal 1465 zcmV;q1xEUbP)UNQ?pzOeJ7M z1ffl=Hf?Q@Qd-*DrQPjbW@mT&{_SbmF4OKb!FZalGdnZq`@i{b=Zs_+2Jtxk=@8wC zap1>Yv#0ey8?Y6a%z7*zI1KDj=)W8LfyaRFfhRIVua6APx0Oy4W$}oPB1zHgx1FgUt!YE|RaYeE7(ayh9Mk=A}i5QMC z{G0$T10Nqe`*xS6M^6e7zY4xNarI3u^Nsz{~jbs{H zJfcsAC!-V7k?=6YuvgmK|M>E7-;K-P3K5iPoPR8q1I@q@pupqy8HFVt)t)Dr#znH> zpN(Xfswl1kuRRge~q_W*>HlF0a`1QV#FwAk(~R?`CowYug4P8H4eM0XG{HSZ8c@}PiKozOy1%Pz!fM8$gToqCdk$YC#4fO z``I_|ZVyK$t2}x61KS?i{eChkH#D!_>c2AHwNWG{i#U?)ffqShJT9N)@vBzeIvcX^ zz?w(vTTTUhr9H2-?ER#&qGAI$tGJ9?*YB;y@p0e>ZbX??z(MYT>nqDE%2d14JmznH z*pfchtaym>9A4_Z+CkA+h-8$-it^R8sd)#L6jpFKo)M+DfxV)~jOn4lkr49X8h-CY zpGX_d6!0(~pp=T1c^CBYTOZ8`uq!Hg-F~XSe*&HV_7Y=pZ|)w2QJW= zi$`g5^UF?=v)dd9iz9tL6&}yL$1lk@RB$I@ zL(%m3gJuH!GG~%BlhL^b=T7ExDdW~W898CXA>mJf4Yv?PrmfhpSoaf?BlDh(Yf&JQ zJ`d#IWtk^42ZE_oDv?T(r5qR@@2A0$p1JG8qy2P!tbeAJE?;Xpm$})7SiW!bK(C%k zG*D9X!yLn*y6Mn&@6gKfTEt(a8^OP6{N{Bk2`r~|4?JU@N8r|zY@d3}1e}AqCQZ|c zDksvuCsHv`n8tb-@Vsn~?fVok=9RG7>0*(Q@qR}X+syBDj zN5g5XZAs(yCSg8@xy3kcmIK^6`y$b>meh>}`~9tKUD`UqoXpKOc(F1Q!1V9IMJl!u z#>`g71e7(yBAAo8*+!<1vRA`{yk$bWG~zLBaSxF7w`VTq1WY6}aOX?YVLML#s>lrTy8;fqqx`F3V5ok7J2~E?M5yThd#yFY{4CGmxy->_f|INYm=(cW>5g!8N*W7}U?~luk?0HB z=6n21`dQ53xq{=wLPm0RoNlpqYsH)F2I(pQiw!>@J=>=Ox>TFiiz zZ$l>dT#z*Zn_+03mWr>+_%yo-{000B@JGl`xeU)Ok%qCfZSS2PGX2lvUjYUHyb&D$ TW~r0900000NkvXXu0mjfvoFX| literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/propertyDeleter@2x_dark.png b/python/resources/icons/com/jetbrains/python/propertyDeleter@2x_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..fc0705981518d27585a4d4f4ebb6abfb70e7c26c GIT binary patch literal 1458 zcmV;j1x@;iP)0{;CS zcscV&>ngx~9|Z@&ox+KDnejv55y{6Cu#=m>i(qNtf+XiuHNeLJpF6ITx2${?$1F}S zf#1Q~`m)o0Apr2Y)~{FqF`7J$`~oZHFn>%DF~!o z+A@=q899|sHo=+avVShxr!5>=uf$Wkg<&c+&L`J$pa<*(^NdK$t!*&0KuGeO7fHcC zh2*fNs^NLjKt5wcE?rEflBuaSYb?H2iKS(d+~N?YbbKWT?gO9Wsij0Bp+xI7lBB9R zq6j^9RBu=m%?8J5Fcm+x1I9bZl@8-*i%9Uatm7znCE+q&A}~%3^Xmg_oExV~6_8J) zfgqT+DR($qd;EDxu{+3?2XaFTw%ZfNgCa4DPQ+D@r}zkj6LkqWJWrjOWdDtmQU^bb z$wxOjly8$MFr-i3_(mo>-D#e$tI?zBbs{m@iJj#Uc$yQ=2*)I&M)UL3<;WrecNk9d zUWN35guU{eSS;2J%{FM?g~V*f@gDFk7oyT-$g@0v&@XCgZqx$0_oTn{R&U|h(Rv$& zf>9bgeT49Is3hWk@w^;vaMhQwGXdB7& zR08KKP^|iTo>@4{f&2Mi#0dGCcRUGg?%hr?BQaAj7A~iKzkE#nLkDU9pn+Yohb1Hr80U$I%eiH4p(Y z5QlaRY#1WiSJi=bRSC?jcOMamMrvpE3n)PfsKLVTspM$sJ$^{Op+Vb*4b`-Aw|Y5H zBXcH6RCWGm>Vi9~pW|K`CnG03G$j0~un`dsc~?T$=eoZ%IXtUx&dh*x;ddgwz_(6m z4vagFlXq-+>Ptuv;fy>t~Ts%qVM^4U^(w5bpV_BPRur03$3|daUlWb8BtF)jN zp%1@!g%&q0$NX#b&-mXoI&q#F5-qf5#Rl&@g0^L|eH!p`-~hbqGEIwkB~)uIjknMZ z4efON)X$VmkCP6Ex>okm+LaHJs_33mz}i^8JpTv09QYEvkjZ37)1uXjzN*pM<-G;2 zE)w2jSX;EOymEj`=ZSPCY1)=svEE@M3j?wV80u<{l`i$l*mDQr-s2yp8Mk6}fi*o@>&)0|VNOX0Ds!CI^-w5gf{-1dNn zFlRXk*vZti>lSLQKf~OY$M9IzU@f6ZejO+}!Tb4P58 zU0^*7tudY465c^Yp9%06_zCP5pKgw??>*O@+iUOjZZiGP?Oy=~0K0MpafN^0=>Px# M07*qoM6N<$f?wagPyhe` literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/propertyDeleter_dark.png b/python/resources/icons/com/jetbrains/python/propertyDeleter_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..65dd90b3a066945412463d183d6cb12c206ea98b GIT binary patch literal 700 zcmV;t0z>_YP)kdMZJgz1wDAsLtCjRqF^mr5LBvH_2xySU5|<=cqw=&hzF7O z;?Hgy(@nNXwwdwGw29q4c=5qw-n^f0zW4Hi8Dr?<%WvpkVw62`dY-o!1i@|Fwx2W_ zjq`+%tC{ZPf^PSREjk^o#Z|;43tY_mY%C~5eirt8x@Q>1Bgb(L!g+#JVQzNFSAS_|wXO#7|{AeWlF;w&9g*nqSPXNdZVDdNx$Y-t5z-3d#?FN?8!X%1G zF0cAc@};Ef`J;~GzS4DlgtsAy9&`3U%b~ZdQZEKUFqUrBKwo1uI2F3mLwRXW&2^iX z(isFEozx9Y#R!X6-^|aVxASvpYrA(;NOkD&h4Rkf>yUEDH^Nfn?3*QnOS=Sv(2oyj znj(q?ZMIQ3appd{ac&0fEf1rowFec5-2vSXxr2cpA9ug%NHC!5QW0&w-qpLX^Ta^e zOqSaQI92c$Xd4%0xMY%ozeSr27zd_^!8}*oI%>DuNeOIGz}ys!0>8 zzt_TeoprR6*jtt7@LV+~jS2F}zo3NHXv<+!*0$bsk-CKf_2r+dEN9~JNL{{*5(Zqj zLo47bzrMSn-wY9rS-MEv<~|;SoV2)uK_Vo!`(d%B!&Y2nv1G$y##p8enA3ZrOJjlD iSlr4=0Q`^q5nupsP&z3tXUSp!0000K@@(o+w5kOH9y!b zHY$edrFiMVYw+g9KR~7UlM3EMktEtuXd-PXS`dE_?4gIE7op%my;?-62MdC?fR&<9 zG-=bMNt(@OXMD5CY!ekc_~2t_zIpH4Z{9q@7=sTlzQVua!SivkTt_S*GJMnbdtyX4 z<5r!{HFuo^Fv&pb9!T_a`fTo_8j!wZ7p{&Vx7uEW)^bak__tzy3HMWoNr`8K1Lk18 zMDG}}5WxV{?8XJeImBf=JG@a^n~wzg=O->bnf7|nsL~ldtf>UBm;$_6eF@8}uY`lp zk%L16iQ$uQ^w6>E+0n&RZO5uNs*U4#w&Ds{HRnV)rntp!u=Z!{;(btjDtyYXn2WC; zDw9`oVWe+sn$oIl*UHyUPbFLd+LHRA^LMvi2z9uiKMcM;UkKMak~Z>`+JwpC3Os4A zsN;ZfVG0cUxm7NJZQDGD_e^a|ljhzW5L%!%i*=r@-8}rxJiX!W2M2~=^i&#{BOEe3 zr(2$YqRDS-)#jO?uJ$;XIG^izc;OOrLGjD)xt{xsswRz9ws$S3#d@wI*4^MaJQt@j z<(e0Rq*z9>UShMx{yzrE3mhca{83?nC`mWf&AT8R@Zf|NA-8^Rlr4N`pbqnfiLW`w z&oIX;?r|W(@0f8MtU0UhB$y+aIG7HRX%YMM&aX?UhFo0lcI68EPy7;K09_3uNrTi7 QX8-^I07*qoM6N<$f`i~hV*mgE literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/propertyGetter@2x.png b/python/resources/icons/com/jetbrains/python/propertyGetter@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bbb02025b6f2b4355549fbcf6c03aa0225c875cb GIT binary patch literal 1375 zcmV-l1)%zgP)|xQ4;*92@#`DybwbnsWHZw_=FDzA*n_l@RP(?ApwJ0 zjEG=FjZzC13)q%^xb5zCw>vw#=G{pB9n?i8%@A__K=Up=&QPXY6SBljNg zXLDdP_yTV&D2ih9mdPXtcV>oK&4K&CMGP*NSCq*vpOlZzyT&hzML`4vnMgnjjgL>v zB$LTVZ-4hDEfL?3`w8%}RSGyXM}bROp@^&fZx(v|C%C^{D+5zAujst0IG`z|W?uW=jQy~nLKj_BTU)1*SR@&UwMfX%a zM8hMO>F_7rG##AezHX*cshKYED7T*3wCCs}wNK2Yqihv{C;5-t^9?HY zDDwqlbpxF_{}BybyFmRHk5fncZob{Ip|PV6oWZp-8q}T&M}lQWHT@~mffmk@TqHT5 zowKc}s3)&Wp>$uLw}Sk|D^u53um769?*dP!ZJ?d1qHumA3RF+~i>nu8HImj+KQqO|nNlRPS<}r8*S*5@y@=OvI=Q>;C`eE*uG|dqaTZE+smrYT$ zn>Mkfdx4(cx~KnU#uoLBsZkI~T`MJ(dFz-{5J0txCsCs~f7wX4(a9mKg29FRqvJy~ zGBGq?N~@bKZCRVgFt+a{5xAly<4vg|Y0K@oLw3`LeLYmOssZ_z=~iHvCZ|WJT&bp( zbz7}h60}hb`D)P0fphS#O;xqjY|YiGS3XEp<#lxVpC2h42~ZInYHRGI*2e9aXhoJO zU~Q}bo~h@o9QX?CjYgv+%if$0*d>`-8#+@gEfUr?tZlRtR&$`AmvAH+Ruh_@vl3E) zdjxB;wsCYjYvlmTzl9LV;n}dBs}3w!F7?=)x_ksE|F>r? z)`ZE=#u${X4)7Xy4qOO?rewcRCQJ6kUG_hJyr7z)#WjMKYB~oba(x#JaQ()LK(U#K ztEyU1sLik~Yp|BFCk*8KVR8~|L(XClNQ7rYx}K`F`3=l{*@kUdgS8AzD&))Pq_J;b z3P*#&L|{w}M?xqhTGp}o8TU!`g$>&p8Yi<2lB?oy$eQ`X1aHy}(OSS8N{n|kY^`?V zY!K%Phfq5VyBpw5W5O-Fx#x4_Wr1Eptc?#D7^p=}#%fKw8XrRcHa^Y11mEWxc*(K+ hZZ(naa{FI^0RRQN=78EJrey#C002ovPDHLkV1gB(k);3t literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/propertyGetter@2x_dark.png b/python/resources/icons/com/jetbrains/python/propertyGetter@2x_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..69e1fe4d52c624296bb23cf9f435f7da1bc09189 GIT binary patch literal 1376 zcmV-m1)utfP);O;TVl9e0l$JH z-~^&#Ipf}PuKnN#&;!0N#{rJg%V3XVlte+)BuVBgKbtWvQ#FiqC9ZAwzX3c7r;g%! z-f<+~33hN7I8=%QE5H|^4aRi8KS-e}A9?+fSHwsG=Aj<4GV}@1wUm)aPOH;1spKS_ z;juCtVJGwjPJ9lk!GWb5=mKAH$6%n+iqr)a*(bQ=MHD=wjCg)|gOseSw|G=N;6o58 zU2{P18*I)(&qa(b|Xm8St803OFXbbu)tzcLw`ql*+Pk|sX!7#r}y5{QBqAtM7lW*S@Z4*+@Qbh%R40OX_TbL@bMz#s_Fe*KVqdEDt!{LsOnh z-I{RwNr6N)JsSBS9Sic(6>@bVzY;#d>)h`PDw0>Q-`fE%GwsrQ= zeN7M3@W=)F=*zt{6`$a~0Y)+dQy$BEtIAk=(5p4h=A!IYinsHhK+uzsD? zzD-*;^-%kUXK3r=yJ*$D8)#OWq2s3y=lXXCGEG`d`jH>KX4nVq=Ww^xsiuok(9RW3 zsgS&uSv=9p>(@}oAEjL1aHyUlmCNkkSFZn_yYC0j=f*(WuA*@MDHN#wu2=4v7lGB1 zN6xPI5+V=^MCRR>JzkQfYzc}dCtSy}HrwDSC{5wt*J?tvNlyvYMhVboNBU_+<2vMDpnCdD%nMRJWQgT>FiZsTftjq0ZJ`>S*o3M5}O3 z0c&Fg@Jv1F=D@e$O;uG%Q9?x>kR^pW*7e#fY6X@tYdh_z+Z;H~OE{$_^^9Q^t%OwI zc_CPnwVk8e2{#8={#}GfNzNp#Vs&6{M2WB_YqO2~7%e;%e+o_~Q*le1)t8O{mHzgu z#hMs$#<5ZGK*DR_MQ|#Xm{cM{ts=?uyX<@Ea9K6ONE-w#J?|WlDfV4(k?S{B1d7dg zTG#cmLY)tfWewJH_JoV2ewYk^XOS}v0-5AY!m{jITbg0+%VT&fYp|B1N#%SQ4LJMu z*`yj5#$%&;GL=9fF$&t|XWYl`i!nUb(HJP_P`WT3oB6{8Z?YGnD*K zkmd@9Q0GqMH^4j2gfq)M6}y#{j~%g2&<#WFx~Z+q+tv6Gde!+f`v&}6%<$X>Y2D$; i^S^2${m<TL==Nvx0{ssRsl3SDED*7|@2{Gy059~Ly z1+T$oTg{*dT(L3r2o(06Ru6vGlFE;o@$E9^7P|0>7=cOc(oQ9Ka3EvonG6M@5Rp!- z!Qx9712=xwT_G$YNG0r&TjMjiL5nDzjlfwrXn8m{isK4n{O5Z6Yk}*|E1W+@A6Epz zN@j-|TWr$KrwJNhS$h2%`W5sWxONQm<~;axKJA>EifZ8QvT4&YGy)_%_5Jc2SXh25 z#ifrQ86GH}z5pkVp1ggCoh>^%Uc>d>GmwI%kic_-^H!cp$#`sM7`y%iXhMT8D@)nu z@1D}}TXPns?->Sd*SDP-sSFlF0@hY?&^^89?jUn1-GW44B8{<$Ngwl!`Gl+T3IepZ zsjGksVg?-Rxml}#@B0EHYNmClNo%hU2&*uk=ZUO7?{G}NxD(EY28QA0#S!3vRLF6i zZAJvtP(L`ktxG9Wiz&E&buRYsQYB)6>guB43!hOll(G7D(+k=>b{!e_y1)o5c4avf zFaHAd>{4Tk&)A34Q6ud)Y$T}usqz9 z5ky5wn>2Ql=4Z2+8D}QhG%NPxgU8N$^S!sGh#PIk&rkpKh&@oP*&B#VaNq>)a5~yoSm$2q*#WmyaJveAu#SU^5Pgt=FR-uxn->*@)pQvI+0va6FXZ*Kqk>+`muJ?RVWUGfvNl>I3h ze0*fyS3KIF;a3H6YW5ktnSI`@+`KUgv4OqN*Ryq$$Hjt0t9GT|l5&TH238U840J1k zvM^fz3?I7%ibsV{U*5sJ7k6Of)Od>LbzOn{a&ZCq8zPdL)akrg)H{tDIYSG8r_JNa z6B~tPX9^9mR*lx3)Cf=}NzTlGZQCvk0)$t`h)9Omw7W4jV6uoFqmySv+`B#sC-*0T zVuvAR_axVBpy=}3;!1VU@To2a7mtp+#^5kuSWq;120MG8>e6t2xoqJYbv?&9w>rmg ztm>5#g1ocJiWQ2Ne$%ngx^}eIE)Yh2X(3O&L6oejOE+Ab$P;=8I=47)T5QfhFs*CB z#bjrm<97_xEOs$)OvB+wWrd`z5{^+Ug%JXbWRhh%O=~_WQIWIXTUm()|6_jy7ytuG VAJc7@P>lcp002ovPDHLkV1koKIlBM= literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/propertySetter@2x.png b/python/resources/icons/com/jetbrains/python/propertySetter@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f9dbee7c19059ea57ff30407a1ed7b2b311c1723 GIT binary patch literal 1447 zcmV;Y1z7rtP)ZI?di zgT8=@(l!{%qg_c&2x%b%TNZjER4I1Y)Y9!6pU8Mx#ig1}cwM zq$Kr61GcqD3w`UB?$Yhf&d&Iq?JVhIc6VB1ILWs&*?aDH&OPVcbLVo3qA-${kMFR> zO2hes(T3IlCx9bBvzCH^{eQ9%_yt%C6h~9y77zgrcnsJMlmjb(Bz4RK^Z<>(&!4os zlrJkXt=JB{3A_=Fl-IEmiqf;d%c@ak;0yttH_?;kdtuBgNx^nJxy#+(98j3DU*(Qz zT#o~Jz$u^<#zdRV!JJF1%xvS$WSWC(3Pmx*T7ZGm=Nrm9Z?`^;e+@22#_?UHFMdHb zP$SY}QcwY$1`-|i1VeJFgELtYK1Y05>PI4UZKsAtCy}7>KT~hTK$8l2M za8KRQuMa;D4hN#>gl0alVejMba0BRgF%S+tY>>iad}=c?Sb%xZSB?!FG@ zpYlou1MkhvSUs`5qW)rPa`v^h&L7jyv^E|H$&x*H*+VDmx4zbNr+=uJwk)Q9fK(`R zBe0qFxy|YjcrzDu#SyuAyOZ?~{lVOi?qrqjJ$!!F8tbir>-L5(50#HkjBVQZ@Ydnl zihb|dEeZXZOY=sJW-bxj*=l<()GESl^ka8er*j)euo6~ZbA%;0T+24BXC=6uzR3wr?W8y6I#5O(PO$K1aL1MGv{lS$bFqkS zk~57ZC!|{`tv!9e8}a`-b+uIeA`k+%3>y-hFGDeYTJc=wEC*KdM$`0u*AW4yJ$aU% z$!KOK-b}BS3Evp)3<2*})i`ZE8QcnN1Vt%e)k;B<0hL58MbY5^74J+vc}9(32hh$S zZt{rQaEMgEt-uCpxuP~AJ;q7?xjQsVHz4|f$?&^t$+E~8uVF)0otoDNJm^+I8NO0p zqah-LW4+h~UHAVV9O-2PqrKCuG-ti$T;e7h>hV1<0^O1vEDZ-sM^`rsc6Q?X*I8ah z5%MpvVb3i#Ha@^oT{*0*c&Bz9fm;fNJ8_qm18wlmEs7FDwZ?TIC;btYmAaB$|La%g zoAfXX9CDY`u=0{>#v3h~sU&Xf0IG{NEeFm32mO9O69i{m2TZ)c%8P2knBOF{=Mc9l zKWNp!1^TR-^!vn+q{QunOy4ZjX9EeDAH9fU~m-Sa6?Pd_$ihE5PCag&Xi zF`9cCeh##wT`GYoF?Ix){?!u~abn6f)kf40650d1fvXraAG;kY$Jxc+ z3n*mk>0*MF90F+pfWrnC6Jz*dVp6{ig4E#*cEC`X zC=@JK$10!}GogACwr_1D1aU7yzG)?&Y`XhA#jB002ovPDHLkV1ng4 BqC5Zq literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/propertySetter@2x_dark.png b/python/resources/icons/com/jetbrains/python/propertySetter@2x_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..072bd5e4e8b779f9aebf7643b7f29af7ed160599 GIT binary patch literal 1428 zcmV;F1#9|=P)h2=7(TvDYZcaA+^%t1MFXavCQSW8og zN^P6eq-iusvoV`yx4YTd*%`mHnGJc&K9W+r@a-&f@BPkq&pG$pxq@k$#O>4v|Im7y zde5~?UCqF8;0VxXH$bF2*B$_V0=5FJnFh&gAQXUyfSo`Ga5v!Rj@X~oAv~@ECx9Q+ zrqNmwOkS}EcmsI-b_B4Oo&^qBMoARJxGX#P$@9a8X@qq>(T}I#sF*nj<1bmzdP$j2ZcCu*!(vU%dnWR&|c!-8NG-d8-)@aNt$Ku14pRf(&h`t^H zUBFjBk=IjT7MFPyhbq{`MGz!1Lek(P8U=S)p(4?x?T6w0x!jvcKsWF;RxJbq0m)aY zz)IE-aj&$VOtllx2z&|SR90T zljSy99<~huD?7y5UR2^$7W}^2-><&ilX^B(Zza{~qoL~q6q^q_MNw9(E1MqO*>%8K zR=oLwNb=FJIC3x{gnMVCKV*MN^QY0VNIACZWAMTigu-0ufrojYyH&3uJB5rZPPdW2 zFVfiL73#ciH+6UJlWR9MtE1zWJnw&TxMOy1`aw0h;YLBS{-{WfG1>G6C8tmX?#)(t zZnX2jaEeQIf;(s1T;4!FcYxAk{l0Q4E~rpBlvl6+CgJ`4)@nKX zH6RIY12%MsZ$}tD?0RnFG6D6ny*hTzo$eQ%cor}?ug8jEO2-OO1DDZg`K5zNWl z)~DOgb^@6GEx1UD+=`ePPd{2QBTq0VbF+=5K3aJiehl=ZT$=HDExQLO|J5@Wb7IN` z%SOfz65a!Qf%Bp8ze=%Cs>qJzLtc5NZ%s8rPv`_L&8mpKmW{0U0zM?3!j3?(2_`g6 zTa&Aog6A>^b1`T70LtfLauRp~F^hvB8MzfU%~Y+;&oGbWIXss+n9Jf^)6Iw{v;hN= z*qjgyO=^*77==X7Xq)?ZOloW_b?gpU94FU%FJPB#Gz&F5|T!t6F1I>Jo izdO`K`k&i>0t^7ad)S>`&S^gY0000n7Ax zCDa})0rejUB7%aRg`PxE4|?>F#ukcJ52Z*!@X)(>(2ICbuPsthgrFx6f`|%A%}0~8 zNwe9^JZCo9H5>5cgU7si^Lvlq{N@coM0of7EBwny=I7}4w(u*$b8>@~DVP{9NX61Q zr^DBJ`>X&+P55Db2g*yB{c;Xz?}mV!9&H|K5L4{pZiU^ATe@ah3J^+U`e_Y6U3Z9k zM#K`oHCjXcz>M0(ZWC8CQ%TJ*RoNeqgY@MCn18QgYC|L$ZA>m0jpH*OK)BZ+X{4t+ zJN%xVO%P!qWEuBmi|5N4+MAfFmIU^EqJ83s)PP74KRjzbQKH(M8CN|v8|4?US$-MN zJbGvr3MbFP%;Efs+_!ff?77`z4y|AGG;rGNR5Gi0ls&`2vUvFcC{YzYetrv&UOj|6 z*VY$gUe^_9HQL)GJ`e?XpJx0!d-Xif*^5mr3DJpYD9>Gzjto`x#rkVFaNg&DLaKVR z0I~yr^v0}znYGCXW$HjL6Wh|$uofoibD*1(^xv!-Q#Oc zhZT^~v=~fABD^Ye+R|clz8k523;kBv;D79o00RK2a3QJdn+vi40000!=NGmyJU(;f=*MRdBG2u-_!!x* zPF@nS3bH?z^RRJPJ6p-IoI3exHc;3IYyg*#m@bHZbMNls{qr~4U<<5$+g<<-d|@Lk z&hyCGLQYmpm`fKP3;+K7W`G1H(|3ZQ&dm4&MF0Ht7ZD5J-@m>4;pt;_H9H%%FE4Jb zXJ+{FM^=%;Qh@&(|LccOZalg9C6=9;`LU!J_X1!Ts6KrBnc?mG?>FEEe0lvm1RCwC#S6gfoR~r82?y)nO*bZ?L zLoNgopd@Xiq@pEJyM<8bwm=a@`@-_t>q}LMhf2HcR^69&d02I|T5TU%En2B!dn2Wk zUX-oqMFE9_&T1kXU22uagejL0lJijzVOSVIseg_|NG`YbH4vK<#`@{ zO`~oSxJjT&fTF0YF6!Cb%Wxca`b6ph!ROs32<~#8wdz>LW@wmz>o}f+ykjC}8Q$5l z;SIZ%_tuBU=A5g=T*SQ=fu4H@BR-LSUJ8l3o7#hNV`~8Q5eC7a1A#4qr3&CEm0T8R zhk=oIk)O9QH)UdGvZUlQ)_=^B^YoD;Gs){F(EGr>e+oB;o@(#y5L?$p5b&45LIvzR zVC6yC1<-BS7K5uQ^aVt`{^hysUzkA=u{;2D-|5reK(L9{Qgg+MZL;`4cYI5In$Oz3@YADt{$ zaoNk$BFe#ot+x+$xAxsmJQd0Di-f>50kWWHvQSg0tWi)uu`T12XPKjfO`3uYmT~KO zj_DQzrms%s2O1-RP^8|EvGWS7l85d!^%%UfnJh>5v5#U0N$@>Y%tZoSL%RmT9bLQI zHr!3T5;Ovsizi_!d88*NCQG^8vnP+7e)SqB>aFTv+m7hIM9BDK=PJ3KMG=kR0HO^N zHVv-8Osu$j&-PUVWZ5T`wRH6%L6Y}3-@1{aXlB7z5(yOM=Mg(Me$Xr$T|WciX)d?7_K25wUo2VV+?qZ0v8MWQpIuBm=x(+7N8*A|qqLCvS}O#p%yayfL!( zmk7+8ho&uZ+w0rQcC%lLsin&4wNq~^+)7*nAYY@9xuI`+?heY5q7N?6LIA4-j#JJYnLvweQN z2tCcAWo-oEFuSNVbAU+bzq8zH1BBu$qBO;n!!-(kwyC6GCIkx0!VLH*XA2B!9LX_wL-zQJ($xa5T8DvAu~E11{MPA0kl> z9IaiE07qtgGz->aP*Ob1T{MuG(UDA;b}DJSLW6qr->;2Z*VT~p{`T(2qMgx~!cmz3 z8>kC2XzBFBFX%Y=?kL$79fMmXWM)*PW-JH{L#ifCh!G;>gilRq&V}>ZUBkoEpI)sY zVXt+D&m8&h-)IcLDAYV3js#@d761 aAiw|wfc$Nmftexz0000h`9(x~~#~Q?- zScp|DgouUf;|J&#+NwnqL=X`aZS7^ND2jyyECg+BG?kqo*jPy_BSPAsiO61eX3p`< zTz7LxK#L4_80OqL-}%08&LA_xZid+&ICFccW2{-$T6GaI#iR&_Kp(sh=ifiPw%$Ci zb|7ZR%(FbH=Z6)T3s^so+;YkLf}3#0XRP^4qc5>NI(<@Rdo2Vq>%#MlE=2q+py7b==JWb;L2NGM1^@WSBZgWjvtMD;21v}Gbml_0dE zSxA0)>FnaS(pFtTl@CX_7m;y>e7y;-0T6^ryomX|-m#Mx!19>pRUx+R@5__cIKmADk$s zmDIt+$iuJyJ|=C=VzoIqS8Y^t@e*qDU`-f(&L;CGuM_?yl_rtsqb2RKn*z4y{A6?u|0K7`UL&w|!aL%9bJn^OHd#m`A7`lCwL!~rR zQsL4^&Yym6aV!K3Gp@y%7kFU)+rU#_q3kE_xIM&|vid4AYH}(LJrrfw48<$_OmV!YCA6@R@(o_9e_| zPqdo*Bhj$v)DRP#1qh-MH-fPP(5{rkBEl0_acf2@Jxf6<1p``+_4`x;InQHDi}#LP zc=qw1wugW=nzXSOI+#i(V@tFb2s_Rhe-u;BID_D3yfl2^=!dkQmte{r9_De?I;8p-&FM)xOGj3<-E}*{Ymw4+DV*wKP6K??F?h;uf@wM!+Q|EU^5{ zfv=x@Up4W*_KOVom|mMUnkzkh||(!CRyIW8KKyKK`YkEXDSBy@ntUzUsYXx(%BE>-QGeF z1`Aw>jjBcB?59q3SA|o}f+&0i^Q)~F6@9S9uOe%%)I=yZX-KlQHh3=%BYPC%*d-du z)EUTUf*C>d*1GffIZyl!bw+8JB(1T!;^C|8XgaH@ois5s=uc)j%VFi>Xj+KArj}}_ ztx~N?zEwxGy%!UJU=xROShIDbejuhU3FGJ+mf}`27f&X8x#211tDE*_#D%v)oM&m* z!d?}ll?jbWlYpv8j7?J+293*OH>IPluo<3MyOy8L(oDeI$8S&WRDY!_5Uvka8_|yV z4fDuGAKJh>|q!frF zf!G>||0uG*T@ojHdMUA900DO(=7Tz$`T1`?10elIk!K!3FE|6SJPnyHc-0RjvFz5rfQF4_M*00000NkvXXu0mjf$nBwY literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/pythonClosed@2x.png b/python/resources/icons/com/jetbrains/python/pythonClosed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..68d99e2eeb8ddd3ffdf3f2bffc5737f5f54280df GIT binary patch literal 981 zcmV;`11kK9P)SQfmmE9@UKAw|f(a53i9!6& zU^a@1sH+mz-PxU)uJ_8XdS-SVSH>6)(Ye&2iVd#|dcF-COrP@>DnYXWX_ z@cV(S(-p%W;Hz#%z!KQq?G&_4q7xcui$teHXi1o9;&mCemSG2ulRya|fE#BG)PQQ^ zTmaqy9=!|!Ic*{QJMgXRI@^_!`6sV4n~|db@XW^EONV8hRHow**fTird6diS3_r`;de|u2A^l8ua8@M#9;{^P`n;&KZA(iTZUFG_|Ks1s$!^U10 zLt``N3UU3Sy}hFZ`irN8xV_?mQSyHy%x3}yiFr)0j3(u-1S!Xs-xx5MJkt(=FV8RW zkn0Ty^Bkx2fe0fOwOH>}s$N(|(_FlKM>7qYS;Q>$ym$Xw?D=s%%7>QBk<$nhK@<@2kRnJ30XWIpP8FCy@~J>pg1=RSY<>|OFcOhl;TxIB_s z7)7Ik-O0zOro}VAJ50ShA}+tCiNJ`>@fXE^4j#MPfBB)#7TmBhB$?h~^ns?Qx~kC- z-Q!5WeJKseL<)AEd~hBH@tewX_NO6Wm(m5k;&|=5&%m#XrwVn}dywHX=K_WO4GRZ%TQGa7L z4-&nNeS&$`VkFyHjF{-{c%0UIftl!xx{5OMWeG$IRKYlO&RNe}HXWV#IKB4EA}fAb zEmsfKMk{N~Q`H4N+Rp~Zf^4`BbJTGHuk@z$u>b=ApI4`Y$42E000000NkvXXu0mjf D7uC{z literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/pythonTests.png b/python/resources/icons/com/jetbrains/python/pythonTests.png new file mode 100644 index 0000000000000000000000000000000000000000..5bcf60420dc9a7ad2fcda01b11ed78e3770c27fc GIT binary patch literal 715 zcmV;+0yO=JP)6 zsuToI6@*9+#vjlgMCn0q{v2!t5wsKo7H?iWNlrBsdXOR%K@VPf(SpUBAPVBqgZ)A1 zp`vZtq;2xDyR*)|G-*t{`FQhqGjH~rZ@!twthMkz7i$GLo1IPyDds$nXBcB)jB>0o z_)%+f`NPxOYt8w*6;VXxNIc*A|i&{@|&HdxBcMBN8Mgj z!j;^tl@SS23daB};~*;PfXitE7`Quih98w1>OAc)Yoi)o7Ss*EN5u}~MZrwAt#0!Tla zj>ThPV*RqDpQ~yO0z(@D9Q4-;)(|K9W|TSEXn}DCjC!okgL>X1XOY^Vkf8wKneyi+ zL$A&t*0NCJo(4!&4AFLCG1PO@mnMG1WhFzXbhA3{b!J%#be83OR_!FLhc-_(BL4A%uEaXy x$NmbX0G5AOp3_^t&-n#5MbGR)f4BZ4zyRqEIQ$gNetrM|002ovPDHLkV1nfrNSgov literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/pythonTests@2x.png b/python/resources/icons/com/jetbrains/python/pythonTests@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2bbbec6755ca157ed358fb96c2d10336c5978ccf GIT binary patch literal 1528 zcmVmVNMnMq-Qjiw*M zrdoR+@Dgxc<8u>602~1}9NhB6o=z0tu?rTjom>IV`TeG8d}LZC$8TGKLP#befgx8M z-17LIju}u)O}05RZS&6(6I!XRV9Fk)WWH_PS9E4VZb1!QXl49jG$ zn;z`y$uirvVWH4U*|x=u32cx8DMvEPw3w9Y+G)kWWZ6KJJ8sIfofL~;-T2=Hy|AaZ zn>p!Jk}<sTa)V8up^Ve0OGlnvI^UDp6MeIlexPG;>@>`>)a3>Xc6m4V?u< zoPcsk2H-l;SgI{1^szLRmRSJW#0u-1<_c&#% z!L_pbKVu6MF0fN66dX&dtL6R2CWUPI6iVEoYOXUVC>1FyDMDpJfjE$43p%GeK=ts_ z{%>DXp%|*Agm!~wKrjytpwzMwO3~J80elS%w^`#;Gup6t=i#e+PrWZAHJ1$IW*n5t zQ$m)oOEH;-u)K}+Kg`XZU;X;+TbDq{HEnFqz<;Z;X1fTOMVnJ8Ck9}>hnOhA$Rfg~ z(2{|c{XntPj|}czb*{cn`u4e_BrJZ4vPO2?j#Xr>Na!r|exscN_z>BLpIsdDVJewH}IT zq`J~CAmDa4ROUdDzxU5J)o}MaxOR)>xVQdjRJPvWmT{}R^0??rwqw8I=|&-Nn$gXO zl%g&eNo_G#u>x^TuQK6}dz-LylP)q+9mRaFakksFf6uJKeD;L6xC=NmVCPpH5Bq*? zIu*AX@rkB9I<6?KGPAnsU6Pau%03G#fetuOei(<>uh?*IuJO~HhnV1Qz0a&U$p?78 zaU)~`dsr}LrlO{Frjrf# zn@YsL^qGznFih)o6h!mAu?kD~xYhDnOEoI5XfR}v;f0~u>U7^lUzOITb>spW zMUR!v6?YH|6Y{)XWPtDBrbCq@y#wCS8BaoVCSG{?)1&;VzmhJHkB$s=^loTa*3L|> zYprElr|E>ssJy~*pa>LzF(8M4?a$s=_|hIIFRujQF@O>DsPGuWz|F_z^bN5#?|8}g z1KZk`$#rk*WNl`7z(&63H(~lAaA%z_#`Xa#j}6Yu|LTp{Vf2kG*v6Ls9Kr%8n4{}L`l?}q;X6_+;-$X1qcOUF!xRzAqRq#Qc+hL z{Bv^^oE@1EQckE`rCN*WAPgr+ip4noyp>=g2~Y-Ro6e{ItNSg0p}nWKu&%^5(Lw6@ z$dM(wCd1H2X;>>``-KpD+MO8I0_WvLV#I3mrI6wUY_3-(&2LQxYleT_FQqswgk)bn zG_4J(T$2nW5u9h4q5yj#0O6!1w6T6A3zK2I4mP$A#J$mO{9X+kf*y^Nm^jaMW8obe zHn#OD6T*;du#rx-82CGuoNH3z^o#hiUU>v?+c@X+`fU9)|j`kd^E<}Yg|eFGv34QX5_0|??* z+l-k!w)X6xQLc|8^Bw#id0bn7oFb#^8)4({37qydXH2gCHQMwGV1|j9%g#}o$cUQU zTdL_yGmB?!0QLy-JjO-FVjB!GfC?{|rF!#WU*`t7)omJhTbgGeyC{uMH39C74qx1S zXzU)UU>g8>tuc3y&+mNdG^}M^I6Z@Ij)KcTk?+*sZs~NL-3bQG&lMNOkPNNgn%CY%|oh)o9o^7f=Dp)l3%$<(C zWmzR#p|wr0uT(7`(8>-KHh*zh&}%=)0K(LW$J=NdKYQgs2{*QbKkSOx6@a?ahZ+A|H0kKuW<9)S`VbNKG1T` z?}vOY1n=Qom}mA^Dh22tL@}lG7%)8g?f$;ewiH=~f?61MmZ`>vX%G%W&NVCHkSn z?Xbvk$nvmjf&!#N1YWVg517w``9Yw!;_a4}6=+6A(ZUL7fR$h85qQtNiu-;jpt%r# z!ZJIc$YI)s$B}Hxn=mmKB7a>3_ z^a|<&P@E**09Fk}uBR+^vWQfR+hQTjQkZ~~`v9OTjDUo5QtM+tvx94XH~Q@4jxdUn ztHs3wkA4fygc-tNj)F)h+m-^Vi3Nmt&qEfnqOB|33nn=l1-Myx^FgE_B|DC_7;i5R zG>u^$8Nz@p;w}?`wvlNS3SFF~OYn9BO~^?E)do=H9gvLUf*~NnaRJ6LnjmOR z5-N+f0$vXSiR5ImYw5i*S+}u}#lp6s0z5S*bi?9$Jki<<$&OWfg7{ANA8*$GVYqOI@v_`9|!vF^G(Vit)f%_E=_lh>y zv-LqNc!~1TOgvL93}7_1PfPYNJ}oM-L5jt2t1@C(4rtvu@XAoF96a*u``;i*erFko zCnqJYJv*{-_fqAnr}hmcW+L#0q8m-G8dRgTS+POT4FPoD@cO~0gQD7n2TR)VCc}7+ zFnrt0`l`l<+_;pUG>Cbp^chs6n@85aHvqpKs7$}pX5Emgqs>ej&#mp_)__ZNq3At= zZrdjt_pXB9_8Ynuc8kf{$r)-Iu`e6CP+8)RLQq-$A$@sD1@b5;kDI)Ka0{&lz4m7EH>>57xoKs7rJL{AU_2-5 zph&AY_(DJjHE~hiyXagiSXw(#jT~IFhC+$Xp+f>l01hXMpxwyK&Th@l$vq`p=e$i$ zx^Ab{!k?I?gC8Z8W)7-RTL!23PGE^3+m##O+}TG8LXi{sLU0)-K;uN(K@;Kgv5qMKmpDy;3KIpeldh`+$nG1Ab)o zg1IX)UAa$%<6NWtPVKfdSy+JYT*=JI4P%Vu80(9cas2ceTyp1w z#5ZRVI13?Sk@HcBg$C4Gizoy^B@&30U}Ym`lR&^Cq!S-qLLf;cCfe9rS&iBg*AU}Lp5@08M) z-;NHfG}^OfM(&I2nQTycRqm%9yW2^AZ_a^cb8V-2iubqJHy$dp$A~8$?DBj;u9T;& zNC_eYcNq{%8R3!abT%ynCvQDDz&v)9i+en1BT{Qyw$>0LRTm1p;Yu+eVN|mqZ^z)G zm=I%|RaHp{cuLF&U-Wp~Ba|_sv?k0l0*VC8=@fJ<7U_I2nDoWiQ{X8j1S0Tz(wTH( zxGfg_b5X4}gc_R=>tJayeg#4O>^1=5ROp&nmkmF-nfJly?(b=SGFIc2|p1nwP`N#Q|yQsM`bJE^w%2 zmBF{6W7iMszH4v8dSSTP&eR*2oUdcrRnMCVJi$kz_3&b}78TtPpsIpr8X1j8mVLtc xS>5z;%iq|%=T6+H8pH>dNNqlyK>SC50RZCvH7TBPg75$U002ovPDHLkV1ly-MT7tV literal 0 HcmV?d00001 diff --git a/python/resources/icons/com/jetbrains/python/virtualenv@2x.png b/python/resources/icons/com/jetbrains/python/virtualenv@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..721a63b883bda6f5040b00a50dc570d33cfd5eb4 GIT binary patch literal 1513 zcmV*F{30363lu?6T3jsOHtHA2{DWoM1%;Ekx3RAMa|R{X;bZNy_PYH4_g~h(HKi20luc)sxS6$1oY(dC z-RPbNt{-Dv2pj-b?c1=lyOw>mT1+snYx8}Ep?_$YhK7F3xk5-LxImNl?A!1}_eEjA zu#DCDd`@%oIkscP{Thuu@XALOl9Mt~#F;-77(+weix|2%0=RB&c3ne(S(a5Evu&H{ z=deKn*p6hTVKOPzbr;PC9M?81$7USbEnN9tta(FYJ#%t)rA>96Sr~Uh$GTtv4(*zq zY`W%OoO+p%iZmOxHF_bd`wxxkhEZOBzSh3vm)aP>u^o!3M#I!uVNzk(FYqjtT#Uz! zRo7^0;$b*<=^I_>mI2cNP}m8Z+N{1YWTdR7X(Qe)LuNorf~ISg(SQZb?YRab5@-Q9 za1dDAf5?BgLI51T9JH;c4RzWuIZTI5qc8&Xl4(rK*ji(zZ9zb=fnNm!5CA^e2>Mzw zXOUxWZEDMDrw{vEM+tx!U!FslIj$4iFRShF<7h2ujG}31GWUn_HJ>7MxetMi?01KUA#kxebgJan|Jcd@ajN++9;)0t<0%SY|vs-tPi0 zDMZT-CFO1LJ~3UX0I>vig#f7|$trYCw1MW{MQz`$RYHAA1Zf77@eh_!f(hy?1Rxrv z7*lIn^cB!M#+-mIqgC_X`F>W@AKMgHQ$Z-#bb~{v2=5{#WRzT5qXi(%$IyQN)WWGp zU%h?P&DiL?DHa^MQ2$}f*(5myjTYh_31Rmz5iWp|9(unj1J#@f6dr%5U^_r4$^IhR67 zH>)R}qjc$BEDM@63 z!h(fI%pVDogWJpvs6cyP)zjJe5?J88<8HDP+6^T3NIxlM%;?V&jjxG){-8O_kU z6E`4Zc&kpd-g+Xk-%qBl2cAxzUjm*>o|jO`R+9i>X(*nQZ>cN4!{M92*2PT~h})E9WS z2)HqG1Jc;p2{E9X=9WTJp%YcpF{(u4f + +This inspection highlights unresolved buildout parts. + + diff --git a/python/resources/inspectionDescriptions/PyAbstractClassInspection.html b/python/resources/inspectionDescriptions/PyAbstractClassInspection.html new file mode 100644 index 000000000000..41d83f7dcb9c --- /dev/null +++ b/python/resources/inspectionDescriptions/PyAbstractClassInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects when there aren't all abstract properties/methods are defined in subclass + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyArgumentEqualDefaultInspection.html b/python/resources/inspectionDescriptions/PyArgumentEqualDefaultInspection.html new file mode 100644 index 000000000000..16d894ec131c --- /dev/null +++ b/python/resources/inspectionDescriptions/PyArgumentEqualDefaultInspection.html @@ -0,0 +1,7 @@ + + + +This inspection highlights situations, where argument passed to function is equal to default parameter value + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyArgumentListInspection.html b/python/resources/inspectionDescriptions/PyArgumentListInspection.html new file mode 100644 index 000000000000..97d74c0f04ed --- /dev/null +++ b/python/resources/inspectionDescriptions/PyArgumentListInspection.html @@ -0,0 +1,8 @@ + + + +This inspection reports discrepancies between declared parameters and actual arguments, as well as +incorrect arguments (e.g. duplicate named arguments) and incorrect argument order. Decorators are analyzed, too. + + + diff --git a/python/resources/inspectionDescriptions/PyAttributeOutsideInitInspection.html b/python/resources/inspectionDescriptions/PyAttributeOutsideInitInspection.html new file mode 100644 index 000000000000..4e0fee15aac0 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyAttributeOutsideInitInspection.html @@ -0,0 +1,7 @@ + + + +This inspection detects instance attribute definition outside __init__ method + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyAugmentAssignmentInspection.html b/python/resources/inspectionDescriptions/PyAugmentAssignmentInspection.html new file mode 100644 index 000000000000..f9684908d722 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyAugmentAssignmentInspection.html @@ -0,0 +1,7 @@ + + + +This inspection highlights assignment that can be replaced with augmented assignment. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyBroadExceptionInspection.html b/python/resources/inspectionDescriptions/PyBroadExceptionInspection.html new file mode 100644 index 000000000000..67c31a550156 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyBroadExceptionInspection.html @@ -0,0 +1,8 @@ + + + +This inspection highlights too broad exception clauses such as +no exception class specified, or specified as 'Exception'. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyByteLiteralInspection.html b/python/resources/inspectionDescriptions/PyByteLiteralInspection.html new file mode 100644 index 000000000000..e26cb4c5f6ed --- /dev/null +++ b/python/resources/inspectionDescriptions/PyByteLiteralInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects characters > 255 in byte literals. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyCallByClassInspection.html b/python/resources/inspectionDescriptions/PyCallByClassInspection.html new file mode 100644 index 000000000000..7bc9775f3135 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyCallByClassInspection.html @@ -0,0 +1,15 @@ + + +

+This inspection checks for calls of a method by class while passing an instance of a different class +as self parameter:

+
+  foo = Foo()
+  Bar.baz(foo, *more)
+
+

+Sometimes this may be intentional and correct. +But when unintentional, this leads to subtle bugs. +

+ + diff --git a/python/resources/inspectionDescriptions/PyCallingNonCallableInspection.html b/python/resources/inspectionDescriptions/PyCallingNonCallableInspection.html new file mode 100644 index 000000000000..fdc8ed156416 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyCallingNonCallableInspection.html @@ -0,0 +1,7 @@ + + + + This inspection highlights attempts to call objects which are not callable, like, for example, tuples. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyChainedComparisonsInspection.html b/python/resources/inspectionDescriptions/PyChainedComparisonsInspection.html new file mode 100644 index 000000000000..657c918d0c8f --- /dev/null +++ b/python/resources/inspectionDescriptions/PyChainedComparisonsInspection.html @@ -0,0 +1,7 @@ + + + +This inspection highlights chained comparisons that can be simplified. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyClassHasNoInitInspection.html b/python/resources/inspectionDescriptions/PyClassHasNoInitInspection.html new file mode 100644 index 000000000000..c31c8f8bf788 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyClassHasNoInitInspection.html @@ -0,0 +1,7 @@ + + + +This inspection used when a class has no __init__ method, neither its parent classes. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyClassicStyleClassInspection.html b/python/resources/inspectionDescriptions/PyClassicStyleClassInspection.html new file mode 100644 index 000000000000..3894d7fe87c3 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyClassicStyleClassInspection.html @@ -0,0 +1,5 @@ + + +This inspection detects classic style classes usage. + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyComparisonWithNoneInspection.html b/python/resources/inspectionDescriptions/PyComparisonWithNoneInspection.html new file mode 100644 index 000000000000..37a8c54b1627 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyComparisonWithNoneInspection.html @@ -0,0 +1,8 @@ + + + + This inspection highlights comparisons with None. That type of comparisons + should always be done with 'is' or 'is not', never the equality operators. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyCompatibilityInspection.html b/python/resources/inspectionDescriptions/PyCompatibilityInspection.html new file mode 100644 index 000000000000..7bb11b11976d --- /dev/null +++ b/python/resources/inspectionDescriptions/PyCompatibilityInspection.html @@ -0,0 +1,8 @@ + + + +Enable this inspection if you need your code to be compatible with a range of Python versions (for example, if you're building a library). +The range of Python versions with which the code needs to be compatible can be specified in the inspection settings. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyDecoratorInspection.html b/python/resources/inspectionDescriptions/PyDecoratorInspection.html new file mode 100644 index 000000000000..1265e99e5579 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyDecoratorInspection.html @@ -0,0 +1,7 @@ + + +

+This inspection reports usages of @classmethod or @staticmethod decorators on functions outside of a class. +

+ + diff --git a/python/resources/inspectionDescriptions/PyDefaultArgumentInspection.html b/python/resources/inspectionDescriptions/PyDefaultArgumentInspection.html new file mode 100644 index 000000000000..3dced26af04e --- /dev/null +++ b/python/resources/inspectionDescriptions/PyDefaultArgumentInspection.html @@ -0,0 +1,9 @@ + + + + This inspection detects when a mutable value as list or dictionary is detected in a default value for an argument.
+ Default argument values are evaluated only once at function definition time, which means that modifying the + default value of the argument will affect all subsequent calls of the function. +
+ + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyDeprecatedModulesInspection.html b/python/resources/inspectionDescriptions/PyDeprecatedModulesInspection.html new file mode 100644 index 000000000000..0d03609e0a00 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyDeprecatedModulesInspection.html @@ -0,0 +1,7 @@ + + + + This inspection highlight import statements references a module which is deprecated in current Python version. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyDeprecationInspection.html b/python/resources/inspectionDescriptions/PyDeprecationInspection.html new file mode 100644 index 000000000000..46c89d8ed8d1 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyDeprecationInspection.html @@ -0,0 +1,8 @@ + + + + This inspection highlights usages of Python functions, classes or methods which are marked as deprecated (which raise a + DeprecationWarning or a PendingDeprecationWarning). + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyDictCreationInspection.html b/python/resources/inspectionDescriptions/PyDictCreationInspection.html new file mode 100644 index 000000000000..af988be8ce9a --- /dev/null +++ b/python/resources/inspectionDescriptions/PyDictCreationInspection.html @@ -0,0 +1,6 @@ + + +This inspection detects situations when dictionary creation + could be rewritten with dictionary literal. + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyDictDuplicateKeysInspection.html b/python/resources/inspectionDescriptions/PyDictDuplicateKeysInspection.html new file mode 100644 index 000000000000..8f828987ba89 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyDictDuplicateKeysInspection.html @@ -0,0 +1,7 @@ + + + +This inspection highlights using the same value as dictionary key twice. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyDocstringInspection.html b/python/resources/inspectionDescriptions/PyDocstringInspection.html new file mode 100644 index 000000000000..f9f48e5e7204 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyDocstringInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects mismatched parameters in docstring, lack of docstring and an empty docstring. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyDocstringTypesInspection.html b/python/resources/inspectionDescriptions/PyDocstringTypesInspection.html new file mode 100644 index 000000000000..18f462f3a161 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyDocstringTypesInspection.html @@ -0,0 +1,5 @@ + + +This inspection highlights types in docstring which don't match dynamically inferred types. + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyExceptClausesOrderInspection.html b/python/resources/inspectionDescriptions/PyExceptClausesOrderInspection.html new file mode 100644 index 000000000000..d6ade17849ec --- /dev/null +++ b/python/resources/inspectionDescriptions/PyExceptClausesOrderInspection.html @@ -0,0 +1,9 @@ + + + + This inspection highlights situations when except clauses are not in the correct order + (from the more specific to the more generic) or one exception class is caught twice.
+ If you don't fix the order, some exceptions may not be catched by the most specific handler. +
+ + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyExceptionInheritInspection.html b/python/resources/inspectionDescriptions/PyExceptionInheritInspection.html new file mode 100644 index 000000000000..71ba2f796ad0 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyExceptionInheritInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects when a custom exception class is raised but doesn't inherit from the builtin "Exception" class. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyFromFutureImportInspection.html b/python/resources/inspectionDescriptions/PyFromFutureImportInspection.html new file mode 100644 index 000000000000..1161ea2b1035 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyFromFutureImportInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects 'from __future__ import' statements which are used not in the beginning of a file. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyGlobalUndefinedInspection.html b/python/resources/inspectionDescriptions/PyGlobalUndefinedInspection.html new file mode 100644 index 000000000000..f493865fdbd7 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyGlobalUndefinedInspection.html @@ -0,0 +1,7 @@ + + + + This inspection is used when a variable is defined through the "global" statement but the variable is not defined in the module scope. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyInconsistentIndentationInspection.html b/python/resources/inspectionDescriptions/PyInconsistentIndentationInspection.html new file mode 100644 index 000000000000..9fefe1fa6f88 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyInconsistentIndentationInspection.html @@ -0,0 +1,7 @@ + + +This inspection reports inconsistent indentation in Python source files (for example, use of a mixture + of tabs and spaces). + + + diff --git a/python/resources/inspectionDescriptions/PyInitNewSignatureInspection.html b/python/resources/inspectionDescriptions/PyInitNewSignatureInspection.html new file mode 100644 index 000000000000..3c44c678c864 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyInitNewSignatureInspection.html @@ -0,0 +1,7 @@ + + + + This inspection checks mutual compatibility of __new__ and __init__ signatures. + + + diff --git a/python/resources/inspectionDescriptions/PyInterpreterInspection.html b/python/resources/inspectionDescriptions/PyInterpreterInspection.html new file mode 100644 index 000000000000..3d33dd83160b --- /dev/null +++ b/python/resources/inspectionDescriptions/PyInterpreterInspection.html @@ -0,0 +1,5 @@ + + +This inspection notifies you if the current project has no Python interpreter configured or an invalid Python interpreter. + + diff --git a/python/resources/inspectionDescriptions/PyListCreationInspection.html b/python/resources/inspectionDescriptions/PyListCreationInspection.html new file mode 100644 index 000000000000..47dfd11bdbc1 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyListCreationInspection.html @@ -0,0 +1,8 @@ + + + + This inspection detects situations when list creation + could be rewritten with list literal. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyMandatoryEncodingInspection.html b/python/resources/inspectionDescriptions/PyMandatoryEncodingInspection.html new file mode 100644 index 000000000000..8f9c1c87332c --- /dev/null +++ b/python/resources/inspectionDescriptions/PyMandatoryEncodingInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects lack of encoding magic comment for file. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyMethodFirstArgAssignmentInspection.html b/python/resources/inspectionDescriptions/PyMethodFirstArgAssignmentInspection.html new file mode 100644 index 000000000000..37914bb36ac9 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyMethodFirstArgAssignmentInspection.html @@ -0,0 +1,6 @@ + + +This inspection detects cases when first parameter, such as 'self' or 'cls', is reassigned in a method. +In most cases imaginable, there's no point in such reassignment, and it indicates an error. + + diff --git a/python/resources/inspectionDescriptions/PyMethodMayBeStaticInspection.html b/python/resources/inspectionDescriptions/PyMethodMayBeStaticInspection.html new file mode 100644 index 000000000000..b6c42bf6bfb6 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyMethodMayBeStaticInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects any methods which may safely be made static. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyMethodOverridingInspection.html b/python/resources/inspectionDescriptions/PyMethodOverridingInspection.html new file mode 100644 index 000000000000..95b3a9fdaac8 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyMethodOverridingInspection.html @@ -0,0 +1,6 @@ + + + This inspection detects inconsistencies in overriding method signatures. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyMethodParametersInspection.html b/python/resources/inspectionDescriptions/PyMethodParametersInspection.html new file mode 100644 index 000000000000..378ed277a5a9 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyMethodParametersInspection.html @@ -0,0 +1,5 @@ + + +This inspection looks for methods that lack a first parameter (which is usually named self). + + diff --git a/python/resources/inspectionDescriptions/PyMissingConstructorInspection.html b/python/resources/inspectionDescriptions/PyMissingConstructorInspection.html new file mode 100644 index 000000000000..281213efbff0 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyMissingConstructorInspection.html @@ -0,0 +1,7 @@ + + + +This inspection warns if call to super constructor in class is missed + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyNestedDecoratorsInspection.html b/python/resources/inspectionDescriptions/PyNestedDecoratorsInspection.html new file mode 100644 index 000000000000..f42239f79e6e --- /dev/null +++ b/python/resources/inspectionDescriptions/PyNestedDecoratorsInspection.html @@ -0,0 +1,7 @@ + + + +This inspection looks for certain decorators that don't nest well. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyNonAsciiCharInspection.html b/python/resources/inspectionDescriptions/PyNonAsciiCharInspection.html new file mode 100644 index 000000000000..c3f32441a4ac --- /dev/null +++ b/python/resources/inspectionDescriptions/PyNonAsciiCharInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects file contains non-ASCII characters and doesn't have an encoding declaration at the top. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyNoneFunctionAssignmentInspection.html b/python/resources/inspectionDescriptions/PyNoneFunctionAssignmentInspection.html new file mode 100644 index 000000000000..18e712623346 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyNoneFunctionAssignmentInspection.html @@ -0,0 +1,6 @@ + + +This inspection + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyOldStyleClassesInspection.html b/python/resources/inspectionDescriptions/PyOldStyleClassesInspection.html new file mode 100644 index 000000000000..49a70216c631 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyOldStyleClassesInspection.html @@ -0,0 +1,7 @@ + + + + This inspection highlights occurrences of new-style class features in old-style classes. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyPackageRequirementsInspection.html b/python/resources/inspectionDescriptions/PyPackageRequirementsInspection.html new file mode 100644 index 000000000000..ad916132fc56 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyPackageRequirementsInspection.html @@ -0,0 +1,5 @@ + + +This inspection warns about imported or required, but not installed packages. + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyPep8Inspection.html b/python/resources/inspectionDescriptions/PyPep8Inspection.html new file mode 100644 index 000000000000..3fa74ec62d48 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyPep8Inspection.html @@ -0,0 +1,5 @@ + + +This inspection runs the pep8.py tool to check for violations of the PEP 8 coding style guide. + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyPropertyAccessInspection.html b/python/resources/inspectionDescriptions/PyPropertyAccessInspection.html new file mode 100644 index 000000000000..437a05918de1 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyPropertyAccessInspection.html @@ -0,0 +1,8 @@ + + + + This inspection checks that properties are accessed correctly: + read-only not set, write-only not read, non-deletable not deleted. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyPropertyDefinitionInspection.html b/python/resources/inspectionDescriptions/PyPropertyDefinitionInspection.html new file mode 100644 index 000000000000..38b322dd58fe --- /dev/null +++ b/python/resources/inspectionDescriptions/PyPropertyDefinitionInspection.html @@ -0,0 +1,8 @@ + + + + This inspection checks that arguments to property() and functions annotated with + @property and friends look reasonably. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyProtectedMemberInspection.html b/python/resources/inspectionDescriptions/PyProtectedMemberInspection.html new file mode 100644 index 000000000000..d48badd5e7fe --- /dev/null +++ b/python/resources/inspectionDescriptions/PyProtectedMemberInspection.html @@ -0,0 +1,7 @@ + + + +This inspection warns if a protected member is access outside the class or a descendant of the class where it's defined. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyRaisingNewStyleClassInspection.html b/python/resources/inspectionDescriptions/PyRaisingNewStyleClassInspection.html new file mode 100644 index 000000000000..e598afdcce23 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyRaisingNewStyleClassInspection.html @@ -0,0 +1,9 @@ + + + + This inspection detects attempts to raise a new-style class as an exception in projects with + language level less than 2.5. Raising new-style classes is only supported in Python 2.5 + or later. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyRedeclarationInspection.html b/python/resources/inspectionDescriptions/PyRedeclarationInspection.html new file mode 100644 index 000000000000..0175bc40b6a6 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyRedeclarationInspection.html @@ -0,0 +1,10 @@ + + +This inspection detects redeclarations of names without being used in between, like this:
+
def x(): pass
+x = 2
+
+It applies to function and class declarations, and assignments.
+Currently it works in a very limited way and is off by default. +
+ diff --git a/python/resources/inspectionDescriptions/PyRedundantParenthesesInspection.html b/python/resources/inspectionDescriptions/PyRedundantParenthesesInspection.html new file mode 100644 index 000000000000..329591d4e425 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyRedundantParenthesesInspection.html @@ -0,0 +1,7 @@ + + + +This inspection highlights redundant parentheses in statements. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyReturnFromInitInspection.html b/python/resources/inspectionDescriptions/PyReturnFromInitInspection.html new file mode 100644 index 000000000000..7820f74cbede --- /dev/null +++ b/python/resources/inspectionDescriptions/PyReturnFromInitInspection.html @@ -0,0 +1,6 @@ + + +This inspection reports occurrences of return statements with a return value inside + __init__ methods of classes. A constructor should not return any value. + + diff --git a/python/resources/inspectionDescriptions/PySetFunctionToLiteralInspection.html b/python/resources/inspectionDescriptions/PySetFunctionToLiteralInspection.html new file mode 100644 index 000000000000..a54baa15f59f --- /dev/null +++ b/python/resources/inspectionDescriptions/PySetFunctionToLiteralInspection.html @@ -0,0 +1,8 @@ + + + + This inspection detects call for function "set" which can be replaced with + set literal. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyShadowingBuiltinsInspection.html b/python/resources/inspectionDescriptions/PyShadowingBuiltinsInspection.html new file mode 100644 index 000000000000..ed1ea275c416 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyShadowingBuiltinsInspection.html @@ -0,0 +1,5 @@ + + +This inspection detects shadowing of built-in names such as "len" or "list". + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PySimplifyBooleanCheckInspection.html b/python/resources/inspectionDescriptions/PySimplifyBooleanCheckInspection.html new file mode 100644 index 000000000000..dc5059e90a35 --- /dev/null +++ b/python/resources/inspectionDescriptions/PySimplifyBooleanCheckInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects equality comparison with a boolean literal. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PySingleQuotedDocstringInspection.html b/python/resources/inspectionDescriptions/PySingleQuotedDocstringInspection.html new file mode 100644 index 000000000000..e1674d5aa517 --- /dev/null +++ b/python/resources/inspectionDescriptions/PySingleQuotedDocstringInspection.html @@ -0,0 +1,7 @@ + + + +This inspection highlights docstrings not using triple double-quoted string format. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyStatementEffectInspection.html b/python/resources/inspectionDescriptions/PyStatementEffectInspection.html new file mode 100644 index 000000000000..99eee87de619 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyStatementEffectInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects statements without any effect. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyStringExceptionInspection.html b/python/resources/inspectionDescriptions/PyStringExceptionInspection.html new file mode 100644 index 000000000000..c2584f6bd36c --- /dev/null +++ b/python/resources/inspectionDescriptions/PyStringExceptionInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects when a string exception is raised. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyStringFormatInspection.html b/python/resources/inspectionDescriptions/PyStringFormatInspection.html new file mode 100644 index 000000000000..2146cacc428f --- /dev/null +++ b/python/resources/inspectionDescriptions/PyStringFormatInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects errors in string formatting operations. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PySuperArgumentsInspection.html b/python/resources/inspectionDescriptions/PySuperArgumentsInspection.html new file mode 100644 index 000000000000..7229a01cfc75 --- /dev/null +++ b/python/resources/inspectionDescriptions/PySuperArgumentsInspection.html @@ -0,0 +1,7 @@ + + + + This inspection check that in any call to super(A, B), B either is an instance of A or a subclass of A. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyTrailingSemicolonInspection.html b/python/resources/inspectionDescriptions/PyTrailingSemicolonInspection.html new file mode 100644 index 000000000000..1d4b70b3dc13 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyTrailingSemicolonInspection.html @@ -0,0 +1,5 @@ + + +This inspection detects trailing semicolons in statements. + + diff --git a/python/resources/inspectionDescriptions/PyTupleAssignmentBalanceInspection.html b/python/resources/inspectionDescriptions/PyTupleAssignmentBalanceInspection.html new file mode 100644 index 000000000000..6aa175b0927f --- /dev/null +++ b/python/resources/inspectionDescriptions/PyTupleAssignmentBalanceInspection.html @@ -0,0 +1,6 @@ + + + + This inspection check that the number of expressions on right-hand side and targets on left-hand side are the same. + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyTupleItemAssignmentInspection.html b/python/resources/inspectionDescriptions/PyTupleItemAssignmentInspection.html new file mode 100644 index 000000000000..49a437b3561f --- /dev/null +++ b/python/resources/inspectionDescriptions/PyTupleItemAssignmentInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects assignments to tuple item. + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyTypeCheckerInspection.html b/python/resources/inspectionDescriptions/PyTypeCheckerInspection.html new file mode 100644 index 000000000000..f2fc714eee0c --- /dev/null +++ b/python/resources/inspectionDescriptions/PyTypeCheckerInspection.html @@ -0,0 +1,8 @@ + + +This inspection detects type errors in function call expressions. +Due to dynamic dispatch and duck typing, this is possible in a limited but +useful number of cases. Types of function parameters can be specified in +docstrings or in Python 3 function annotations. + + diff --git a/python/resources/inspectionDescriptions/PyUnboundLocalVariableInspection.html b/python/resources/inspectionDescriptions/PyUnboundLocalVariableInspection.html new file mode 100644 index 000000000000..c65de68ae122 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyUnboundLocalVariableInspection.html @@ -0,0 +1,5 @@ + + +This inspection warns about local variables referenced before assignment. + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyUnnecessaryBackslashInspection.html b/python/resources/inspectionDescriptions/PyUnnecessaryBackslashInspection.html new file mode 100644 index 000000000000..75d0bd3ba6d5 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyUnnecessaryBackslashInspection.html @@ -0,0 +1,7 @@ + + + +This inspection highlights backslashes in places where line continuation is implicit (inside (), [], {}). + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyUnreachableCodeInspection.html b/python/resources/inspectionDescriptions/PyUnreachableCodeInspection.html new file mode 100644 index 000000000000..ed689c3de81b --- /dev/null +++ b/python/resources/inspectionDescriptions/PyUnreachableCodeInspection.html @@ -0,0 +1,3 @@ + +This inspection detects code which can not be normally reached. + diff --git a/python/resources/inspectionDescriptions/PyUnresolvedReferencesInspection.html b/python/resources/inspectionDescriptions/PyUnresolvedReferencesInspection.html new file mode 100644 index 000000000000..8841b4687e61 --- /dev/null +++ b/python/resources/inspectionDescriptions/PyUnresolvedReferencesInspection.html @@ -0,0 +1,7 @@ + + +This inspection detects names that should resolve but don't. +Due to dynamic dispatch and duck typing, this is possible in a limited but useful +number of cases. Top-level and class-level items are supported better than instance items. + + diff --git a/python/resources/inspectionDescriptions/PyUnsupportedFeaturesInspection.html b/python/resources/inspectionDescriptions/PyUnsupportedFeaturesInspection.html new file mode 100644 index 000000000000..b0c92cf6725b --- /dev/null +++ b/python/resources/inspectionDescriptions/PyUnsupportedFeaturesInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects usage of language features which not supported by current Python version + + + \ No newline at end of file diff --git a/python/resources/inspectionDescriptions/PyUnusedLocalInspection.html b/python/resources/inspectionDescriptions/PyUnusedLocalInspection.html new file mode 100644 index 000000000000..95ce583e518d --- /dev/null +++ b/python/resources/inspectionDescriptions/PyUnusedLocalInspection.html @@ -0,0 +1,3 @@ + + This inspection highlights local variables,parameters or local functions unused in scope. + diff --git a/python/resources/inspectionDescriptions/RestRoleInspection.html b/python/resources/inspectionDescriptions/RestRoleInspection.html new file mode 100644 index 000000000000..75809b6562be --- /dev/null +++ b/python/resources/inspectionDescriptions/RestRoleInspection.html @@ -0,0 +1,7 @@ + + + + This inspection detects undefined roles. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/after.py.template b/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/after.py.template new file mode 100644 index 000000000000..ea988e4ae394 --- /dev/null +++ b/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/after.py.template @@ -0,0 +1 @@ +print("{0: 5.3F}".format(12)) \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/before.py.template b/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/before.py.template new file mode 100644 index 000000000000..fdf53299f13f --- /dev/null +++ b/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/before.py.template @@ -0,0 +1 @@ +print("% 5.3F" % 12) diff --git a/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/description.html b/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/description.html new file mode 100644 index 000000000000..64adb58c79e3 --- /dev/null +++ b/python/resources/intentionDescriptions/ConvertFormatOperatorToMethodIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention replaces a string format operator with the equivalent 'format' method call. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ConvertVariadicParamIntention/after.py.template b/python/resources/intentionDescriptions/ConvertVariadicParamIntention/after.py.template new file mode 100644 index 000000000000..4a19285fe1f5 --- /dev/null +++ b/python/resources/intentionDescriptions/ConvertVariadicParamIntention/after.py.template @@ -0,0 +1,2 @@ +def foo(foo): + doSomething(foo) \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ConvertVariadicParamIntention/before.py.template b/python/resources/intentionDescriptions/ConvertVariadicParamIntention/before.py.template new file mode 100644 index 000000000000..ca5b415454d2 --- /dev/null +++ b/python/resources/intentionDescriptions/ConvertVariadicParamIntention/before.py.template @@ -0,0 +1,2 @@ +def foo(**kwargs): + doSomething(kwargs['foo']) \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ConvertVariadicParamIntention/description.html b/python/resources/intentionDescriptions/ConvertVariadicParamIntention/description.html new file mode 100644 index 000000000000..10db640519f0 --- /dev/null +++ b/python/resources/intentionDescriptions/ConvertVariadicParamIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention replaces variadic parameter(s) with usual. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ImportFromToImportIntention/after.py.template b/python/resources/intentionDescriptions/ImportFromToImportIntention/after.py.template new file mode 100644 index 000000000000..3158f1b50510 --- /dev/null +++ b/python/resources/intentionDescriptions/ImportFromToImportIntention/after.py.template @@ -0,0 +1,2 @@ +import sys +name = sys.argv[0] diff --git a/python/resources/intentionDescriptions/ImportFromToImportIntention/before.py.template b/python/resources/intentionDescriptions/ImportFromToImportIntention/before.py.template new file mode 100644 index 000000000000..8ccd26c2c6ae --- /dev/null +++ b/python/resources/intentionDescriptions/ImportFromToImportIntention/before.py.template @@ -0,0 +1,2 @@ +from sys import argv +name = argv[0] diff --git a/python/resources/intentionDescriptions/ImportFromToImportIntention/description.html b/python/resources/intentionDescriptions/ImportFromToImportIntention/description.html new file mode 100644 index 000000000000..96be99018b8f --- /dev/null +++ b/python/resources/intentionDescriptions/ImportFromToImportIntention/description.html @@ -0,0 +1,8 @@ + + + +This instenton transforms from module_name import ... into import module_name +and qualifies any names imported from that module by module name. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ImportToImportFromIntention/after.py.template b/python/resources/intentionDescriptions/ImportToImportFromIntention/after.py.template new file mode 100644 index 000000000000..8ccd26c2c6ae --- /dev/null +++ b/python/resources/intentionDescriptions/ImportToImportFromIntention/after.py.template @@ -0,0 +1,2 @@ +from sys import argv +name = argv[0] diff --git a/python/resources/intentionDescriptions/ImportToImportFromIntention/before.py.template b/python/resources/intentionDescriptions/ImportToImportFromIntention/before.py.template new file mode 100644 index 000000000000..3158f1b50510 --- /dev/null +++ b/python/resources/intentionDescriptions/ImportToImportFromIntention/before.py.template @@ -0,0 +1,2 @@ +import sys +name = sys.argv[0] diff --git a/python/resources/intentionDescriptions/ImportToImportFromIntention/description.html b/python/resources/intentionDescriptions/ImportToImportFromIntention/description.html new file mode 100644 index 000000000000..880f1e8deea2 --- /dev/null +++ b/python/resources/intentionDescriptions/ImportToImportFromIntention/description.html @@ -0,0 +1,8 @@ + + + +This intention replaces import foo with from foo import ... +and drop qualifiers at references to names from foo. + + + diff --git a/python/resources/intentionDescriptions/ImportToggleAliasIntention/after.py.template b/python/resources/intentionDescriptions/ImportToggleAliasIntention/after.py.template new file mode 100644 index 000000000000..3331304b1da8 --- /dev/null +++ b/python/resources/intentionDescriptions/ImportToggleAliasIntention/after.py.template @@ -0,0 +1,2 @@ +from urllib import url2pathname as u2p +name = u2p("/") diff --git a/python/resources/intentionDescriptions/ImportToggleAliasIntention/before.py.template b/python/resources/intentionDescriptions/ImportToggleAliasIntention/before.py.template new file mode 100644 index 000000000000..6db525770030 --- /dev/null +++ b/python/resources/intentionDescriptions/ImportToggleAliasIntention/before.py.template @@ -0,0 +1,2 @@ +from urllib import url2pathname +name = url2pathname("/") diff --git a/python/resources/intentionDescriptions/ImportToggleAliasIntention/description.html b/python/resources/intentionDescriptions/ImportToggleAliasIntention/description.html new file mode 100644 index 000000000000..de5fc8167a1c --- /dev/null +++ b/python/resources/intentionDescriptions/ImportToggleAliasIntention/description.html @@ -0,0 +1,8 @@ + + + +This intention allows to add or remove an alias from an import element, renaming references accordingly. +Works both for import ... as ... and from ... import ... as statements. + + + diff --git a/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/after.py.template b/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/after.py.template new file mode 100644 index 000000000000..4429ea5a8361 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/after.py.template @@ -0,0 +1,7 @@ +def func2(x, y): + return (x+y)/y + +def func(seq): + ... + newlist = reduce(func2, seq) + ... diff --git a/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/before.py.template b/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/before.py.template new file mode 100644 index 000000000000..fd61cfd76461 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/before.py.template @@ -0,0 +1,4 @@ +def func(seq): + ... + newlist = reduce(lambda x, y: (x+y)/y, seq) + ... diff --git a/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/description.html b/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/description.html new file mode 100644 index 000000000000..2e58675974a3 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertLambdaToFunctionIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention converts lambda function to function definition statement. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/after.py.template b/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/after.py.template new file mode 100644 index 000000000000..1c8040301451 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/after.py.template @@ -0,0 +1,13 @@ +class MyClass(object): + """ + My class to show intention. + """ + def __init__(self): + self._x = None + + @property + def x(self): + return self._x + + +x = MyClass().x \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/before.py.template b/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/before.py.template new file mode 100644 index 000000000000..7940289de5cb --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/before.py.template @@ -0,0 +1,12 @@ +class MyClass(object): + """ + My class to show intention. + """ + def __init__(self): + self._x = None + + def x(self): + return self._x + + +x = MyClass().x() \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/description.html b/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/description.html new file mode 100644 index 000000000000..82ae5ebfe544 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertMethodToPropertyIntention/description.html @@ -0,0 +1,5 @@ + + +This intention converts method to property. + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/after.py.template b/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/after.py.template new file mode 100644 index 000000000000..f393b5ef1e73 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/after.py.template @@ -0,0 +1,14 @@ +class MyClass(object): + """ + My class to show intention. + """ + + def __init__(self): + self.a = 1 + +def my_static_method(): + import code + import time + + time.sleep(100) + print code diff --git a/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/before.py.template b/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/before.py.template new file mode 100644 index 000000000000..a2e4b7985e54 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/before.py.template @@ -0,0 +1,15 @@ +class MyClass(object): + """ + My class to show intention. + """ + + def __init__(self): + self.a = 1 + + @staticmethod + def my_static_method(): + import code + import time + + time.sleep(100) + print code diff --git a/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/description.html b/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/description.html new file mode 100644 index 000000000000..ea7e64f10d6b --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertStaticMethodToFunctionIntention/description.html @@ -0,0 +1,5 @@ + + +This intention converts static method to function. + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/after.py.template b/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/after.py.template new file mode 100644 index 000000000000..af439511d107 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/after.py.template @@ -0,0 +1,3 @@ +a = ("This line is ok," "\n" + "but \"this\" includes far too much" "\n" + "whitespace at the start") \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/before.py.template b/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/before.py.template new file mode 100644 index 000000000000..b556824b48f0 --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/before.py.template @@ -0,0 +1,3 @@ +a = """This line is ok, + but "this" includes far too much + whitespace at the start""" \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/description.html b/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/description.html new file mode 100644 index 000000000000..a75a51a90fbf --- /dev/null +++ b/python/resources/intentionDescriptions/PyConvertTripleQuotedStringIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention converts triple-quoted string to single-quoted. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDemorganIntention/after.py.template b/python/resources/intentionDescriptions/PyDemorganIntention/after.py.template new file mode 100644 index 000000000000..de9e125e7530 --- /dev/null +++ b/python/resources/intentionDescriptions/PyDemorganIntention/after.py.template @@ -0,0 +1,2 @@ +if not (not a and not b): + pass \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDemorganIntention/before.py.template b/python/resources/intentionDescriptions/PyDemorganIntention/before.py.template new file mode 100644 index 000000000000..1a0e3f300de4 --- /dev/null +++ b/python/resources/intentionDescriptions/PyDemorganIntention/before.py.template @@ -0,0 +1,2 @@ +if a or b: + pass \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDemorganIntention/description.html b/python/resources/intentionDescriptions/PyDemorganIntention/description.html new file mode 100644 index 000000000000..4dfbca1bdc31 --- /dev/null +++ b/python/resources/intentionDescriptions/PyDemorganIntention/description.html @@ -0,0 +1,14 @@ + + + +This intention replaces either +
+a or b with not(not a and not b) or
+a and b with not(not a or not b)
+
+ + +inside boolean expression. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/after.py.template b/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/after.py.template new file mode 100644 index 000000000000..684a858f604c --- /dev/null +++ b/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/after.py.template @@ -0,0 +1 @@ +{'a': 3, 'b': 5} \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/before.py.template b/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/before.py.template new file mode 100644 index 000000000000..2bfbfb98c348 --- /dev/null +++ b/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/before.py.template @@ -0,0 +1 @@ +dict(a=3, b=5) \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/description.html b/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/description.html new file mode 100644 index 000000000000..ee5f619cd7f4 --- /dev/null +++ b/python/resources/intentionDescriptions/PyDictConstructorToLiteralFormIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention converts translation from dict constructor to dict literal form. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/after.py.template b/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/after.py.template new file mode 100644 index 000000000000..2bfbfb98c348 --- /dev/null +++ b/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/after.py.template @@ -0,0 +1 @@ +dict(a=3, b=5) \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/before.py.template b/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/before.py.template new file mode 100644 index 000000000000..684a858f604c --- /dev/null +++ b/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/before.py.template @@ -0,0 +1 @@ +{'a': 3, 'b': 5} \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/description.html b/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/description.html new file mode 100644 index 000000000000..9af5246228d3 --- /dev/null +++ b/python/resources/intentionDescriptions/PyDictLiteralFormToConstructorIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention converts translation from dict literal form to dict constructor. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyFlipComparisonIntention/after.py.template b/python/resources/intentionDescriptions/PyFlipComparisonIntention/after.py.template new file mode 100644 index 000000000000..37b79e3f1d30 --- /dev/null +++ b/python/resources/intentionDescriptions/PyFlipComparisonIntention/after.py.template @@ -0,0 +1,2 @@ +if a > b: + return a \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyFlipComparisonIntention/before.py.template b/python/resources/intentionDescriptions/PyFlipComparisonIntention/before.py.template new file mode 100644 index 000000000000..1814460d6f27 --- /dev/null +++ b/python/resources/intentionDescriptions/PyFlipComparisonIntention/before.py.template @@ -0,0 +1,2 @@ +if b < a: + return a \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyFlipComparisonIntention/description.html b/python/resources/intentionDescriptions/PyFlipComparisonIntention/description.html new file mode 100644 index 000000000000..c6b67f5acfe2 --- /dev/null +++ b/python/resources/intentionDescriptions/PyFlipComparisonIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention swaps the operands of a comparison expression. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyGenerateDocstringIntention/after.py.template b/python/resources/intentionDescriptions/PyGenerateDocstringIntention/after.py.template new file mode 100644 index 000000000000..bf0cffa3e944 --- /dev/null +++ b/python/resources/intentionDescriptions/PyGenerateDocstringIntention/after.py.template @@ -0,0 +1,7 @@ +def foo(a, b): + """ + :param a: + :param b: + :return: + """ + pass \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyGenerateDocstringIntention/before.py.template b/python/resources/intentionDescriptions/PyGenerateDocstringIntention/before.py.template new file mode 100644 index 000000000000..7898e8a5a596 --- /dev/null +++ b/python/resources/intentionDescriptions/PyGenerateDocstringIntention/before.py.template @@ -0,0 +1,2 @@ +def foo(a,b): + pass \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyGenerateDocstringIntention/description.html b/python/resources/intentionDescriptions/PyGenerateDocstringIntention/description.html new file mode 100644 index 000000000000..87e9bb7c4b80 --- /dev/null +++ b/python/resources/intentionDescriptions/PyGenerateDocstringIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention generates documentation string stub. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyJoinIfIntention/after.py.template b/python/resources/intentionDescriptions/PyJoinIfIntention/after.py.template new file mode 100644 index 000000000000..e2fcd5989953 --- /dev/null +++ b/python/resources/intentionDescriptions/PyJoinIfIntention/after.py.template @@ -0,0 +1,2 @@ +if a and b: + return \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyJoinIfIntention/before.py.template b/python/resources/intentionDescriptions/PyJoinIfIntention/before.py.template new file mode 100644 index 000000000000..c680e979fc94 --- /dev/null +++ b/python/resources/intentionDescriptions/PyJoinIfIntention/before.py.template @@ -0,0 +1,3 @@ +if a: + if b: + return \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyJoinIfIntention/description.html b/python/resources/intentionDescriptions/PyJoinIfIntention/description.html new file mode 100644 index 000000000000..794e24c6b87c --- /dev/null +++ b/python/resources/intentionDescriptions/PyJoinIfIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention converts two nested if statements into one if statement containing conjuction operation in it. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyNegateComparisonIntention/after.py.template b/python/resources/intentionDescriptions/PyNegateComparisonIntention/after.py.template new file mode 100644 index 000000000000..89ed0f8d31a2 --- /dev/null +++ b/python/resources/intentionDescriptions/PyNegateComparisonIntention/after.py.template @@ -0,0 +1,2 @@ +if a != b: + return a \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyNegateComparisonIntention/before.py.template b/python/resources/intentionDescriptions/PyNegateComparisonIntention/before.py.template new file mode 100644 index 000000000000..7283065cd014 --- /dev/null +++ b/python/resources/intentionDescriptions/PyNegateComparisonIntention/before.py.template @@ -0,0 +1,2 @@ +if not a == b: + return a \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyNegateComparisonIntention/description.html b/python/resources/intentionDescriptions/PyNegateComparisonIntention/description.html new file mode 100644 index 000000000000..acb11fef7ac6 --- /dev/null +++ b/python/resources/intentionDescriptions/PyNegateComparisonIntention/description.html @@ -0,0 +1,8 @@ + + + + This intention converts boolean comparison expression not(a negop b) into a op b. + Where op and negop are mutually inverse comparison operators, like == and !=. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyQuotedStringIntention/after.py.template b/python/resources/intentionDescriptions/PyQuotedStringIntention/after.py.template new file mode 100644 index 000000000000..cbf185626543 --- /dev/null +++ b/python/resources/intentionDescriptions/PyQuotedStringIntention/after.py.template @@ -0,0 +1 @@ +"\"Hello\" - said man." \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyQuotedStringIntention/before.py.template b/python/resources/intentionDescriptions/PyQuotedStringIntention/before.py.template new file mode 100644 index 000000000000..904c28a98492 --- /dev/null +++ b/python/resources/intentionDescriptions/PyQuotedStringIntention/before.py.template @@ -0,0 +1 @@ +'"Hello" - said man.' \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyQuotedStringIntention/description.html b/python/resources/intentionDescriptions/PyQuotedStringIntention/description.html new file mode 100644 index 000000000000..cfd35d664f82 --- /dev/null +++ b/python/resources/intentionDescriptions/PyQuotedStringIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention allows conversion between single-quoted and double-quoted strings. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PySplitIfIntention/after.py.template b/python/resources/intentionDescriptions/PySplitIfIntention/after.py.template new file mode 100644 index 000000000000..c0f7384ea7c6 --- /dev/null +++ b/python/resources/intentionDescriptions/PySplitIfIntention/after.py.template @@ -0,0 +1,3 @@ +if a: + if b: + return \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PySplitIfIntention/before.py.template b/python/resources/intentionDescriptions/PySplitIfIntention/before.py.template new file mode 100644 index 000000000000..9e841f5ee358 --- /dev/null +++ b/python/resources/intentionDescriptions/PySplitIfIntention/before.py.template @@ -0,0 +1,2 @@ +if a and b: + return \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PySplitIfIntention/description.html b/python/resources/intentionDescriptions/PySplitIfIntention/description.html new file mode 100644 index 000000000000..643c3c79571f --- /dev/null +++ b/python/resources/intentionDescriptions/PySplitIfIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention converts if statement containing conjuction operation into two nested if statements with simplified conditions. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/after.py.template b/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/after.py.template new file mode 100644 index 000000000000..56cd89aef1c8 --- /dev/null +++ b/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/after.py.template @@ -0,0 +1 @@ +"a%sc" % (b) \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/before.py.template b/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/before.py.template new file mode 100644 index 000000000000..96db9539c962 --- /dev/null +++ b/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/before.py.template @@ -0,0 +1 @@ +"a" + b + "c" \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/description.html b/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/description.html new file mode 100644 index 000000000000..908daa21be31 --- /dev/null +++ b/python/resources/intentionDescriptions/PyStringConcatenationToFormatIntention/description.html @@ -0,0 +1,8 @@ + + + + This intention replaces a string concatenation with the equivalent expression with string formatting operator usage + or with str.format() method call (for Python versions >= 2.7). + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/after.py.template b/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/after.py.template new file mode 100644 index 000000000000..24e157d011dc --- /dev/null +++ b/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/after.py.template @@ -0,0 +1,4 @@ +if cond: + x = a +else: + x = b \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/before.py.template b/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/before.py.template new file mode 100644 index 000000000000..601e958f079d --- /dev/null +++ b/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/before.py.template @@ -0,0 +1 @@ +x = a if cond else b \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/description.html b/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/description.html new file mode 100644 index 000000000000..c0552efb32e6 --- /dev/null +++ b/python/resources/intentionDescriptions/PyTransformConditionalExpressionIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention transforms conditional expression into if/else statement. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyYieldFromIntention/after.py.template b/python/resources/intentionDescriptions/PyYieldFromIntention/after.py.template new file mode 100644 index 000000000000..773e592b09e0 --- /dev/null +++ b/python/resources/intentionDescriptions/PyYieldFromIntention/after.py.template @@ -0,0 +1 @@ +yield from b \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyYieldFromIntention/before.py.template b/python/resources/intentionDescriptions/PyYieldFromIntention/before.py.template new file mode 100644 index 000000000000..aa447f1e3b13 --- /dev/null +++ b/python/resources/intentionDescriptions/PyYieldFromIntention/before.py.template @@ -0,0 +1,2 @@ +for a in b: + yield a \ No newline at end of file diff --git a/python/resources/intentionDescriptions/PyYieldFromIntention/description.html b/python/resources/intentionDescriptions/PyYieldFromIntention/description.html new file mode 100644 index 000000000000..667a76164b3f --- /dev/null +++ b/python/resources/intentionDescriptions/PyYieldFromIntention/description.html @@ -0,0 +1,5 @@ + + + This intention transforms explicit iteration with 'yield' into 'yield from'. + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/after.py.template b/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/after.py.template new file mode 100644 index 000000000000..036345d596d1 --- /dev/null +++ b/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/after.py.template @@ -0,0 +1,3 @@ +a = [] +for x in xrange(5): + a.add(x) \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/before.py.template b/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/before.py.template new file mode 100644 index 000000000000..eef9ef7bb5dd --- /dev/null +++ b/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/before.py.template @@ -0,0 +1 @@ +a = [x for x in xrange(5)] \ No newline at end of file diff --git a/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/description.html b/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/description.html new file mode 100644 index 000000000000..54da12726567 --- /dev/null +++ b/python/resources/intentionDescriptions/ReplaceListComprehensionWithForIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention replaces a list comprehension with for loop. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/after.html.template b/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/after.html.template new file mode 100644 index 000000000000..489da3518483 --- /dev/null +++ b/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/after.html.template @@ -0,0 +1,5 @@ +def foo(var): + """ + @type var: string + """ + var. \ No newline at end of file diff --git a/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/before.html.template b/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/before.html.template new file mode 100644 index 000000000000..fcdfce0ebee8 --- /dev/null +++ b/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/before.html.template @@ -0,0 +1,2 @@ +def foo(var): + var. \ No newline at end of file diff --git a/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/description.html b/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/description.html new file mode 100644 index 000000000000..9ff83f3b28bc --- /dev/null +++ b/python/resources/intentionDescriptions/SpecifyTypeInDocstringIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention used to specify type for expression in docstring. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/after.html.template b/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/after.html.template new file mode 100644 index 000000000000..5f5265fc0bd6 --- /dev/null +++ b/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/after.html.template @@ -0,0 +1,2 @@ +def foo(var: object): + var. \ No newline at end of file diff --git a/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/before.html.template b/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/before.html.template new file mode 100644 index 000000000000..fcdfce0ebee8 --- /dev/null +++ b/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/before.html.template @@ -0,0 +1,2 @@ +def foo(var): + var. \ No newline at end of file diff --git a/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/description.html b/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/description.html new file mode 100644 index 000000000000..dce9825a7ef6 --- /dev/null +++ b/python/resources/intentionDescriptions/SpecifyTypeInPy3AnnotationsIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention used to specify type for expression in Python 3 using type annotations. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/TypeAssertionIntention/after.html.template b/python/resources/intentionDescriptions/TypeAssertionIntention/after.html.template new file mode 100644 index 000000000000..fd8ffc7fb452 --- /dev/null +++ b/python/resources/intentionDescriptions/TypeAssertionIntention/after.html.template @@ -0,0 +1,3 @@ +var = unknown() +assert isinstance(var, object) +var. \ No newline at end of file diff --git a/python/resources/intentionDescriptions/TypeAssertionIntention/before.html.template b/python/resources/intentionDescriptions/TypeAssertionIntention/before.html.template new file mode 100644 index 000000000000..3ce25401f353 --- /dev/null +++ b/python/resources/intentionDescriptions/TypeAssertionIntention/before.html.template @@ -0,0 +1,2 @@ +var = unknown() +var. \ No newline at end of file diff --git a/python/resources/intentionDescriptions/TypeAssertionIntention/description.html b/python/resources/intentionDescriptions/TypeAssertionIntention/description.html new file mode 100644 index 000000000000..be57cd3b6847 --- /dev/null +++ b/python/resources/intentionDescriptions/TypeAssertionIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention used to specify type for expression by assertion. + + + \ No newline at end of file diff --git a/python/resources/intentionDescriptions/WrapTransTagIntention/after.html.template b/python/resources/intentionDescriptions/WrapTransTagIntention/after.html.template new file mode 100644 index 000000000000..d26fc1258f3e --- /dev/null +++ b/python/resources/intentionDescriptions/WrapTransTagIntention/after.html.template @@ -0,0 +1 @@ +{% blocktrans %}This will have {{ myvar }} inside.{% endblocktrans %} \ No newline at end of file diff --git a/python/resources/intentionDescriptions/WrapTransTagIntention/before.html.template b/python/resources/intentionDescriptions/WrapTransTagIntention/before.html.template new file mode 100644 index 000000000000..e7f818a2378b --- /dev/null +++ b/python/resources/intentionDescriptions/WrapTransTagIntention/before.html.template @@ -0,0 +1 @@ +This will have {{ myvar }} inside. \ No newline at end of file diff --git a/python/resources/intentionDescriptions/WrapTransTagIntention/description.html b/python/resources/intentionDescriptions/WrapTransTagIntention/description.html new file mode 100644 index 000000000000..6646903b6258 --- /dev/null +++ b/python/resources/intentionDescriptions/WrapTransTagIntention/description.html @@ -0,0 +1,7 @@ + + + + This intention wraps selected template part with {% trans %} tag. + + + \ No newline at end of file diff --git a/python/resources/liveTemplates/Python.xml b/python/resources/liveTemplates/Python.xml new file mode 100644 index 000000000000..314f81c6cfb9 --- /dev/null +++ b/python/resources/liveTemplates/Python.xml @@ -0,0 +1,24 @@ + + + + + From 7ad2460e68f6cfe2c988f30feb3d1d102dc61feb Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Aug 2013 18:44:39 +0200 Subject: [PATCH 06/10] better to keep appinfo under resources --- python/{src => resources}/idea/PyCharmCoreApplicationInfo.xml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/{src => resources}/idea/PyCharmCoreApplicationInfo.xml (100%) diff --git a/python/src/idea/PyCharmCoreApplicationInfo.xml b/python/resources/idea/PyCharmCoreApplicationInfo.xml similarity index 100% rename from python/src/idea/PyCharmCoreApplicationInfo.xml rename to python/resources/idea/PyCharmCoreApplicationInfo.xml From 5c033c237f70c270bcca1bce7723d0a4b08adc3a Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Aug 2013 18:50:19 +0200 Subject: [PATCH 07/10] introduce property --- python/build/pycharm_build.gant | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index c023154a5458..99daebdecc66 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -14,6 +14,7 @@ ant.xmlproperty(file: "$home/python/resources/idea/PythonApplicationInfo.xml", c setProperty("system_selector", "PyCharm${p("component.version.major")}0") setProperty("ch", "$home/community") +setProperty("pythonCommunityHome", "$home/python/community") setProperty("dryRun", false) setProperty("jdk16", guessJdk()) @@ -138,7 +139,7 @@ target('default': "Build artifacts") { List resourcePaths = ["$home/community/community-resources/src", "$home/community/platform/icons/src", "$home/python/resources", - "$home/python/community/resources"] + "$pythonCommunityHome/resources"] buildWinLauncher("$home/community", "$home/community/bin/WinLauncher/WinLauncher.exe", launcher, appInfoFile(), "$home/python/build/pycharm_launcher.properties", system_selector, resourcePaths) signExe(launcher) @@ -268,7 +269,7 @@ private layoutFull(Map args, String target, Set usedJars) { fileset(dir: "$home/python/resources") { include(name: "**/tips/**") } - fileset(dir: "$home/python/community/resources") { + fileset(dir: "$pythonCommunityHome/resources") { include(name: "**/tips/**") } module("platform-resources-en") { From 21b566cd5db6073457c688e119d94eab82987dcb Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Aug 2013 19:24:03 +0200 Subject: [PATCH 08/10] pycharm community build script initial --- python/build/plugin-list.txt | 48 --- python/build/pycharm_community_build.gant | 374 ++++++++++++++++++++++ python/build/python-community-build.iml | 15 + 3 files changed, 389 insertions(+), 48 deletions(-) create mode 100644 python/build/pycharm_community_build.gant create mode 100644 python/build/python-community-build.iml diff --git a/python/build/plugin-list.txt b/python/build/plugin-list.txt index 6c9663172bef..0b27fa9432c9 100644 --- a/python/build/plugin-list.txt +++ b/python/build/plugin-list.txt @@ -1,61 +1,13 @@ -htmltools -JavaScriptLanguage -JavaScriptDebugger -FirefoxConnector -ChromeConnector -python-javascript-debugger cvsIntegration cvs-core cvs-plugin javacvs-src smartcvs-src -PerforceIntegration -Perforce -perforce_util svn4idea git4idea -CSS -css-api -JSInspections -JSIntentionPowerPack -less -sass -haml -haml-plugin hg4idea tasks tasks-core tasks-api github -webDeployment -jdbc-console -django-db-config -database-impl -DatabaseSupport -database-plugin -sql -sql-plugin -coffeescript -remote-run -python-remote-interpreter -vagrant -diagram-api -uml -python-uml -localization -python-localization -rest -python-rest -pycharm-flask -pycharm-numpy -textmate -restClient -puppet -fileWatcher terminal -IntelliLang -IntelliLang-xml -IntelliLang-js -IntelliLang-python -ini4idea -stylus diff --git a/python/build/pycharm_community_build.gant b/python/build/pycharm_community_build.gant new file mode 100644 index 000000000000..29fd37469040 --- /dev/null +++ b/python/build/pycharm_community_build.gant @@ -0,0 +1,374 @@ +import org.jetbrains.jps.LayoutInfo + +import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome + +includeTargets << new File("${guessHome(this as Script)}/community/build/scripts/utils.gant") +includeTargets << new File("${guessHome(this)}/build/scripts/libLicenses.gant") +includeTargets << new File("${guessHome(this)}/python/build/python_common.gant") + +requireProperty("buildNumber", requireProperty("build.number", snapshot)) + +setProperty("ch", "$home/community") +setProperty("pythonCommunityHome", "$home/python/community") + +// load ApplicationInfo.xml properties +ant.xmlproperty(file: "$pythonCommunityHome/resources/idea/PyCharmCoreApplicationInfo.xml", collapseAttributes: "true") + +setProperty("system_selector", "PyCharm${p("component.version.major")}0") +setProperty("dryRun", false) +setProperty("jdk16", guessJdk()) + +//modules to compile +setProperty("pluginFilter", new File("$pythonCommunityHome/build/plugin-list.txt").readLines()) + +private List pycharmPlatformApiModules() { + return [platformApiModules, "dom-openapi"].flatten() +} + + +private List pycharmImplementationModules() { //modules to put into pycharm.jar + return [platformImplementationModules, "dom-impl", "python-community", "python-ide-community", "python-openapi", "python-psi-api"] +} + +class Paths { + final sandbox + final distAll + final distWin + final distMac + final distUnix + final artifacts + final ideaSystem + final ideaConfig + + def Paths(String home) { + sandbox = "$home/out/pycharmCE" + + distAll = "$sandbox/layout" + distWin = "$sandbox/win" + distMac = "$sandbox/mac" + distUnix = "$sandbox/unix" + artifacts = "$home/out/pycharmCE/artifacts" + + ideaSystem = "$sandbox/system" + ideaConfig = "$sandbox/config" + } +} + +setProperty("paths", new Paths(home)) +setProperty("buildName", "PC-$buildNumber") + +target('default': "Build artifacts") { + def modules = [ + "python-pydev", "colorSchemes", pycharmPlatformApiModules(), pycharmImplementationModules(), pluginFilter + ].flatten() + + loadProject() + + projectBuilder.stage("Cleaning up sandbox folder") + + projectBuilder.targetFolder = "${paths.sandbox}/classes" + projectBuilder.dryRun = dryRun + + if (!dryRun) { + forceDelete(paths.sandbox) + ant.mkdir(dir: paths.sandbox) + } + + ant.tstamp() { + format(property: "todayYear", pattern: "yyyy") + } + + ant.patternset(id: "resources.included") { + include(name: "**/*.properties") + include(name: "fileTemplates/**/*") + include(name: "inspectionDescriptions/**/*") + include(name: "intentionDescriptions/**/*") + include(name: "tips/**/*") + include(name: "search/**/*") + } + + ant.patternset(id: "resources.excluded") { + exclude(name: "**/*.properties") + exclude(name: "fileTemplates/**/*") + exclude(name: "fileTemplates") + exclude(name: "inspectionDescriptions/**/*") + exclude(name: "inspectionDescriptions") + exclude(name: "intentionDescriptions/**/*") + exclude(name: "intentionDescriptions") + exclude(name: "tips/**/*") + exclude(name: "tips") + } + + zipSources(home, paths.artifacts) + + def usedJars = buildModules(modules, ["python/lib"]) + + buildSearchableOptions("${projectBuilder.moduleOutput(findModule("platform-resources"))}/search", [], { + projectBuilder.moduleRuntimeClasspath(findModule("main_pycharm_ce"), false).each { + ant.pathelement(location: it) + } + }, "-Didea.platform.prefix=PyCharmCore -Didea.no.jre.check=true") + + if (!dryRun) { + wireBuildDate(buildName, appInfoFile()) + } + + Map args = [ + buildNumber: buildName, + system_selector: system_selector, + ide_jvm_args: "-Didea.platform.prefix=PyCharmCore -Didea.no.jre.check=true"] + + LayoutInfo layoutInfo = layoutFull(args, paths.distAll, usedJars) + generateLicensesTable("$paths.artifacts/third-party-libraries.txt", layoutInfo.usedModules); + + def egg = buildDebuggerEgg(paths.sandbox, "$home/python", buildName) + ant.copy(file: egg, todir: paths.distAll) + def eggPy3k = buildDebuggerEggPy3K(paths.sandbox, "$home/python", buildName) + ant.copy(file: eggPy3k, todir: paths.distAll) + + layoutWin(args, paths.distWin) + layoutUnix(args, paths.distUnix) + layoutMac(args, paths.distMac) + + ant.echo(message: buildName, file: "${paths.sandbox}/layout/build.txt") + + /* + def launcher = "${paths.distWin}/bin/pycharm.exe" + List resourcePaths = ["$home/community/community-resources/src", + "$home/community/platform/icons/src", + "$home/python/resources", + "$home/python/community/resources"] + buildWinLauncher("$home/community", "$home/community/bin/WinLauncher/WinLauncher.exe", launcher, + appInfoFile(), "$home/python/build/pycharm_launcher.properties", system_selector, resourcePaths) + signExe(launcher) + + buildWinZip("${paths.artifacts}/pycharm${buildName}.zip", [paths.distAll, paths.distWin]) + buildNSIS([paths.distAll, paths.distWin], + "$home/python/build/strings.nsi", "$home/python/build/paths.nsi", + "pycharm", false, true, system_selector) + + String tarRoot = isEap() ? "pycharm-$buildNumber" : "pycharm-${p("component.version.major")}.${p("component.version.minor")}" + buildTarGz(tarRoot, "$paths.artifacts/pycharm${buildName}.tar", [paths.distAll, paths.distUnix]) + + String macAppRoot = isEap() ? "PyCharm ${p("component.version.major")}.${p("component.version.minor")} EAP.app" : "PyCharm.app" + buildMacZip(macAppRoot, "${paths.artifacts}/pycharm${buildName}.sit", [paths.distAll], paths.distMac) + signMacZip("pycharm") + buildDmg("pycharm", "${home}/python/build/DMG_background.png") + */ +} + +private layoutPlugins(layouts) { + dir("plugins") { + /* + layouts.layoutPlugin("django-db-config") + layouts.layoutPlugin("python-javascript-debugger") + layouts.layoutPlugin("remote-run") { + fileset(dir: "$home/plugins/remote-run/lib") { + include(name: "jediterm-0.2.jar") + } + } + layouts.layoutPlugin("python-remote-interpreter") + layouts.layoutPlugin("vagrant") { + fileset(dir: "$home/plugins/vagrant/lib") { + include(name: "jrubyparser-0.2.jar") + } + } + layouts.layoutPlugin("python-uml") + layouts.layoutPlugin("localization") + layouts.layoutPlugin("python-localization") + 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.layoutPlugins() +} + +private String appInfoFile() { + return "$home/out/pycharm/classes/production/python-ide-community/idea/PyCharmCoreApplicationInfo.xml" +} + +private layoutFull(Map args, String target, Set usedJars) { + def openapiModules = pycharmPlatformApiModules() + def superLayouts = includeFile("$home/build/scripts/layouts.gant") + def result = layout(target) { + dir("lib") { + jar("util.jar") { + module("util") + module("util-rt") + } + + jar("openapi.jar") { + openapiModules.each { module it } + } + + jar("annotations.jar") { module("annotations") } + jar("extensions.jar") { module("extensions") } + + jar("pycharm.jar") { + pycharmImplementationModules().each { + module(it) { + exclude(name: "**/tips/**") + } + } + } + + jar("pycharm-pydev.jar") { + module("python-pydev") + } + + jar("bootstrap.jar") { module("bootstrap") } + jar("resources.jar") { + module("platform-resources") + module("colorSchemes") + } + + jar("forms_rt.jar") { + module("forms_rt") + } + + //noinspection GroovyAssignabilityCheck + jar([name: "resources_en.jar", duplicate: "preserve"]) { + // custom resources should go first + fileset(dir: "$home/python/resources") { + include(name: "**/tips/**") + } + fileset(dir: "$home/python/community/resources") { + include(name: "**/tips/**") + } + module("platform-resources-en") { + ant.patternset { + exclude(name: "tips/images/switcher.png") + exclude(name: "tips/images/navigateToFilePath.gif") + } + } + } + + jar("icons.jar") { module("icons") } + jar("boot.jar") { module("boot") } + + usedJars.each { + fileset(file: it) + } + + dir("ext") { + fileset(dir: "$home/community/lib") { + include(name: "cglib*.jar") + } + } + + dir("src") { + fileset(dir: "$home/community/lib/src") { + include(name: "trove4j_changes.txt") + include(name: "trove4j_src.jar") + } + + jar("pycharm-pydev-src.zip") { + fileset(dir: "$home/python/pydevSrc") + } + jar("pycharm-openapi-src.zip") { + fileset(dir: "$home/python/openapi/src") + fileset(dir: "$home/python/psi-api/src") + } + } + } + + dir("help") { + fileset(dir: "$home/python/help") { + include(name: "*.pdf") + } + } + + dir("helpers") { + fileset(dir: "$home/python/helpers") + } + + dir("license") { + fileset(dir: "$home/community/license") + } + + layoutPlugins(superLayouts) + + dir("bin") { + fileset(dir: "$home/community/bin") { + exclude(name: "appletviewer.policy") + include(name: "*.*") + } + } + } + patchPropertiesFile(target, args + [appendices: ["$home/build/conf/ideaJNC.properties"]]) + return result +} + +private layoutWin(Map args, String target) { + layout(target) { + dir("bin") { + fileset(dir: "$home/community/bin/win") { + exclude(name: "breakgen*") + } + } + + dir("skeletons") { + fileset(dir: "$home/python/skeletons") { + include(name: "skeletons-win*.zip") + } + } + } + + winScripts(target, "$home/community", "pycharm.bat", args) + winVMOptions(target, args.system_selector, "pycharm.exe") +} + +private layoutUnix(Map args, String target) { + layout(target) { + dir("bin") { + fileset(dir: "$home/community/bin/linux") { + exclude(name: "libbreakgen*") + } + } + } + + ant.copy(file: "$home/python/resources/PyCharm_128.png", tofile: "$target/bin/pycharm.png") + + unixScripts(target, "$home/community", "pycharm.sh", args) + unixVMOptions(target, "pycharm") +} + +private layoutMac(Map _args, String target) { + layout(target) { + dir("bin") { + fileset(dir: "$home/bin") { + include(name: "*.jnilib") + } + } + + dir("skeletons") { + fileset(dir: "$home/python/skeletons") { + include(name: "skeletons-mac*.zip") + } + } + } + + Map args = new HashMap(_args) + args.icns = "$home/python/resources/PyCharm.icns" + args.bundleIdentifier = "com.jetbrains.pycharm" + args.platform_prefix = "Python" + args.help_id = "PY" + args."idea.properties.path" = "${paths.distAll}/bin/idea.properties" + args."idea.properties" = ["idea.no.jre.check": true, "ide.mac.useNativeClipboard": "false"]; + layoutMacApp(target, "$home/community", args) +} diff --git a/python/build/python-community-build.iml b/python/build/python-community-build.iml new file mode 100644 index 000000000000..9dcf7cae7b5e --- /dev/null +++ b/python/build/python-community-build.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + From 1cde3f6b847ada81844c0fa959190f26e3900c7c Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Aug 2013 19:49:55 +0200 Subject: [PATCH 09/10] fix registration of CythonFileTypeFactory --- python/src/META-INF/python-plugin-common.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 0d6326a88198..a6c3ac9c83a8 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -21,6 +21,7 @@ id="com.jetbrains.python.templateLanguages.TemplateLanguageModulesConfigurable" displayName="Python Template Languages"/> + @@ -423,7 +424,6 @@ - From f499c86f7a32035748ff7808f0ae831ca792371e Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 2 Sep 2013 12:46:49 +0200 Subject: [PATCH 10/10] temp fix for build script --- python/build/pycharm_build.gant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index 99daebdecc66..7c17d12ad023 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -216,7 +216,7 @@ private scramble() { } private String appInfoFile() { - return "$home/out/pycharm/classes/production/python-ide/idea/PythonApplicationInfo.xml" + return "$home/out/pycharm/classes/production/python-ide-community/idea/PythonApplicationInfo.xml" } private layoutFull(Map args, String target, Set usedJars) {