Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Redirect Logger Output into PyQt Text Widget

Tags:

python

pyqt

A code posted on Redirecting Output in PyQt does two good things at once: it takes advantage of logging module to nicely format messages and it redirects standard stdout and stderr in to QT QTextBrowser widget. But I would like QTextBrowser to receive all the print output coming out of running code. Particularly I want to redirect the nicely formatted messages that come from logger. An ideal solution would re-direct every logger. output in to QTextBrowser (and not just stdout and stderr). As a matter of fact I would rather redirect logger's messages instead of stdout and stderr ones if I would have to make a choice between the twos.... So here are the commands used to printout formatted messages:

logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')

And here is the code: enter image description here

========

import sys
from PyQt4 import QtCore, QtGui
import logging
logger = logging.getLogger(__name__)

class XStream(QtCore.QObject):
    _stdout = None
    _stderr = None
    messageWritten = QtCore.pyqtSignal(str)
    def flush( self ):
        pass
    def fileno( self ):
        return -1
    def write( self, msg ):
        if ( not self.signalsBlocked() ):
            self.messageWritten.emit(unicode(msg))

    @staticmethod
    def stdout():
        if ( not XStream._stdout ):
            XStream._stdout = XStream()
            sys.stdout = XStream._stdout
        return XStream._stdout

    @staticmethod
    def stderr():
        if ( not XStream._stderr ):
            XStream._stderr = XStream()
            sys.stderr = XStream._stderr
        return XStream._stderr

class MyDialog(QtGui.QDialog):
    def __init__( self, parent = None ):
        super(MyDialog, self).__init__(parent)

        self._console = QtGui.QTextBrowser(self)
        self._button  = QtGui.QPushButton(self)
        self._button.setText('Test Me')

        layout = QtGui.QVBoxLayout()
        layout.addWidget(self._console)
        layout.addWidget(self._button)
        self.setLayout(layout)

        XStream.stdout().messageWritten.connect( self._console.insertPlainText )
        XStream.stderr().messageWritten.connect( self._console.insertPlainText )

        self._button.clicked.connect(self.test)

    def test( self ):
        print 'printing LINE 1'
        print 'printing LINE 2'
        logger.debug('debug message')
        logger.info('info message')
        logger.warning('warning message')
        logger.error('error message')
        # error out something
        print blah

if ( __name__ == '__main__' ):
    # logging.basicConfig()
    # logging.basicConfig(filename='example.log',level=logging.DEBUG)
    logging.basicConfig(level=logging.DEBUG)

    app = None
    if ( not QtGui.QApplication.instance() ):
        app = QtGui.QApplication([])

    dlg = MyDialog()
    dlg.show()

    if ( app ):
        app.exec_()

POSTED LATER::FULLY WORKING EXAMPLE::SOLVED BY Mr.Dano

import sys
from PyQt4 import QtCore, QtGui
import logging

class QtHandler(logging.Handler):
    def __init__(self):
        logging.Handler.__init__(self)
    def emit(self, record):
        record = self.format(record)
        if record: XStream.stdout().write('%s\n'%record)
        # originally: XStream.stdout().write("{}\n".format(record))


logger = logging.getLogger(__name__)
handler = QtHandler()
handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)


class XStream(QtCore.QObject):
    _stdout = None
    _stderr = None
    messageWritten = QtCore.pyqtSignal(str)
    def flush( self ):
        pass
    def fileno( self ):
        return -1
    def write( self, msg ):
        if ( not self.signalsBlocked() ):
            self.messageWritten.emit(unicode(msg))
    @staticmethod
    def stdout():
        if ( not XStream._stdout ):
            XStream._stdout = XStream()
            sys.stdout = XStream._stdout
        return XStream._stdout
    @staticmethod
    def stderr():
        if ( not XStream._stderr ):
            XStream._stderr = XStream()
            sys.stderr = XStream._stderr
        return XStream._stderr

class MyDialog(QtGui.QDialog):
    def __init__( self, parent = None ):
        super(MyDialog, self).__init__(parent)

        self._console = QtGui.QTextBrowser(self)
        self._button  = QtGui.QPushButton(self)
        self._button.setText('Test Me')

        layout = QtGui.QVBoxLayout()
        layout.addWidget(self._console)
        layout.addWidget(self._button)
        self.setLayout(layout)

        XStream.stdout().messageWritten.connect( self._console.insertPlainText )
        XStream.stderr().messageWritten.connect( self._console.insertPlainText )

        self._button.clicked.connect(self.test)

    def test( self ):
        logger.debug('debug message')
        logger.info('info message')
        logger.warning('warning message')
        logger.error('error message')
        print 'Old school hand made print message'

if ( __name__ == '__main__' ):
    app = None
    if ( not QtGui.QApplication.instance() ):
        app = QtGui.QApplication([])
    dlg = MyDialog()
    dlg.show()
    if ( app ):
        app.exec_()
like image 333
alphanumeric Avatar asked Jun 28 '14 18:06

alphanumeric


People also ask

How to redirect tqdm output to widget?

So the other approach I found is to redirect stderr in the same stream/queue stdout is redirected to. Since tqdm writes to stderr by default, this way all tqdm outputs are redirected to widget.

How many threads does PyQt have?

3 4 5 Thread Modes [PyQt] Newbe question about Print() to PyQt TimW Unladen Swallow Posts: 4 Threads: 1 Joined: Dec 2017 Reputation: 0 #1 Dec-18-2017, 10:32 PM

Is PyQt a good choice for a GUI developer?

I've been programming in Python for almost 10 years. I did many CLI tools, some web applications (mainly using Flask ), but I had never built a GUI. PyQt seems to be one of the most popular framework. I had a look at it but I was not hooked. It looks like you really need to embrace the Qt world.

Is the tqdm progress bar being redirected to console output?

However, only logger lines are redirected. TQDM progress bar is still directed to the console output. Here is my current code:


1 Answers

The answer given by dano works for 2.7.x, but not for 3.x.

To get the code provided by @dano working in 3.4.3 I had to make the obvious changes to the print statements and also change the write() method in the XStream class from self.messageWritten.emit(unicode(msg)) to self.messageWritten.emit(msg). That unicode call just made the dialog sit there and stare back at me in amusement.

like image 66
Todd Vanyo Avatar answered Sep 22 '22 16:09

Todd Vanyo