Snapshot idea/138.1029 from git://git.jetbrains.org/idea/community.git

Update from idea/138.538 to idea/138.1029

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