def on_configButton_clicked(self): """ Private slot to edit the Subversion config file. """ cfgFile = self.__plugin.getConfigPath() editor = MiniEditor(cfgFile, "Properties", self) editor.show()
def on_configButton_clicked(self): """ Private slot to edit the (per user) Git configuration file. """ from QScintilla.MiniEditor import MiniEditor cfgFile = self.__plugin.getConfigPath() if not os.path.exists(cfgFile): from ..GitUserConfigDataDialog import GitUserConfigDataDialog dlg = GitUserConfigDataDialog() if dlg.exec_() == QDialog.Accepted: firstName, lastName, email = dlg.getData() else: firstName, lastName, email = ("Firstname", "Lastname", "email_address") try: f = open(cfgFile, "w") f.write("[user]\n") f.write(" name = {0} {1}\n".format(firstName, lastName)) f.write(" email = {0}\n".format(email)) f.close() except (IOError, OSError): # ignore these pass editor = MiniEditor(cfgFile, "Properties", self) editor.show()
def on_showScriptSourceButton_clicked(self): """ Private slot to show an editor window with the script source code. """ from QScintilla.MiniEditor import MiniEditor editor = MiniEditor(self.__scriptFileName, "JavaScript", self) editor.show()
def on_serversButton_clicked(self): """ Private slot to edit the Subversion servers file. """ serversFile = self.__plugin.getServersPath() editor = MiniEditor(serversFile, "Properties", self) editor.show()
def on_configButton_clicked(self): """ Private slot to edit the Subversion config file. """ from QScintilla.MiniEditor import MiniEditor cfgFile = self.__plugin.getConfigPath() editor = MiniEditor(cfgFile, "Properties", self) editor.show()
def on_serversButton_clicked(self): """ Private slot to edit the Subversion servers file. """ from QScintilla.MiniEditor import MiniEditor serversFile = self.__plugin.getServersPath() editor = MiniEditor(serversFile, "Properties", self) editor.show()
def on_showScriptSourceButton_clicked(self): """ Private slot to show an editor window with the source code. """ from Helpviewer import HelpUtilities tmpFileName = HelpUtilities.ensureUniqueFilename( os.path.join(QDir.tempPath(), "tmp-userscript.js")) if QFile.copy(self.__script.fileName(), tmpFileName): from QScintilla.MiniEditor import MiniEditor editor = MiniEditor(tmpFileName, "JavaScript", self) editor.show()
def createMainWidget(argv): """ Function to create the main widget. @param argv list of commandline parameters (list of strings) @return reference to the main widget (QWidget) """ from QScintilla.MiniEditor import MiniEditor if len(argv) > 1: return MiniEditor(argv[1]) else: return MiniEditor()
def __editConfiguration(self, venvName=""): """ Private method to edit a configuration. @param venvName name of the environment to act upon @type str """ from QScintilla.MiniEditor import MiniEditor if venvName: cfgFile = self.__pip.getVirtualenvConfig(venvName) if not cfgFile: return else: cfgFile = self.__pip.getUserConfig() cfgDir = os.path.dirname(cfgFile) if not cfgDir: E5MessageBox.critical( None, self.tr("Edit Configuration"), self.tr("""No valid configuration path determined.""" """ 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 configuration path determined.""" """ 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 configuration path determined.""" """ Aborting""")) return self.__editor = MiniEditor(cfgFile, "Properties") self.__editor.show()
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 on_editorButton_clicked(self): """ Private slot to open the user configuration file in a text editor. """ from QScintilla.MiniEditor import MiniEditor cfgFile = getConfigPath() yes = E5MessageBox.yesNo( self, self.tr("Edit User Configuration"), self.tr("""You will loose all changes made in this dialog.""" """ Shall the data be saved first?"""), icon=E5MessageBox.Warning, yesDefault=True) if yes: self.writeUserConfig() self.__editor = MiniEditor(cfgFile, "Properties", self) self.__editor.setWindowModality(Qt.WindowModal) self.__editor.installEventFilter(self) self.__editor.show()
def on_configButton_clicked(self): """ Private slot to edit the (per user) Mercurial configuration file. """ from QScintilla.MiniEditor import MiniEditor cfgFile = self.__plugin.getConfigPath() if not os.path.exists(cfgFile): from ..HgUserConfigDataDialog import HgUserConfigDataDialog dlg = HgUserConfigDataDialog() if dlg.exec_() == QDialog.Accepted: firstName, lastName, email, extensions, extensionsData = \ dlg.getData() else: firstName, lastName, email, extensions, extensionsData = ( "Firstname", "Lastname", "email_address", [], {}) try: f = open(cfgFile, "w") f.write("[ui]\n") f.write("username = {0} {1} <{2}>\n".format( firstName, lastName, email)) if extensions: f.write("\n[extensions]\n") f.write(" =\n".join(extensions)) f.write(" =\n") # complete the last line if "largefiles" in extensionsData: dataDict = extensionsData["largefiles"] f.write("\n[largefiles]\n") if "minsize" in dataDict: f.write("minsize = {0}\n".format(dataDict["minsize"])) if "patterns" in dataDict: f.write("patterns =\n") f.write(" {0}\n".format("\n ".join( dataDict["patterns"]))) f.close() except (IOError, OSError): # ignore these pass editor = MiniEditor(cfgFile, "Properties", self) editor.show()
def on_configButton_clicked(self): """ Private slot to edit the (per user) Mercurial configuration file. """ from QScintilla.MiniEditor import MiniEditor cfgFile = self.__plugin.getConfigPath() if not os.path.exists(cfgFile): from ..HgUserConfigDataDialog import HgUserConfigDataDialog dlg = HgUserConfigDataDialog() if dlg.exec_() == QDialog.Accepted: firstName, lastName, email, extensions, extensionsData = \ dlg.getData() else: firstName, lastName, email, extensions, extensionsData = ( "Firstname", "Lastname", "email_address", [], {}) try: f = open(cfgFile, "w") f.write("[ui]\n") f.write("username = {0} {1} <{2}>\n".format( firstName, lastName, email)) if extensions: f.write("\n[extensions]\n") f.write(" =\n".join(extensions)) f.write(" =\n") # complete the last line if "largefiles" in extensionsData: dataDict = extensionsData["largefiles"] f.write("\n[largefiles]\n") if "minsize" in dataDict: f.write("minsize = {0}\n".format(dataDict["minsize"])) if "patterns" in dataDict: f.write("patterns =\n") f.write(" {0}\n".format( "\n ".join(dataDict["patterns"]))) f.close() except (IOError, OSError): # ignore these pass editor = MiniEditor(cfgFile, "Properties", self) editor.show()
def __editUserConfiguration(self): """ Private slot to edit the user configuration. """ from QScintilla.MiniEditor import MiniEditor cfgFile = CondaInterface.userConfiguration() if not cfgFile: return if not os.path.exists(cfgFile): self.__conda.writeDefaultConfiguration() # check, if the destination is writeable if not os.access(cfgFile, os.W_OK): E5MessageBox.critical( None, self.tr("Edit Configuration"), self.tr("""The configuration file "{0}" does not exist""" """ or is not writable.""")) return self.__editor = MiniEditor(cfgFile, "YAML") self.__editor.show()
class HgUserConfigDialog(QDialog, Ui_HgUserConfigDialog): """ Class implementing a dialog to enter some user data. """ def __init__(self, version=(0, 0, 0), parent=None): """ Constructor @param version Mercurial version info @type tuple of three integers @param parent reference to the parent widget @type QWidget """ super(HgUserConfigDialog, self).__init__(parent) self.setupUi(self) self.__version = version self.__minimumProtocols = { "tls1.0": self.tr("TLS 1.0"), "tls1.1": self.tr("TLS 1.1"), "tls1.2": self.tr("TLS 1.2"), } self.lfUserCachePicker.setMode(E5PathPickerModes.DirectoryMode) if Globals.isLinuxPlatform(): self.lfUserCachePicker.setDefaultDirectory( os.path.expanduser("~/.cache/largefiles")) elif Globals.isMacPlatform(): self.lfUserCachePicker.setDefaultDirectory( os.path.expanduser("~/Library/Caches/largefiles")) else: self.lfUserCachePicker.setDefaultDirectory( os.path.expanduser("~\\AppData\\Local\\largefiles")) self.fpAddButton.setIcon(UI.PixmapCache.getIcon("plus.png")) self.fpDeleteButton.setIcon(UI.PixmapCache.getIcon("minus.png")) self.fpEditButton.setIcon(UI.PixmapCache.getIcon("edit.png")) self.protocolAddButton.setIcon(UI.PixmapCache.getIcon("plus.png")) self.protocolDeleteButton.setIcon(UI.PixmapCache.getIcon("minus.png")) self.protocolEditButton.setIcon(UI.PixmapCache.getIcon("edit.png")) self.minimumProtocolComboBox.addItem(self.tr("Default"), "") for protocol in sorted(self.__minimumProtocols.keys()): self.minimumProtocolComboBox.addItem( self.__minimumProtocols[protocol], protocol) self.fingerprintsList.headerItem().setText( self.fingerprintsList.columnCount(), "") self.protocolsList.headerItem().setText( self.protocolsList.columnCount(), "") if self.__version < (3, 9, 0): self.disableTls10WarningCheckBox.setEnabled(False) self.minimumProtocolComboBox.setEnabled(False) self.minimumProtcolGroupBox.setEnabled(False) self.tabWidget.setCurrentIndex(0) self.__editor = None self.__config = None self.readUserConfig() self.__updateFingerprintsButtons() self.__updateProtocolsButtons() def writeUserConfig(self): """ Public method to write the user configuration file. """ if self.__config is None: self.__config = ConfigParser() ################################################################### ## ui section ################################################################### if "ui" not in self.__config: self.__config["ui"] = {} self.__config["ui"]["username"] = "******".format( self.userNameEdit.text(), self.emailEdit.text(), ) ################################################################### ## extensions section ################################################################### if "extensions" not in self.__config: self.__config["extensions"] = {} if self.fetchCheckBox.isChecked(): self.__config["extensions"]["fetch"] = "" else: if "fetch" in self.__config["extensions"]: del self.__config["extensions"]["fetch"] self.__config["extensions"]["#fetch"] = "" if self.gpgCheckBox.isChecked(): self.__config["extensions"]["gpg"] = "" else: if "gpg" in self.__config["extensions"]: del self.__config["extensions"]["gpg"] self.__config["extensions"]["#gpg"] = "" if self.purgeCheckBox.isChecked(): self.__config["extensions"]["purge"] = "" else: if "purge" in self.__config["extensions"]: del self.__config["extensions"]["purge"] self.__config["extensions"]["#purge"] = "" if self.queuesCheckBox.isChecked(): self.__config["extensions"]["mq"] = "" else: if "mq" in self.__config["extensions"]: del self.__config["extensions"]["mq"] self.__config["extensions"]["#mq"] = "" if self.rebaseCheckBox.isChecked(): self.__config["extensions"]["rebase"] = "" else: if "rebase" in self.__config["extensions"]: del self.__config["extensions"]["rebase"] self.__config["extensions"]["#rebase"] = "" if self.shelveCheckBox.isChecked(): self.__config["extensions"]["shelve"] = "" else: if "shelve" in self.__config["extensions"]: del self.__config["extensions"]["shelve"] self.__config["extensions"]["#shelve"] = "" if self.stripCheckBox.isChecked(): self.__config["extensions"]["strip"] = "" else: if "strip" in self.__config["extensions"]: del self.__config["extensions"]["strip"] self.__config["extensions"]["#strip"] = "" if self.histeditCheckBox.isChecked(): self.__config["extensions"]["histedit"] = "" else: if "histedit" in self.__config["extensions"]: del self.__config["extensions"]["histedit"] self.__config["extensions"]["#histedit"] = "" if self.largefilesCheckBox.isChecked(): self.__config["extensions"]["largefiles"] = "" ############################################################### ## largefiles section ############################################################### if "largefiles" not in self.__config: self.__config["largefiles"] = {} self.__config["largefiles"]["minsize"] = (str( self.lfFileSizeSpinBox.value())) lfFilePatterns = self.lfFilePatternsEdit.text() if lfFilePatterns: self.__config["largefiles"]["patterns"] = lfFilePatterns elif "patterns" in self.__config["largefiles"]: del self.__config["largefiles"]["patterns"] lfUserCache = self.lfUserCachePicker.text() if lfUserCache: self.__config["largefiles"]["usercache"] = lfUserCache elif "usercache" in self.__config["largefiles"]: del self.__config["largefiles"]["usercache"] else: if "largefiles" in self.__config["extensions"]: del self.__config["extensions"]["largefiles"] self.__config["extensions"]["#largefiles"] = "" if self.closeheadCheckBox.isChecked() and self.__version >= (4, 8, 0): self.__config["extensions"]["closehead"] = "" else: if "closehead" in self.__config["extensions"]: del self.__config["extensions"]["closehead"] self.__config["extensions"]["#closehead"] = "" ################################################################### ## http_proxy section ################################################################### if self.proxyHostEdit.text(): self.__config["http_proxy"] = { "host": self.proxyHostEdit.text(), "user": self.proxyUserEdit.text(), "passwd": self.proxyPasswordEdit.text() } if self.proxyBypassEdit.text(): self.__config["http_proxy"]["no"] = ( self.proxyBypassEdit.text()) else: if "http_proxy" in self.__config: del self.__config["http_proxy"] ################################################################### ## hostfingerprints/hostsecurity section ################################################################### if self.__version < (3, 9, 0): # # delete hostsecurity section # if "hostsecurity" in self.__config: del self.__config["hostsecurity"] # # hostfingerprints section # if self.fingerprintsList.topLevelItemCount() > 0: self.__config["hostfingerprints"] = {} for row in range(self.fingerprintsList.topLevelItemCount()): itm = self.fingerprintsList.topLevelItem(row) fingerprint = itm.text(1) if fingerprint.startswith("sha1:"): fingerprint = fingerprint[5:] self.__config["hostfingerprints"][itm.text(0)] = ( fingerprint) else: if "hostfingerprints" in self.__config: del self.__config["hostfingerprints"] else: # # delete hostfingerprints section # if "hostfingerprints" in self.__config: del self.__config["hostfingerprints"] # # hostsecurity section # if "hostsecurity" not in self.__config: self.__config["hostsecurity"] = {} if self.fingerprintsList.topLevelItemCount() > 0: self.__clearFingerprints() fingerprints = self.__assembleFingerprints() for host in fingerprints: key = "{0}:fingerprints".format(host) self.__config["hostsecurity"][key] = (", ".join( fingerprints[host])) else: self.__clearFingerprints() if self.disableTls10WarningCheckBox.isChecked(): disabletls10warning = "true" else: disabletls10warning = "false" self.__config["hostsecurity"]["disabletls10warning"] = ( disabletls10warning) if self.minimumProtocolComboBox.currentIndex() == 0: self.__config.remove_option("hostsecurity", "minimumprotocol") else: minimumProtocol = self.minimumProtocolComboBox.itemData( self.minimumProtocolComboBox.currentIndex()) self.__config["hostsecurity"]["minimumprotocol"] = ( minimumProtocol) if self.protocolsList.topLevelItemCount() > 0: self.__clearMinimumProtocols() minimumProtocols = self.__assembleMinimumProtocols() for host in minimumProtocols: key = "{0}:minimumprotocol".format(host) self.__config["hostsecurity"][key] = minimumProtocols[host] else: self.__clearMinimumProtocols() if len(self.__config.options("hostsecurity")) == 0: del self.__config["hostsecurity"] ################################################################### cfgFile = getConfigPath() with open(cfgFile, "w") as configFile: self.__config.write(configFile) def readUserConfig(self): """ Public method to read the user configuration file. """ cfgFile = getConfigPath() self.__config = ConfigParser(delimiters=("=", )) if self.__config.read(cfgFile): # step 1: extract user name and email try: username = self.__config["ui"]["username"].strip() if "<" in username and username.endswith(">"): name, email = username[:-1].rsplit("<", 1) else: name = username email = "" self.userNameEdit.setText(name.strip()), self.emailEdit.setText(email.strip()), except KeyError: pass # step 2: extract extensions information if "extensions" in self.__config: self.fetchCheckBox.setChecked( "fetch" in self.__config["extensions"]) self.gpgCheckBox.setChecked( "gpg" in self.__config["extensions"]) self.purgeCheckBox.setChecked( "purge" in self.__config["extensions"]) self.queuesCheckBox.setChecked( "mq" in self.__config["extensions"]) self.rebaseCheckBox.setChecked( "rebase" in self.__config["extensions"]) self.shelveCheckBox.setChecked( "shelve" in self.__config["extensions"]) self.largefilesCheckBox.setChecked( "largefiles" in self.__config["extensions"]) self.stripCheckBox.setChecked( "strip" in self.__config["extensions"]) self.histeditCheckBox.setChecked( "histedit" in self.__config["extensions"]) self.closeheadCheckBox.setChecked( "closehead" in self.__config["extensions"]) self.closeheadCheckBox.setEnabled(self.__version >= (4, 8, 0)) # step 3: extract large files information if "largefiles" in self.__config: if "minsize" in self.__config["largefiles"]: self.lfFileSizeSpinBox.setValue( self.__config.getint("largefiles", "minsize")) if "patterns" in self.__config["largefiles"]: self.lfFilePatternsEdit.setText( self.__config["largefiles"]["patterns"]) if "usercache" in self.__config["largefiles"]: self.lfUserCachePicker.setText( self.__config["largefiles"]["usercache"]) # step 4: extract http proxy information if "http_proxy" in self.__config: if "host" in self.__config["http_proxy"]: self.proxyHostEdit.setText( self.__config["http_proxy"]["host"]) if "user" in self.__config["http_proxy"]: self.proxyUserEdit.setText( self.__config["http_proxy"]["user"]) if "passwd" in self.__config["http_proxy"]: self.proxyPasswordEdit.setText( self.__config["http_proxy"]["passwd"]) if "no" in self.__config["http_proxy"]: self.proxyBypassEdit.setText( self.__config["http_proxy"]["no"]) # step 5a: extract host fingerprints if "hostfingerprints" in self.__config: for host in self.__config.options("hostfingerprints"): if self.__version < (3, 9, 0): QTreeWidgetItem( self.fingerprintsList, [host, self.__config["hostfingerprints"][host]]) else: # convert to hostsecurity fingerprint QTreeWidgetItem(self.fingerprintsList, [ host, "sha1:" + self.__config["hostfingerprints"][host] ]) # step 5b: extract hostsecurity fingerprints if "hostsecurity" in self.__config: for key in self.__config.options("hostsecurity"): if key.endswith(":fingerprints"): host = key.replace(":fingerprints", "") fingerprints = ( self.__config["hostsecurity"][key].split(",")) for fingerprint in fingerprints: if self.__version < (3, 9, 0): # downgrade from a newer version if fingerprint.startswith("sha1:"): fingerprint = fingerprint[5:] else: # Mercurial < 3.9.0 supports sha1 # fingerprints only continue QTreeWidgetItem( self.fingerprintsList, [host, fingerprint.replace("\\", "").strip()]) elif key == "disabletls10warning": self.disableTls10WarningCheckBox.setChecked( self.__config.getboolean("hostsecurity", "disabletls10warning")) elif key == "minimumprotocol": minimumProtocol = self.__config["hostsecurity"][key] index = self.minimumProtocolComboBox.findData( minimumProtocol) if index == -1: index = 0 self.minimumProtocolComboBox.setCurrentIndex(index) elif key.endswith(":minimumprotocol"): host = key.replace(":minimumprotocol", "") protocol = self.__config["hostsecurity"][key].strip() if protocol in self.__minimumProtocols: itm = QTreeWidgetItem( self.protocolsList, [host, self.__minimumProtocols[protocol]]) itm.setData(1, Qt.UserRole, protocol) self.__finalizeFingerprintsColumns() self.__finalizeProtocolsColumns() @pyqtSlot() def accept(self): """ Public slot to accept the dialog. """ self.writeUserConfig() super(HgUserConfigDialog, self).accept() def __clearDialog(self): """ Private method to clear the data of the dialog. """ self.userNameEdit.clear() self.emailEdit.clear() self.fetchCheckBox.setChecked(False) self.gpgCheckBox.setChecked(False) self.purgeCheckBox.setChecked(False) self.queuesCheckBox.setChecked(False) self.rebaseCheckBox.setChecked(False) self.shelveCheckBox.setChecked(False) self.stripCheckBox.setChecked(False) self.largefilesCheckBox.setChecked(False) self.lfFileSizeSpinBox.setValue(10) self.lfFilePatternsEdit.clear() self.lfUserCachePicker.clear() self.proxyHostEdit.clear() self.proxyUserEdit.clear() self.proxyPasswordEdit.clear() self.proxyBypassEdit.clear() self.fingerprintsList.clear() self.__finalizeFingerprintsColumns() self.__updateFingerprintsButtons() self.protocolsList.clear() self.__finalizeProtocolsColumns() self.__updateProtocolsButtons() ####################################################################### ## Methods and slots for the host fingerprint handling below ####################################################################### def __clearFingerprints(self): """ Private method to clear the fingerprints from the hostsecurity section. """ if "hostsecurity" in self.__config: for key in self.__config.options("hostsecurity"): if key.endswith(":fingerprints"): self.__config.remove_option("hostsecurity", key) def __assembleFingerprints(self): """ Private method to assemble a list of host fingerprints. @return dictionary with list of fingerprints per host @rtype dict with str as key and list of str as value """ hostFingerprints = {} for row in range(self.fingerprintsList.topLevelItemCount()): itm = self.fingerprintsList.topLevelItem(row) host = itm.text(0) fingerprint = itm.text(1) if host in hostFingerprints: hostFingerprints[host].append(fingerprint) else: hostFingerprints[host] = [fingerprint] return hostFingerprints @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) def on_fingerprintsList_currentItemChanged(self, current, previous): """ Private slot handling a change of the current fingerprints item. @param current reference to the current item @type QTreeWidgetItem @param previous reference to the previous current item @type QTreeWidgetItem """ self.__updateFingerprintsButtons() @pyqtSlot() def on_fpAddButton_clicked(self): """ Private slot to add a fingerprints entry. """ dlg = HgUserConfigHostFingerprintDialog(self, version=self.__version) if dlg.exec_() == QDialog.Accepted: host, fingerprint = dlg.getData() itm = QTreeWidgetItem(self.fingerprintsList, [host, fingerprint]) self.__finalizeFingerprintsColumns() self.fingerprintsList.setCurrentItem(itm) self.fingerprintsList.scrollToItem(itm) @pyqtSlot() def on_fpDeleteButton_clicked(self): """ Private slot to delete the current fingerprints item. """ itm = self.fingerprintsList.currentItem() if itm is not None: host = itm.text(0) yes = E5MessageBox.yesNo( self, self.tr("Delete Host Fingerprint"), self.tr("""<p>Shall the fingerprint for host <b>{0}</b>""" """ really be deleted?</p>""").format(host)) if yes: self.fingerprintsList.takeTopLevelItem( self.fingerprintsList.indexOfTopLevelItem(itm)) del itm self.__finalizeFingerprintsColumns() @pyqtSlot() def on_fpEditButton_clicked(self): """ Private slot to edit the current fingerprints item. """ itm = self.fingerprintsList.currentItem() if itm is not None: host = itm.text(0) fingerprint = itm.text(1) dlg = HgUserConfigHostFingerprintDialog(self, host, fingerprint, version=self.__version) if dlg.exec_() == QDialog.Accepted: host, fingerprint = dlg.getData() itm.setText(0, host) itm.setText(1, fingerprint) self.__finalizeFingerprintsColumns() self.fingerprintsList.scrollToItem(itm) def __finalizeFingerprintsColumns(self): """ Private method to resize and sort the host fingerprints columns. """ for col in range(self.fingerprintsList.columnCount()): self.fingerprintsList.resizeColumnToContents(col) self.fingerprintsList.sortItems(0, Qt.AscendingOrder) def __updateFingerprintsButtons(self): """ Private slot to update the host fingerprints edit buttons. """ enable = self.fingerprintsList.currentItem() is not None self.fpDeleteButton.setEnabled(enable) self.fpEditButton.setEnabled(enable) ####################################################################### ## Methods and slots for the host minimum protocol handling below ####################################################################### def __clearMinimumProtocols(self): """ Private method to clear the minimum protocols from the hostsecurity section. """ if "hostsecurity" in self.__config: for key in self.__config.options("hostsecurity"): if key.endswith(":minimumprotocol"): self.__config.remove_option("hostsecurity", key) def __assembleMinimumProtocols(self): """ Private method to assemble a list of host minimum protocols. @return dictionary with list of minimum protocol per host @rtype dict with str as key and str as value """ minimumProtocols = {} for row in range(self.protocolsList.topLevelItemCount()): itm = self.protocolsList.topLevelItem(row) host = itm.text(0) minimumProtocol = itm.data(1, Qt.UserRole) minimumProtocols[host] = minimumProtocol return minimumProtocols @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) def on_protocolsList_currentItemChanged(self, current, previous): """ Private slot handling a change of the current minimum protocol item. @param current reference to the current item @type QTreeWidgetItem @param previous reference to the previous current item @type QTreeWidgetItem """ self.__updateProtocolsButtons() @pyqtSlot() def on_protocolAddButton_clicked(self): """ Private slot to add a minimum protocol entry. """ dlg = HgUserConfigHostMinimumProtocolDialog(self.__minimumProtocols, self) if dlg.exec_() == QDialog.Accepted: host, protocol = dlg.getData() itm = QTreeWidgetItem(self.protocolsList, [host, self.__minimumProtocols[protocol]]) itm.setData(1, Qt.UserRole, protocol) self.__finalizeProtocolsColumns() self.protocolsList.setCurrentItem(itm) self.protocolsList.scrollToItem(itm) @pyqtSlot() def on_protocolDeleteButton_clicked(self): """ Private slot to delete the current minimum protocol item. """ itm = self.protocolsList.currentItem() if itm is not None: host = itm.text(0) yes = E5MessageBox.yesNo( self, self.tr("Delete Host Minimum Protocol"), self.tr("""<p>Shall the minimum protocol entry for host""" """ <b>{0}</b> really be deleted?</p>""").format(host)) if yes: self.protocolsList.takeTopLevelItem( self.protocolsList.indexOfTopLevelItem(itm)) del itm self.__finalizeProtocolsColumns() @pyqtSlot() def on_protocolEditButton_clicked(self): """ Private slot to edit the current minimum protocol item. """ itm = self.protocolsList.currentItem() if itm is not None: host = itm.text(0) protocol = itm.data(1, Qt.UserRole) dlg = HgUserConfigHostMinimumProtocolDialog( self.__minimumProtocols, self, host, protocol) if dlg.exec_() == QDialog.Accepted: host, protocol = dlg.getData() itm.setText(0, host) itm.setText(1, self.__minimumProtocols[protocol]) itm.setData(1, Qt.UserRole, protocol) self.__finalizeProtocolsColumns() self.protocolsList.scrollToItem(itm) def __finalizeProtocolsColumns(self): """ Private method to resize and sort the host fingerprints columns. """ for col in range(self.protocolsList.columnCount()): self.protocolsList.resizeColumnToContents(col) self.protocolsList.sortItems(0, Qt.AscendingOrder) def __updateProtocolsButtons(self): """ Private slot to update the host minimum protocol edit buttons. """ enable = self.protocolsList.currentItem() is not None self.protocolDeleteButton.setEnabled(enable) self.protocolEditButton.setEnabled(enable) ####################################################################### ## Slot to edit the user configuration in an editor below ####################################################################### @pyqtSlot() def on_editorButton_clicked(self): """ Private slot to open the user configuration file in a text editor. """ from QScintilla.MiniEditor import MiniEditor cfgFile = getConfigPath() yes = E5MessageBox.yesNo( self, self.tr("Edit User Configuration"), self.tr("""You will loose all changes made in this dialog.""" """ Shall the data be saved first?"""), icon=E5MessageBox.Warning, yesDefault=True) if yes: self.writeUserConfig() self.__editor = MiniEditor(cfgFile, "Properties", self) self.__editor.setWindowModality(Qt.WindowModal) self.__editor.installEventFilter(self) self.__editor.show() def eventFilter(self, watched, event): """ Public method called to filter the event queue. @param watched reference to the object being watched @type QObject @param event event to be handled @type QEvent @return flag indicating, if we handled the event @rtype bool """ if watched is self.__editor and event.type() == QEvent.Close: self.__editor.closeEvent(event) if event.isAccepted(): self.__clearDialog() self.readUserConfig() return True return False
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 ############################################## 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.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.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 (list of string) @param cmd pip command to be used (string) @return tuple containing a flag indicating success and the output of the process (string) """ 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')) res = dia.startProcesses([ (python, ["-m", "ensurepip"]), (python, ["-m", "pip", "install", "--upgrade", "pip"]), ]) 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 args = ["-m", "pip", "install", "--upgrade", "pip"] dia = PipDialog(self.tr('Upgrade PIP')) res = dia.startProcess(python, args) if res: dia.exec_() return res 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 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 not cmd: cmd = self.__plugin.getPreferences("CurrentPipExecutable") args = ["install", "--upgrade"] + 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") args = ["install"] + 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") args = ["install", "--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")
class PipPackagesWidget(QWidget, Ui_PipPackagesWidget): """ Class implementing the pip packages management widget. """ ShowProcessGeneralMode = 0 ShowProcessClassifiersMode = 1 ShowProcessEntryPointsMode = 2 ShowProcessFilesListMode = 3 SearchStopwords = { "a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", } SearchVersionRole = Qt.UserRole + 1 def __init__(self, pip, parent=None): """ Constructor @param pip reference to the global pip interface @type Pip @param parent reference to the parent widget @type QWidget """ super(PipPackagesWidget, self).__init__(parent) self.setupUi(self) self.pipMenuButton.setObjectName("pip_supermenu_button") self.pipMenuButton.setIcon(UI.PixmapCache.getIcon("superMenu")) self.pipMenuButton.setToolTip(self.tr("pip Menu")) self.pipMenuButton.setPopupMode(QToolButton.InstantPopup) self.pipMenuButton.setToolButtonStyle(Qt.ToolButtonIconOnly) self.pipMenuButton.setFocusPolicy(Qt.NoFocus) self.pipMenuButton.setAutoRaise(True) self.pipMenuButton.setShowMenuInside(True) self.refreshButton.setIcon(UI.PixmapCache.getIcon("reload")) self.upgradeButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) self.upgradeAllButton.setIcon(UI.PixmapCache.getIcon("2uparrow")) self.uninstallButton.setIcon(UI.PixmapCache.getIcon("minus")) self.showPackageDetailsButton.setIcon(UI.PixmapCache.getIcon("info")) self.searchToggleButton.setIcon(UI.PixmapCache.getIcon("find")) self.searchButton.setIcon(UI.PixmapCache.getIcon("findNext")) self.installButton.setIcon(UI.PixmapCache.getIcon("plus")) self.installUserSiteButton.setIcon(UI.PixmapCache.getIcon("addUser")) self.showDetailsButton.setIcon(UI.PixmapCache.getIcon("info")) self.__pip = pip self.__client = E5XmlRpcClient(self.__pip.getIndexUrlXml(), self) self.packagesList.header().setSortIndicator(0, Qt.AscendingOrder) self.__infoLabels = { "name": self.tr("Name:"), "version": self.tr("Version:"), "location": self.tr("Location:"), "requires": self.tr("Requires:"), "summary": self.tr("Summary:"), "home-page": self.tr("Homepage:"), "author": self.tr("Author:"), "author-email": self.tr("Author Email:"), "license": self.tr("License:"), "metadata-version": self.tr("Metadata Version:"), "installer": self.tr("Installer:"), "classifiers": self.tr("Classifiers:"), "entry-points": self.tr("Entry Points:"), "files": self.tr("Files:"), } self.infoWidget.setHeaderLabels(["Key", "Value"]) venvManager = e5App().getObject("VirtualEnvManager") venvManager.virtualEnvironmentAdded.connect( self.on_refreshButton_clicked) venvManager.virtualEnvironmentRemoved.connect( self.on_refreshButton_clicked) project = e5App().getObject("Project") project.projectOpened.connect(self.on_refreshButton_clicked) project.projectClosed.connect(self.on_refreshButton_clicked) self.__initPipMenu() self.__populateEnvironments() self.__updateActionButtons() self.statusLabel.hide() self.searchWidget.hide() self.__queryName = [] self.__querySummary = [] self.__packageDetailsDialog = None def __populateEnvironments(self): """ Private method to get a list of environments and populate the selector. """ self.environmentsComboBox.addItem("") projectVenv = self.__pip.getProjectEnvironmentString() if projectVenv: self.environmentsComboBox.addItem(projectVenv) self.environmentsComboBox.addItems( self.__pip.getVirtualenvNames(noRemote=True)) def __isPipAvailable(self): """ Private method to check, if the pip package is available for the selected environment. @return flag indicating availability @rtype bool """ available = False venvName = self.environmentsComboBox.currentText() if venvName: available = len( self.packagesList.findItems( "pip", Qt.MatchExactly | Qt.MatchCaseSensitive)) == 1 return available ####################################################################### ## Slots handling widget signals below ####################################################################### def __selectedUpdateableItems(self): """ Private method to get a list of selected items that can be updated. @return list of selected items that can be updated @rtype list of QTreeWidgetItem """ return [ itm for itm in self.packagesList.selectedItems() if bool(itm.text(2)) ] def __allUpdateableItems(self): """ Private method to get a list of all items that can be updated. @return list of all items that can be updated @rtype list of QTreeWidgetItem """ updateableItems = [] for index in range(self.packagesList.topLevelItemCount()): itm = self.packagesList.topLevelItem(index) if itm.text(2): updateableItems.append(itm) return updateableItems def __updateActionButtons(self): """ Private method to set the state of the action buttons. """ if self.__isPipAvailable(): self.upgradeButton.setEnabled( bool(self.__selectedUpdateableItems())) self.uninstallButton.setEnabled( bool(self.packagesList.selectedItems())) self.upgradeAllButton.setEnabled(bool(self.__allUpdateableItems())) self.showPackageDetailsButton.setEnabled( len(self.packagesList.selectedItems()) == 1) else: self.upgradeButton.setEnabled(False) self.uninstallButton.setEnabled(False) self.upgradeAllButton.setEnabled(False) self.showPackageDetailsButton.setEnabled(False) def __refreshPackagesList(self): """ Private method to referesh the packages list. """ self.packagesList.clear() venvName = self.environmentsComboBox.currentText() if venvName: interpreter = self.__pip.getVirtualenvInterpreter(venvName) if interpreter: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.statusLabel.show() self.statusLabel.setText( self.tr("Getting installed packages...")) QApplication.processEvents() # 1. populate with installed packages self.packagesList.setUpdatesEnabled(False) installedPackages = self.__pip.getInstalledPackages( venvName, localPackages=self.localCheckBox.isChecked(), notRequired=self.notRequiredCheckBox.isChecked(), usersite=self.userCheckBox.isChecked(), ) for package, version in installedPackages: QTreeWidgetItem(self.packagesList, [package, version]) self.packagesList.setUpdatesEnabled(True) self.statusLabel.setText( self.tr("Getting outdated packages...")) QApplication.processEvents() # 2. update with update information self.packagesList.setUpdatesEnabled(False) outdatedPackages = self.__pip.getOutdatedPackages( venvName, localPackages=self.localCheckBox.isChecked(), notRequired=self.notRequiredCheckBox.isChecked(), usersite=self.userCheckBox.isChecked(), ) for package, _version, latest in outdatedPackages: items = self.packagesList.findItems( package, Qt.MatchExactly | Qt.MatchCaseSensitive) if items: itm = items[0] itm.setText(2, latest) self.packagesList.sortItems(0, Qt.AscendingOrder) for col in range(self.packagesList.columnCount()): self.packagesList.resizeColumnToContents(col) self.packagesList.setUpdatesEnabled(True) QApplication.restoreOverrideCursor() self.statusLabel.hide() self.__updateActionButtons() self.__updateSearchActionButtons() self.__updateSearchButton() @pyqtSlot(int) def on_environmentsComboBox_currentIndexChanged(self, index): """ Private slot handling the selection of a Python environment. @param index index of the selected Python environment @type int """ self.__refreshPackagesList() @pyqtSlot(bool) def on_localCheckBox_clicked(self, checked): """ Private slot handling the switching of the local mode. @param checked state of the local check box @type bool """ self.__refreshPackagesList() @pyqtSlot(bool) def on_notRequiredCheckBox_clicked(self, checked): """ Private slot handling the switching of the 'not required' mode. @param checked state of the 'not required' check box @type bool """ self.__refreshPackagesList() @pyqtSlot(bool) def on_userCheckBox_clicked(self, checked): """ Private slot handling the switching of the 'user-site' mode. @param checked state of the 'user-site' check box @type bool """ self.__refreshPackagesList() @pyqtSlot() def on_packagesList_itemSelectionChanged(self): """ Private slot handling the selection of a package. """ self.infoWidget.clear() if len(self.packagesList.selectedItems()) == 1: itm = self.packagesList.selectedItems()[0] environment = self.environmentsComboBox.currentText() interpreter = self.__pip.getVirtualenvInterpreter(environment) if not interpreter: return QApplication.setOverrideCursor(Qt.WaitCursor) args = ["-m", "pip", "show"] if self.verboseCheckBox.isChecked(): args.append("--verbose") if self.installedFilesCheckBox.isChecked(): args.append("--files") args.append(itm.text(0)) success, output = self.__pip.runProcess(args, interpreter) if success and output: mode = self.ShowProcessGeneralMode for line in output.splitlines(): line = line.rstrip() if line != "---": if mode != self.ShowProcessGeneralMode: if line[0] == " ": QTreeWidgetItem(self.infoWidget, [" ", line.strip()]) else: mode = self.ShowProcessGeneralMode if mode == self.ShowProcessGeneralMode: try: label, info = line.split(": ", 1) except ValueError: label = line[:-1] info = "" label = label.lower() if label in self.__infoLabels: QTreeWidgetItem( self.infoWidget, [self.__infoLabels[label], info]) if label == "files": mode = self.ShowProcessFilesListMode elif label == "classifiers": mode = self.ShowProcessClassifiersMode elif label == "entry-points": mode = self.ShowProcessEntryPointsMode self.infoWidget.scrollToTop() header = self.infoWidget.header() header.setStretchLastSection(False) header.resizeSections(QHeaderView.ResizeToContents) if header.sectionSize(0) + header.sectionSize(1) < header.width(): header.setStretchLastSection(True) QApplication.restoreOverrideCursor() self.__updateActionButtons() @pyqtSlot(QTreeWidgetItem, int) def on_packagesList_itemActivated(self, item, column): """ Private slot reacting on a package item activation. @param item reference to the activated item @type QTreeWidgetItem @param column activated column @type int """ packageName = item.text(0) if column == 1: # show details for installed version packageVersion = item.text(1) else: # show details for available version or installed one if item.text(2): packageVersion = item.text(2) else: packageVersion = item.text(1) self.__showPackageDetails(packageName, packageVersion) @pyqtSlot(bool) def on_verboseCheckBox_clicked(self, checked): """ Private slot to handle a change of the verbose package information checkbox. @param checked state of the checkbox @type bool """ self.on_packagesList_itemSelectionChanged() @pyqtSlot(bool) def on_installedFilesCheckBox_clicked(self, checked): """ Private slot to handle a change of the installed files information checkbox. @param checked state of the checkbox @type bool """ self.on_packagesList_itemSelectionChanged() @pyqtSlot() def on_refreshButton_clicked(self): """ Private slot to refresh the display. """ currentEnvironment = self.environmentsComboBox.currentText() self.environmentsComboBox.clear() self.packagesList.clear() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) QApplication.processEvents() self.__populateEnvironments() index = self.environmentsComboBox.findText( currentEnvironment, Qt.MatchExactly | Qt.MatchCaseSensitive) if index != -1: self.environmentsComboBox.setCurrentIndex(index) QApplication.restoreOverrideCursor() self.__updateActionButtons() @pyqtSlot() def on_upgradeButton_clicked(self): """ Private slot to upgrade selected packages of the selected environment. """ packages = [itm.text(0) for itm in self.__selectedUpdateableItems()] if packages: ok = self.__executeUpgradePackages(packages) if ok: self.on_refreshButton_clicked() @pyqtSlot() def on_upgradeAllButton_clicked(self): """ Private slot to upgrade all packages of the selected environment. """ packages = [itm.text(0) for itm in self.__allUpdateableItems()] if packages: ok = self.__executeUpgradePackages(packages) if ok: self.on_refreshButton_clicked() @pyqtSlot() def on_uninstallButton_clicked(self): """ Private slot to remove selected packages of the selected environment. """ packages = [itm.text(0) for itm in self.packagesList.selectedItems()] if packages: ok = self.__pip.uninstallPackages( packages, venvName=self.environmentsComboBox.currentText()) if ok: self.on_refreshButton_clicked() def __executeUpgradePackages(self, packages): """ Private method to execute the pip upgrade command. @param packages list of package names to be upgraded @type list of str @return flag indicating success @rtype bool """ ok = self.__pip.upgradePackages( packages, venvName=self.environmentsComboBox.currentText(), userSite=self.userCheckBox.isChecked()) return ok @pyqtSlot() def on_showPackageDetailsButton_clicked(self): """ Private slot to show information for the selected package. """ item = self.packagesList.selectedItems()[0] if item: packageName = item.text(0) # show details for available version or installed one if item.text(2): packageVersion = item.text(2) else: packageVersion = item.text(1) self.__showPackageDetails(packageName, packageVersion) ####################################################################### ## Search widget related methods below ####################################################################### def __updateSearchActionButtons(self): """ Private method to update the action button states of the search widget. """ installEnable = (len(self.searchResultList.selectedItems()) > 0 and self.environmentsComboBox.currentIndex() > 0 and self.__isPipAvailable()) self.installButton.setEnabled(installEnable) self.installUserSiteButton.setEnabled(installEnable) self.showDetailsButton.setEnabled( len(self.searchResultList.selectedItems()) == 1 and self.__isPipAvailable()) def __updateSearchButton(self): """ Private method to update the state of the search button. """ self.searchButton.setEnabled((bool(self.searchEditName.text()) or bool(self.searchEditSummary.text())) and self.__isPipAvailable()) @pyqtSlot(bool) def on_searchToggleButton_toggled(self, checked): """ Private slot to togle the search widget. @param checked state of the search widget button @type bool """ self.searchWidget.setVisible(checked) if checked: self.searchEditName.setFocus(Qt.OtherFocusReason) self.searchEditName.selectAll() self.__updateSearchActionButtons() self.__updateSearchButton() @pyqtSlot(str) def on_searchEditName_textChanged(self, txt): """ Private slot handling a change of the search term. @param txt search term @type str """ self.__updateSearchButton() @pyqtSlot() def on_searchEditName_returnPressed(self): """ Private slot initiating a search via a press of the Return key. """ self.__search() @pyqtSlot(str) def on_searchEditSummary_textChanged(self, txt): """ Private slot handling a change of the search term. @param txt search term @type str """ self.__updateSearchButton() @pyqtSlot() def on_searchEditSummary_returnPressed(self): """ Private slot initiating a search via a press of the Return key. """ self.__search() @pyqtSlot() def on_searchButton_clicked(self): """ Private slot handling a press of the search button. """ self.__search() @pyqtSlot() def on_searchResultList_itemSelectionChanged(self): """ Private slot handling changes of the search result selection. """ self.__updateSearchActionButtons() def __search(self): """ Private method to perform the search. """ self.searchResultList.clear() self.searchInfoLabel.clear() self.searchButton.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) QApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.__queryName = [ term for term in self.searchEditName.text().strip().split() if term not in self.SearchStopwords ] self.__querySummary = [ term for term in self.searchEditSummary.text().strip().split() if term not in self.SearchStopwords ] self.__client.call("search", ({ "name": self.__queryName, "summary": self.__querySummary }, self.searchTermCombineComboBox.currentText()), self.__processSearchResult, self.__searchError) def __processSearchResult(self, data): """ Private method to process the search result data from PyPI. @param data result data with hits in the first element @type tuple """ if data: packages = self.__transformHits(data[0]) if packages: self.searchInfoLabel.setText( self.tr("%n package(s) found.", "", len(packages))) wrapper = textwrap.TextWrapper(width=80) count = 0 total = 0 for package in packages: itm = QTreeWidgetItem(self.searchResultList, [ package['name'].strip(), "{0:4d}".format( package['score']), "\n".join([ wrapper.fill(line) for line in package['summary'].strip().splitlines() ]) ]) itm.setData(0, self.SearchVersionRole, package['version']) count += 1 total += 1 if count == 100: count = 0 QApplication.processEvents() else: QApplication.restoreOverrideCursor() E5MessageBox.warning( self, self.tr("Search PyPI"), self.tr("""<p>The package search did not return""" """ anything.</p>""")) self.searchInfoLabel.setText( self.tr("""<p>The package search did not return""" """ anything.</p>""")) else: QApplication.restoreOverrideCursor() E5MessageBox.warning( self, self.tr("Search PyPI"), self.tr("""<p>The package search did not return anything.""" """</p>""")) self.searchInfoLabel.setText( self.tr("""<p>The package search did not return anything.""" """</p>""")) header = self.searchResultList.header() self.searchResultList.sortItems(1, Qt.DescendingOrder) header.setStretchLastSection(False) header.resizeSections(QHeaderView.ResizeToContents) headerSize = 0 for col in range(header.count()): headerSize += header.sectionSize(col) if headerSize < header.width(): header.setStretchLastSection(True) self.__finishSearch() def __finishSearch(self): """ Private slot performing the search finishing actions. """ QApplication.restoreOverrideCursor() self.__updateSearchActionButtons() self.__updateSearchButton() self.searchEditName.setFocus(Qt.OtherFocusReason) def __searchError(self, errorCode, errorString): """ Private method handling a search error. @param errorCode code of the error @type int @param errorString error message @type str """ self.__finish() E5MessageBox.warning( self, self.tr("Search PyPI"), self.tr("""<p>The package search failed.</p><p>Reason: {0}</p>"""). format(errorString)) self.searchInfoLabel.setText(self.tr("Error: {0}").format(errorString)) def __transformHits(self, hits): """ Private method to convert the list returned from pypi into a packages list. @param hits list returned from pypi @type list of dict @return list of packages @rtype list of dict """ # we only include the record with the highest score packages = {} for hit in hits: name = hit['name'].strip() summary = (hit['summary'] or "").strip() version = hit['version'].strip() score = self.__score(name, summary) # cleanup the summary if summary in ["UNKNOWN", "."]: summary = "" if name not in packages: packages[name] = { 'name': name, 'summary': summary, 'version': [version.strip()], 'score': score } else: if score > packages[name]['score']: packages[name]['score'] = score packages[name]['summary'] = summary packages[name]['version'].append(version.strip()) return list(packages.values()) def __score(self, name, summary): """ Private method to calculate some score for a search result. @param name name of the returned package @type str @param summary summary text for the package @type str @return score value @rtype int """ score = 0 for queryTerm in self.__queryName: if queryTerm.lower() in name.lower(): score += 4 if queryTerm.lower() == name.lower(): score += 4 for queryTerm in self.__querySummary: if queryTerm.lower() in summary.lower(): if QRegExp(r'\b{0}\b'.format(QRegExp.escape(queryTerm)), Qt.CaseInsensitive).indexIn(summary) != -1: # word match gets even higher score score += 2 else: score += 1 return score @pyqtSlot() def on_installButton_clicked(self): """ Private slot to handle pressing the Install button.. """ self.__install() @pyqtSlot() def on_installUserSiteButton_clicked(self): """ Private slot to handle pressing the Install to User-Site button.. """ self.__install(userSite=True) def __install(self, userSite=False): """ Private slot to install the selected packages. @param userSite flag indicating to install to the user directory @type bool """ venvName = self.environmentsComboBox.currentText() if venvName: packages = [] for itm in self.searchResultList.selectedItems(): packages.append(itm.text(0).strip()) if packages: self.__pip.installPackages(packages, venvName=venvName, userSite=userSite) @pyqtSlot() def on_showDetailsButton_clicked(self): """ Private slot to handle pressing the Show Details button. """ self.__showSearchedDetails() @pyqtSlot(QTreeWidgetItem, int) def on_searchResultList_itemActivated(self, item, column): """ Private slot reacting on an search result item activation. @param item reference to the activated item @type QTreeWidgetItem @param column activated column @type int """ self.__showSearchedDetails(item) def __showSearchedDetails(self, item=None): """ Private slot to show details about the selected search result package. @param item reference to the search result item to show details for @type QTreeWidgetItem """ self.showDetailsButton.setEnabled(False) if not item: item = self.searchResultList.selectedItems()[0] packageVersions = item.data(0, self.SearchVersionRole) if len(packageVersions) == 1: packageVersion = packageVersions[0] elif len(packageVersions) == 0: packageVersion = "" else: packageVersion, ok = QInputDialog.getItem( self, self.tr("Show Package Details"), self.tr("Select the package version:"), packageVersions, 0, False) if not ok: return packageName = item.text(0) self.__showPackageDetails(packageName, packageVersion) def __showPackageDetails(self, packageName, packageVersion): """ Private method to populate the package details dialog. @param packageName name of the package to show details for @type str @param packageVersion version of the package @type str """ QApplication.setOverrideCursor(Qt.WaitCursor) QApplication.processEvents(QEventLoop.ExcludeUserInputEvents) packageData = self.__pip.getPackageDetails(packageName, packageVersion) QApplication.restoreOverrideCursor() if packageData: from .PipPackageDetailsDialog import PipPackageDetailsDialog self.showDetailsButton.setEnabled(True) if self.__packageDetailsDialog is not None: self.__packageDetailsDialog.close() self.__packageDetailsDialog = (PipPackageDetailsDialog( packageData, self)) self.__packageDetailsDialog.show() else: E5MessageBox.warning( self, self.tr("Search PyPI"), self.tr("""<p>No package details info for <b>{0}</b>""" """ available.</p>""").format(packageName)) ####################################################################### ## Menu related methods below ####################################################################### def __initPipMenu(self): """ Private method to create the super menu and attach it to the super menu button. """ self.__pipMenu = QMenu() self.__installPipAct = self.__pipMenu.addAction( self.tr("Install Pip"), self.__installPip) self.__installPipUserAct = self.__pipMenu.addAction( self.tr("Install Pip to User-Site"), self.__installPipUser) self.__repairPipAct = self.__pipMenu.addAction(self.tr("Repair Pip"), self.__repairPip) self.__pipMenu.addSeparator() self.__installPackagesAct = self.__pipMenu.addAction( self.tr("Install Packages"), self.__installPackages) self.__installLocalPackageAct = self.__pipMenu.addAction( self.tr("Install Local Package"), self.__installLocalPackage) self.__pipMenu.addSeparator() self.__installRequirementsAct = self.__pipMenu.addAction( self.tr("Install Requirements"), self.__installRequirements) self.__uninstallRequirementsAct = self.__pipMenu.addAction( self.tr("Uninstall Requirements"), self.__uninstallRequirements) self.__generateRequirementsAct = self.__pipMenu.addAction( self.tr("Generate Requirements..."), self.__generateRequirements) self.__pipMenu.addSeparator() # editUserConfigAct self.__pipMenu.addAction(self.tr("Edit User Configuration..."), self.__editUserConfiguration) self.__editVirtualenvConfigAct = self.__pipMenu.addAction( self.tr("Edit Environment Configuration..."), self.__editVirtualenvConfiguration) self.__pipMenu.addSeparator() # pipConfigAct self.__pipMenu.addAction(self.tr("Configure..."), self.__pipConfigure) self.__pipMenu.aboutToShow.connect(self.__aboutToShowPipMenu) self.pipMenuButton.setMenu(self.__pipMenu) def __aboutToShowPipMenu(self): """ Private slot to set the action enabled status. """ enable = bool(self.environmentsComboBox.currentText()) enablePip = self.__isPipAvailable() self.__installPipAct.setEnabled(not enablePip) self.__installPipUserAct.setEnabled(not enablePip) self.__repairPipAct.setEnabled(enablePip) self.__installPackagesAct.setEnabled(enablePip) self.__installLocalPackageAct.setEnabled(enablePip) self.__installRequirementsAct.setEnabled(enablePip) self.__uninstallRequirementsAct.setEnabled(enablePip) self.__generateRequirementsAct.setEnabled(enablePip) self.__editVirtualenvConfigAct.setEnabled(enable) @pyqtSlot() def __installPip(self): """ Private slot to install pip into the selected environment. """ venvName = self.environmentsComboBox.currentText() if venvName: self.__pip.installPip(venvName) @pyqtSlot() def __installPipUser(self): """ Private slot to install pip into the user site for the selected environment. """ venvName = self.environmentsComboBox.currentText() if venvName: self.__pip.installPip(venvName, userSite=True) @pyqtSlot() def __repairPip(self): """ Private slot to repair the pip installation of the selected environment. """ venvName = self.environmentsComboBox.currentText() if venvName: self.__pip.repairPip(venvName) @pyqtSlot() def __installPackages(self): """ Private slot to install packages to be given by the user. """ venvName = self.environmentsComboBox.currentText() if venvName: from .PipPackagesInputDialog import PipPackagesInputDialog dlg = PipPackagesInputDialog(self, self.tr("Install Packages")) if dlg.exec_() == QDialog.Accepted: packages, user = dlg.getData() if packages: self.__pip.installPackages(packages, venvName=venvName, userSite=user) @pyqtSlot() def __installLocalPackage(self): """ Private slot to install a package available on local storage. """ venvName = self.environmentsComboBox.currentText() if venvName: from .PipFileSelectionDialog import PipFileSelectionDialog dlg = PipFileSelectionDialog(self, "package") if dlg.exec_() == QDialog.Accepted: package, user = dlg.getData() if package and os.path.exists(package): self.__pip.installPackages([package], venvName=venvName, userSite=user) @pyqtSlot() def __installRequirements(self): """ Private slot to install packages as given in a requirements file. """ venvName = self.environmentsComboBox.currentText() if venvName: self.__pip.installRequirements(venvName) @pyqtSlot() def __uninstallRequirements(self): """ Private slot to uninstall packages as given in a requirements file. """ venvName = self.environmentsComboBox.currentText() if venvName: self.__pip.uninstallRequirements(venvName) @pyqtSlot() def __generateRequirements(self): """ Private slot to generate the contents for a requirements file. """ venvName = self.environmentsComboBox.currentText() if venvName: from .PipFreezeDialog import PipFreezeDialog self.__freezeDialog = PipFreezeDialog(self.__pip, self) self.__freezeDialog.show() self.__freezeDialog.start(venvName) @pyqtSlot() def __editUserConfiguration(self): """ Private slot to edit the user configuration. """ self.__editConfiguration() @pyqtSlot() def __editVirtualenvConfiguration(self): """ Private slot to edit the configuration of the selected environment. """ venvName = self.environmentsComboBox.currentText() if venvName: self.__editConfiguration(venvName=venvName) def __editConfiguration(self, venvName=""): """ Private method to edit a configuration. @param venvName name of the environment to act upon @type str """ from QScintilla.MiniEditor import MiniEditor if venvName: cfgFile = self.__pip.getVirtualenvConfig(venvName) if not cfgFile: return else: cfgFile = self.__pip.getUserConfig() cfgDir = os.path.dirname(cfgFile) if not cfgDir: E5MessageBox.critical( None, self.tr("Edit Configuration"), self.tr("""No valid configuration path determined.""" """ 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 configuration path determined.""" """ 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 configuration path determined.""" """ Aborting""")) return self.__editor = MiniEditor(cfgFile, "Properties") self.__editor.show() def __pipConfigure(self): """ Private slot to open the configuration page. """ e5App().getObject("UserInterface").showPreferences("pipPage")
class CondaPackagesWidget(QWidget, Ui_CondaPackagesWidget): """ Class implementing the conda packages management widget. """ # Role definition of packages list PackageVersionRole = Qt.UserRole + 1 PackageBuildRole = Qt.UserRole + 2 # Role definitions of search results list PackageDetailedDataRole = Qt.UserRole + 1 def __init__(self, conda, parent=None): """ Constructor @param conda reference to the conda interface @type Conda @param parent reference to the parent widget @type QWidget """ super(CondaPackagesWidget, self).__init__(parent) self.setupUi(self) self.__conda = conda if not CondaInterface.isCondaAvailable(): self.baseWidget.hide() self.searchWidget.hide() else: self.notAvailableWidget.hide() self.__initCondaInterface() def __initCondaInterface(self): """ Private method to initialize the conda interface elements. """ self.statusLabel.hide() self.condaMenuButton.setObjectName( "conda_supermenu_button") self.condaMenuButton.setIcon(UI.PixmapCache.getIcon("superMenu")) self.condaMenuButton.setToolTip(self.tr("Conda Menu")) self.condaMenuButton.setPopupMode(QToolButton.InstantPopup) self.condaMenuButton.setToolButtonStyle(Qt.ToolButtonIconOnly) self.condaMenuButton.setFocusPolicy(Qt.NoFocus) self.condaMenuButton.setAutoRaise(True) self.condaMenuButton.setShowMenuInside(True) self.refreshButton.setIcon(UI.PixmapCache.getIcon("reload")) self.upgradeButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) self.upgradeAllButton.setIcon(UI.PixmapCache.getIcon("2uparrow")) self.uninstallButton.setIcon(UI.PixmapCache.getIcon("minus")) self.searchToggleButton.setIcon(UI.PixmapCache.getIcon("find")) self.searchButton.setIcon(UI.PixmapCache.getIcon("findNext")) self.installButton.setIcon(UI.PixmapCache.getIcon("plus")) self.showDetailsButton.setIcon(UI.PixmapCache.getIcon("info")) if CondaInterface.condaVersion() >= (4, 4, 0): self.searchOptionsWidget.hide() else: self.platformComboBox.addItems(sorted([ "", "win-32", "win-64", "osx-64", "linux-32", "linux-64", ])) self.__initCondaMenu() self.__populateEnvironments() self.__updateActionButtons() self.searchWidget.hide() self.__conda.condaEnvironmentCreated.connect( self.on_refreshButton_clicked) self.__conda.condaEnvironmentRemoved.connect( self.on_refreshButton_clicked) def __populateEnvironments(self): """ Private method to get a list of environments and populate the selector. """ environments = [("", "")] + sorted( self.__conda.getCondaEnvironmentsList()) for environment in environments: self.environmentsComboBox.addItem(environment[0], environment[1]) def __initCondaMenu(self): """ Private method to create the super menu and attach it to the super menu button. """ self.__condaMenu = QMenu(self) self.__envActs = [] self.__cleanMenu = QMenu(self.tr("Clean"), self) self.__cleanMenu.addAction( self.tr("All"), lambda: self.__conda.cleanConda("all")) self.__cleanMenu.addAction( self.tr("Cache"), lambda: self.__conda.cleanConda("index-cache")) self.__cleanMenu.addAction( self.tr("Lock Files"), lambda: self.__conda.cleanConda("lock")) self.__cleanMenu.addAction( self.tr("Packages"), lambda: self.__conda.cleanConda("packages")) self.__cleanMenu.addAction( self.tr("Tarballs"), lambda: self.__conda.cleanConda("tarballs")) self.__condaMenu.addAction( self.tr("About Conda..."), self.__aboutConda) self.__condaMenu.addSeparator() self.__condaMenu.addAction( self.tr("Update Conda"), self.__conda.updateConda) self.__condaMenu.addSeparator() self.__envActs.append(self.__condaMenu.addAction( self.tr("Install Packages"), self.__installPackages)) self.__envActs.append(self.__condaMenu.addAction( self.tr("Install Requirements"), self.__installRequirements)) self.__condaMenu.addSeparator() self.__envActs.append(self.__condaMenu.addAction( self.tr("Generate Requirements"), self.__generateRequirements)) self.__condaMenu.addSeparator() self.__condaMenu.addAction( self.tr("Create Environment from Requirements"), self.__createEnvironment) self.__envActs.append(self.__condaMenu.addAction( self.tr("Clone Environment"), self.__cloneEnvironment)) self.__deleteEnvAct = self.__condaMenu.addAction( self.tr("Delete Environment"), self.__deleteEnvironment) self.__condaMenu.addSeparator() self.__condaMenu.addMenu(self.__cleanMenu) self.__condaMenu.addSeparator() self.__condaMenu.addAction( self.tr("Edit User Configuration..."), self.__editUserConfiguration) self.__condaMenu.addSeparator() self.__condaMenu.addAction( self.tr("Configure..."), self.__condaConfigure) self.condaMenuButton.setMenu(self.__condaMenu) self.__condaMenu.aboutToShow.connect(self.__aboutToShowCondaMenu) def __selectedUpdateableItems(self): """ Private method to get a list of selected items that can be updated. @return list of selected items that can be updated @rtype list of QTreeWidgetItem """ return [ itm for itm in self.packagesList.selectedItems() if bool(itm.text(2)) ] def __allUpdateableItems(self): """ Private method to get a list of all items that can be updated. @return list of all items that can be updated @rtype list of QTreeWidgetItem """ updateableItems = [] for index in range(self.packagesList.topLevelItemCount()): itm = self.packagesList.topLevelItem(index) if itm.text(2): updateableItems.append(itm) return updateableItems def __updateActionButtons(self): """ Private method to set the state of the action buttons. """ self.upgradeButton.setEnabled( bool(self.__selectedUpdateableItems())) self.uninstallButton.setEnabled( bool(self.packagesList.selectedItems())) self.upgradeAllButton.setEnabled( bool(self.__allUpdateableItems())) @pyqtSlot(int) def on_environmentsComboBox_currentIndexChanged(self, index): """ Private slot handling the selection of a conda environment. @param index index of the selected conda environment @type int """ self.packagesList.clear() prefix = self.environmentsComboBox.itemData(index) if prefix: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.statusLabel.show() self.statusLabel.setText(self.tr("Getting installed packages...")) QApplication.processEvents() # 1. populate with installed packages self.packagesList.setUpdatesEnabled(False) installedPackages = self.__conda.getInstalledPackages( prefix=prefix) for package, version, build in installedPackages: itm = QTreeWidgetItem(self.packagesList, [package, version]) itm.setData(1, self.PackageVersionRole, version) itm.setData(1, self.PackageBuildRole, build) self.packagesList.setUpdatesEnabled(True) self.statusLabel.setText(self.tr("Getting outdated packages...")) QApplication.processEvents() # 2. update with update information self.packagesList.setUpdatesEnabled(False) updateablePackages = self.__conda.getUpdateablePackages( prefix=prefix) for package, version, build in updateablePackages: items = self.packagesList.findItems( package, Qt.MatchExactly | Qt.MatchCaseSensitive) if items: itm = items[0] itm.setText(2, version) itm.setData(2, self.PackageVersionRole, version) itm.setData(2, self.PackageBuildRole, build) if itm.data(1, self.PackageVersionRole) == version: # build must be different, show in version display itm.setText(1, self.tr("{0} (Build: {1})").format( itm.data(1, self.PackageVersionRole), itm.data(1, self.PackageBuildRole), )) itm.setText(2, self.tr("{0} (Build: {1})").format( itm.data(2, self.PackageVersionRole), itm.data(2, self.PackageBuildRole), )) self.packagesList.sortItems(0, Qt.AscendingOrder) for col in range(self.packagesList.columnCount()): self.packagesList.resizeColumnToContents(col) self.packagesList.setUpdatesEnabled(True) QApplication.restoreOverrideCursor() self.statusLabel.hide() self.__updateActionButtons() self.__updateSearchActionButtons() @pyqtSlot() def on_packagesList_itemSelectionChanged(self): """ Private slot to handle the selection of some items.. """ self.__updateActionButtons() @pyqtSlot() def on_refreshButton_clicked(self): """ Private slot to refresh the display. """ currentEnvironment = self.environmentsComboBox.currentText() self.environmentsComboBox.clear() self.packagesList.clear() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) QApplication.processEvents() self.__populateEnvironments() index = self.environmentsComboBox.findText( currentEnvironment, Qt.MatchExactly | Qt.MatchCaseSensitive) if index != -1: self.environmentsComboBox.setCurrentIndex(index) QApplication.restoreOverrideCursor() self.__updateActionButtons() @pyqtSlot() def on_upgradeButton_clicked(self): """ Private slot to upgrade selected packages of the selected environment. """ packages = [itm.text(0) for itm in self.__selectedUpdateableItems()] if packages: prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) ok = self.__conda.updatePackages(packages, prefix=prefix) if ok: self.on_refreshButton_clicked() @pyqtSlot() def on_upgradeAllButton_clicked(self): """ Private slot to upgrade all packages of the selected environment. """ prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) ok = self.__conda.updateAllPackages(prefix=prefix) if ok: self.on_refreshButton_clicked() @pyqtSlot() def on_uninstallButton_clicked(self): """ Private slot to remove selected packages of the selected environment. """ packages = [itm.text(0) for itm in self.packagesList.selectedItems()] if packages: prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) ok = self.__conda.uninstallPackages(packages, prefix=prefix) if ok: self.on_refreshButton_clicked() ####################################################################### ## Search widget related methods below ####################################################################### def __updateSearchActionButtons(self): """ Private method to update the action button states of the search widget. """ enable = len(self.searchResultList.selectedItems()) == 1 self.installButton.setEnabled( enable and self.environmentsComboBox.currentIndex() > 0) self.showDetailsButton.setEnabled( enable and bool(self.searchResultList.selectedItems()[0].parent())) def __doSearch(self): """ Private method to search for packages. """ self.searchResultList.clear() pattern = self.searchEdit.text() if pattern: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) QApplication.processEvents() if CondaInterface.condaVersion() >= (4, 4, 0): prefix = "" else: prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) ok, result = self.__conda.searchPackages( pattern, fullNameOnly=self.fullNameButton.isChecked(), packageSpec=self.packageSpecButton.isChecked(), platform=self.platformComboBox.currentText(), prefix=prefix, ) if result: if ok: self.searchResultList.setUpdatesEnabled(False) for package in result: itm = QTreeWidgetItem(self.searchResultList, [package]) itm.setExpanded(False) for detail in result[package]: version = detail["version"] build = detail["build"] if "subdir" in detail: platform = detail["subdir"] elif "platform" in detail: platform = detail["platform"] else: platform = "" citm = QTreeWidgetItem( itm, ["", version, build, platform]) citm.setData(0, self.PackageDetailedDataRole, detail) self.searchResultList.sortItems(0, Qt.AscendingOrder) self.searchResultList.resizeColumnToContents(0) self.searchResultList.setUpdatesEnabled(True) else: QApplication.restoreOverrideCursor() try: message = result["message"] except KeyError: message = result["error"] E5MessageBox.warning( self, self.tr("Conda Search Package Error"), message) QApplication.restoreOverrideCursor() def __showDetails(self, item): """ Private method to show a dialog with details about a package item. @param item reference to the package item @type QTreeWidgetItem """ details = item.data(0, self.PackageDetailedDataRole) if details: from .CondaPackageDetailsWidget import CondaPackageDetailsDialog dlg = CondaPackageDetailsDialog(details, self) dlg.exec_() @pyqtSlot(str) def on_searchEdit_textChanged(self, txt): """ Private slot handling changes of the entered search specification. @param txt current search entry @type str """ self.searchButton.setEnabled(bool(txt)) @pyqtSlot() def on_searchEdit_returnPressed(self): """ Private slot handling the user pressing the Return button in the search edit. """ self.__doSearch() @pyqtSlot() def on_searchButton_clicked(self): """ Private slot handling the press of the search button. """ self.__doSearch() @pyqtSlot() def on_installButton_clicked(self): """ Private slot to install a selected package. """ if len(self.searchResultList.selectedItems()) == 1: item = self.searchResultList.selectedItems()[0] if item.parent() is None: # it is just the package item package = item.text(0) else: # item with version and build package = "{0}={1}={2}".format( item.parent().text(0), item.text(1), item.text(2), ) prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) ok = self.__conda.installPackages([package], prefix=prefix) if ok: self.on_refreshButton_clicked() @pyqtSlot() def on_showDetailsButton_clicked(self): """ Private slot handling the 'Show Details' button. """ item = self.searchResultList.selectedItems()[0] self.__showDetails(item) @pyqtSlot() def on_searchResultList_itemSelectionChanged(self): """ Private slot handling a change of selected search results. """ self.__updateSearchActionButtons() @pyqtSlot(QTreeWidgetItem) def on_searchResultList_itemExpanded(self, item): """ Private slot handling the expansion of an item. @param item reference to the expanded item @type QTreeWidgetItem """ for col in range(1, self.searchResultList.columnCount()): self.searchResultList.resizeColumnToContents(col) @pyqtSlot(QTreeWidgetItem, int) def on_searchResultList_itemDoubleClicked(self, item, column): """ Private slot handling a double click of an item. @param item reference to the item that was double clicked @type QTreeWidgetItem @param column column of the double click @type int """ if item.parent() is not None: self.__showDetails(item) @pyqtSlot(bool) def on_searchToggleButton_toggled(self, checked): """ Private slot to togle the search widget. @param checked state of the search widget button @type bool """ self.searchWidget.setVisible(checked) if checked: self.searchEdit.setFocus(Qt.OtherFocusReason) self.searchEdit.selectAll() self.__updateSearchActionButtons() ####################################################################### ## Menu related methods below ####################################################################### @pyqtSlot() def __aboutToShowCondaMenu(self): """ Private slot to handle the conda menu about to be shown. """ selectedEnvironment = self.environmentsComboBox.currentText() enable = selectedEnvironment not in [""] for act in self.__envActs: act.setEnabled(enable) self.__deleteEnvAct.setEnabled( selectedEnvironment not in ["", self.__conda.RootName]) @pyqtSlot() def __aboutConda(self): """ Private slot to show some information about the conda installation. """ infoDict = self.__conda.getCondaInformation() from .CondaInfoDialog import CondaInfoDialog dlg = CondaInfoDialog(infoDict, self) dlg.exec_() @pyqtSlot() def __installPackages(self): """ Private slot to install packages. """ prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) if prefix: ok, packageSpecs = E5TextInputDialog.getText( self, self.tr("Install Packages"), self.tr("Package Specifications (separated by whitespace):"), QLineEdit.Normal, minimumWidth=600) if ok and packageSpecs.strip(): packages = [p.strip() for p in packageSpecs.split()] ok = self.__conda.installPackages(packages, prefix=prefix) if ok: self.on_refreshButton_clicked() @pyqtSlot() def __installRequirements(self): """ Private slot to install packages from requirements files. """ prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) if prefix: requirements = E5FileDialog.getOpenFileNames( self, self.tr("Install Packages"), "", self.tr("Text Files (*.txt);;All Files (*)")) if requirements: args = [] for requirement in requirements: args.extend(["--file", requirement]) ok = self.__conda.installPackages(args, prefix=prefix) if ok: self.on_refreshButton_clicked() @pyqtSlot() def __generateRequirements(self): """ Private slot to generate a requirements file. """ prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) if prefix: env = self.environmentsComboBox.currentText() from .CondaExportDialog import CondaExportDialog self.__requirementsDialog = CondaExportDialog( self.__conda, env, prefix) self.__requirementsDialog.show() QApplication.processEvents() self.__requirementsDialog.start() @pyqtSlot() def __cloneEnvironment(self): """ Private slot to clone a conda environment. """ from .CondaNewEnvironmentDataDialog import ( CondaNewEnvironmentDataDialog) prefix = self.environmentsComboBox.itemData( self.environmentsComboBox.currentIndex()) if prefix: dlg = CondaNewEnvironmentDataDialog(self.tr("Clone Environment"), False, self) if dlg.exec_() == QDialog.Accepted: virtEnvName, envName, _ = dlg.getData() args = [ "--name", envName.strip(), "--clone", prefix, ] ok, prefix, interpreter = self.__conda.createCondaEnvironment( args) if ok: e5App().getObject("VirtualEnvManager").addVirtualEnv( virtEnvName, prefix, interpreter, isConda=True) @pyqtSlot() def __createEnvironment(self): """ Private slot to create a conda environment from a requirements file. """ from .CondaNewEnvironmentDataDialog import ( CondaNewEnvironmentDataDialog) dlg = CondaNewEnvironmentDataDialog(self.tr("Create Environment"), True, self) if dlg.exec_() == QDialog.Accepted: virtEnvName, envName, requirements = dlg.getData() args = [ "--name", envName.strip(), "--file", requirements, ] ok, prefix, interpreter = self.__conda.createCondaEnvironment(args) if ok: e5App().getObject("VirtualEnvManager").addVirtualEnv( virtEnvName, prefix, interpreter, isConda=True) @pyqtSlot() def __deleteEnvironment(self): """ Private slot to delete a conda environment. """ envName = self.environmentsComboBox.currentText() ok = E5MessageBox.yesNo( self, self.tr("Delete Environment"), self.tr("""<p>Shall the environment <b>{0}</b> really be""" """ deleted?</p>""").format(envName) ) if ok: self.__conda.removeCondaEnvironment(name=envName) @pyqtSlot() def __editUserConfiguration(self): """ Private slot to edit the user configuration. """ from QScintilla.MiniEditor import MiniEditor cfgFile = CondaInterface.userConfiguration() if not cfgFile: return if not os.path.exists(cfgFile): self.__conda.writeDefaultConfiguration() # check, if the destination is writeable if not os.access(cfgFile, os.W_OK): E5MessageBox.critical( None, self.tr("Edit Configuration"), self.tr("""The configuration file "{0}" does not exist""" """ or is not writable.""")) return self.__editor = MiniEditor(cfgFile, "YAML") self.__editor.show() @pyqtSlot() def __condaConfigure(self): """ Private slot to open the configuration page. """ e5App().getObject("UserInterface").showPreferences("condaPage") @pyqtSlot() def on_recheckButton_clicked(self): """ Private slot to re-check the availability of conda and adjust the interface if it became available. """ if CondaInterface.isCondaAvailable(): self.__initCondaInterface() self.notAvailableWidget.hide() self.baseWidget.show()