Skip to content

Simplify ColorFormatter and keep level names when color is off - #18

Merged
ESultanik merged 1 commit into
masterfrom
logger-cleanup
Aug 7, 2026
Merged

Simplify ColorFormatter and keep level names when color is off#18
ESultanik merged 1 commit into
masterfrom
logger-cleanup

Conversation

@ESultanik

@ESultanik ESultanik commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Stacked on #17.

ColorFormatter reached logging.Formatter through a ComposableFormatter that wrapped a formatter and forwarded every attribute via __getattr__. That returns Any, so type checking was silently disabled on everything it delegated — to support one level of composition that was never reused. It now subclasses logging.Formatter directly, with that class's parameters spelled out rather than forwarded through *args, **kwargs, which typed them as object.

Behaviour fix

With color disabled, format returned record.getMessage() for every level, not just INFO. Redirecting stderr to a file therefore discarded the level entirely, and an ERROR read as ordinary prose:

use_color=True:  '\x1b[0m\x1b[1;31m\x1b[1mERROR   \x1b[0m disk full'
use_color=False: 'disk full'           # before
use_color=False: 'ERROR    disk full'  # after

INFO stays bare at either setting, which is the intended conversational case.

Also replaces the %-formatting with an ansi_color() helper and f-strings, and corrects the format(self, *args, **kwargs) signature to format(self, record).

Verification

First tests for this module: 17 cases covering the INFO special case, per-level coloring, $LEVELCOLOR resolving per record, placeholder expansion and stripping, multi-line continuation markers, and use as a real handler formatter. ruff and ty are both clean on it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01367hFob9sd4xpDmVT4uoFy

`ColorFormatter` reached `logging.Formatter` through a `ComposableFormatter` that
wrapped a formatter and forwarded every attribute via `__getattr__`. That returns
`Any`, so type checking was silently disabled on everything it delegated -- to
support one level of composition that was never reused. It now subclasses
`logging.Formatter` directly, with that class's parameters spelled out rather than
forwarded through `*args, **kwargs`, which typed them as `object`.

Behaviour fix: with colour disabled, `format` returned `record.getMessage()` for
*every* level, not just INFO. Redirecting stderr to a file therefore discarded the
level entirely, and an ERROR read as ordinary prose:

    use_color=True:  '\x1b[0m\x1b[1;31m\x1b[1mERROR   \x1b[0m disk full'
    use_color=False: 'disk full'           # before
    use_color=False: 'ERROR    disk full'  # after

INFO stays bare at either setting, which is the intended conversational case.

Also replaces the `%`-formatting with an `ansi_color()` helper and f-strings, and
corrects the `format(self, *args, **kwargs)` signature to `format(self, record)`.

First tests for this module: 17 cases covering the INFO special case, per-level
colouring, `$LEVELCOLOR` resolving per record, placeholder expansion and
stripping, multi-line continuation markers, and use as a real handler formatter.
`ruff` and `ty` are both clean on it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01367hFob9sd4xpDmVT4uoFy
Base automatically changed from utils-generics to master August 7, 2026 19:32
@ESultanik ESultanik changed the title Simplify ColorFormatter and keep level names when colour is off Simplify ColorFormatter and keep level names when color is off Aug 7, 2026
@ESultanik
ESultanik merged commit 0941f0d into master Aug 7, 2026
11 checks passed
@ESultanik
ESultanik deleted the logger-cleanup branch August 7, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant