diff -r e9e7eca7efee -r bf71ee032bb4 src/eric7/PluginManager/PluginUninstallDialog.py --- a/src/eric7/PluginManager/PluginUninstallDialog.py Wed Jul 13 11:16:20 2022 +0200 +++ b/src/eric7/PluginManager/PluginUninstallDialog.py Wed Jul 13 14:55:47 2022 +0200 @@ -29,62 +29,62 @@ class PluginUninstallWidget(QWidget, Ui_PluginUninstallDialog): """ Class implementing a dialog for plugin deinstallation. - + @signal accepted() emitted to indicate the removal of a plug-in """ + accepted = pyqtSignal() - + def __init__(self, pluginManager, parent=None): """ Constructor - + @param pluginManager reference to the plugin manager object @param parent parent of this dialog (QWidget) """ super().__init__(parent) self.setupUi(self) - + if pluginManager is None: # started as external plugin deinstaller from .PluginManager import PluginManager + self.__pluginManager = PluginManager(doLoadPlugins=False) self.__external = True else: self.__pluginManager = pluginManager self.__external = False - + self.pluginDirectoryCombo.addItem( - self.tr("User plugins directory"), - self.__pluginManager.getPluginDir("user")) - + self.tr("User plugins directory"), self.__pluginManager.getPluginDir("user") + ) + globalDir = self.__pluginManager.getPluginDir("global") if globalDir is not None and os.access(globalDir, os.W_OK): self.pluginDirectoryCombo.addItem( - self.tr("Global plugins directory"), - globalDir) - + self.tr("Global plugins directory"), globalDir + ) + @pyqtSlot(int) def on_pluginDirectoryCombo_currentIndexChanged(self, index): """ Private slot to populate the plugin name combo upon a change of the plugin area. - + @param index index of the selected item (integer) """ pluginDirectory = self.pluginDirectoryCombo.itemData(index) - pluginNames = sorted(self.__pluginManager.getPluginModules( - pluginDirectory)) - + pluginNames = sorted(self.__pluginManager.getPluginModules(pluginDirectory)) + self.pluginsList.clear() for pluginName in pluginNames: fname = "{0}.py".format(os.path.join(pluginDirectory, pluginName)) itm = QListWidgetItem(pluginName) itm.setData(Qt.ItemDataRole.UserRole, fname) - itm.setFlags(Qt.ItemFlag.ItemIsEnabled | - Qt.ItemFlag.ItemIsUserCheckable) + itm.setFlags(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsUserCheckable) itm.setCheckState(Qt.CheckState.Unchecked) self.pluginsList.addItem(itm) - + @pyqtSlot() def on_buttonBox_accepted(self): """ @@ -92,11 +92,11 @@ """ if self.__uninstallPlugins(): self.accepted.emit() - + def __getCheckedPlugins(self): """ Private method to get the list of plugins to be uninstalled. - + @return list of tuples with the plugin name and plugin file name @rtype list of tuples of (str, str) """ @@ -104,14 +104,13 @@ for row in range(self.pluginsList.count()): itm = self.pluginsList.item(row) if itm.checkState() == Qt.CheckState.Checked: - plugins.append((itm.text(), - itm.data(Qt.ItemDataRole.UserRole))) + plugins.append((itm.text(), itm.data(Qt.ItemDataRole.UserRole))) return plugins - + def __uninstallPlugins(self): """ Private method to uninstall the selected plugins. - + @return flag indicating success @rtype bool """ @@ -121,11 +120,11 @@ if self.__uninstallPlugin(pluginName, pluginFile): uninstallCount += 1 return uninstallCount == len(checkedPlugins) - + def __uninstallPlugin(self, pluginName, pluginFile): """ Private method to uninstall a given plugin. - + @param pluginName name of the plugin @type str @param pluginFile file name of the plugin @@ -134,17 +133,20 @@ @rtype bool """ pluginDirectory = self.pluginDirectoryCombo.itemData( - self.pluginDirectoryCombo.currentIndex()) - + self.pluginDirectoryCombo.currentIndex() + ) + if not self.__pluginManager.unloadPlugin(pluginName): EricMessageBox.critical( self, self.tr("Plugin Uninstallation"), self.tr( """<p>The plugin <b>{0}</b> could not be unloaded.""" - """ Aborting...</p>""").format(pluginName)) + """ Aborting...</p>""" + ).format(pluginName), + ) return False - + if pluginDirectory not in sys.path: sys.path.insert(2, pluginDirectory) spec = importlib.util.spec_from_file_location(pluginName, pluginFile) @@ -156,9 +158,11 @@ self.tr("Plugin Uninstallation"), self.tr( """<p>The plugin <b>{0}</b> has no 'packageName'""" - """ attribute. Aborting...</p>""").format(pluginName)) + """ attribute. Aborting...</p>""" + ).format(pluginName), + ) return False - + package = getattr(module, "packageName", None) if package is None: package = "None" @@ -166,45 +170,45 @@ else: packageDir = os.path.join(pluginDirectory, package) if ( - hasattr(module, "prepareUninstall") and - not self.keepConfigurationCheckBox.isChecked() + hasattr(module, "prepareUninstall") + and not self.keepConfigurationCheckBox.isChecked() ): module.prepareUninstall() internalPackages = [] if hasattr(module, "internalPackages"): # it is a comma separated string - internalPackages = [p.strip() for p in - module.internalPackages.split(",")] + internalPackages = [p.strip() for p in module.internalPackages.split(",")] del module - + # clean sys.modules self.__pluginManager.removePluginFromSysModules( - pluginName, package, internalPackages) - + pluginName, package, internalPackages + ) + try: if packageDir and os.path.exists(packageDir): shutil.rmtree(packageDir) - + fnameo = "{0}o".format(pluginFile) if os.path.exists(fnameo): os.remove(fnameo) - + fnamec = "{0}c".format(pluginFile) if os.path.exists(fnamec): os.remove(fnamec) - - pluginDirCache = os.path.join( - os.path.dirname(pluginFile), "__pycache__") + + pluginDirCache = os.path.join(os.path.dirname(pluginFile), "__pycache__") if os.path.exists(pluginDirCache): - pluginFileName = os.path.splitext( - os.path.basename(pluginFile))[0] - for fnameo in glob.glob(os.path.join( - pluginDirCache, "{0}*.pyo".format(pluginFileName))): + pluginFileName = os.path.splitext(os.path.basename(pluginFile))[0] + for fnameo in glob.glob( + os.path.join(pluginDirCache, "{0}*.pyo".format(pluginFileName)) + ): os.remove(fnameo) - for fnamec in glob.glob(os.path.join( - pluginDirCache, "{0}*.pyc".format(pluginFileName))): + for fnamec in glob.glob( + os.path.join(pluginDirCache, "{0}*.pyc".format(pluginFileName)) + ): os.remove(fnamec) - + os.remove(pluginFile) except OSError as err: EricMessageBox.critical( @@ -213,9 +217,11 @@ self.tr( """<p>The plugin package <b>{0}</b> could not be""" """ removed. Aborting...</p>""" - """<p>Reason: {1}</p>""").format(packageDir, str(err))) + """<p>Reason: {1}</p>""" + ).format(packageDir, str(err)), + ) return False - + if not self.__external: ui = ericApp().getObject("UserInterface") ui.showNotification( @@ -223,17 +229,19 @@ self.tr("Plugin Uninstallation"), self.tr( """<p>The plugin <b>{0}</b> was uninstalled""" - """ successfully from {1}.</p>""") - .format(pluginName, pluginDirectory)) + """ successfully from {1}.</p>""" + ).format(pluginName, pluginDirectory), + ) return True - + EricMessageBox.information( self, self.tr("Plugin Uninstallation"), self.tr( """<p>The plugin <b>{0}</b> was uninstalled successfully""" - """ from {1}.</p>""") - .format(pluginName, pluginDirectory)) + """ from {1}.</p>""" + ).format(pluginName, pluginDirectory), + ) return True @@ -241,26 +249,27 @@ """ Class for the dialog variant. """ + def __init__(self, pluginManager, parent=None): """ Constructor - + @param pluginManager reference to the plugin manager object @param parent reference to the parent widget (QWidget) """ super().__init__(parent) self.setSizeGripEnabled(True) - + self.__layout = QVBoxLayout(self) self.__layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.__layout) - + self.cw = PluginUninstallWidget(pluginManager, self) size = self.cw.size() self.__layout.addWidget(self.cw) self.resize(size) self.setWindowTitle(self.cw.windowTitle()) - + self.cw.buttonBox.accepted.connect(self.accept) self.cw.buttonBox.rejected.connect(self.reject) @@ -269,10 +278,11 @@ """ Main window class for the standalone dialog. """ + def __init__(self, parent=None): """ Constructor - + @param parent reference to the parent widget (QWidget) """ super().__init__(parent) @@ -281,9 +291,8 @@ self.setCentralWidget(self.cw) self.resize(size) self.setWindowTitle(self.cw.windowTitle()) - - self.setStyle(Preferences.getUI("Style"), - Preferences.getUI("StyleSheet")) - + + self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet")) + self.cw.buttonBox.accepted.connect(self.close) self.cw.buttonBox.rejected.connect(self.close)