[0cd8612] | 1 | import os |
---|
| 2 | import sys |
---|
| 3 | import logging |
---|
| 4 | |
---|
[4992ff2] | 5 | from PyQt5.QtCore import * |
---|
[0cd8612] | 6 | |
---|
| 7 | |
---|
[4992ff2] | 8 | class XStream(QObject): |
---|
[5dba493] | 9 | """ |
---|
| 10 | Imitates, loosely, an `io.TextIOWrapper` class in order to intercept |
---|
| 11 | messages going to stdout and stderr. |
---|
| 12 | |
---|
| 13 | To intercept messages to stdout, use: |
---|
| 14 | |
---|
| 15 | .. code-block:: python |
---|
| 16 | XStream.stdout().messageWritten.mySignalHandler() |
---|
| 17 | |
---|
| 18 | All messages to stdout will now also be emitted to your handler. Use |
---|
| 19 | `XStream.stderr()` in the same way to intercept stderr messages. |
---|
| 20 | |
---|
| 21 | An additional function, `XStream.write_log()`, emits a message only to the |
---|
| 22 | messageWritten signal, and not the stdout or stderr streams. It is intended |
---|
| 23 | for separation of log handling between console and Qt, as reflected in the |
---|
| 24 | name. |
---|
| 25 | """ |
---|
[0cd8612] | 26 | _stdout = None |
---|
| 27 | _stderr = None |
---|
[4992ff2] | 28 | messageWritten = pyqtSignal(str) |
---|
[0cd8612] | 29 | |
---|
[5dba493] | 30 | _real_stream = None |
---|
| 31 | |
---|
[0cd8612] | 32 | def flush(self): |
---|
| 33 | pass |
---|
| 34 | |
---|
| 35 | def fileno(self): |
---|
| 36 | return -1 |
---|
| 37 | |
---|
| 38 | def write(self, msg): |
---|
[5dba493] | 39 | """ |
---|
| 40 | 'msg' is emitted in the messageWritten signal, and is also written to |
---|
| 41 | the original stream. This means stdout/stderr messages have been |
---|
| 42 | redirected to a custom location (e.g. in-widget), but also reach |
---|
| 43 | console output. |
---|
| 44 | |
---|
| 45 | :param msg: message to write |
---|
| 46 | :return: None |
---|
| 47 | """ |
---|
| 48 | if(not self.signalsBlocked()): |
---|
| 49 | self.messageWritten.emit(str(msg)) |
---|
| 50 | self._real_stream.write(msg) |
---|
| 51 | |
---|
| 52 | def write_log(self, msg): |
---|
| 53 | """ |
---|
| 54 | 'msg' is only emitted in the messageWritten signal, not in the original |
---|
| 55 | stdout/stderr stream, for the purposes of logging. Use in, e.g. a |
---|
| 56 | custom logging handler's emit() function. |
---|
| 57 | |
---|
| 58 | :param msg: message to write |
---|
| 59 | :return: None |
---|
| 60 | """ |
---|
[0cd8612] | 61 | if(not self.signalsBlocked()): |
---|
[b3e8629] | 62 | self.messageWritten.emit(str(msg)) |
---|
[0cd8612] | 63 | |
---|
| 64 | @staticmethod |
---|
| 65 | def stdout(): |
---|
[5dba493] | 66 | """ |
---|
| 67 | Creates imitation of sys.stdout. |
---|
| 68 | :return: An XStream instance that interfaces exactly like sys.stdout, |
---|
| 69 | but, has redirection capabilities through the |
---|
| 70 | messageWritten(str) signal. |
---|
| 71 | """ |
---|
[0cd8612] | 72 | if(not XStream._stdout): |
---|
| 73 | XStream._stdout = XStream() |
---|
[5dba493] | 74 | XStream._stdout._real_stream = sys.stdout |
---|
[0cd8612] | 75 | sys.stdout = XStream._stdout |
---|
| 76 | return XStream._stdout |
---|
| 77 | |
---|
| 78 | @staticmethod |
---|
| 79 | def stderr(): |
---|
[5dba493] | 80 | """ |
---|
| 81 | Creates imitation of sys.stderr. |
---|
| 82 | :return: An XStream instance that interfaces exactly like sys.stderr, |
---|
| 83 | but, has redirection capabilities through the |
---|
| 84 | messageWritten(str) signal. |
---|
| 85 | """ |
---|
[0cd8612] | 86 | if(not XStream._stderr): |
---|
| 87 | XStream._stderr = XStream() |
---|
[5dba493] | 88 | XStream._stderr._real_stream = sys.stderr |
---|
[0cd8612] | 89 | sys.stderr = XStream._stderr |
---|
| 90 | return XStream._stderr |
---|
| 91 | |
---|
[5dba493] | 92 | |
---|
[0cd8612] | 93 | class QtHandler(logging.Handler): |
---|
| 94 | """ |
---|
[5dba493] | 95 | Version of logging handler "emitting" the message to custom stdout() |
---|
[0cd8612] | 96 | """ |
---|
| 97 | def __init__(self): |
---|
| 98 | logging.Handler.__init__(self) |
---|
| 99 | |
---|
| 100 | def emit(self, record): |
---|
| 101 | record = self.format(record) |
---|
| 102 | if record: |
---|
[5dba493] | 103 | XStream.stdout().write_log('%s\n'%record) |
---|
[0cd8612] | 104 | |
---|
| 105 | |
---|
| 106 | # Define the default logger |
---|
| 107 | logger = logging.getLogger() |
---|
| 108 | |
---|
| 109 | # Add the qt-signal logger |
---|
| 110 | handler = QtHandler() |
---|
[5dba493] | 111 | handler.setFormatter(logging.Formatter( |
---|
| 112 | fmt="%(asctime)s - %(levelname)s: %(message)s", |
---|
| 113 | datefmt="%H:%M:%S" |
---|
| 114 | )) |
---|
[0cd8612] | 115 | logger.addHandler(handler) |
---|