Source code for scrnatools._configs

"""
sc-rna-tools package global settings manager
From scrnatools package

Created on Mon Jan 10 15:57:46 2022

@author: joe germino (joe.germino@ucsf.edu)
"""
# external package imports
import logging
import os

# scrnatools package imports
from ._utils import type_check


[docs]class Config: """Config manager for scrnatools"""
[docs] def __init__( self, verbosity="warning", log_path="sc-rna-tools_logs", save_logs=False, ): self._verbosity = verbosity self._log_path = log_path self._save_logs = save_logs self._loggers = [] # list of loggers created by modules
@property def verbosity(self) -> str: """The logging level, allowed are: 'debug', 'info', 'warning', 'error', 'critical'""" return self._verbosity @verbosity.setter def verbosity(self, verbosity: str): """Sets the verbosity level of the logger Allowed are: 'debug', 'info', 'warning', 'error', 'critical' """ type_check(verbosity, "verbosity", str) # set the level of all the loggers for logger in self._loggers: self._set_log_level(logger, verbosity) self._verbosity = verbosity @property def log_path(self) -> str: """The path where log files are saved""" return self._log_path @log_path.setter def log_path(self, path: str): type_check(path, "path", str) self._log_path = path @property def save_logs(self) -> bool: """Determines whether logging messages are saved to a log file""" return self._save_logs @save_logs.setter def save_logs(self, save_logs: bool): type_check(save_logs, "save_logs", bool) # if logs are not currently being written to a file, but being updated to be written to a file, add a # FileHandler to each logger if not self.save_logs and save_logs: # make sure log directory exists self.check_log_path() # create the logging format and FileHandler formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s: %(message)s", "%Y-%m-%d %H:%M:%S") file_handler = logging.FileHandler(f"{self.log_path}/sc-rna-tools.log") file_handler.setFormatter(formatter) # add the FileHandler to each logger if it doesn't already have a FileHandler for logger in self._loggers: handlers = logger.handlers if sum([isinstance(h, logging.FileHandler) for h in handlers]) == 0: # check if there is a FileHandler logger.addHandler(file_handler) # if logs are currently being written to a file, but being updated to not be written to a file, remove the # FileHandler to each logger if self.save_logs and not save_logs: for logger in self._loggers: # find the FileHandler for this logger and remove it for h in logger.handlers: if isinstance(h, logging.FileHandler): logger.removeHandler(h) self._save_logs = save_logs def __str__(self) -> str: return f"ScoreConfig(" \ f"verbosity: {self.verbosity}, " \ f"log_path: {self.log_path}, " \ f"save_logs: {self.save_logs})" def clear_logs(self): """Clears all logs saved in the logs path""" if os.path.exists(self._log_path): for f in os.listdir(self._log_path): # Remove all the files in the log directory os.remove(os.path.join(self._log_path, f)) # remove the log directory os.rmdir(self._log_path) def check_log_path(self): """Checks if the log path exists, and creates it if it doesn't""" if not os.path.exists(self._log_path): os.makedirs(self._log_path) def create_logger(self, name: str): """Called by modules to create a logger for that function Parameters ---------- name The name of the logger (typically the module name creating the logger) """ type_check(name, 'name', str) # create a logger, StreamHandler, and the formatter for that logger logger = logging.getLogger(name) handler = logging.StreamHandler() formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s: %(message)s", "%Y-%m-%d %H:%M:%S") handler.setFormatter(formatter) handlers = logger.handlers if sum([isinstance(h, logging.StreamHandler) for h in handlers]) == 0: # check if there is a StreamHandler logger.addHandler(handler) # if logs are being saved to a file as well, create a FileHandler for the new logger too if self.save_logs: self.check_log_path() file_handler = logging.FileHandler(f"{self.log_path}/sc-rna-tools.log") file_handler.setFormatter(formatter) if sum([isinstance(h, logging.FileHandler) for h in handlers]) == 0: # check if there is a StreamHandler logger.addHandler(file_handler) # Set the log level to the current verbosity self._set_log_level(logger, self.verbosity) # Add the logger to the master list self._loggers.append(logger) return logger @staticmethod def _set_log_level(logger: logging.Logger, level: str): """Sets the log level of a modules logger Parameters ---------- logger The logger to set the level of level String corresponding to the name of the logging level to set. Allowed: 'info', 'debug', 'warning', 'error', 'critical' """ log_levels = { "info": logging.INFO, "debug": logging.DEBUG, "warning": logging.WARNING, "error": logging.ERROR, "critical": logging.CRITICAL } if level not in log_levels: raise ValueError(f"'{level}' is not a valid logging level " f"('info', 'debug', 'warning', 'error', 'critical')") logger.setLevel(log_levels[level])
configs = Config()