Tue, 15 May 2018 18:25:26 +0200
pip interface: added a TODO comment to install a downloaded wheel
# -*- coding: utf-8 -*- # Copyright (c) 2015 - 2018 Detlev Offenbach <detlev@die-offenbachs.de> # """ Package implementing the pip GUI logic. """ from __future__ import unicode_literals try: str = unicode # __IGNORE_EXCEPTION__ except NameError: pass import os import re import sys from PyQt5.QtCore import pyqtSlot, QObject, QProcess, QDir from PyQt5.QtWidgets import QMenu, QInputDialog, QDialog from E5Gui import E5MessageBox, E5FileDialog from E5Gui.E5Action import E5Action from E5Gui.E5Application import e5App from .PipDialog import PipDialog import Preferences import Globals class Pip(QObject): """ Class implementing the pip GUI logic. """ def __init__(self, plugin, parent=None): """ Constructor @param plugin reference to the plugin object @param parent parent (QObject) """ super(Pip, self).__init__(parent) self.__plugin = plugin self.__ui = parent self.__menus = {} # dictionary with references to menus self.__plugin.currentPipChanged.connect(self.__handleTearOffMenu) def initActions(self): """ Public method to define the Django actions. """ self.actions = [] self.selectExecutableAct = E5Action( self.tr('pip Executable'), self.tr('pip &Executable'), 0, 0, self, 'pip_select_executable') self.selectExecutableAct.setStatusTip(self.tr( 'Selects the pip executable to be used')) self.selectExecutableAct.setWhatsThis(self.tr( """<b>pip Executable</b>""" """<p>This selects the pip executable to be used. Multiple""" """ executables can be pre-configured via the configuration""" """ dialog.</p>""" )) self.selectExecutableAct.triggered.connect(self.__selectPipExecutable) self.actions.append(self.selectExecutableAct) ############################################## ## Actions for listing packages ############################################## self.listPackagesAct = E5Action( self.tr('List Installed Packages'), self.tr('&List Installed Packages...'), 0, 0, self, 'pip_list_packages') self.listPackagesAct.setStatusTip(self.tr( 'List all installed packages with versions')) self.listPackagesAct.setWhatsThis(self.tr( """<b>List Installed Packages</b>""" """<p>This lists all the installed packages together""" """ with their versions.</p>""" )) self.listPackagesAct.triggered.connect(self.__listPackages) self.actions.append(self.listPackagesAct) self.listUptodatePackagesAct = E5Action( self.tr('List Up-to-date Packages'), self.tr('List Up-to-&date Packages...'), 0, 0, self, 'pip_list_uptodate_packages') self.listUptodatePackagesAct.setStatusTip(self.tr( 'List all installed, up-to-date packages with versions')) self.listUptodatePackagesAct.setWhatsThis(self.tr( """<b>List Up-to-date Packages</b>""" """<p>This lists all the installed, up-to-date packages together""" """ with their versions.</p>""" )) self.listUptodatePackagesAct.triggered.connect( self.__listUptodatePackages) self.actions.append(self.listUptodatePackagesAct) self.listOutdatedPackagesAct = E5Action( self.tr('List Outdated Packages'), self.tr('List &Outdated Packages...'), 0, 0, self, 'pip_list_outdated_packages') self.listOutdatedPackagesAct.setStatusTip(self.tr( 'List all installed, outdated packages with versions')) self.listOutdatedPackagesAct.setWhatsThis(self.tr( """<b>List Up-to-date Packages</b>""" """<p>This lists all the installed, outdated packages together""" """ with their current and latest versions.</p>""" )) self.listOutdatedPackagesAct.triggered.connect( self.__listOutdatedPackages) self.actions.append(self.listOutdatedPackagesAct) ############################################## ## 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'), 0, 0, self, 'pip_install_packages') self.installPackagesAct.setStatusTip(self.tr( 'Install packages according to user input')) self.installPackagesAct.setWhatsThis(self.tr( """<b>Install Packages</b>""" """<p>This installs packages according to user input.</p>""" )) self.installPackagesAct.triggered.connect(self.__installPackages) self.actions.append(self.installPackagesAct) self.installRequirementsAct = E5Action( self.tr('Install Requirements'), self.tr('Install Requirements'), 0, 0, self, 'pip_install_requirements') self.installRequirementsAct.setStatusTip(self.tr( 'Install packages according to a requirements file')) self.installRequirementsAct.setWhatsThis(self.tr( """<b>Install Requirements</b>""" """<p>This installs packages according to a requirements""" """ file.</p>""" )) self.installRequirementsAct.triggered.connect( self.__installRequirements) self.actions.append(self.installRequirementsAct) self.installPipAct = E5Action( self.tr('Install Pip'), self.tr('Install Pip'), 0, 0, self, 'pip_install_pip') self.installPipAct.setStatusTip(self.tr( 'Install the pip package itself')) self.installPipAct.setWhatsThis(self.tr( """<b>Install Pip</b>""" """<p>This install the pip package itself.</p>""" )) self.installPipAct.triggered.connect(self.__installPip) self.actions.append(self.installPipAct) self.repairPipAct = E5Action( self.tr('Repair Pip'), self.tr('Repair Pip'), 0, 0, self, 'pip_repair_pip') self.repairPipAct.setStatusTip(self.tr( 'Repair the pip package')) self.repairPipAct.setWhatsThis(self.tr( """<b>Repair Pip</b>""" """<p>This repairs the pip package by re-installing it.</p>""" )) self.repairPipAct.triggered.connect(self.__repairPip) self.actions.append(self.repairPipAct) self.upgradePipAct = E5Action( self.tr('Upgrade Pip'), self.tr('Upgrade &Pip'), 0, 0, self, 'pip_upgrade_pip') self.upgradePipAct.setStatusTip(self.tr( 'Upgrade the pip package itself')) self.upgradePipAct.setWhatsThis(self.tr( """<b>Upgrade Pip</b>""" """<p>This upgrades the pip package itself.</p>""" )) self.upgradePipAct.triggered.connect(self.upgradePip) self.actions.append(self.upgradePipAct) self.upgradePackagesAct = E5Action( self.tr('Upgrade Packages'), self.tr('&Upgrade Packages'), 0, 0, self, 'pip_upgrade_packages') self.upgradePackagesAct.setStatusTip(self.tr( 'Upgrade packages according to user input')) self.upgradePackagesAct.setWhatsThis(self.tr( """<b>Upgrade Packages</b>""" """<p>This upgrades packages according to user input.</p>""" )) self.upgradePackagesAct.triggered.connect(self.__upgradePackages) self.actions.append(self.upgradePackagesAct) ############################################## ## Actions for uninstalling packages ############################################## self.uninstallPackagesAct = E5Action( self.tr('Uninstall Packages'), self.tr('Uninstall Packages'), 0, 0, self, 'pip_uninstall_packages') self.uninstallPackagesAct.setStatusTip(self.tr( 'Uninstall packages according to user input')) self.uninstallPackagesAct.setWhatsThis(self.tr( """<b>Uninstall Packages</b>""" """<p>This uninstalls packages according to user input.</p>""" )) self.uninstallPackagesAct.triggered.connect(self.__uninstallPackages) self.actions.append(self.uninstallPackagesAct) self.uninstallRequirementsAct = E5Action( self.tr('Uninstall Requirements'), self.tr('Uninstall Requirements'), 0, 0, self, 'pip_uninstall_requirements') self.uninstallRequirementsAct.setStatusTip(self.tr( 'Uninstall packages according to a requirements file')) self.uninstallRequirementsAct.setWhatsThis(self.tr( """<b>Uninstall Requirements</b>""" """<p>This uninstalls packages according to a requirements""" """ file.</p>""" )) self.uninstallRequirementsAct.triggered.connect( self.__uninstallRequirements) self.actions.append(self.uninstallRequirementsAct) ############################################## ## Actions for generating requirements files ############################################## self.generateRequirementsAct = E5Action( self.tr('Generate Requirements'), self.tr('&Generate Requirements...'), 0, 0, self, 'pip_generate_requirements') self.generateRequirementsAct.setStatusTip(self.tr( 'Generate the contents of a requirements file')) self.generateRequirementsAct.setWhatsThis(self.tr( """<b>Generate Requirements</b>""" """<p>This generates the contents of a requirements file.</p>""" )) self.generateRequirementsAct.triggered.connect( self.__generateRequirements) self.actions.append(self.generateRequirementsAct) ############################################## ## Actions for generating requirements files ############################################## self.searchPyPIAct = E5Action( self.tr('Search PyPI'), self.tr('&Search PyPI...'), 0, 0, self, 'pip_search_pypi') self.searchPyPIAct.setStatusTip(self.tr( 'Open a dialog to search the Python Package Index')) self.searchPyPIAct.setWhatsThis(self.tr( """<b>Search PyPI</b>""" """<p>This opens a dialog to search the Python Package""" """ Index.</p>""" )) self.searchPyPIAct.triggered.connect(self.__searchPyPI) self.actions.append(self.searchPyPIAct) ############################################## ## Actions for editing configuration files ############################################## self.editUserConfigAct = E5Action( self.tr('Edit User Configuration'), self.tr('Edit User Configuration...'), 0, 0, self, 'pip_edit_user_config') self.editUserConfigAct.setStatusTip(self.tr( 'Open the per user configuration file in an editor')) self.editUserConfigAct.setWhatsThis(self.tr( """<b>Edit User Configuration</b>""" """<p>This opens the per user configuration file in an editor.""" """</p>""" )) self.editUserConfigAct.triggered.connect(self.__editUserConfiguration) self.actions.append(self.editUserConfigAct) self.editVirtualenvConfigAct = E5Action( self.tr('Edit Current Virtualenv Configuration'), self.tr('Edit Current Virtualenv Configuration...'), 0, 0, self, 'pip_edit_virtualenv_config') self.editVirtualenvConfigAct.setStatusTip(self.tr( 'Open the current virtualenv configuration file in an editor')) self.editVirtualenvConfigAct.setWhatsThis(self.tr( """<b>Edit Current Virtualenv Configuration</b>""" """<p>This opens the current virtualenv configuration file in""" """ an editor. </p>""" )) self.editVirtualenvConfigAct.triggered.connect( self.__editVirtualenvConfiguration) self.actions.append(self.editVirtualenvConfigAct) self.pipConfigAct = E5Action( self.tr('Configure'), self.tr('Configure...'), 0, 0, self, 'pip_configure') self.pipConfigAct.setStatusTip(self.tr( 'Show the configuration dialog with the Python Package Management' ' page selected' )) self.pipConfigAct.setWhatsThis(self.tr( """<b>Configure</b>""" """<p>Show the configuration dialog with the Python Package""" """ Management page selected.</p>""" )) self.pipConfigAct.triggered.connect(self.__pipConfigure) self.actions.append(self.pipConfigAct) def initMenu(self): """ Public slot to initialize the Django menu. @return the menu generated (QMenu) """ self.__menus = {} # clear menus references menu = QMenu(self.tr('P&ython Package Management'), self.__ui) menu.setTearOffEnabled(True) menu.addAction(self.selectExecutableAct) menu.addSeparator() menu.addAction(self.listPackagesAct) menu.addAction(self.listUptodatePackagesAct) menu.addAction(self.listOutdatedPackagesAct) menu.addSeparator() menu.addAction(self.installPipAct) menu.addAction(self.installPackagesAct) menu.addAction(self.installRequirementsAct) menu.addSeparator() menu.addAction(self.upgradePipAct) menu.addAction(self.upgradePackagesAct) menu.addSeparator() menu.addAction(self.uninstallPackagesAct) menu.addAction(self.uninstallRequirementsAct) menu.addSeparator() menu.addAction(self.generateRequirementsAct) menu.addSeparator() menu.addAction(self.searchPyPIAct) menu.addSeparator() menu.addAction(self.repairPipAct) menu.addSeparator() menu.addAction(self.editUserConfigAct) menu.addAction(self.editVirtualenvConfigAct) menu.addSeparator() menu.addAction(self.pipConfigAct) self.__menus["main"] = menu menu.aboutToShow.connect(self.__aboutToShowMenu) return menu def __aboutToShowMenu(self): """ Private slot to set the action enabled status. """ enable = bool(self.__plugin.getPreferences("CurrentPipExecutable")) for act in self.actions: if act not in [self.selectExecutableAct, self.installPipAct, self.editUserConfigAct, self.editVirtualenvConfigAct, self.pipConfigAct]: act.setEnabled(enable) def getMenu(self, name): """ Public method to get a reference to the requested menu. @param name name of the menu (string) @return reference to the menu (QMenu) or None, if no menu with the given name exists """ if name in self.__menus: return self.__menus[name] else: return None def getMenuNames(self): """ Public method to get the names of all menus. @return menu names (list of string) """ return list(self.__menus.keys()) def __handleTearOffMenu(self, pip): """ Private slot to handle a change of the pip executable. @param pip path of the pip executable @type str """ if self.__menus["main"].isTearOffMenuVisible(): # determine, if torn off menu needs to be refreshed enabled = self.listPackagesAct.isEnabled() if ((bool(pip) and not enabled) or (not bool(pip) and enabled)): self.__menus["main"].hideTearOffMenu() ########################################################################## ## Methods below implement some utility functions ########################################################################## def runProcess(self, args, cmd=""): """ Public method to execute the current pip with the given arguments. The selected pip executable is called with the given arguments and waited for its end. @param args list of command line arguments @type list of str @param cmd pip executable to be used @type str @return tuple containing a flag indicating success and the output of the process @rtype tuple of (bool, str) """ if not cmd: cmd = self.__plugin.getPreferences("CurrentPipExecutable") ioEncoding = Preferences.getSystem("IOEncoding") process = QProcess() process.start(cmd, args) procStarted = process.waitForStarted() if procStarted: finished = process.waitForFinished(30000) if finished: if process.exitCode() == 0: output = str(process.readAllStandardOutput(), ioEncoding, 'replace') return True, output else: return False, self.tr("pip exited with an error ({0}).")\ .format(process.exitCode()) else: process.terminate() process.waitForFinished(2000) process.kill() process.waitForFinished(3000) return False, self.tr("pip did not finish within 30 seconds.") return False, self.tr("pip could not be started.") def __getUserConfig(self): """ Private method to get the name of the user configuration file. @return path of the user configuration file (string) """ # Unix: ~/.config/pip/pip.conf # OS X: ~/Library/Application Support/pip/pip.conf # Windows: %APPDATA%\pip\pip.ini # Environment: $PIP_CONFIG_FILE try: return os.environ["PIP_CONFIG_FILE"] except KeyError: pass if Globals.isWindowsPlatform(): config = os.path.join(os.environ["APPDATA"], "pip", "pip.ini") elif Globals.isMacPlatform(): config = os.path.expanduser( "~/Library/Application Support/pip/pip.conf") else: config = os.path.expanduser("~/.config/pip/pip.conf") return config def __getVirtualenvConfig(self): """ Private method to get the name of the virtualenv configuration file. @return path of the virtualenv configuration file (string) """ # Unix, OS X: $VIRTUAL_ENV/pip.conf # Windows: %VIRTUAL_ENV%\pip.ini if Globals.isWindowsPlatform(): pip = "pip.ini" else: pip = "pip.conf" try: virtualenv = os.environ["VIRTUAL_ENV"] except KeyError: # determine from pip executable file virtualenv = os.path.dirname(os.path.dirname( self.__plugin.getPreferences("CurrentPipExecutable"))) return os.path.join(virtualenv, pip) ########################################################################## ## Methods below implement the individual menu entries ########################################################################## def __selectPipExecutable(self): """ Private method to select the pip executable to be used. """ pipExecutables = sorted(self.__plugin.getPreferences("PipExecutables")) if pipExecutables: currentExecutable = self.__plugin.getPreferences( "CurrentPipExecutable") try: index = pipExecutables.index(currentExecutable) except ValueError: index = 0 executable, ok = QInputDialog.getItem( None, self.tr("pip Executable"), self.tr("Select pip Executable to be used:"), pipExecutables, index, False) if ok and executable: self.__plugin.setPreferences("CurrentPipExecutable", executable) else: res = E5MessageBox.yesNo( None, self.tr("pip Executable"), self.tr("""No pip executables have been configured yet.""" """ Shall this be done now?"""), yesDefault=True) if res: e5App().getObject("UserInterface").showPreferences("pipPage") def __listPackages(self): """ Private slot to list all installed packages. """ from .PipListDialog import PipListDialog self.__listDialog = PipListDialog( self, "list", self.__plugin, self.tr("Installed Packages")) self.__listDialog.show() self.__listDialog.start() def __listUptodatePackages(self): """ Private slot to list all installed, up-to-date packages. """ from .PipListDialog import PipListDialog self.__listUptodateDialog = PipListDialog( self, "uptodate", self.__plugin, self.tr("Up-to-date Packages")) self.__listUptodateDialog.show() self.__listUptodateDialog.start() def __listOutdatedPackages(self): """ Private slot to list all installed, up-to-date packages. """ from .PipListDialog import PipListDialog self.__listOutdatedDialog = PipListDialog( self, "outdated", self.__plugin, self.tr("Outdated Packages")) self.__listOutdatedDialog.show() self.__listOutdatedDialog.start() def __editUserConfiguration(self): """ Private slot to edit the user configuration. """ self.__editConfiguration() def __editVirtualenvConfiguration(self): """ Private slot to edit the current virtualenv configuration. """ self.__editConfiguration(virtualenv=True) def __editConfiguration(self, virtualenv=False): """ Private method to edit a configuration. @param virtualenv flag indicating to edit the current virtualenv configuration file (boolean) """ from QScintilla.MiniEditor import MiniEditor if virtualenv: cfgFile = self.__getVirtualenvConfig() else: cfgFile = self.__getUserConfig() cfgDir = os.path.dirname(cfgFile) if not cfgDir: E5MessageBox.critical( None, self.tr("Edit Configuration"), self.tr("""No valid configuartion path determined.""" """ Is a virtual environment selected? Aborting""")) return try: if not os.path.isdir(cfgDir): os.makedirs(cfgDir) except OSError: E5MessageBox.critical( None, self.tr("Edit Configuration"), self.tr("""No valid configuartion path determined.""" """ Is a virtual environment selected? Aborting""")) return if not os.path.exists(cfgFile): try: f = open(cfgFile, "w") f.write("[global]\n") f.close() except (IOError, OSError): # ignore these pass # check, if the destination is writeable if not os.access(cfgFile, os.W_OK): E5MessageBox.critical( None, self.tr("Edit Configuration"), self.tr("""No valid configuartion path determined.""" """ Is a virtual environment selected? Aborting""")) return self.__editor = MiniEditor(cfgFile, "Properties") self.__editor.show() def __installPip(self): """ Private slot to install pip. """ python = E5FileDialog.getOpenFileName( None, self.tr("Select Python Executable")) if python: python = QDir.toNativeSeparators(python) dia = PipDialog(self.tr('Install PIP')) commands = [(python, ["-m", "ensurepip"])] if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + "/simple" commands.append( (python, ["-m", "pip", "install", "--index-url", indexUrl, "--upgrade", "pip"])) else: commands.append( (python, ["-m", "pip", "install", "--upgrade", "pip"])) res = dia.startProcesses(commands) if res: dia.exec_() pip = E5FileDialog.getOpenFileName( None, self.tr("Select PIP Executable"), os.path.dirname(python)) if pip: pip = QDir.toNativeSeparators(pip) pipExecutables = \ self.__plugin.getPreferences("PipExecutables") if pip not in pipExecutables: pipExecutables.append(pip) self.__plugin.setPreferences( "PipExecutables", pipExecutables) @pyqtSlot() def upgradePip(self, pip=""): """ Public method to upgrade pip itself. @param pip pip command to be used @type str @return flag indicating a successful execution @rtype bool """ # Upgrading pip needs to be treated specially because # it must be done using the python executable if not pip: default = self.tr("<Default>") pipExecutables = sorted( self.__plugin.getPreferences("PipExecutables")) pip, ok = QInputDialog.getItem( None, self.tr("Upgrade pip"), self.tr("Select pip Executable:"), [default] + pipExecutables, 0, False) if not ok or not pip: return False if pip == default: pip = self.__plugin.getPreferences("CurrentPipExecutable") python = self.__getPython(pip) if not python: python = E5FileDialog.getOpenFileName( None, self.tr("Select Python Executable"), os.path.dirname(pip)) if python: python = QDir.toNativeSeparators(python) else: return False if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + "/simple" args = ["-m", "pip", "install", "--index-url", indexUrl, "--upgrade", "pip"] else: args = ["-m", "pip", "install", "--upgrade", "pip"] dia = PipDialog(self.tr('Upgrade PIP')) res = dia.startProcess(python, args) if res: dia.exec_() return res @pyqtSlot() def __repairPip(self): """ Private method to repair the pip installation. @return flag indicating a successful execution @rtype bool """ default = self.tr("<Default>") pipExecutables = sorted( self.__plugin.getPreferences("PipExecutables")) pip, ok = QInputDialog.getItem( None, self.tr("Upgrade pip"), self.tr("Select pip Executable:"), [default] + pipExecutables, 0, False) if not ok or not pip: return False if pip == default: pip = self.__plugin.getPreferences("CurrentPipExecutable") python = self.__getPython(pip) if not python: python = E5FileDialog.getOpenFileName( None, self.tr("Select Python Executable"), os.path.dirname(pip)) if python: python = QDir.toNativeSeparators(python) else: return False # pip install --ignore-installed pip if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + "/simple" args = ["-m", "pip", "install", "--index-url", indexUrl, "--ignore-installed", "pip"] else: args = ["-m", "pip", "install", "--ignore-installed", "pip"] dia = PipDialog(self.tr('Repair PIP')) res = dia.startProcess(python, args) if res: dia.exec_() def __getPython(self, cmd): """ Private method to derive the path to the python executable given the path to the pip executable. @param cmd path of the pip executable @type str @return path of the python executable @rtype str """ path, prog = os.path.split(cmd) paths = (path, os.path.split(path)[0]) # to try the parent directory if Globals.isWindowsPlatform(): subPatterns = ((r"\d\.\d", ""), (r"\d\.", ".")) for pyname in ("python", "pypy"): python = prog.replace("pip", pyname) for pattern, repl in subPatterns: if re.search(pattern, python): python = re.sub(pattern, repl, python) break for path in paths: pypath = os.path.join(path, python) if os.path.exists(pypath): return pypath else: subPatterns = ((r"\.\d$", ""), (r"\d\.\d$", ""), (r"\d$", "")) for pyname in ("python", "pypy"): python = prog.replace("pip", pyname) for path in paths: pypath = os.path.join(path, python) if os.path.exists(pypath): return pypath for pattern, repl in subPatterns: if re.search(pattern, cmd): newpy = re.sub(pattern, repl, python) pypath = os.path.join(path, newpy) if os.path.exists(pypath): return pypath return "" def __checkUpgradePyQt(self, packages): """ Private method to check, if an upgrade of PyQt packages is attempted. @param packages list of packages to upgrade @type list of str @return flag indicating to abort the upgrade attempt @rtype bool """ pyqtPackages = [p for p in packages if p.lower() in ["pyqt5", "qscintilla", "sip"]] if bool(pyqtPackages): abort = not E5MessageBox.yesNo( None, self.tr("Upgrade Packages"), self.tr( """You are trying to upgrade PyQt packages. This will""" """ not work for the current instance of Python ({0}).""" """ Do you want to continue?""").format(sys.executable), icon=E5MessageBox.Critical) else: abort = False return abort def upgradePackages(self, packages, cmd=""): """ Public method to upgrade the given list of packages. @param packages list of packages to upgrade (list of string) @param cmd pip command to be used (string) @return flag indicating a successful execution (boolean) """ if self.__checkUpgradePyQt(packages): return False if not cmd: cmd = self.__plugin.getPreferences("CurrentPipExecutable") if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + "/simple" args = ["install", "--index-url", indexUrl, "--upgrade"] else: args = ["install", "--upgrade"] args += packages dia = PipDialog(self.tr('Upgrade Packages')) res = dia.startProcess(cmd, args) if res: dia.exec_() return res def __upgradePackages(self): """ Private slot to upgrade packages to be given by the user. """ from .PipPackagesInputDialog import PipPackagesInputDialog dlg = PipPackagesInputDialog( self.__plugin, self.tr("Upgrade Packages")) if dlg.exec_() == QDialog.Accepted: command, packages = dlg.getData() if packages: self.upgradePackages(packages, cmd=command) def installPackages(self, packages, cmd=""): """ Public method to install the given list of packages. @param packages list of packages to install (list of string) @param cmd pip command to be used (string) """ if not cmd: cmd = self.__plugin.getPreferences("CurrentPipExecutable") if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + "/simple" args = ["install", "--index-url", indexUrl] else: args = ["install"] args += packages dia = PipDialog(self.tr('Install Packages')) res = dia.startProcess(cmd, args) if res: dia.exec_() def __installPackages(self): """ Private slot to install packages to be given by the user. """ from .PipPackagesInputDialog import PipPackagesInputDialog dlg = PipPackagesInputDialog( self.__plugin, self.tr("Install Packages")) if dlg.exec_() == QDialog.Accepted: command, packages = dlg.getData() if packages: self.installPackages(packages, cmd=command) def __installRequirements(self): """ Private slot to install packages as given in a requirements file. """ from .PipRequirementsSelectionDialog import \ PipRequirementsSelectionDialog dlg = PipRequirementsSelectionDialog(self.__plugin) if dlg.exec_() == QDialog.Accepted: command, requirements = dlg.getData() if requirements and os.path.exists(requirements): if not command: command = self.__plugin.getPreferences( "CurrentPipExecutable") if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + \ "/simple" args = ["install", "--index-url", indexUrl] else: args = ["install"] args += ["--requirement", requirements] dia = PipDialog(self.tr('Install Packages from Requirements')) res = dia.startProcess(command, args) if res: dia.exec_() def uninstallPackages(self, packages, cmd=""): """ Public method to uninstall the given list of packages. @param packages list of packages to uninstall (list of string) @param cmd pip command to be used (string) @return flag indicating a successful execution (boolean) """ res = False if packages: from UI.DeleteFilesConfirmationDialog import \ DeleteFilesConfirmationDialog dlg = DeleteFilesConfirmationDialog( self.parent(), self.tr("Uninstall Packages"), self.tr( "Do you really want to uninstall these packages?"), packages) if dlg.exec_() == QDialog.Accepted: if not cmd: cmd = self.__plugin.getPreferences("CurrentPipExecutable") args = ["uninstall", "--yes"] + packages dia = PipDialog(self.tr('Uninstall Packages')) res = dia.startProcess(cmd, args) if res: dia.exec_() return res def __uninstallPackages(self): """ Private slot to uninstall packages to be given by the user. """ from .PipPackagesInputDialog import PipPackagesInputDialog dlg = PipPackagesInputDialog( self.__plugin, self.tr("Uninstall Packages")) if dlg.exec_() == QDialog.Accepted: command, packages = dlg.getData() if packages: self.uninstallPackages(packages, cmd=command) def __uninstallRequirements(self): """ Private slot to uninstall packages as given in a requirements file. """ from .PipRequirementsSelectionDialog import \ PipRequirementsSelectionDialog dlg = PipRequirementsSelectionDialog(self.__plugin) if dlg.exec_() == QDialog.Accepted: command, requirements = dlg.getData() if requirements and os.path.exists(requirements): try: f = open(requirements, "r") reqs = f.read().splitlines() f.close() except (OSError, IOError): return from UI.DeleteFilesConfirmationDialog import \ DeleteFilesConfirmationDialog dlg = DeleteFilesConfirmationDialog( self.parent(), self.tr("Uninstall Packages"), self.tr( "Do you really want to uninstall these packages?"), reqs) if dlg.exec_() == QDialog.Accepted: if not command: command = self.__plugin.getPreferences( "CurrentPipExecutable") args = ["uninstall", "--requirement", requirements] dia = PipDialog( self.tr('Uninstall Packages from Requirements')) res = dia.startProcess(command, args) if res: dia.exec_() def __generateRequirements(self): """ Private slot to generate the contents for a requirements file. """ from .PipFreezeDialog import PipFreezeDialog self.__freezeDialog = PipFreezeDialog(self, self.__plugin) self.__freezeDialog.show() self.__freezeDialog.start() def __searchPyPI(self): """ Private slot to search the Python Package Index. """ from .PipSearchDialog import PipSearchDialog self.__searchDialog = PipSearchDialog(self, self.__plugin) self.__searchDialog.show() def __pipConfigure(self): """ Private slot to open the configuration page. """ e5App().getObject("UserInterface").showPreferences("pipPage")