Source code for ClearMap.gui.gui_logging
# -*- coding: utf-8 -*-
"""
gui_logging
===========
Defines the Printer class used to log to file and to the GUI widgets from simple prints
"""
import sys
from datetime import datetime
from io import UnsupportedOperation
import lxml.html
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget
from matplotlib.colors import cnames
__author__ = 'Charly Rousseau <charly.rousseau@icm-institute.org>'
__license__ = 'GPLv3 - GNU General Public License v3 (see LICENSE.txt)'
__copyright__ = 'Copyright © 2022 by Charly Rousseau'
__webpage__ = 'https://idisco.info'
__download__ = 'https://www.github.com/ChristophKirst/ClearMap2'
[docs]
class Printer(QWidget):
text_updated = QtCore.pyqtSignal(str)
original_std_out = sys.stdout
original_std_err = sys.stderr
def __init__(self, log_path=None, color=None, logger_type='info', app=None, open_mode='a', redirects=None, parent=None):
super().__init__(parent)
self.file = None
self.n_lines = 0
self.color = color
self.type = logger_type
self.redirects = redirects
self.set_file(log_path, open_mode)
if app is None:
self.app = QApplication.instance()
else:
self.app = app
def __del__(self):
self.close_file()
[docs]
def close_file(self):
try:
self.file.close()
except AttributeError:
pass
self.__unset_redirects()
[docs]
def set_file(self, log_path, open_mode='a'):
self.close_file()
if log_path:
self.file = open(log_path, open_mode)
self.n_lines = 0
self.__set_redirects()
def __set_redirects(self):
if self.redirects == 'stdout':
sys.stdout = self
elif self.redirects == 'stderr':
sys.stderr = self
def __unset_redirects(self):
if self.redirects == 'stdout':
sys.stdout = self.original_std_out
elif self.redirects == 'stderr':
sys.stderr = self.original_std_err
[docs]
def write(self, msg):
if self.file is not None:
if self.type in ('error', 'progress'):
self.file.write(f'{datetime.now().strftime("%y-%m-%d %H:%M:%S")}: ')
self.file.write(msg+'\n')
self.file.flush()
self.text_updated.emit(self.colourise(msg))
[docs]
def flush(self):
try:
self.file.flush()
except AttributeError:
pass
[docs]
def fileno(self):
if self.file is not None:
return self.file.fileno()
else:
raise UnsupportedOperation('Cannot access fileno without a file object')
[docs]
def colourise(self, msg, force=False):
"""
Convert msg to the self.color colour in html
Parameters
----------
msg str:
The message to colourise
force bool:
By default, do not colorise html code (to avoid messing up existing colours). This
forces the colorise nonetheless.
Returns
-------
"""
if self.color is not None:
try:
html = lxml.html.fromstring(msg)
is_html = html.find('.//*') is not None
except lxml.etree.ParserError:
is_html = False
if force or not is_html:
if len(msg.split(':')) > 2 and msg.split(':')[2].endswith('Warning'):
html_col = cnames['yellow']
else:
html_col = cnames[self.color]
colour_msg = f'<p style="color:{html_col}">{msg}</p>'
else:
colour_msg = msg
else:
colour_msg = msg
return colour_msg