ProjectFlask/FlaskCommandDialog.py

Thu, 30 Dec 2021 11:20:01 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 30 Dec 2021 11:20:01 +0100
branch
eric7
changeset 66
0d3168d0e310
parent 64
0ee58185b8df
child 70
22e1d0f69668
permissions
-rw-r--r--

Updated copyright for 2022.

# -*- coding: utf-8 -*-

# Copyright (c) 2020 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog to run a flask command and show its output.
"""

from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QTimer
from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton

from EricWidgets import EricMessageBox

from .Ui_FlaskCommandDialog import Ui_FlaskCommandDialog


class FlaskCommandDialog(QDialog, Ui_FlaskCommandDialog):
    """
    Class implementing a dialog to run a flask command and show its output.
    """
    def __init__(self, project, title="", msgSuccess="", msgError="",
                 parent=None):
        """
        Constructor
        
        @param project reference to the project object
        @type Project
        @param title window title of the dialog
        @type str
        @param msgSuccess success message to be shown
        @type str
        @param msgError message to be shown on error
        @type str
        @param parent reference to the parent widget
        @type QWidget
        """
        super().__init__(parent)
        self.setupUi(self)
        
        if title:
            self.setWindowTitle(title)
        
        self.__project = project
        self.__successMessage = msgSuccess
        self.__errorMessage = msgError
        
        self.__process = None
        
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Close).setEnabled(True)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Close).setDefault(True)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
    
    def startCommand(self, command, args=None):
        """
        Public method to start a flask command and show its output.
        
        @param command flask command to be run
        @type str
        @param args list of command line arguments for the command
        @type list of str
        @return flag indicating a successful start
        @rtype bool
        """
        self.__normal = False
        workdir, env = self.__project.prepareRuntimeEnvironment()
        if env is not None:
            flaskCommand = self.__project.getFlaskCommand()
            
            self.__process = QProcess()
            self.__process.setProcessEnvironment(env)
            self.__process.setWorkingDirectory(workdir)
            self.__process.setProcessChannelMode(
                QProcess.ProcessChannelMode.MergedChannels)
            
            self.__process.readyReadStandardOutput.connect(self.__readStdOut)
            self.__process.finished.connect(self.__processFinished)
            
            self.outputEdit.clear()
            
            flaskArgs = [command]
            if args:
                flaskArgs += args
            
            self.__process.start(flaskCommand, flaskArgs)
            ok = self.__process.waitForStarted(10000)
            if not ok:
                EricMessageBox.critical(
                    None,
                    self.tr("Execute Flask Command"),
                    self.tr("""The Flask process could not be started."""))
            else:
                self.buttonBox.button(
                    QDialogButtonBox.StandardButton.Close).setEnabled(False)
                self.buttonBox.button(
                    QDialogButtonBox.StandardButton.Cancel).setDefault(True)
                self.buttonBox.button(
                    QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
                self.buttonBox.button(
                    QDialogButtonBox.StandardButton.Cancel).setFocus(
                        Qt.FocusReason.OtherFocusReason)
        else:
            ok = False
        
        return ok
    
    def closeEvent(self, evt):
        """
        Protected method handling the close event of the dialog.
        
        @param evt reference to the close event object
        @type QCloseEvent
        """
        self.__cancelProcess()
        evt.accept()
    
    @pyqtSlot()
    def __readStdOut(self):
        """
        Private slot to add the server process output to the output pane.
        """
        if self.__process is not None:
            out = str(self.__process.readAllStandardOutput(), "utf-8")
            self.outputEdit.insertPlainText(out)
    
    def __processFinished(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.__normal = (
            exitStatus == QProcess.ExitStatus.NormalExit and
            exitCode == 0
        )
        self.__cancelProcess()
        
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Close).setEnabled(True)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Close).setDefault(True)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Close).setFocus(
                Qt.FocusReason.OtherFocusReason)
        
        if self.__normal and self.__successMessage:
            self.outputEdit.insertPlainText(self.__successMessage)
        elif not self.__normal and self.__errorMessage:
            self.outputEdit.insertPlainText(self.__errorMessage)
    
    @pyqtSlot()
    def __cancelProcess(self):
        """
        Private slot to terminate the current process.
        """
        if (
            self.__process is not None and
            self.__process.state() != QProcess.ProcessState.NotRunning
        ):
            self.__process.terminate()
            QTimer.singleShot(2000, self.__process.kill)
            self.__process.waitForFinished(3000)
        
        self.__process = None
    
    @pyqtSlot(QAbstractButton)
    def on_buttonBox_clicked(self, button):
        """
        Private slot handling presses of the button box buttons.
        
        @param button reference to the button been clicked
        @type QAbstractButton
        """
        if button is self.buttonBox.button(
            QDialogButtonBox.StandardButton.Close
        ):
            self.close()
        elif button is self.buttonBox.button(
            QDialogButtonBox.StandardButton.Cancel
        ):
            self.__cancelProcess()
    
    def normalExit(self):
        """
        Public method to test, if the process ended without errors.
        
        @return flag indicating a normal process exit
        @rtype bool
        """
        return self.__normal

eric ide

mercurial