diff --git a/CHANGELOG.md b/CHANGELOG.md index 8922767..4790ff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * removed deprecated alias `entity_base()`. use `declarative_base()` instead. * fix imports. + Module `functools`: add `cooldown()` ++ Module `color`: add `ColorFormatter()` ## 0.12.6 diff --git a/src/suou/__init__.py b/src/suou/__init__.py index c90e37c..8b51746 100644 --- a/src/suou/__init__.py +++ b/src/suou/__init__.py @@ -35,13 +35,15 @@ from .strtools import PrefixIdentifier from .validators import matches, not_less_than, not_greater_than, yesno from .redact import redact_url_password from .http import WantsContentType -from .color import OKLabColor, chalk, WebColor, RGBColor, LinearRGBColor, XYZColor, OKLCHColor +from .color import OKLabColor, chalk, WebColor, RGBColor, LinearRGBColor, \ + XYZColor, OKLCHColor, ColorFormatter from .mat import Matrix from .argparse import LetterSubparsers -__version__ = "0.13.0a2" +__version__ = "0.13.0a3" __all__ = ( + 'ColorFormatter', 'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue', 'DictConfigSource', 'EnvConfigSource', 'I18n', 'Incomplete', 'JsonI18n', 'LetterSubparsers', 'LinearRGBColor', diff --git a/src/suou/argparse.py b/src/suou/argparse.py index c235a30..563d6be 100644 --- a/src/suou/argparse.py +++ b/src/suou/argparse.py @@ -19,7 +19,7 @@ from __future__ import annotations import argparse import sys -from typing import Callable, Mapping +from typing import Callable class LetterSubparsers(object): """ diff --git a/src/suou/color.py b/src/suou/color.py index 26bf060..5755a9c 100644 --- a/src/suou/color.py +++ b/src/suou/color.py @@ -21,6 +21,7 @@ from __future__ import annotations from collections import namedtuple from functools import lru_cache +import logging import math from suou.functools import deprecated @@ -331,4 +332,48 @@ class OKLCHColor(namedtuple('_OKLCHColor', 'l c h')): return sum(abs(i - j) / k for i, j, k in zip(self, other, (1, 1, 36))) -__all__ = ('chalk', 'WebColor', "RGBColor", 'LinearRGBColor', 'XYZColor', 'OKLabColor', 'OKLCHColor') +class ColorFormatter(logging.Formatter): + """ + Colored logging formatter. + + Opinionated. + + Taken from https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output + """ + + def _get_base_format(color): + return f"[%(asctime)s] {color('%(levelname)s')}{chalk.grey(': ')}{color('%(name)s')}{chalk.grey(': ')}%(message)s" + + FORMATS = { + logging.DEBUG: _get_base_format(chalk.cyan), + logging.INFO: _get_base_format(chalk.green), + logging.WARNING: _get_base_format(chalk.yellow), + logging.ERROR: _get_base_format(chalk.red), + logging.CRITICAL: _get_base_format(chalk.bold.red) + } + + del _get_base_format + + def format(self, record: logging.LogRecord) -> str: + log_fmt = self.FORMATS.get(record.levelno) + formatter = logging.Formatter(log_fmt) + return formatter.format(record) + + @classmethod + def apply_handler(cls, logger: logging.Logger, level = logging.INFO): + """ + Apply the colored formatter to a logger. + + Use this with logging.root, instead of logging.basicConfig(). + + Should not be called more than once. + """ + logger.setLevel(level) + ch = logging.StreamHandler() + ch.setLevel(level) + ch.setFormatter(cls()) + logger.addHandler(ch) + + +__all__ = ('chalk', 'WebColor', "RGBColor", 'LinearRGBColor', 'XYZColor', + 'OKLabColor', 'OKLCHColor', 'ColorFormatter')