pip Interface: added an action to install a locally available package/wheel

Fri, 18 May 2018 19:04:15 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 18 May 2018 19:04:15 +0200
changeset 6294
58f82c179d2b
parent 6293
509768769afe
child 6295
79bfd24e2fee

pip Interface: added an action to install a locally available package/wheel

Plugins/UiExtensionPlugins/PipInterface/Pip.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.ui file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipRequirementsSelectionDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipRequirementsSelectionDialog.ui file | annotate | diff | comparison | revisions
changelog file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- a/Plugins/UiExtensionPlugins/PipInterface/Pip.py	Fri May 18 18:31:14 2018 +0200
+++ b/Plugins/UiExtensionPlugins/PipInterface/Pip.py	Fri May 18 19:04:15 2018 +0200
@@ -127,7 +127,6 @@
         ## Actions for installing packages
         ##############################################
         
-        # TODO: add action to install a downloaded wheel via pip
         self.installPackagesAct = E5Action(
             self.tr('Install Packages'),
             self.tr('&Install Packages'),
@@ -142,6 +141,21 @@
         self.installPackagesAct.triggered.connect(self.__installPackages)
         self.actions.append(self.installPackagesAct)
         
+        self.installLocalPackageAct = E5Action(
+            self.tr('Install Local Package'),
+            self.tr('Install Local Package'),
+            0, 0,
+            self, 'pip_install_local_package')
+        self.installLocalPackageAct.setStatusTip(self.tr(
+            'Install a package from local storage'))
+        self.installLocalPackageAct.setWhatsThis(self.tr(
+            """<b>Install Local Package</b>"""
+            """<p>This installs a package available on local storage.</p>"""
+        ))
+        self.installLocalPackageAct.triggered.connect(
+            self.__installLocalPackage)
+        self.actions.append(self.installLocalPackageAct)
+        
         self.installRequirementsAct = E5Action(
             self.tr('Install Requirements'),
             self.tr('Install Requirements'),
@@ -356,6 +370,7 @@
         menu.addSeparator()
         menu.addAction(self.installPipAct)
         menu.addAction(self.installPackagesAct)
+        menu.addAction(self.installLocalPackageAct)
         menu.addAction(self.installRequirementsAct)
         menu.addSeparator()
         menu.addAction(self.upgradePipAct)
@@ -932,13 +947,23 @@
             if packages:
                 self.installPackages(packages, cmd=command)
     
+    def __installLocalPackage(self):
+        """
+        Private slot to install a package available on local storage.
+        """
+        from .PipFileSelectionDialog import PipFileSelectionDialog
+        dlg = PipFileSelectionDialog(self.__plugin, "package")
+        if dlg.exec_() == QDialog.Accepted:
+            command, package = dlg.getData()
+            if package and os.path.exists(package):
+                self.installPackages([package], cmd=command)
+    
     def __installRequirements(self):
         """
         Private slot to install packages as given in a requirements file.
         """
-        from .PipRequirementsSelectionDialog import \
-            PipRequirementsSelectionDialog
-        dlg = PipRequirementsSelectionDialog(self.__plugin)
+        from .PipFileSelectionDialog import PipFileSelectionDialog
+        dlg = PipFileSelectionDialog(self.__plugin, "requirements")
         if dlg.exec_() == QDialog.Accepted:
             command, requirements = dlg.getData()
             if requirements and os.path.exists(requirements):
@@ -1002,9 +1027,8 @@
         """
         Private slot to uninstall packages as given in a requirements file.
         """
-        from .PipRequirementsSelectionDialog import \
-            PipRequirementsSelectionDialog
-        dlg = PipRequirementsSelectionDialog(self.__plugin)
+        from .PipFileSelectionDialog import PipFileSelectionDialog
+        dlg = PipFileSelectionDialog(self.__plugin, "requirements")
         if dlg.exec_() == QDialog.Accepted:
             command, requirements = dlg.getData()
             if requirements and os.path.exists(requirements):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.py	Fri May 18 19:04:15 2018 +0200
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015 - 2018 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+
+"""
+Module implementing a dialog to enter a file to be processed.
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtWidgets import QDialog, QDialogButtonBox
+
+from E5Gui.E5PathPicker import E5PathPickerModes
+
+from .Ui_PipFileSelectionDialog import Ui_PipFileSelectionDialog
+
+import Utilities
+
+
+class PipFileSelectionDialog(QDialog, Ui_PipFileSelectionDialog):
+    """
+    Class implementing a dialog to enter a file to be processed.
+    """
+    def __init__(self, plugin, mode, parent=None):
+        """
+        Constructor
+        
+        @param plugin reference to the plugin object
+        @type PipInterfacePlugin
+        @param mode mode of the dialog
+        @type str
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super(PipFileSelectionDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        if mode == "requirements":
+            self.fileLabel.setText(self.tr("Enter requirements file:"))
+            self.filePicker.setMode(E5PathPickerModes.OpenFileMode)
+            self.filePicker.setToolTip(self.tr(
+                "Press to select the requirements file through a file"
+                " selection dialog."))
+            self.filePicker.setFilters(
+                self.tr("Text Files (*.txt);;All Files (*)"))
+        elif mode == "package":
+            self.fileLabel.setText(self.tr("Enter package file:"))
+            self.filePicker.setMode(E5PathPickerModes.OpenFileMode)
+            self.filePicker.setToolTip(self.tr(
+                "Press to select the package file through a file"
+                " selection dialog."))
+            self.filePicker.setFilters(
+                self.tr("Python Wheel (*.whl);;"
+                        "Archive Files (*.tar.gz *.zip);;"
+                        "All Files (*)"))
+        else:
+            self.fileLabel.setText(self.tr("Enter file:"))
+            self.filePicker.setMode(E5PathPickerModes.OpenFileMode)
+            self.filePicker.setToolTip(self.tr(
+                "Press to select a file through a file selection dialog."))
+            self.filePicker.setFilters(self.tr("All Files (*)"))
+        self.filePicker.setDefaultDirectory(os.path.expanduser("~"))
+        
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
+        
+        self.__default = self.tr("<Default>")
+        pipExecutables = sorted(plugin.getPreferences("PipExecutables"))
+        self.pipComboBox.addItem(self.__default)
+        self.pipComboBox.addItems(pipExecutables)
+        
+        msh = self.minimumSizeHint()
+        self.resize(max(self.width(), msh.width()), msh.height())
+    
+    @pyqtSlot(str)
+    def on_filePicker_textChanged(self, txt):
+        """
+        Private slot to handle entering the name of a file.
+        
+        @param txt name of the file
+        @type str
+        """
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(
+            bool(txt) and
+            os.path.exists(Utilities.toNativeSeparators(txt))
+        )
+    
+    def getData(self):
+        """
+        Public method to get the entered data.
+        
+        @return tuple with the pip command and the name of the
+            selected file
+        @rtype tuple of (str, str)
+        """
+        command = self.pipComboBox.currentText()
+        if command == self.__default:
+            command = ""
+        
+        return command, self.filePicker.text()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.ui	Fri May 18 19:04:15 2018 +0200
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PipFileSelectionDialog</class>
+ <widget class="QDialog" name="PipFileSelectionDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>121</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Select File</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Select the pip executable to be used:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QComboBox" name="pipComboBox">
+     <property name="toolTip">
+      <string>Select the pip command to use</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="fileLabel">
+     <property name="text">
+      <string>Enter file name:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="E5PathPicker" name="filePicker" native="true">
+     <property name="focusPolicy">
+      <enum>Qt::StrongFocus</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>E5PathPicker</class>
+   <extends>QWidget</extends>
+   <header>E5Gui/E5PathPicker.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>PipFileSelectionDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>PipFileSelectionDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- a/Plugins/UiExtensionPlugins/PipInterface/PipRequirementsSelectionDialog.py	Fri May 18 18:31:14 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2015 - 2018 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-
-"""
-Module implementing a dialog to enter a requirements file.
-"""
-
-from __future__ import unicode_literals
-
-import os
-
-from PyQt5.QtCore import pyqtSlot
-from PyQt5.QtWidgets import QDialog, QDialogButtonBox
-
-from E5Gui import E5FileDialog
-
-from .Ui_PipRequirementsSelectionDialog import \
-    Ui_PipRequirementsSelectionDialog
-
-import Utilities
-import UI.PixmapCache
-
-
-class PipRequirementsSelectionDialog(QDialog,
-                                     Ui_PipRequirementsSelectionDialog):
-    """
-    Class implementing a dialog to enter a requirements file.
-    """
-    def __init__(self, plugin, parent=None):
-        """
-        Constructor
-        
-        @param plugin reference to the plugin object (ToolPipPlugin)
-        @param parent reference to the parent widget (QWidget)
-        """
-        super(PipRequirementsSelectionDialog, self).__init__(parent)
-        self.setupUi(self)
-        
-        self.fileButton.setIcon(UI.PixmapCache.getIcon("open.png"))
-        
-        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
-        
-        self.__default = self.tr("<Default>")
-        pipExecutables = sorted(plugin.getPreferences("PipExecutables"))
-        self.pipComboBox.addItem(self.__default)
-        self.pipComboBox.addItems(pipExecutables)
-        
-        msh = self.minimumSizeHint()
-        self.resize(max(self.width(), msh.width()), msh.height())
-    
-    @pyqtSlot()
-    def on_fileButton_clicked(self):
-        """
-        Private slot to enter the requirements file via a file selection
-        dialog.
-        """
-        fileName = E5FileDialog.getOpenFileName(
-            self,
-            self.tr("Select the requirements file"),
-            self.requirementsEdit.text() or os.path.expanduser("~"),
-            self.tr("Text Files (*.txt);;All Files (*)")
-        )
-        if fileName:
-            self.requirementsEdit.setText(
-                Utilities.toNativeSeparators(fileName))
-    
-    @pyqtSlot(str)
-    def on_requirementsEdit_textChanged(self, txt):
-        """
-        Private slot handling entering the name of a requirements file.
-        
-        @param txt name of the requirements file (string)
-        """
-        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(
-            bool(txt) and
-            os.path.exists(Utilities.toNativeSeparators(txt))
-        )
-    
-    def getData(self):
-        """
-        Public method to get the entered data.
-        
-        @return tuple with the pip command (string) and the name of the
-            requirements file (string)
-        """
-        command = self.pipComboBox.currentText()
-        if command == self.__default:
-            command = ""
-        
-        return command, self.requirementsEdit.text()
--- a/Plugins/UiExtensionPlugins/PipInterface/PipRequirementsSelectionDialog.ui	Fri May 18 18:31:14 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>PipRequirementsSelectionDialog</class>
- <widget class="QDialog" name="PipRequirementsSelectionDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>600</width>
-    <height>143</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Select Requirements</string>
-  </property>
-  <property name="sizeGripEnabled">
-   <bool>true</bool>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <widget class="QLabel" name="label">
-     <property name="text">
-      <string>Select the pip executable to be used:</string>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QComboBox" name="pipComboBox">
-     <property name="toolTip">
-      <string>Select the pip command to use</string>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QLabel" name="label_2">
-     <property name="text">
-      <string>Enter requirements file:</string>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <widget class="QLineEdit" name="requirementsEdit"/>
-     </item>
-     <item>
-      <widget class="QToolButton" name="fileButton">
-       <property name="toolTip">
-        <string>Select the requirements file through a file selection dialog</string>
-       </property>
-       <property name="text">
-        <string notr="true"/>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>PipRequirementsSelectionDialog</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>PipRequirementsSelectionDialog</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
--- a/changelog	Fri May 18 18:31:14 2018 +0200
+++ b/changelog	Fri May 18 19:04:15 2018 +0200
@@ -5,6 +5,8 @@
 - Editor
   -- added a configuration option (Editor->Style page) to show the marker map
      on the left or right of the editor
+- pip Interface
+  -- added an action to install a locally available package/wheel
 - Web Browser (NG)
   -- improved the sending of the "Referer" header like it is done by Firefox
 
--- a/eric6.e4p	Fri May 18 18:31:14 2018 +0200
+++ b/eric6.e4p	Fri May 18 19:04:15 2018 +0200
@@ -534,11 +534,11 @@
     <Source>Plugins/UiExtensionPlugins/PipInterface/ConfigurationPage/__init__.py</Source>
     <Source>Plugins/UiExtensionPlugins/PipInterface/Pip.py</Source>
     <Source>Plugins/UiExtensionPlugins/PipInterface/PipDialog.py</Source>
+    <Source>Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.py</Source>
     <Source>Plugins/UiExtensionPlugins/PipInterface/PipFreezeDialog.py</Source>
     <Source>Plugins/UiExtensionPlugins/PipInterface/PipListDialog.py</Source>
     <Source>Plugins/UiExtensionPlugins/PipInterface/PipPackageDetailsDialog.py</Source>
     <Source>Plugins/UiExtensionPlugins/PipInterface/PipPackagesInputDialog.py</Source>
-    <Source>Plugins/UiExtensionPlugins/PipInterface/PipRequirementsSelectionDialog.py</Source>
     <Source>Plugins/UiExtensionPlugins/PipInterface/PipSearchDialog.py</Source>
     <Source>Plugins/UiExtensionPlugins/PipInterface/__init__.py</Source>
     <Source>Plugins/UiExtensionPlugins/Translator/ConfigurationPage/TranslatorPage.py</Source>
@@ -1798,11 +1798,11 @@
     <Form>Plugins/DocumentationPlugins/Ericdoc/EricdocExecDialog.ui</Form>
     <Form>Plugins/UiExtensionPlugins/PipInterface/ConfigurationPage/PipPage.ui</Form>
     <Form>Plugins/UiExtensionPlugins/PipInterface/PipDialog.ui</Form>
+    <Form>Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.ui</Form>
     <Form>Plugins/UiExtensionPlugins/PipInterface/PipFreezeDialog.ui</Form>
     <Form>Plugins/UiExtensionPlugins/PipInterface/PipListDialog.ui</Form>
     <Form>Plugins/UiExtensionPlugins/PipInterface/PipPackageDetailsDialog.ui</Form>
     <Form>Plugins/UiExtensionPlugins/PipInterface/PipPackagesInputDialog.ui</Form>
-    <Form>Plugins/UiExtensionPlugins/PipInterface/PipRequirementsSelectionDialog.ui</Form>
     <Form>Plugins/UiExtensionPlugins/PipInterface/PipSearchDialog.ui</Form>
     <Form>Plugins/UiExtensionPlugins/Translator/ConfigurationPage/TranslatorPage.ui</Form>
     <Form>Plugins/UiExtensionPlugins/Translator/TranslatorWidget.ui</Form>
@@ -2203,14 +2203,14 @@
   </Resources>
   <Others>
     <Other>.hgignore</Other>
-    <Other>APIs/Python/zope-2.10.7.api</Other>
-    <Other>APIs/Python/zope-2.11.2.api</Other>
-    <Other>APIs/Python/zope-3.3.1.api</Other>
     <Other>APIs/Python3/PyQt4.bas</Other>
     <Other>APIs/Python3/PyQt5.bas</Other>
     <Other>APIs/Python3/QScintilla2.bas</Other>
     <Other>APIs/Python3/eric6.api</Other>
     <Other>APIs/Python3/eric6.bas</Other>
+    <Other>APIs/Python/zope-2.10.7.api</Other>
+    <Other>APIs/Python/zope-2.11.2.api</Other>
+    <Other>APIs/Python/zope-3.3.1.api</Other>
     <Other>APIs/QSS/qss.api</Other>
     <Other>APIs/Ruby/Ruby-1.8.7.api</Other>
     <Other>APIs/Ruby/Ruby-1.8.7.bas</Other>

eric ide

mercurial