From 5bb0a582abb0d04cb94ec731075e2855fd4db621 Mon Sep 17 00:00:00 2001 From: Zen Date: Sun, 12 Jul 2026 13:42:21 -0500 Subject: [PATCH 1/5] remove dumb setattr logging, improve typing Signed-off-by: Zen --- src/zenlib/logging/loggermixin.py | 7 ++----- src/zenlib/logging/utils.py | 31 ++++++------------------------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/zenlib/logging/loggermixin.py b/src/zenlib/logging/loggermixin.py index a003193..e651283 100644 --- a/src/zenlib/logging/loggermixin.py +++ b/src/zenlib/logging/loggermixin.py @@ -1,9 +1,9 @@ __author__ = "desultory" -__version__ = "1.3.1" +__version__ = "1.4.0" from logging import Logger, getLogger -from zenlib.logging.utils import add_handler_if_not_exists, handle_additional_logging, log_init +from zenlib.logging.utils import add_handler_if_not_exists, log_init class LoggerMixIn: @@ -39,6 +39,3 @@ def init_logger(self, args, kwargs): # 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/utils.py b/src/zenlib/logging/utils.py index 2381466..2d2557c 100644 --- a/src/zenlib/logging/utils.py +++ b/src/zenlib/logging/utils.py @@ -5,7 +5,7 @@ from zenlib.logging.colorlognameformatter import ColorLognameFormatter -def _logger_has_handler(logger): +def _logger_has_handler(logger: Logger | None) -> bool: """Checks if a logger or its parents has a handler already""" while logger: if logger.handlers: @@ -14,7 +14,7 @@ def _logger_has_handler(logger): return False -def add_handler_if_not_exists(logger): +def add_handler_if_not_exists(logger: Logger) -> None: """Adds a ColorLognameFormatter handler to the logger if it doesn't have a handler already Coloring is diabled by the _ZENLIB_COLOR_TEXT variable in the colorize function """ @@ -28,7 +28,7 @@ def add_handler_if_not_exists(logger): logger.info("Added default handler to logger: %s", logger) -def log_init(self, args, kwargs): +def log_init(self, args, kwargs) -> None: """If _log_init is in the kwargs and set to True, logs init args, kwargs, class name, and version""" class_name = self.__class__.__name__ logger = self.logger @@ -46,31 +46,12 @@ def log_init(self, args, kwargs): try: logger.info("[%s] Package version: %s" % (package_name, version(package_name))) except (NameError, PackageNotFoundError) as ex: - if ex.msg != "No package metadata was found for builtins": - logger.debug("[%s] Package version not found for: %s" % (class_name, package_name)) + if str(ex) == "No package metadata was found for builtins": + package_name = "builtins" + logger.debug(f"[{class_name}] Package version not found for: {package_name}") if module_version := getattr(modules.get(self.__module__), "__version__", None): logger.info("[%s] Module version: %s" % (self.__module__, module_version)) if class_version := getattr(self, "__version__", None): logger.info("[%s] Class version: %s" % (class_name, class_version)) - - -def handle_additional_logging(self, kwargs): - """Sets __setattr__ to log_setattr if _log_setattr is in the kwargs and set to True""" - if kwargs.pop("_log_setattr", False): - setattr(self, "__setattr__", log_setattr) - - -def log_setattr(self, name, value): - """Logs when an attribute is set""" - super().__setattr__(name, value) - # check if the logger is defined - if not isinstance(self.logger, Logger): - raise ValueError("Logger is not defined") - - # Log containers or strings with newlines on a new line - if isinstance(value, list) or isinstance(value, dict) or isinstance(value, str) and "\n" in value: - self.logger.log(5, "Setattr '%s' to:\n%s" % (name, getattr(self, name))) - else: - self.logger.log(5, "Setattr '%s' to: %s" % (name, getattr(self, name))) From 17e9b02362ec9b3cea9f3c531f9e99f628487021 Mon Sep 17 00:00:00 2001 From: Zen Date: Sun, 12 Jul 2026 13:45:41 -0500 Subject: [PATCH 2/5] use fstrings Signed-off-by: Zen --- src/zenlib/logging/utils.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/zenlib/logging/utils.py b/src/zenlib/logging/utils.py index 2d2557c..e9969a8 100644 --- a/src/zenlib/logging/utils.py +++ b/src/zenlib/logging/utils.py @@ -16,7 +16,7 @@ def _logger_has_handler(logger: Logger | None) -> bool: def add_handler_if_not_exists(logger: Logger) -> None: """Adds a ColorLognameFormatter handler to the logger if it doesn't have a handler already - Coloring is diabled by the _ZENLIB_COLOR_TEXT variable in the colorize function + Coloring is disabled by the _ZENLIB_COLOR_TEXT variable in the colorize function """ if _logger_has_handler(logger): return @@ -25,7 +25,7 @@ def add_handler_if_not_exists(logger: Logger) -> None: stream_handler.setFormatter(formatter) logger.addHandler(stream_handler) - logger.info("Added default handler to logger: %s", logger) + logger.info(f"Added default handler to logger: {logger}") def log_init(self, args, kwargs) -> None: @@ -33,25 +33,25 @@ def log_init(self, args, kwargs) -> None: class_name = self.__class__.__name__ logger = self.logger if not kwargs.pop("_log_init", False): - return logger.log(5, "Init logging disabled for class: %s", class_name) + return logger.log(5, f"Init logging disabled for class: {class_name}") - logger.info("Initializing class: %s", class_name) + logger.info(f"Initializing class: {class_name}") if args: - logger.debug("[%s] Init args: %s" % (class_name, args)) + logger.debug(f"[{class_name}] Init args: {args}") if kwargs: - logger.debug("[%s] Init kwargs: %s" % (class_name, kwargs)) + logger.debug(f"[{class_name}] Init kwargs: {kwargs}") package_name = self.__module__.split(".")[0] try: - logger.info("[%s] Package version: %s" % (package_name, version(package_name))) + logger.info(f"[{package_name}] Package version: {version(package_name)}") except (NameError, PackageNotFoundError) as ex: if str(ex) == "No package metadata was found for builtins": package_name = "builtins" logger.debug(f"[{class_name}] Package version not found for: {package_name}") if module_version := getattr(modules.get(self.__module__), "__version__", None): - logger.info("[%s] Module version: %s" % (self.__module__, module_version)) + logger.info(f"[{self.__module__}] Module version: {module_version}") if class_version := getattr(self, "__version__", None): - logger.info("[%s] Class version: %s" % (class_name, class_version)) + logger.info(f"[{class_name}] Class version: {class_version}") From 2a4397d7012b598611786c69b5961f0ee5523cf1 Mon Sep 17 00:00:00 2001 From: Zen Date: Sun, 12 Jul 2026 14:01:52 -0500 Subject: [PATCH 3/5] clean up logger init, add type hints Signed-off-by: Zen --- src/zenlib/logging/loggermixin.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/zenlib/logging/loggermixin.py b/src/zenlib/logging/loggermixin.py index e651283..3c3d8f3 100644 --- a/src/zenlib/logging/loggermixin.py +++ b/src/zenlib/logging/loggermixin.py @@ -15,9 +15,10 @@ class LoggerMixIn: Otherwise, the log level is not set, and the logger will use the parent's level. """ - def init_logger(self, args, kwargs): + def init_logger(self, args, kwargs) -> None: # 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__) @@ -25,14 +26,8 @@ def init_logger(self, args, kwargs): # Set the logger's level if _log_level is passed self.logger.setLevel(log_level) elif log_bump := kwargs.pop("_log_bump", None): - # get the parent logger's level, or the parent's parent logger's level - parent_logger = self.logger.parent - while parent_logger: - if parent_logger.level != 0: - break - parent_logger = parent_logger.parent - - self.logger.setLevel(parent_logger.level + log_bump) + # bump the class's logger using the level of the parent logger + self.logger.setLevel(parent_logger.getEffectiveLevel() + log_bump) # Add a colored stream handler if one does not exist add_handler_if_not_exists(self.logger) From 7206241ea995b9ae28839a80da514b2f22910d20 Mon Sep 17 00:00:00 2001 From: Zen Date: Sun, 12 Jul 2026 14:05:34 -0500 Subject: [PATCH 4/5] default to log level 5 for handle_plural also use fstrings level 10 was a bit noisy Signed-off-by: Zen --- src/zenlib/util/handle_plural.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/zenlib/util/handle_plural.py b/src/zenlib/util/handle_plural.py index 6cd1c60..aa8c5a1 100644 --- a/src/zenlib/util/handle_plural.py +++ b/src/zenlib/util/handle_plural.py @@ -4,7 +4,7 @@ from collections.abc import KeysView, ValuesView -def handle_plural(function, log_level=10): +def handle_plural(function, log_level=5): """ Wraps functions to take a list/dict and iterate over it. The last passed argument should be the iterable. @@ -24,23 +24,23 @@ def log(msg, level=log_level): other_args = args[:-1] if isinstance(focus_arg, list) and not isinstance(focus_arg, str): - log("Expanding list: %s" % focus_arg) + log(f"Expanding list: {focus_arg}") for item in focus_arg: function(self, *(other_args + (item,)), **kwargs) elif isinstance(focus_arg, set): - log("Expanding set: %s" % focus_arg) + log(f"Expanding set: {focus_arg}") for item in focus_arg: function(self, *(other_args + (item,)), **kwargs) elif isinstance(focus_arg, ValuesView): - log("Expanding dict values: %s" % focus_arg) + log(f"Expanding dict values: {focus_arg}") for value in focus_arg: function(self, *(other_args + (value,)), **kwargs) elif isinstance(focus_arg, KeysView): - log("Expanding dict keys: %s" % focus_arg) + log(f"Expanding dict keys: {focus_arg}") for key in focus_arg: function(self, *(other_args + (key,)), **kwargs) elif isinstance(focus_arg, dict): - log("Expanding dict: %s" % focus_arg) + log(f"Expanding dict: {focus_arg}") for key, value in focus_arg.items(): function( self, From c9020b14bbf0cd8296dd0a2c0a4390af6a52a800 Mon Sep 17 00:00:00 2001 From: Zen Date: Sun, 12 Jul 2026 14:20:58 -0500 Subject: [PATCH 5/5] improve typing for handle_plural Signed-off-by: Zen --- src/zenlib/util/handle_plural.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/zenlib/util/handle_plural.py b/src/zenlib/util/handle_plural.py index aa8c5a1..efe7370 100644 --- a/src/zenlib/util/handle_plural.py +++ b/src/zenlib/util/handle_plural.py @@ -2,23 +2,24 @@ __version__ = "2.2.1" from collections.abc import KeysView, ValuesView +from typing import Any, Callable -def handle_plural(function, log_level=5): +def handle_plural(function: Callable[..., Any], log_level: int = 5) -> Callable[..., Any]: """ Wraps functions to take a list/dict and iterate over it. The last passed argument should be the iterable. Logs using the logger attribute if it exists. """ - def wrapper(self, *args, **kwargs): - def log(msg, level=log_level): + def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: + def log(msg: str, level: int = log_level): if hasattr(self, "logger"): self.logger.log(level, msg) if len(args) == 1: focus_arg = args[0] - other_args = tuple() + other_args: tuple[Any, ...] = tuple() else: focus_arg = args[-1] other_args = args[:-1]