Logging

Thin wrapper around the shared application logger.

The class provides a simple console_print method used by the GUI to write messages to the configured logger identified by constants.LOG_NAME.

Source code in utils\logging.py
14
15
16
17
18
19
20
21
22
23
24
class ConsoleLogging:
    """Thin wrapper around the shared application logger.

    The class provides a simple ``console_print`` method used by the GUI to
    write messages to the configured logger identified by ``constants.LOG_NAME``.
    """
    def __init__(self):
        self.logger = logging.getLogger(constants.LOG_NAME)

    def console_print(self, level=10, message=None):
        self.logger.log(level, message)
Logging decorator usable as

@with_logging @with_logging() @with_logging(log_level=...)

Source code in utils\logging.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def with_logging(func=None, *, log_level: int = 10):
    """
    Logging decorator usable as:
        @with_logging
        @with_logging()
        @with_logging(log_level=...)
    """
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            logger = logging.getLogger(constants.LOG_NAME)
            logger.log(log_level, f"Calling {func.__qualname__}")
            value = func(*args, **kwargs)
            logger.log(log_level, f"Finished calling {func.__qualname__}")
            return value
        return wrapper

    # CASE 1: @with_logging  → func is the decorated function
    if callable(func):
        return decorator(func)

    # CASE 2: @with_logging(...) → func is None, return real decorator
    return decorator

Class decorator that wraps explicitly defined methods on a class with with_logging, without touching Qt signals or other descriptors.

  • Only items in cls.__dict__ that are real functions (or class/staticmethods) are wrapped.
  • By default, public methods (no leading underscore) are wrapped.
  • You can narrow/adjust behaviour with include / exclude.
Source code in utils\logging.py
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def decorate_class_with_logging(
    log_level: int = 10,
    include: set[str] | None = None,
    exclude: set[str] | None = None,
):
    """
    Class decorator that wraps explicitly defined *methods* on a class
    with `with_logging`, without touching Qt signals or other descriptors.

    - Only items in `cls.__dict__` that are real functions (or class/staticmethods)
      are wrapped.
    - By default, public methods (no leading underscore) are wrapped.
    - You can narrow/adjust behaviour with `include` / `exclude`.
    """

    def decorator(cls):
        for name, attr in cls.__dict__.items():
            # unwrap classmethod / staticmethod
            is_classmethod = isinstance(attr, classmethod)
            is_staticmethod = isinstance(attr, staticmethod)
            func = attr.__func__ if (is_classmethod or is_staticmethod) else attr

            # only wrap *real* functions, not pyqtSignal, properties, etc.
            if not isinstance(func, FunctionType):
                continue

            # skip dunder + private-ish names
            if name.startswith("__") and name.endswith("__"):
                continue
            if name.startswith("_"):
                continue

            # optional filters
            if include is not None and name not in include:
                continue
            if exclude is not None and name in exclude:
                continue

            # your existing with_logging(func, log_level=...)
            wrapped_func = with_logging(func, log_level=log_level)

            # re-wrap as classmethod/staticmethod if needed
            if is_classmethod:
                wrapped_attr = classmethod(wrapped_func)
            elif is_staticmethod:
                wrapped_attr = staticmethod(wrapped_func)
            else:
                wrapped_attr = wrapped_func

            setattr(cls, name, wrapped_attr)

        return cls

    return decorator