diff --git a/pyproject.toml b/pyproject.toml index 659c56e..37455f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "zenlib" -version = "3.0.0" +version = "3.0.1" authors = [ { name="Desultory", email="dev@pyl.onl" }, ] diff --git a/src/zenlib/logging/__init__.py b/src/zenlib/logging/__init__.py index f5b6ff0..c0fdd45 100644 --- a/src/zenlib/logging/__init__.py +++ b/src/zenlib/logging/__init__.py @@ -1,6 +1,7 @@ from .colorlognameformatter import ColorLognameFormatter +from .classlogger import ClassLogger from .loggify import loggify +from .loggermixin import LoggerMixIn from .log_call import log_call -from .classlogger import ClassLogger -__all__ = ['ColorLognameFormatter', 'loggify', 'log_call', 'ClassLogger'] +__all__ = ["ColorLognameFormatter", "loggify", "LoggerMixIn", "log_call", "ClassLogger"] diff --git a/src/zenlib/logging/classlogger.py b/src/zenlib/logging/classlogger.py index dcf39d1..4ac359b 100644 --- a/src/zenlib/logging/classlogger.py +++ b/src/zenlib/logging/classlogger.py @@ -1,28 +1,12 @@ __author__ = "desultory" -__version__ = "2.2.0" +__version__ = "3.0.0" -from .utils import add_handler_if_not_exists, log_init, handle_additional_logging +from .loggermixin import LoggerMixIn -from logging import Logger, getLogger - -class ClassLogger: +class ClassLogger(LoggerMixIn): def __init__(self, *args, **kwargs): - # Get the parent logger from the root if one was not passed - parent_logger = kwargs.pop('logger') if isinstance(kwargs.get('logger'), Logger) else getLogger() - # Get a child logger from the parent logger, set self.logger - self.logger = parent_logger.getChild(self.__class__.__name__) - # Bump the log level if _log_bump is passed - self.logger.setLevel(self.logger.parent.level + kwargs.pop('_log_bump', 0)) - - # Add a colored stream handler if one does not exist - add_handler_if_not_exists(self.logger) - - # Log class init if _log_init is passed - log_init(self, args, kwargs) - - # Add logging to _log_setattr if set - handle_additional_logging(self, kwargs) + self.init_logger(args, kwargs) if super().__class__.__class__ is not type: super().__init__(*args, **kwargs) diff --git a/src/zenlib/logging/colorlognameformatter.py b/src/zenlib/logging/colorlognameformatter.py index 3256493..203c09c 100644 --- a/src/zenlib/logging/colorlognameformatter.py +++ b/src/zenlib/logging/colorlognameformatter.py @@ -1,10 +1,8 @@ __author__ = "desultory" -__version__ = "3.0.0" +__version__ = "3.1.0" from logging import Formatter -from zenlib.util import colorize - class ColorLognameFormatter(Formatter): """A logging formatter which colors the levelname of the log message. @@ -12,7 +10,7 @@ class ColorLognameFormatter(Formatter): Normal levelnames are padded to the length of the longest levelname.""" level_colors = { - "DEBUG": {"color": "white"}, + "DEBUG": {"color": "white", "bright": True}, "INFO": {"color": "blue"}, "WARNING": {"color": "yellow"}, "ERROR": {"color": "red", "bold": True}, @@ -21,11 +19,13 @@ class ColorLognameFormatter(Formatter): def __init__(self, fmt="%(levelname)s | %(message)s", *args, **kwargs): super().__init__(fmt, *args, **kwargs) - self.level_str_width = max(len(name) for name in self.level_colors) - 1 + self.level_str_width = max(len(name) for name in self.level_colors) def format(self, record): # When calling format, replace the levelname with a colored version # Note: the string size is greatly increased because of the color codes + from zenlib.util import colorize + old_levelname = record.levelname color_info = self.level_colors.get(record.levelname, {"color": "white"}) record.levelname = colorize(record.levelname.ljust(self.level_str_width), **color_info) diff --git a/src/zenlib/logging/loggermixin.py b/src/zenlib/logging/loggermixin.py new file mode 100644 index 0000000..c3eca38 --- /dev/null +++ b/src/zenlib/logging/loggermixin.py @@ -0,0 +1,25 @@ +__author__ = "desultory" +__version__ = "1.2.0" + +from logging import Logger, getLogger + +from .utils import add_handler_if_not_exists, handle_additional_logging, log_init + + +class LoggerMixIn: + def init_logger(self, args, kwargs): + # Get the parent logger from the root if one was not passed + parent_logger = kwargs.pop("logger") if isinstance(kwargs.get("logger"), Logger) else getLogger() + # Get a child logger from the parent logger, set self.logger + self.logger = parent_logger.getChild(self.__class__.__name__) + # Bump the log level if _log_bump is passed + self.logger.setLevel(self.logger.parent.level + kwargs.pop("_log_bump", 0)) + + # Add a colored stream handler if one does not exist + add_handler_if_not_exists(self.logger) + + # Log class init if _log_init is passed + log_init(self, args, kwargs) + + # Add logging to _log_setattr if set + handle_additional_logging(self, kwargs) diff --git a/src/zenlib/logging/loggify.py b/src/zenlib/logging/loggify.py index f52215a..41c1683 100644 --- a/src/zenlib/logging/loggify.py +++ b/src/zenlib/logging/loggify.py @@ -1,32 +1,15 @@ __author__ = "desultory" -__version__ = "2.4.2" - -from logging import Logger, getLogger +__version__ = "3.0.0" from zenlib.util import merge_class -from .utils import add_handler_if_not_exists, log_init, handle_additional_logging +from .loggermixin import LoggerMixIn def loggify(cls): - class ClassLogger(cls): + class ClassLogger(cls, LoggerMixIn): def __init__(self, *args, **kwargs): - # Get the parent logger from the root if one was not passed - parent_logger = kwargs.pop("logger") if isinstance(kwargs.get("logger"), Logger) else getLogger() - # Get a child logger from the parent logger, set self.logger - self.logger = parent_logger.getChild(cls.__name__) - # Bump the log level if _log_bump is passed - self.logger.setLevel(self.logger.parent.level + kwargs.pop("_log_bump", 0)) - - # Add a colored stream handler if one does not exist - add_handler_if_not_exists(self.logger) - - # Log class init if _log_init is passed - log_init(self, args, kwargs) - - # Add logging to _log_setattr if set - handle_additional_logging(self, kwargs) - + self.init_logger(args, kwargs) super().__init__(*args, **kwargs) merge_class(cls, ClassLogger, ignored_attributes=["__setattr__"]) diff --git a/src/zenlib/types/validated_dataclass.py b/src/zenlib/types/validated_dataclass.py index c0ff115..abc99b4 100644 --- a/src/zenlib/types/validated_dataclass.py +++ b/src/zenlib/types/validated_dataclass.py @@ -1,11 +1,11 @@ from dataclasses import dataclass from typing import get_type_hints -from zenlib.util import merge_class -from zenlib.logging import loggify - def validatedDataclass(cls): + from zenlib.logging import loggify + from zenlib.util import merge_class + cls = loggify(dataclass(cls)) class ValidatedDataclass(cls): @@ -28,5 +28,5 @@ def _validate_attribute(self, attribute, value): raise TypeError(f"[{attribute}] Type mismatch: '{expected_type}' != {type(value)}") return value - merge_class(cls, ValidatedDataclass, ignored_attributes = ["__setattr__"]) + merge_class(cls, ValidatedDataclass, ignored_attributes=["__setattr__"]) return ValidatedDataclass diff --git a/src/zenlib/util/__init__.py b/src/zenlib/util/__init__.py index 48b82cb..bbeaf64 100644 --- a/src/zenlib/util/__init__.py +++ b/src/zenlib/util/__init__.py @@ -1,10 +1,11 @@ -from .dict_check import contains, unset from .colorize import colorize +from .dict_check import contains, unset from .handle_plural import handle_plural from .main_funcs import get_args_n_logger, get_kwargs, get_kwargs_from_args, init_argparser, init_logger, process_args from .merge_class import merge_class from .pretty_print import pretty_print from .replace_file_line import replace_file_line +from ..types import NoDupFlatList __all__ = [ "handle_plural", diff --git a/tests/test_nodupflatlist.py b/tests/test_nodupflatlist.py index 2e954b3..8120661 100644 --- a/tests/test_nodupflatlist.py +++ b/tests/test_nodupflatlist.py @@ -4,6 +4,10 @@ class TestNoDupFlatList(TestCase): + def test_util_import(self): + from zenlib.util import NoDupFlatList as NDFL + self.assertEqual(NoDupFlatList, NDFL) + def test_dedup1(self): test_list = NoDupFlatList(no_warn=True) test_list += 1