From 9c2acc2dd4bd03a091109d13dec8c701ea00d871 Mon Sep 17 00:00:00 2001 From: Andrew Vaillancourt Date: Fri, 13 Jun 2025 17:21:12 -0400 Subject: [PATCH] Fix docstrings in automation_logger.py Fix all linting warnings without adjusting code or altering docstring content beyond what is needed to pass pre-commit hooks Formatting done by black pre-commit hook stage. Change-Id: Ie510e8ba8a4148839d46121438e1c960f94d6cf0 Signed-off-by: Andrew Vaillancourt --- framework/logging/automation_logger.py | 208 ++++++++++++------------- 1 file changed, 96 insertions(+), 112 deletions(-) diff --git a/framework/logging/automation_logger.py b/framework/logging/automation_logger.py index d8e71d3d..ae334a9d 100644 --- a/framework/logging/automation_logger.py +++ b/framework/logging/automation_logger.py @@ -17,106 +17,116 @@ class AutomationLogger(logging.getLoggerClass()): The logging class defines the operations available to the AutomationLogger. """ - GENERAL_LOGGER_FORMAT = '[%(asctime)s] %(source)-3s %(levelname)-5s ' '%(threadName)-8s %(module)s.%(funcName)-1s %(lineno)-1d :: %(message)s' - EXCEPTION_LOGGER_FORMAT = '%(message)s' + GENERAL_LOGGER_FORMAT = "[%(asctime)s] %(source)-3s %(levelname)-7s " "%(threadName)-8s %(module)s.%(funcName)-1s %(lineno)-1d :: %(message)s" + EXCEPTION_LOGGER_FORMAT = "%(message)s" - def __init__(self, name='', level=logging.INFO): + def __init__(self, name: str = "", level: int = logging.INFO): + """Initialize the AutomationLogger.""" super().__init__(name, level) self.log_folder = None self.test_case_log_dir = None - self._step_counter = 0 # for use in test case step + self._step_counter = 0 # for use in test case step - def log(self, level, message, *args, **kwargs): + def log(self, level: int, message: str, *args, **kwargs) -> None: """ - An override of the base logging function. This should only be used by external libraries - and no automation code explicitly. + An override of the base logging function. This should only be used by external libraries and no automation code explicitly. + Args: - level: The LogLevel to be used - message: The message that will be logged. + level (int): The LogLevel to be used. + message (str): The message that will be logged. + *args: Additional positional arguments for the logger. + **kwargs: Additional keyword arguments for the logger. """ - self._log(level, message, None, stacklevel=2, extra={'source': 'LIB'}) + self._log(level, message, None, stacklevel=2, extra={"source": "LIB"}) - def log_debug(self, message): + def log_debug(self, message: str) -> None: """ The logging function to use to log debugging information for the user. - Args: - message: The message that will be logged. - """ - self._log(logging.DEBUG, message, None, stacklevel=2, extra={'source': 'AUT'}) - def log_info(self, message): + Args: + message (str): The message that will be logged. + """ + self._log(logging.DEBUG, message, None, stacklevel=2, extra={"source": "AUT"}) + + def log_info(self, message: str) -> None: """ The default logging function to use to log a informative message to the user. - Args: - message: The message that will be logged. - """ - self._log(logging.INFO, message, None, stacklevel=2, extra={'source': 'AUT'}) - def log_warning(self, message): + Args: + message (str): The message that will be logged. + """ + self._log(logging.INFO, message, None, stacklevel=2, extra={"source": "AUT"}) + + def log_warning(self, message: str) -> None: """ Logs a warning message, indicating a potential issue that is not critical but requires attention. Args: message (str): The warning message to be logged. """ - self._log(logging.WARNING, message, None, stacklevel=2, extra={'source': 'AUT'}) + self._log(logging.WARNING, message, None, stacklevel=2, extra={"source": "AUT"}) - def log_error(self, message): + def log_error(self, message: str) -> None: """ The function to call when logging an automation or a software error or exception. - Args: - message: The message that will be logged. - """ - self._log(logging.ERROR, message, None, stacklevel=2, extra={'source': 'AUT'}) - def log_exception(self, message): + Args: + message (str): The message that will be logged. + """ + self._log(logging.ERROR, message, None, stacklevel=2, extra={"source": "AUT"}) + + def log_exception(self, message: str) -> None: """ The function to call only by the framework when logging exceptions and stacktraces. - Args: - message: The message that will be logged. - """ - self._log(logging.ERROR, message, None, extra={'source': 'EXC'}) - def log_keyword(self, message): - """ - This debug-level log statement is meant to automatically log all the function calls made. It - shouldn't be called explicitly in keywords and test cases. Args: - message: The message that will be logged. + message (str): The message that will be logged. """ + self._log(logging.ERROR, message, None, extra={"source": "EXC"}) + def log_keyword(self, message: str) -> None: + """ + This debug-level log statement is meant to automatically log all the function calls made. It shouldn't be called explicitly in keywords and test cases. + + Args: + message (str): The message that will be logged. + """ # Setting stacklevel=4 to avoid the find the last stack element before the keyword wrappers - self._log(logging.DEBUG, message, None, stacklevel=4, extra={'source': 'KEY'}) + self._log(logging.DEBUG, message, None, stacklevel=4, extra={"source": "KEY"}) - def log_ssh(self, message): + def log_ssh(self, message: str) -> None: """ - This info-level log statement logs everything that is sent and observed from the software - under test through an SSH connection. - Args: - message: The message that will be logged. - """ - self._log(logging.INFO, message, None, stacklevel=2, extra={'source': 'SSH'}) + This info-level log statement logs everything that is sent and observed from the software under test through an SSH connection. - def log_kpi(self, message): - """This info-level log statement is used to log elapsed time for KPIs. Args: - message: The message that will be logged. + message (str): The message that will be logged. + """ + self._log(logging.INFO, message, None, stacklevel=2, extra={"source": "SSH"}) + + def log_kpi(self, message: str) -> None: + """ + This info-level log statement is used to log elapsed time for KPIs. + + Args: + message (str): The message that will be logged. """ self._log(logging.INFO, message, None, stacklevel=2, extra={"source": "KPI"}) def get_log_folder(self) -> str: """ - Getter for log folder - Returns: + Getter for log folder. + Returns: + str: The log folder path. """ return self.log_folder def get_test_case_log_dir(self) -> str: """ - Returns the directory containing the test case logs - Returns: + Returns the directory containing the test case logs. + Returns: + str: The test case log directory. """ return self.test_case_log_dir @@ -137,68 +147,54 @@ class AutomationLogger(logging.getLoggerClass()): message = f"Test Step {self._step_counter}: {description}" else: message = f"Test Step: {description}" - self._log(logging.INFO, message, None, stacklevel=2, extra={'source': 'TST'}) + self._log(logging.INFO, message, None, stacklevel=2, extra={"source": "TST"}) @staticmethod -def configure_logger(): +def configure_logger() -> None: """ Creates and configures a new logger instance that will be used by the singleton. + This function must be called before we start using the logger. - Returns: - None """ logger_config = ConfigurationManager.get_logger_config() lab_configuration = ConfigurationManager.get_lab_config() - # If logger_config is not defined, crash with appropriate exception, if not logger_config: raise ValueError("You must define a Logger Configuration before using the logger.") - # Create the LOGGER instance logging.setLoggerClass(AutomationLogger) global _LOGGER - _LOGGER = logging.getLogger('automation_log') + _LOGGER = logging.getLogger("automation_log") - # create the root folder and make the dirs _LOGGER.log_folder = logger_config.get_log_location() - if logger_config.get_append_lab_and_timestamp(): - _LOGGER.log_folder = os.path.join(_LOGGER.log_folder, lab_configuration.get_lab_name(), strftime('%Y%m%d%H%M')) + _LOGGER.log_folder = os.path.join(_LOGGER.log_folder, lab_configuration.get_lab_name(), strftime("%Y%m%d%H%M")) os.makedirs(_LOGGER.log_folder, exist_ok=True) log_file = os.path.join(_LOGGER.get_log_folder(), "full_logs.txt") - - # Set the Log handlers so that we get Console and File logs. _configure_general_log_handlers(logger_config, log_file) _configure_exception_log_handlers(logger_config, log_file) - _LOGGER.log_info(f"LOG File Location: {log_file}") @staticmethod -def _configure_general_log_handlers(logger_config: LoggerConfig, log_file: str): +def _configure_general_log_handlers(logger_config: LoggerConfig, log_file: str) -> None: """ This function will add the console and file handlers for general logging. + Args: - logger_config: LoggerConfig object - log_file: Full path where we want to store the logs. - - Returns: None - + logger_config (LoggerConfig): LoggerConfig object. + log_file (str): Full path where we want to store the logs. """ + log_formatter = logging.Formatter(_LOGGER.GENERAL_LOGGER_FORMAT, datefmt="%Y-%m-%d %H:%M:%S") - # Define the General Log Handlers - log_formatter = logging.Formatter(_LOGGER.GENERAL_LOGGER_FORMAT, datefmt='%Y-%m-%d %H:%M:%S') - - # Ensure that the Logs will be printed to a log file file_handler = logging.FileHandler(log_file) file_handler.setFormatter(log_formatter) file_handler.addFilter(LogNonExceptionFilter()) file_handler.setLevel(logger_config.get_file_log_level_value()) _LOGGER.addHandler(file_handler) - # Ensure that the Logs will be printed to the console console_handler = logging.StreamHandler() console_handler.setFormatter(log_formatter) console_handler.addFilter(LogNonExceptionFilter()) @@ -206,30 +202,26 @@ def _configure_general_log_handlers(logger_config: LoggerConfig, log_file: str): _LOGGER.addHandler(console_handler) -def configure_testcase_log_handler(logger_config: LoggerConfig, log_file: str): +def configure_testcase_log_handler(logger_config: LoggerConfig, log_file: str) -> None: """ - Configure the log for the testcase + Configure the log for the testcase. + Args: - logger_config (): the logger config - log_file (): the log file name - - Returns: - + logger_config (LoggerConfig): The logger config. + log_file (str): The log file name. """ - log_formatter = logging.Formatter(_LOGGER.GENERAL_LOGGER_FORMAT, datefmt='%Y-%m-%d %H:%M:%S') - _LOGGER.test_case_log_dir = os.path.join(_LOGGER.get_log_folder(), f'{log_file}') + log_formatter = logging.Formatter(_LOGGER.GENERAL_LOGGER_FORMAT, datefmt="%Y-%m-%d %H:%M:%S") + _LOGGER.test_case_log_dir = os.path.join(_LOGGER.get_log_folder(), f"{log_file}") os.makedirs(_LOGGER.test_case_log_dir, exist_ok=True) - full_log_file_path = os.path.join(_LOGGER.test_case_log_dir, 'log.txt') - # Ensure that the Logs will be printed to a log file + full_log_file_path = os.path.join(_LOGGER.test_case_log_dir, "log.txt") + file_handler = logging.FileHandler(full_log_file_path) file_handler.setFormatter(log_formatter) file_handler.addFilter(LogNonExceptionFilter()) file_handler.setLevel(logger_config.get_file_log_level_value()) _LOGGER.addHandler(file_handler) - exception_formatter = logging.Formatter(_LOGGER.EXCEPTION_LOGGER_FORMAT, datefmt='%Y-%m-%d %H:%M:%S') - - # Ensure that the Logs will be printed to a log file + exception_formatter = logging.Formatter(_LOGGER.EXCEPTION_LOGGER_FORMAT, datefmt="%Y-%m-%d %H:%M:%S") exception_file_handler = logging.FileHandler(full_log_file_path) exception_file_handler.setFormatter(exception_formatter) exception_file_handler.addFilter(LogExceptionFilter()) @@ -237,43 +229,35 @@ def configure_testcase_log_handler(logger_config: LoggerConfig, log_file: str): _LOGGER.addHandler(exception_file_handler) -def remove_testcase_handler(test_name): +def remove_testcase_handler(test_name: str) -> None: """ - Remove the testcase holder + Remove the testcase handler for the given test. + Args: - test_name (): the test name - - Returns: - + test_name (str): The test name whose log handler should be removed. """ for handler in _LOGGER.handlers: - if hasattr(handler, 'baseFilename') and f'{test_name}' in handler.baseFilename: + if hasattr(handler, "baseFilename") and f"{test_name}" in handler.baseFilename: _LOGGER.removeHandler(handler) @staticmethod -def _configure_exception_log_handlers(logger_config: LoggerConfig, log_file: str): +def _configure_exception_log_handlers(logger_config: LoggerConfig, log_file: str) -> None: """ This function will add the console and file handlers for Exception and stack trace logging. + Args: - logger_config: LoggerConfig object - log_file: Full path where we want to store the logs. - - Returns: None - + logger_config (LoggerConfig): LoggerConfig object. + log_file (str): Full path where we want to store the logs. """ + exception_formatter = logging.Formatter("%(message)s", datefmt="%Y-%m-%d %H:%M:%S") - EXCEPTION_FORMAT = '%(message)s' - exception_formatter = logging.Formatter(EXCEPTION_FORMAT, datefmt='%Y-%m-%d %H:%M:%S') - - # Ensure that the Logs will be printed to a log file exception_file_handler = logging.FileHandler(log_file) exception_file_handler.setFormatter(exception_formatter) exception_file_handler.addFilter(LogExceptionFilter()) exception_file_handler.setLevel(logger_config.get_file_log_level_value()) _LOGGER.addHandler(exception_file_handler) - # Ensure that the Logs will be printed to the console exception_console_handler = logging.StreamHandler() exception_console_handler.setFormatter(exception_formatter) exception_console_handler.addFilter(LogExceptionFilter()) @@ -282,13 +266,13 @@ def _configure_exception_log_handlers(logger_config: LoggerConfig, log_file: str @staticmethod -def get_logger(): +def get_logger() -> AutomationLogger: """ This function should be used to access the logger. - Returns: - The singleton instance of the logger if it has been configured. - """ + Returns: + AutomationLogger: The singleton instance of the logger if it has been configured. + """ global _LOGGER if _LOGGER is None: configure_logger()