Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
baca79ce82 | ||
|
|
4265be6430 | ||
|
|
c16b086467 | ||
|
|
48a98c0206 | ||
|
|
f1788f057f | ||
|
|
0ad8883809 | ||
|
|
51e9b1ce7c | ||
|
|
0d3104f60a | ||
|
|
d29f827fc9 |
@@ -1,7 +1,7 @@
|
|||||||
# MARK: Project info
|
# MARK: Project info
|
||||||
[project]
|
[project]
|
||||||
name = "corelibs"
|
name = "corelibs"
|
||||||
version = "0.37.0"
|
version = "0.39.2"
|
||||||
description = "Collection of utils for Python scripts"
|
description = "Collection of utils for Python scripts"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class ConsoleFormat(Flag):
|
|||||||
FILE = auto()
|
FILE = auto()
|
||||||
FUNCTION = auto()
|
FUNCTION = auto()
|
||||||
LINENO = auto()
|
LINENO = auto()
|
||||||
|
LEVEL = auto()
|
||||||
|
|
||||||
|
|
||||||
class ConsoleFormatSettings:
|
class ConsoleFormatSettings:
|
||||||
@@ -43,14 +44,17 @@ class ConsoleFormatSettings:
|
|||||||
ConsoleFormat.NAME |
|
ConsoleFormat.NAME |
|
||||||
ConsoleFormat.FILE |
|
ConsoleFormat.FILE |
|
||||||
ConsoleFormat.FUNCTION |
|
ConsoleFormat.FUNCTION |
|
||||||
ConsoleFormat.LINENO
|
ConsoleFormat.LINENO |
|
||||||
|
ConsoleFormat.LEVEL
|
||||||
)
|
)
|
||||||
# show time with no time zone, file and line
|
# show time with no time zone, file, line and level
|
||||||
CONDENSED = ConsoleFormat.TIME | ConsoleFormat.FILE | ConsoleFormat.LINENO
|
CONDENSED = ConsoleFormat.TIME | ConsoleFormat.FILE | ConsoleFormat.LINENO | ConsoleFormat.LEVEL
|
||||||
# only time
|
# only time and level
|
||||||
MINIMAL = ConsoleFormat.TIME
|
MINIMAL = ConsoleFormat.TIME | ConsoleFormat.LEVEL
|
||||||
|
# only level
|
||||||
|
BARE = ConsoleFormat.LEVEL
|
||||||
# only message
|
# only message
|
||||||
BARE = ConsoleFormat(0)
|
NONE = ConsoleFormat(0)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_string(setting_str: str, default: ConsoleFormat | None = None) -> ConsoleFormat | None:
|
def from_string(setting_str: str, default: ConsoleFormat | None = None) -> ConsoleFormat | None:
|
||||||
@@ -445,6 +449,9 @@ class Log(LogParent):
|
|||||||
logger setup
|
logger setup
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CONSOLE_HANDLER: str = 'stream_handler'
|
||||||
|
FILE_HANDLER: str = 'file_handler'
|
||||||
|
|
||||||
# spacer lenght characters and the character
|
# spacer lenght characters and the character
|
||||||
SPACER_CHAR: str = '='
|
SPACER_CHAR: str = '='
|
||||||
SPACER_LENGTH: int = 32
|
SPACER_LENGTH: int = 32
|
||||||
@@ -510,13 +517,13 @@ class Log(LogParent):
|
|||||||
# in the file writer too, for the ones where color is set BEFORE the format
|
# in the file writer too, for the ones where color is set BEFORE the format
|
||||||
# Any is logging.StreamHandler, logging.FileHandler and all logging.handlers.*
|
# Any is logging.StreamHandler, logging.FileHandler and all logging.handlers.*
|
||||||
self.handlers: dict[str, Any] = {}
|
self.handlers: dict[str, Any] = {}
|
||||||
self.add_handler('file_handler', self.__create_file_handler(
|
self.add_handler(self.FILE_HANDLER, self.__create_file_handler(
|
||||||
'file_handler', self.log_settings['log_level_file'], log_path)
|
self.FILE_HANDLER, self.log_settings['log_level_file'], log_path)
|
||||||
)
|
)
|
||||||
if self.log_settings['console_enabled']:
|
if self.log_settings['console_enabled']:
|
||||||
# console
|
# console
|
||||||
self.add_handler('stream_handler', self.__create_console_handler(
|
self.add_handler(self.CONSOLE_HANDLER, self.__create_console_handler(
|
||||||
'stream_handler',
|
self.CONSOLE_HANDLER,
|
||||||
self.log_settings['log_level_console'],
|
self.log_settings['log_level_console'],
|
||||||
console_format_type=self.log_settings['console_format_type'],
|
console_format_type=self.log_settings['console_format_type'],
|
||||||
))
|
))
|
||||||
@@ -613,19 +620,17 @@ class Log(LogParent):
|
|||||||
self.handlers[handler_name] = handler
|
self.handlers[handler_name] = handler
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# MARK: console handler
|
# MARK: console logger format
|
||||||
def __create_console_handler(
|
def __build_console_format_from_string(self, console_format_type: ConsoleFormat) -> str:
|
||||||
self, handler_name: str,
|
"""
|
||||||
log_level_console: LoggingLevel = LoggingLevel.WARNING,
|
Build console format string from the given console format type
|
||||||
filter_exceptions: bool = True,
|
|
||||||
console_format_type: ConsoleFormat = ConsoleFormatSettings.ALL,
|
Arguments:
|
||||||
) -> logging.StreamHandler[TextIO]:
|
console_format_type {ConsoleFormat} -- _description_
|
||||||
# console logger
|
|
||||||
if not self.validate_log_level(log_level_console):
|
Returns:
|
||||||
log_level_console = self.DEFAULT_LOG_LEVEL_CONSOLE
|
str -- _description_
|
||||||
console_handler = logging.StreamHandler()
|
"""
|
||||||
print(f"Console format type: {console_format_type}")
|
|
||||||
# build the format string based on what flags are set
|
|
||||||
format_string = ''
|
format_string = ''
|
||||||
# time part if any of the times are requested
|
# time part if any of the times are requested
|
||||||
if (
|
if (
|
||||||
@@ -654,17 +659,23 @@ class Log(LogParent):
|
|||||||
set_group.append('%(lineno)d')
|
set_group.append('%(lineno)d')
|
||||||
format_string += ':'.join(set_group)
|
format_string += ':'.join(set_group)
|
||||||
format_string += '] '
|
format_string += '] '
|
||||||
# always level + message
|
# level if wanted
|
||||||
format_string += '<%(levelname)s> %(message)s'
|
if ConsoleFormat.LEVEL in console_format_type:
|
||||||
# basic date, but this will be overridden to ISO in formatTime
|
format_string += '<%(levelname)s> '
|
||||||
# format_date = "%Y-%m-%d %H:%M:%S"
|
# always message
|
||||||
# color or not
|
format_string += '%(message)s'
|
||||||
if self.log_settings['console_color_output_enabled']:
|
return format_string
|
||||||
# formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date)
|
|
||||||
formatter_console = CustomConsoleFormatter(format_string)
|
def __set_time_format_for_console_formatter(
|
||||||
else:
|
self, formatter_console: CustomConsoleFormatter | logging.Formatter, console_format_type: ConsoleFormat
|
||||||
# formatter_console = logging.Formatter(format_string, datefmt=format_date)
|
) -> None:
|
||||||
formatter_console = logging.Formatter(format_string)
|
"""
|
||||||
|
Format time for a given format handler, this is for console format only
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
formatter_console {CustomConsoleFormatter | logging.Formatter} -- _description_
|
||||||
|
console_format_type {ConsoleFormat} -- _description_
|
||||||
|
"""
|
||||||
# default for TIME is milliseconds
|
# default for TIME is milliseconds
|
||||||
# if we have multiple set, the smallest precision wins
|
# if we have multiple set, the smallest precision wins
|
||||||
if ConsoleFormat.TIME_MICROSECONDS in console_format_type:
|
if ConsoleFormat.TIME_MICROSECONDS in console_format_type:
|
||||||
@@ -701,11 +712,80 @@ class Log(LogParent):
|
|||||||
.fromtimestamp(record.created)
|
.fromtimestamp(record.created)
|
||||||
.isoformat(sep=" ", timespec=iso_precision)
|
.isoformat(sep=" ", timespec=iso_precision)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __set_console_formatter(self, console_format_type: ConsoleFormat) -> CustomConsoleFormatter | logging.Formatter:
|
||||||
|
"""
|
||||||
|
Build the full formatter and return it
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
console_format_type {ConsoleFormat} -- _description_
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
CustomConsoleFormatter | logging.Formatter -- _description_
|
||||||
|
"""
|
||||||
|
format_string = self.__build_console_format_from_string(console_format_type)
|
||||||
|
if self.log_settings['console_color_output_enabled']:
|
||||||
|
# formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date)
|
||||||
|
formatter_console = CustomConsoleFormatter(format_string)
|
||||||
|
else:
|
||||||
|
# formatter_console = logging.Formatter(format_string, datefmt=format_date)
|
||||||
|
formatter_console = logging.Formatter(format_string)
|
||||||
|
self.__set_time_format_for_console_formatter(formatter_console, console_format_type)
|
||||||
|
self.log_settings['console_format_type'] = console_format_type
|
||||||
|
return formatter_console
|
||||||
|
|
||||||
|
# MARK: console handler update
|
||||||
|
def update_console_formatter(
|
||||||
|
self,
|
||||||
|
console_format_type: ConsoleFormat,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Update the console formatter for format layout and time stamp format
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
console_format_type {ConsoleFormat} -- _description_
|
||||||
|
"""
|
||||||
|
# skip if console not enabled
|
||||||
|
if not self.log_settings['console_enabled']:
|
||||||
|
return
|
||||||
|
# skip if format has not changed
|
||||||
|
if self.log_settings['console_format_type'] == console_format_type:
|
||||||
|
return
|
||||||
|
# update the formatter
|
||||||
|
self.handlers[self.CONSOLE_HANDLER].setFormatter(
|
||||||
|
self.__set_console_formatter(console_format_type)
|
||||||
|
)
|
||||||
|
|
||||||
|
# MARK: console handler
|
||||||
|
def __create_console_handler(
|
||||||
|
self, handler_name: str,
|
||||||
|
log_level_console: LoggingLevel = LoggingLevel.WARNING,
|
||||||
|
filter_exceptions: bool = True,
|
||||||
|
console_format_type: ConsoleFormat = ConsoleFormatSettings.ALL,
|
||||||
|
) -> logging.StreamHandler[TextIO]:
|
||||||
|
# console logger
|
||||||
|
if not self.validate_log_level(log_level_console):
|
||||||
|
log_level_console = self.DEFAULT_LOG_LEVEL_CONSOLE
|
||||||
|
console_handler = logging.StreamHandler()
|
||||||
|
# print(f"Console format type: {console_format_type}")
|
||||||
|
# build the format string based on what flags are set
|
||||||
|
# format_string = self.__build_console_format_from_string(console_format_type)
|
||||||
|
# # basic date, but this will be overridden to ISO in formatTime
|
||||||
|
# # format_date = "%Y-%m-%d %H:%M:%S"
|
||||||
|
# # color or not
|
||||||
|
# if self.log_settings['console_color_output_enabled']:
|
||||||
|
# # formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date)
|
||||||
|
# formatter_console = CustomConsoleFormatter(format_string)
|
||||||
|
# else:
|
||||||
|
# # formatter_console = logging.Formatter(format_string, datefmt=format_date)
|
||||||
|
# formatter_console = logging.Formatter(format_string)
|
||||||
|
# # set the time format
|
||||||
|
# self.__set_time_format_for_console_formatter(formatter_console, console_format_type)
|
||||||
console_handler.set_name(handler_name)
|
console_handler.set_name(handler_name)
|
||||||
console_handler.setLevel(log_level_console.name)
|
console_handler.setLevel(log_level_console.name)
|
||||||
# do not show exceptions logs on console
|
# do not show exceptions logs on console
|
||||||
console_handler.addFilter(CustomHandlerFilter('console', filter_exceptions))
|
console_handler.addFilter(CustomHandlerFilter('console', filter_exceptions))
|
||||||
console_handler.setFormatter(formatter_console)
|
console_handler.setFormatter(self.__set_console_formatter(console_format_type))
|
||||||
return console_handler
|
return console_handler
|
||||||
|
|
||||||
# MARK: file handler
|
# MARK: file handler
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ def main():
|
|||||||
"log_level_file": 'DEBUG',
|
"log_level_file": 'DEBUG',
|
||||||
# "console_color_output_enabled": False,
|
# "console_color_output_enabled": False,
|
||||||
"per_run_log": True,
|
"per_run_log": True,
|
||||||
# Set console log type, must be sent as value for ConsoleFormat or bitwise of ConsoleFormatType
|
# "console_format_type": ConsoleFormatSettings.NONE,
|
||||||
# "console_format_type": ConsoleFormatSettings.BARE,
|
|
||||||
# "console_format_type": ConsoleFormatSettings.MINIMAL,
|
# "console_format_type": ConsoleFormatSettings.MINIMAL,
|
||||||
# "console_format_type": ConsoleFormatType.TIME_MICROSECONDS | ConsoleFormatType.NAME,
|
"console_format_type": ConsoleFormat.TIME_MICROSECONDS | ConsoleFormat.NAME | ConsoleFormat.LEVEL,
|
||||||
# "console_format_type": ConsoleFormatType.NAME,
|
# "console_format_type": ConsoleFormat.NAME,
|
||||||
"console_format_type": ConsoleFormat.TIME | ConsoleFormat.TIMEZONE | ConsoleFormat.LINENO,
|
# "console_format_type": (
|
||||||
|
# ConsoleFormat.TIME | ConsoleFormat.TIMEZONE | ConsoleFormat.LINENO | ConsoleFormat.LEVEL
|
||||||
|
# ),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
logn = Logger(log.get_logger_settings())
|
logn = Logger(log.get_logger_settings())
|
||||||
@@ -104,10 +105,16 @@ def main():
|
|||||||
|
|
||||||
for key, handler in log.handlers.items():
|
for key, handler in log.handlers.items():
|
||||||
print(f"Handler (handlers) [{key}] {handler} -> {handler.level} -> {LoggingLevel.from_any(handler.level)}")
|
print(f"Handler (handlers) [{key}] {handler} -> {handler.level} -> {LoggingLevel.from_any(handler.level)}")
|
||||||
log.set_log_level('stream_handler', LoggingLevel.ERROR)
|
log.set_log_level(Log.CONSOLE_HANDLER, LoggingLevel.ERROR)
|
||||||
log.logger.warning('[NORMAL] Invisible Warning test: %s', log.logger.name)
|
log.logger.warning('[NORMAL] Invisible Warning test: %s', log.logger.name)
|
||||||
log.logger.error('[NORMAL] Visible Error test: %s', log.logger.name)
|
log.logger.error('[NORMAL] Visible Error test: %s', log.logger.name)
|
||||||
# log.handlers['stream_handler'].se
|
|
||||||
|
log.set_log_level(Log.CONSOLE_HANDLER, LoggingLevel.DEBUG)
|
||||||
|
log.debug('Current logging format: %s', log.log_settings['console_format_type'])
|
||||||
|
log.update_console_formatter(ConsoleFormat.TIME | ConsoleFormat.LINENO)
|
||||||
|
log.info('Does hit show less')
|
||||||
|
log.update_console_formatter(ConsoleFormat.TIME | ConsoleFormat.LINENO)
|
||||||
|
log.info('Does hit show less B')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -153,6 +153,19 @@ class TestLogSettingsParsing:
|
|||||||
|
|
||||||
assert log.log_settings["console_format_type"] == ConsoleFormatSettings.BARE
|
assert log.log_settings["console_format_type"] == ConsoleFormatSettings.BARE
|
||||||
|
|
||||||
|
def test_parse_console_format_type_none(self, tmp_log_path: Path):
|
||||||
|
"""Test parsing with console_format_type set to NONE"""
|
||||||
|
settings: dict[str, Any] = {
|
||||||
|
"console_format_type": ConsoleFormatSettings.NONE,
|
||||||
|
}
|
||||||
|
log = Log(
|
||||||
|
log_path=tmp_log_path,
|
||||||
|
log_name="test",
|
||||||
|
log_settings=settings # type: ignore
|
||||||
|
)
|
||||||
|
|
||||||
|
assert log.log_settings["console_format_type"] == ConsoleFormatSettings.NONE
|
||||||
|
|
||||||
def test_parse_console_format_type_invalid(self, tmp_log_path: Path):
|
def test_parse_console_format_type_invalid(self, tmp_log_path: Path):
|
||||||
"""Test parsing with invalid console_format_type raises TypeError"""
|
"""Test parsing with invalid console_format_type raises TypeError"""
|
||||||
settings: dict[str, Any] = {
|
settings: dict[str, Any] = {
|
||||||
@@ -207,6 +220,11 @@ class TestConsoleFormatSettingsFromString:
|
|||||||
result = ConsoleFormatSettings.from_string('BARE')
|
result = ConsoleFormatSettings.from_string('BARE')
|
||||||
assert result == ConsoleFormatSettings.BARE
|
assert result == ConsoleFormatSettings.BARE
|
||||||
|
|
||||||
|
def test_from_string_none(self):
|
||||||
|
"""Test from_string with 'NONE' returns correct format"""
|
||||||
|
result = ConsoleFormatSettings.from_string('NONE')
|
||||||
|
assert result == ConsoleFormatSettings.NONE
|
||||||
|
|
||||||
def test_from_string_invalid_returns_none(self):
|
def test_from_string_invalid_returns_none(self):
|
||||||
"""Test from_string with invalid string returns None"""
|
"""Test from_string with invalid string returns None"""
|
||||||
result = ConsoleFormatSettings.from_string('INVALID')
|
result = ConsoleFormatSettings.from_string('INVALID')
|
||||||
@@ -234,6 +252,7 @@ class TestConsoleFormatSettingsFromString:
|
|||||||
("CONDENSED", ConsoleFormatSettings.CONDENSED),
|
("CONDENSED", ConsoleFormatSettings.CONDENSED),
|
||||||
("MINIMAL", ConsoleFormatSettings.MINIMAL),
|
("MINIMAL", ConsoleFormatSettings.MINIMAL),
|
||||||
("BARE", ConsoleFormatSettings.BARE),
|
("BARE", ConsoleFormatSettings.BARE),
|
||||||
|
("NONE", ConsoleFormatSettings.NONE),
|
||||||
])
|
])
|
||||||
def test_from_string_all_valid_settings(self, setting_name: str, expected: Any):
|
def test_from_string_all_valid_settings(self, setting_name: str, expected: Any):
|
||||||
"""Test from_string with all valid setting names"""
|
"""Test from_string with all valid setting names"""
|
||||||
|
|||||||
@@ -140,4 +140,172 @@ class TestCustomConsoleFormatter:
|
|||||||
assert "Critical message" in result
|
assert "Critical message" in result
|
||||||
assert "CRITICAL" in result
|
assert "CRITICAL" in result
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: Test update_console_formatter
|
||||||
|
class TestUpdateConsoleFormatter:
|
||||||
|
"""Test cases for update_console_formatter method"""
|
||||||
|
|
||||||
|
def test_update_console_formatter_to_minimal(self, log_instance: Log):
|
||||||
|
"""Test updating console formatter to MINIMAL format"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
|
||||||
|
# Get the console handler's formatter
|
||||||
|
console_handler = log_instance.handlers[log_instance.CONSOLE_HANDLER]
|
||||||
|
formatter = console_handler.formatter
|
||||||
|
|
||||||
|
# Verify formatter was updated
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_update_console_formatter_to_condensed(self, log_instance: Log):
|
||||||
|
"""Test updating console formatter to CONDENSED format"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.CONDENSED)
|
||||||
|
|
||||||
|
# Get the console handler's formatter
|
||||||
|
console_handler = log_instance.handlers[log_instance.CONSOLE_HANDLER]
|
||||||
|
formatter = console_handler.formatter
|
||||||
|
|
||||||
|
# Verify formatter was updated
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_update_console_formatter_to_bare(self, log_instance: Log):
|
||||||
|
"""Test updating console formatter to BARE format"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.BARE)
|
||||||
|
|
||||||
|
# Get the console handler's formatter
|
||||||
|
console_handler = log_instance.handlers[log_instance.CONSOLE_HANDLER]
|
||||||
|
formatter = console_handler.formatter
|
||||||
|
|
||||||
|
# Verify formatter was updated
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_update_console_formatter_to_none(self, log_instance: Log):
|
||||||
|
"""Test updating console formatter to NONE format"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.NONE)
|
||||||
|
|
||||||
|
# Get the console handler's formatter
|
||||||
|
console_handler = log_instance.handlers[log_instance.CONSOLE_HANDLER]
|
||||||
|
formatter = console_handler.formatter
|
||||||
|
|
||||||
|
# Verify formatter was updated
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_update_console_formatter_to_all(self, log_instance: Log):
|
||||||
|
"""Test updating console formatter to ALL format"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.ALL)
|
||||||
|
|
||||||
|
# Get the console handler's formatter
|
||||||
|
console_handler = log_instance.handlers[log_instance.CONSOLE_HANDLER]
|
||||||
|
formatter = console_handler.formatter
|
||||||
|
|
||||||
|
# Verify formatter was updated
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_update_console_formatter_when_disabled(
|
||||||
|
self, tmp_log_path: Path, basic_log_settings: LogSettings
|
||||||
|
):
|
||||||
|
"""Test that update_console_formatter does nothing when console is disabled"""
|
||||||
|
# Disable console
|
||||||
|
basic_log_settings['console_enabled'] = False
|
||||||
|
log = Log(
|
||||||
|
log_path=tmp_log_path,
|
||||||
|
log_name="test_log",
|
||||||
|
log_settings=basic_log_settings
|
||||||
|
)
|
||||||
|
|
||||||
|
# This should not raise an error and should return early
|
||||||
|
log.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
|
||||||
|
# Verify console handler doesn't exist
|
||||||
|
assert log.CONSOLE_HANDLER not in log.handlers
|
||||||
|
|
||||||
|
def test_update_console_formatter_with_color_enabled(
|
||||||
|
self, tmp_log_path: Path, basic_log_settings: LogSettings
|
||||||
|
):
|
||||||
|
"""Test updating console formatter with color output enabled"""
|
||||||
|
basic_log_settings['console_color_output_enabled'] = True
|
||||||
|
log = Log(
|
||||||
|
log_path=tmp_log_path,
|
||||||
|
log_name="test_log",
|
||||||
|
log_settings=basic_log_settings
|
||||||
|
)
|
||||||
|
|
||||||
|
log.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
|
||||||
|
# Get the console handler's formatter
|
||||||
|
console_handler = log.handlers[log.CONSOLE_HANDLER]
|
||||||
|
formatter = console_handler.formatter
|
||||||
|
|
||||||
|
# Verify formatter is CustomConsoleFormatter when colors enabled
|
||||||
|
assert isinstance(formatter, CustomConsoleFormatter)
|
||||||
|
|
||||||
|
def test_update_console_formatter_without_color(self, log_instance: Log):
|
||||||
|
"""Test updating console formatter without color output"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
|
||||||
|
# Get the console handler's formatter
|
||||||
|
console_handler = log_instance.handlers[log_instance.CONSOLE_HANDLER]
|
||||||
|
formatter = console_handler.formatter
|
||||||
|
|
||||||
|
# Verify formatter is standard Formatter when colors disabled
|
||||||
|
assert isinstance(formatter, logging.Formatter)
|
||||||
|
# But not the colored version
|
||||||
|
assert not isinstance(formatter, CustomConsoleFormatter)
|
||||||
|
|
||||||
|
def test_update_console_formatter_multiple_times(self, log_instance: Log):
|
||||||
|
"""Test updating console formatter multiple times"""
|
||||||
|
# Update to MINIMAL
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
console_handler = log_instance.handlers[log_instance.CONSOLE_HANDLER]
|
||||||
|
formatter1 = console_handler.formatter
|
||||||
|
|
||||||
|
# Update to CONDENSED
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.CONDENSED)
|
||||||
|
formatter2 = console_handler.formatter
|
||||||
|
|
||||||
|
# Update to ALL
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.ALL)
|
||||||
|
formatter3 = console_handler.formatter
|
||||||
|
|
||||||
|
# Verify each update created a new formatter
|
||||||
|
assert formatter1 is not formatter2
|
||||||
|
assert formatter2 is not formatter3
|
||||||
|
assert formatter1 is not formatter3
|
||||||
|
|
||||||
|
def test_update_console_formatter_preserves_handler_level(self, log_instance: Log):
|
||||||
|
"""Test that updating formatter preserves the handler's log level"""
|
||||||
|
original_level = log_instance.handlers[log_instance.CONSOLE_HANDLER].level
|
||||||
|
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
|
||||||
|
new_level = log_instance.handlers[log_instance.CONSOLE_HANDLER].level
|
||||||
|
assert original_level == new_level
|
||||||
|
|
||||||
|
def test_update_console_formatter_format_output(
|
||||||
|
self, log_instance: Log, caplog: pytest.LogCaptureFixture
|
||||||
|
):
|
||||||
|
"""Test that updated formatter actually affects log output"""
|
||||||
|
# Set to BARE format (message only)
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.BARE)
|
||||||
|
|
||||||
|
# Configure caplog to capture at the appropriate level
|
||||||
|
with caplog.at_level(logging.WARNING):
|
||||||
|
log_instance.warning("Test warning message")
|
||||||
|
|
||||||
|
# Verify message was logged
|
||||||
|
assert "Test warning message" in caplog.text
|
||||||
|
|
||||||
|
def test_update_console_formatter_none_format_output(
|
||||||
|
self, log_instance: Log, caplog: pytest.LogCaptureFixture
|
||||||
|
):
|
||||||
|
"""Test that NONE formatter outputs only the message without any formatting"""
|
||||||
|
# Set to NONE format (message only, no level indicator)
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.NONE)
|
||||||
|
|
||||||
|
# Configure caplog to capture at the appropriate level
|
||||||
|
with caplog.at_level(logging.WARNING):
|
||||||
|
log_instance.warning("Test warning message")
|
||||||
|
|
||||||
|
# Verify message was logged
|
||||||
|
assert "Test warning message" in caplog.text
|
||||||
|
|
||||||
# __END__
|
# __END__
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from corelibs.logging_handling.log import (
|
|||||||
LogParent,
|
LogParent,
|
||||||
LogSettings,
|
LogSettings,
|
||||||
ConsoleFormatSettings,
|
ConsoleFormatSettings,
|
||||||
|
ConsoleFormat,
|
||||||
)
|
)
|
||||||
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
|
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
|
||||||
|
|
||||||
@@ -108,4 +109,101 @@ class TestHandlerManagement:
|
|||||||
result2 = log.add_handler("test", handler2)
|
result2 = log.add_handler("test", handler2)
|
||||||
assert result2 is False
|
assert result2 is False
|
||||||
|
|
||||||
|
def test_change_console_format_to_minimal(self, log_instance: Log):
|
||||||
|
"""Test changing console handler format to MINIMAL"""
|
||||||
|
original_formatter = log_instance.handlers[log_instance.CONSOLE_HANDLER].formatter
|
||||||
|
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
|
||||||
|
new_formatter = log_instance.handlers[log_instance.CONSOLE_HANDLER].formatter
|
||||||
|
assert new_formatter is not original_formatter
|
||||||
|
assert new_formatter is not None
|
||||||
|
|
||||||
|
def test_change_console_format_to_condensed(self, log_instance: Log):
|
||||||
|
"""Test changing console handler format to CONDENSED"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.CONDENSED)
|
||||||
|
|
||||||
|
formatter = log_instance.handlers[log_instance.CONSOLE_HANDLER].formatter
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_change_console_format_to_bare(self, log_instance: Log):
|
||||||
|
"""Test changing console handler format to BARE"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.BARE)
|
||||||
|
|
||||||
|
formatter = log_instance.handlers[log_instance.CONSOLE_HANDLER].formatter
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_change_console_format_to_none(self, log_instance: Log):
|
||||||
|
"""Test changing console handler format to NONE"""
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.NONE)
|
||||||
|
|
||||||
|
formatter = log_instance.handlers[log_instance.CONSOLE_HANDLER].formatter
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_change_console_format_to_all(self, log_instance: Log):
|
||||||
|
"""Test changing console handler format to ALL"""
|
||||||
|
# Start with a different format
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
|
||||||
|
log_instance.update_console_formatter(ConsoleFormatSettings.ALL)
|
||||||
|
|
||||||
|
formatter = log_instance.handlers[log_instance.CONSOLE_HANDLER].formatter
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
def test_change_console_format_multiple_times(self, log_instance: Log):
|
||||||
|
"""Test changing console handler format multiple times"""
|
||||||
|
formatters: list[logging.Formatter | None] = []
|
||||||
|
|
||||||
|
for format_type in [
|
||||||
|
ConsoleFormatSettings.MINIMAL,
|
||||||
|
ConsoleFormatSettings.CONDENSED,
|
||||||
|
ConsoleFormatSettings.BARE,
|
||||||
|
ConsoleFormatSettings.NONE,
|
||||||
|
ConsoleFormatSettings.ALL,
|
||||||
|
]:
|
||||||
|
log_instance.update_console_formatter(format_type)
|
||||||
|
formatter = log_instance.handlers[log_instance.CONSOLE_HANDLER].formatter
|
||||||
|
formatters.append(formatter)
|
||||||
|
assert formatter is not None
|
||||||
|
|
||||||
|
# Verify each formatter is unique (new instance each time)
|
||||||
|
for i, formatter in enumerate(formatters):
|
||||||
|
for j, other_formatter in enumerate(formatters):
|
||||||
|
if i != j:
|
||||||
|
assert formatter is not other_formatter
|
||||||
|
|
||||||
|
def test_change_console_format_with_disabled_console(
|
||||||
|
self, tmp_log_path: Path, basic_log_settings: LogSettings
|
||||||
|
):
|
||||||
|
"""Test changing console format when console is disabled does nothing"""
|
||||||
|
basic_log_settings['console_enabled'] = False
|
||||||
|
log = Log(
|
||||||
|
log_path=tmp_log_path,
|
||||||
|
log_name="test_log",
|
||||||
|
log_settings=basic_log_settings
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should not raise error, just return early
|
||||||
|
log.update_console_formatter(ConsoleFormatSettings.MINIMAL)
|
||||||
|
|
||||||
|
# Console handler should not exist
|
||||||
|
assert log.CONSOLE_HANDLER not in log.handlers
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("format_type", [
|
||||||
|
ConsoleFormatSettings.ALL,
|
||||||
|
ConsoleFormatSettings.CONDENSED,
|
||||||
|
ConsoleFormatSettings.MINIMAL,
|
||||||
|
ConsoleFormatSettings.BARE,
|
||||||
|
ConsoleFormatSettings.NONE,
|
||||||
|
])
|
||||||
|
def test_change_console_format_parametrized(
|
||||||
|
self, log_instance: Log, format_type: ConsoleFormat # type: ignore
|
||||||
|
):
|
||||||
|
"""Test changing console format with all format types"""
|
||||||
|
log_instance.update_console_formatter(format_type)
|
||||||
|
|
||||||
|
formatter = log_instance.handlers[log_instance.CONSOLE_HANDLER].formatter
|
||||||
|
assert formatter is not None
|
||||||
|
assert isinstance(formatter, logging.Formatter)
|
||||||
|
|
||||||
# __END__
|
# __END__
|
||||||
|
|||||||
2
uv.lock
generated
2
uv.lock
generated
@@ -108,7 +108,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "corelibs"
|
name = "corelibs"
|
||||||
version = "0.37.0"
|
version = "0.39.2"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "corelibs-datetime" },
|
{ name = "corelibs-datetime" },
|
||||||
|
|||||||
Reference in New Issue
Block a user