Thu, 10 Jan 2019 14:18:48 +0100
Updated copyright for 2019.
# -*- coding: utf-8 -*- # Copyright (c) 2015 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a dialog showing the output of a pip command. """ from __future__ import unicode_literals try: str = unicode # __IGNORE_EXCEPTION__ except NameError: pass from PyQt5.QtCore import pyqtSlot, Qt, QCoreApplication, QTimer, \ QProcess from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton from E5Gui import E5MessageBox from .Ui_PipDialog import Ui_PipDialog import Preferences class PipDialog(QDialog, Ui_PipDialog): """ Class implementing a dialog showing the output of a 'python -m pip' command. """ def __init__(self, text, parent=None): """ Constructor @param text text to be shown by the label @type str @param parent reference to the parent widget @type QWidget """ super(PipDialog, self).__init__(parent) self.setupUi(self) self.proc = None self.__processQueue = [] self.__ioEncoding = Preferences.getSystem("IOEncoding") self.outputGroup.setTitle(text) self.show() QCoreApplication.processEvents() def closeEvent(self, e): """ Protected slot implementing a close event handler. @param e close event @type QCloseEvent """ self.__processQueue = [] if self.proc is not None and \ self.proc.state() != QProcess.NotRunning: self.proc.terminate() QTimer.singleShot(2000, self.proc.kill) self.proc.waitForFinished(3000) self.proc = None e.accept() def __finish(self): """ Private slot called when the process finished or the user pressed the button. """ if self.proc is not None and \ self.proc.state() != QProcess.NotRunning: self.proc.terminate() QTimer.singleShot(2000, self.proc.kill) self.proc.waitForFinished(3000) self.proc = None self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) self.buttonBox.button(QDialogButtonBox.Close).setFocus( Qt.OtherFocusReason) if self.__processQueue: cmd, args = self.__processQueue.pop(0) self.__addOutput("\n\n") self.startProcess(cmd, args) @pyqtSlot(QAbstractButton) def on_buttonBox_clicked(self, button): """ Private slot called by a button of the button box clicked. @param button button that was clicked @type QAbstractButton """ if button == self.buttonBox.button(QDialogButtonBox.Close): self.close() def __procFinished(self, exitCode, exitStatus): """ Private slot connected to the finished signal. @param exitCode exit code of the process @type int @param exitStatus exit status of the process @type QProcess.ExitStatus """ self.__finish() def startProcess(self, cmd, args, showArgs=True): """ Public slot used to start the process. @param cmd name of the pip executable to be used @type str @param args list of arguments for the process @type list of str @keyparam showArgs flag indicating to show the arguments @type bool @return flag indicating a successful start of the process @rtype bool """ if len(self.errors.toPlainText()) == 0: self.errorGroup.hide() if showArgs: self.resultbox.append(cmd + ' ' + ' '.join(args)) self.resultbox.append('') self.proc = QProcess() self.proc.finished.connect(self.__procFinished) self.proc.readyReadStandardOutput.connect(self.__readStdout) self.proc.readyReadStandardError.connect(self.__readStderr) self.proc.start(cmd, args) procStarted = self.proc.waitForStarted(5000) if not procStarted: self.buttonBox.setFocus() E5MessageBox.critical( self, self.tr('Process Generation Error'), self.tr( 'The process {0} could not be started.' ).format(cmd)) return procStarted def startProcesses(self, processParams): """ Public method to issue a list of commands to be executed. @param processParams list of tuples containing the command and arguments @type list of tuples of (str, list of str) @return flag indicating a successful start of the first process @rtype bool """ if len(processParams) > 1: for cmd, args in processParams[1:]: self.__processQueue.append((cmd, args[:])) cmd, args = processParams[0] return self.startProcess(cmd, args) def __readStdout(self): """ Private slot to handle the readyReadStandardOutput signal. It reads the output of the process, formats it and inserts it into the contents pane. """ if self.proc is not None: txt = str(self.proc.readAllStandardOutput(), self.__ioEncoding, 'replace') self.__addOutput(txt) def __addOutput(self, txt): """ Private method to add some text to the output pane. @param txt text to be added @type str """ self.resultbox.insertPlainText(txt) self.resultbox.ensureCursorVisible() QCoreApplication.processEvents() def __readStderr(self): """ Private slot to handle the readyReadStandardError signal. It reads the error output of the process and inserts it into the error pane. """ if self.proc is not None: s = str(self.proc.readAllStandardError(), self.__ioEncoding, 'replace') self.errorGroup.show() self.errors.insertPlainText(s) self.errors.ensureCursorVisible() QCoreApplication.processEvents()