ProjectFlask/RunServerDialog.py

Tue, 10 Nov 2020 19:38:00 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 10 Nov 2020 19:38:00 +0100
changeset 5
550e5ea385cb
parent 4
e164b9ad3819
child 6
d491ccab7343
permissions
-rw-r--r--

Continued implementing the "Run Server" function.

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

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

"""
Module implementing a dialog to run the Flask server.
"""

import re

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

from E5Gui import E5MessageBox

from .Ui_RunServerDialog import Ui_RunServerDialog


class RunServerDialog(QDialog, Ui_RunServerDialog):
    """
    Class implementing a dialog to run the Flask server.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(RunServerDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.__process = None
        
        self.__ansiRe = re.compile("(\\x1b\[\d+m)")
        
        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
        self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
        
        self.__defaultTextFormat = self.outputEdit.currentCharFormat()
    
    def startServer(self, command, workdir, env):
        """
        Public method to start the Flask server process.
        
        @param command path of the flask command
        @type str
        @param workdir working directory for the Flask server
        @type str
        @param env environment for the Flask server process
        @type QProcessEnvironment
        @return flag indicating a successful start
        @rtype bool
        """
        self.__process = QProcess()
        self.__process.setProcessEnvironment(env)
        self.__process.setWorkingDirectory(workdir)
        self.__process.setProcessChannelMode(QProcess.MergedChannels)
        
        self.__process.readyReadStandardOutput.connect(self.__readStdOut)
        self.__process.finished.connect(self.__processFinished)
        
        self.__process.start(command, ["run"])
        ok = self.__process.waitForStarted(10000)
        if not ok:
            E5MessageBox.critical(
                None,
                self.tr("Run Flask Server"),
                self.tr("""The Flask server process could not be started."""))
        else:
            self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
            self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True)
            self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
        
        return ok
    
    def closeEvent(self, evt):
        """
        Private method handling a close event.
        
        @param evt reference to the close event
        @type QCloseEvent
        """
        self.__cancel()
        evt.accept()
    
    @pyqtSlot(QAbstractButton)
    def on_buttonBox_clicked(self, button):
        """
        Private slot handling button presses.
        
        @param button button that was pressed
        @type QAbstractButton
        """
        if button is self.buttonBox.button(QDialogButtonBox.Cancel):
            self.__cancel()
        elif button is self.buttonBox.button(QDialogButtonBox.Close):
            self.close()
    
    @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")
            for txt in self.__ansiRe.split(out):
                if txt.startswith("\x1b["):
                    # TODO: process ANSI escape sequences for coloring
                    pass
                else:
                    self.outputEdit.insertPlainText(txt)
    
    @pyqtSlot()
    def __processFinished(self):
        """
        Private slot handling the finishing of the server process.
        """
        if (
            self.__process is not None and
            self.__process.state() != QProcess.NotRunning
        ):
            self.__process.terminate()
            QTimer.singleShot(2000, self.__process.kill)
            self.__process.waitForFinished(3000)
        
        self.__process = None
        
        
        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
        self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
        self.buttonBox.button(QDialogButtonBox.Close).setFocus(
            Qt.OtherFocusReason)
    
    @pyqtSlot()
    def __cancel(self):
        """
        Private slot to cancel the running server.
        """
        self.__processFinished()

eric ide

mercurial