diff --git a/docs/database.md b/docs/database.md index 96e9a3c..5b2cb58 100644 --- a/docs/database.md +++ b/docs/database.md @@ -212,9 +212,10 @@ def resolve_user_key(value: str) -> str | None: - By default a transaction is logged with an `action by user` header followed by the diff lines. Added paths are colored green, deleted paths red. -- `kanta.transaction(..., extra="...")` accepts a display-only string that is - appended after the action in the header (colored by Kanta); it is never - persisted in the `ChangeRecord`. +- `kanta.transaction(..., extra=...)` accepts a display-only value that is + shown after the action in the header. Anything other than `None` is + printed str-converted (colored by Kanta), unless a custom logemit handler + does something else with it; it is never persisted in the `ChangeRecord`. - `kanta.transaction(..., logdiff=False)` skips building and printing the diff body and logs only the header, which is useful for large or noisy changesets. Diff output can also be disabled globally with diff --git a/kanta/kanta.py b/kanta/kanta.py index 9422977..6eca545 100644 --- a/kanta/kanta.py +++ b/kanta/kanta.py @@ -5,7 +5,7 @@ import logging from datetime import datetime from pathlib import Path from types import ModuleType, SimpleNamespace -from typing import Generic, TypeVar +from typing import Any, Generic, TypeVar from kanta.kantaimpl import KantaImpl from kanta.serialization import JsonSerializer, Serializer @@ -345,7 +345,7 @@ class Kanta(Generic[T]): action: str, *, user: str | None = None, - extra: str | None = None, + extra: Any = None, mtime: bool | datetime = True, log: bool | logging.Logger = True, logdiff: bool = True, @@ -357,9 +357,11 @@ class Kanta(Generic[T]): user: Optional user identifier stored in metadata and rendered in the log header. Register a ``@kanta.logfmt`` callback to format the user value; the path ``"$user"`` is passed for this case. - extra: Optional display-only string appended after the action in - the log header (colored by Kanta). It is never persisted in - the change record. + extra: Optional display-only value shown after the action in the + log header. Anything other than ``None`` is printed + str-converted (colored by Kanta), unless a custom + ``@kanta.logemit`` handler does something else with it. It is + never persisted in the change record. mtime: Controls the modification time ``m``. ``True`` (default) sets ``m`` to the current UTC time. ``False`` omits ``m`` so the previous modification time remains in effect; this is used for diff --git a/kanta/logging.py b/kanta/logging.py index 094440d..910ea26 100644 --- a/kanta/logging.py +++ b/kanta/logging.py @@ -55,7 +55,7 @@ class LogEvent(msgspec.Struct, kw_only=True): kanta: Any = None action: str | None = None user: str | None = None - extra: str | None = None + extra: Any = None error: BaseException | None = None diff: dict = msgspec.field(default_factory=dict) previous: dict | None = None @@ -413,13 +413,13 @@ def format_diff( def format_action_header( action: str, user: str | None = None, - extra: str | None = None, + extra: Any = None, ) -> str: """Format the default action header line.""" line = Line().action(action) - if extra: + if extra is not None and (extra := f"{extra}"): line(" ").target(extra) - if user: + if user is not None and (user := f"{user}"): line(" by ").user(user) return str(line) @@ -429,7 +429,7 @@ def log_change( diff: dict, user: str | None = None, previous: dict | None = None, - extra: str | None = None, + extra: Any = None, logfmt: Callable[[Any, str], str | None] | None = None, *, logger: logging.Logger = transaction_logger, @@ -447,8 +447,10 @@ def log_change( diff: The JSON diff dict. user: Optional already-formatted user name to show in the header. previous: The previous state dict (for determining add vs update). - extra: Optional display-only string appended after the action in the - header (colored by Kanta). + extra: Optional display-only value shown after the action in the + header. Anything other than ``None`` is printed str-converted + (colored by Kanta), unless a custom logemit handler does + something else with it. logfmt: Optional formatter callable ``(value, path) -> str | None``. logger: Logger to write to. Defaults to the ``kanta.transaction`` logger. level: Log level to use. Defaults to ``logging.INFO``. diff --git a/kanta/transaction.py b/kanta/transaction.py index 0f44cae..bea48a5 100644 --- a/kanta/transaction.py +++ b/kanta/transaction.py @@ -5,6 +5,7 @@ from __future__ import annotations import logging from contextlib import contextmanager from datetime import datetime +from typing import Any from kanta.diff import compute_diff from kanta.exceptions import DataIntegrityError @@ -40,7 +41,7 @@ def transaction( action: str, *, user: str | None = None, - extra: str | None = None, + extra: Any = None, mtime: bool | datetime = True, log: bool | logging.Logger = True, logdiff: bool = True,