"""Module containing py_cui logging utilities """ # Author: Jakub Wlodek # Created: 18-Mar-2020 import os import logging import inspect import py_cui def _enable_logging(logger, filename='py_cui_log.txt', logging_level=logging.DEBUG): """Function that creates basic logging configuration for selected logger Parameters ---------- logger : PyCUILogger Main logger object filename : os.Pathlike File path for output logfile logging_level : logging.LEVEL, optional Level of messages to display, by default logging.DEBUG Raises ------ PermissionError py_cui logs require permission to cwd to operate. TypeError Only the custom PyCUILogger can be used here. """ abs_path = os.path.abspath(filename) if not os.access(os.path.dirname(abs_path), os.W_OK): raise PermissionError('You do not have permission to create py_cui.log file.') if not isinstance(logger, PyCUILogger): raise TypeError('Only the PyCUILogger can be used for logging in the py_cui module.') log_file = logging.FileHandler(filename) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s | %(message)s') log_file.setFormatter(formatter) logger.addHandler(log_file) logger.setLevel(logging_level) def _initialize_logger(py_cui_root, name=None, custom_logger=True): """Function that retrieves an instance of either the default or custom py_cui logger. Parameters ---------- py_cui_root : py_cui.PyCUI reference to the root py_cui window name : str, optional The name of the logger, by default None custom_logger : bool, optional Use a custom py_cui logger, by default True Returns ------- logger : py_cui.debug.PyCUILogger A custom logger that allows for live debugging """ if not custom_logger: return logging.getLogger(name) else: logging._acquireLock() try: logger = PyCUILogger(name) logger._assign_root_window(py_cui_root) return logger finally: logging._releaseLock() class PyCUILogger(logging.Logger): """Custom logger class for py_cui, extends the base logging.Logger Class Attributes ---------- py_cui_root : py_cui.PyCUI The root py_cui program for which the logger runs live_debug : bool Flag to toggle live debugging messages """ def __init__(self, name): """Initializer for the PyCUILogger helper class Raises ------ TypeError If root variable instance is not a PyCUI object raise a typeerror """ super(PyCUILogger, self).__init__(name) self._live_debug_level = logging.ERROR self._live_debug_enabled = False def _assign_root_window(self, py_cui_root): """Attaches logger to the root window for live debugging """ if not isinstance(py_cui_root, py_cui.PyCUI): raise TypeError('py_cui_root type must be py_cui.PyCUI') self.py_cui_root = py_cui_root def _get_debug_text(self, text): """Function that generates full debug text for the log """ func = inspect.currentframe().f_back.f_back.f_code return "{}: Function {} in {}:{}".format(text, func.co_name, os.path.basename(func.co_filename), func.co_firstlineno) def info(self, text): """Adds stacktrace info to log Parameters ---------- text : str The log text ot display """ debug_text = self._get_debug_text(text) super().debug(debug_text) def debug(self, text): """Function that allows for live debugging of py_cui programs by displaying log messages in the satus bar Parameters ---------- text : str The log text ot display """ debug_text = self._get_debug_text(text) if self._live_debug_level == logging.DEBUG and self._live_debug_enabled: if self.py_cui_root is not None: self.py_cui_root.status_bar.set_text(debug_text) super().debug(debug_text) else: super().debug(debug_text) def warn(self, text): """Function that allows for live debugging of py_cui programs by displaying log messages in the satus bar Parameters ---------- text : str The log text ot display """ debug_text = self._get_debug_text(text) if self._live_debug_level < logging.WARN and self._live_debug_enabled: if self.py_cui_root is not None: self.py_cui_root.status_bar.set_text(debug_text) super().debug(debug_text) else: super().warn(debug_text) def error(self, text): """Function that displays error messages live in status bar for py_cui logging Parameters ---------- text : str The log text ot display """ debug_text = self._get_debug_text(text) if self._live_debug_level < logging.ERROR and self._live_debug_enabled: if self.py_cui_root is not None: self.py_cui_root.status_bar.set_text(debug_text) super().debug(debug_text) else: super().error(debug_text) def toggle_live_debug(self, level=logging.ERROR): """Toggles live debugging mode """ self._live_debug_enabled = not self._live_debug_enabled self._live_debug_level = level