Skip to content

topmark.diagnostic.model

topmark / diagnostic / model

Core diagnostic types and helpers for TopMark.

This module defines internal diagnostic primitives used throughout the project to report informational messages, warnings, and errors. These are intentionally separate from the public API schemas so that internal diagnostics can evolve without breaking external contracts.

Sections

DiagnosticLevel

Bases: str, Enum

Severity levels for diagnostics collected during processing.

Levels map to semantic style roles and are ordered by importance: ERROR > WARNING > INFO. This enum is internal; the public API exposes string literals.

role property

role

Return the semantic StyleRole for this diagnostic level.

Renderers may map this role to concrete styling (e.g., colors).

Diagnostic dataclass

Diagnostic(*, level, message)

Internal structured diagnostic with a severity level and message.

Note

This type is not part of the public API surface. Conversions to DiagnosticEntry happen at the API boundary.

DiagnosticStats dataclass

DiagnosticStats(*, n_info, n_warning, n_error)

Aggregated counts for diagnostics by severity level.

total property

total

Return the total count of diagnostics.

get

get(level)

Return the count for the given diagnostic level.

Parameters:

Name Type Description Default
level DiagnosticLevel

Diagnostic severity level to retrieve.

required

Returns:

Type Description
int

The aggregated count for the requested diagnostic level.

Raises:

Type Description
ValueError

If level is not a supported DiagnosticLevel.

Source code in src/topmark/diagnostic/model.py
def get(
    self,
    level: DiagnosticLevel,
) -> int:
    """Return the count for the given diagnostic level.

    Args:
        level: Diagnostic severity level to retrieve.

    Returns:
        The aggregated count for the requested diagnostic level.

    Raises:
        ValueError: If `level` is not a supported
            [`DiagnosticLevel`][topmark.diagnostic.model.DiagnosticLevel].
    """
    if level == DiagnosticLevel.INFO:
        return self.n_info
    if level == DiagnosticLevel.WARNING:
        return self.n_warning
    if level == DiagnosticLevel.ERROR:
        return self.n_error
    # Defensive guard:
    raise ValueError(f"Unsupported diagnostic level: {level!r}")

triage_summary

triage_summary(severity_threshold=DiagnosticLevel.INFO)

Return a compact triage summary ordered by decreasing severity.

The summary is built from the aggregated per-level counts stored on this object and is suitable for concise human-facing suffixes such as: "1 error, 2 warnings".

The severity_threshold controls how far the summary descends:

  • DiagnosticLevel.ERROR: include only errors
  • DiagnosticLevel.WARNING: include errors and warnings
  • DiagnosticLevel.INFO: include errors, warnings, and infos

Parameters:

Name Type Description Default
severity_threshold DiagnosticLevel

Lowest severity level that may be included; default: INFO (all).

INFO

Returns:

Type Description
str

Compact triage summary string. Returns an empty string when no

str

matching counts are present.

Source code in src/topmark/diagnostic/model.py
def triage_summary(
    self,
    severity_threshold: DiagnosticLevel = DiagnosticLevel.INFO,
) -> str:
    """Return a compact triage summary ordered by decreasing severity.

    The summary is built from the aggregated per-level counts stored on this
    object and is suitable for concise human-facing suffixes such as:
    ``"1 error, 2 warnings"``.

    The `severity_threshold` controls how far the summary descends:

    - `DiagnosticLevel.ERROR`: include only errors
    - `DiagnosticLevel.WARNING`: include errors and warnings
    - `DiagnosticLevel.INFO`: include errors, warnings, and infos

    Args:
        severity_threshold: Lowest severity level that may be included;
            default: `INFO` (all).

    Returns:
        Compact triage summary string. Returns an empty string when no
        matching counts are present.
    """
    parts: list[str] = []

    n_info: int = self.n_info
    n_warn: int = self.n_warning
    n_err: int = self.n_error

    # Compose a compact triage summary like "1 error, 2 warnings" while
    # respecting the requested lowest included severity.
    stop: bool = False
    if n_err:
        parts.append(f"{n_err} error" + ("s" if n_err != 1 else ""))
        if severity_threshold == DiagnosticLevel.ERROR:
            stop = True

    if n_warn:
        if not stop:
            parts.append(f"{n_warn} warning" + ("s" if n_warn != 1 else ""))
        if severity_threshold == DiagnosticLevel.WARNING:
            stop = True

    if not stop and n_info:
        parts.append(f"{n_info} info" + ("s" if n_info != 1 else ""))

    if parts:
        return ", ".join(parts)
    return ""

MutableDiagnosticLog dataclass

MutableDiagnosticLog(*, items=(lambda: [])())

Mutable collection of diagnostics.

It provides convenience helpers for adding diagnostics at a given level and exposes simple aggregation helpers (stats, to_dict) for reporting.

from_iterable classmethod

from_iterable(diagnostics)

Create a FrozenDiagnosticLog from an iterable of diagnostics.

Parameters:

Name Type Description Default
diagnostics Iterable[Diagnostic]

Existing diagnostics (e.g., from a frozen snapshot).

required

Returns:

Type Description
MutableDiagnosticLog
MutableDiagnosticLog

containing the provided diagnostics.

Source code in src/topmark/diagnostic/model.py
@classmethod
def from_iterable(cls, diagnostics: Iterable[Diagnostic]) -> MutableDiagnosticLog:
    """Create a `FrozenDiagnosticLog` from an iterable of diagnostics.

    Args:
        diagnostics: Existing diagnostics (e.g., from a frozen snapshot).

    Returns:
        A new [`MutableDiagnosticLog`][topmark.diagnostic.model.MutableDiagnosticLog]
        containing the provided diagnostics.
    """
    return cls(items=list(diagnostics))

freeze

freeze()

Return an immutable snapshot of this log's diagnostics.

Source code in src/topmark/diagnostic/model.py
def freeze(self) -> FrozenDiagnosticLog:
    """Return an immutable snapshot of this log's diagnostics."""
    return FrozenDiagnosticLog(items=tuple(self.items))

add

add(diagnostic)

Add a diagnostic to the diagnostic log.

The diagnostic is appended to the context in place.

Parameters:

Name Type Description Default
diagnostic Diagnostic

The diagnostic object.

required
Source code in src/topmark/diagnostic/model.py
def add(self, diagnostic: Diagnostic) -> None:
    """Add a diagnostic to the diagnostic log.

    The diagnostic is appended to the context in place.

    Args:
        diagnostic: The diagnostic object.
    """
    self.items.append(diagnostic)
    logger.trace("Adding [%s]: %r", diagnostic.level.value, diagnostic.message)

add_info

add_info(message)

Add an info diagnostic to the diagnostic log.

The diagnostic is appended to the context in place.

Parameters:

Name Type Description Default
message str

The diagnostic message.

required
Source code in src/topmark/diagnostic/model.py
def add_info(self, message: str) -> None:
    """Add an ``info`` diagnostic to the diagnostic log.

    The diagnostic is appended to the context in place.

    Args:
        message: The diagnostic message.
    """
    self.add(
        Diagnostic(
            level=DiagnosticLevel.INFO,
            message=message,
        )
    )
    logger.info(
        message,
        stacklevel=2,
    )

add_warning

add_warning(message)

Add a warning diagnostic to the diagnostic log.

Parameters:

Name Type Description Default
message str

The diagnostic message.

required
Source code in src/topmark/diagnostic/model.py
def add_warning(self, message: str) -> None:
    """Add a ``warning`` diagnostic to the diagnostic log.

    Args:
        message: The diagnostic message.
    """
    self.add(
        Diagnostic(
            level=DiagnosticLevel.WARNING,
            message=message,
        )
    )
    logger.warning(
        message,
        stacklevel=2,
    )

add_error

add_error(message)

Add an error diagnostic to the diagnostic log.

The diagnostic is appended to the context in place.

Parameters:

Name Type Description Default
message str

The diagnostic message.

required
Source code in src/topmark/diagnostic/model.py
def add_error(self, message: str) -> None:
    """Add an ``error`` diagnostic to the diagnostic log.

    The diagnostic is appended to the context in place.

    Args:
        message: The diagnostic message.
    """
    self.add(
        Diagnostic(
            level=DiagnosticLevel.ERROR,
            message=message,
        )
    )
    logger.error(
        message,
        stacklevel=2,
    )

stats

stats()

Return per-level counts for diagnostics in this log.

The returned DiagnosticStats object can be used both for human summaries and for machine-readable reporting via to_dict.

Source code in src/topmark/diagnostic/model.py
def stats(self) -> DiagnosticStats:
    """Return per-level counts for diagnostics in this log.

    The returned [`DiagnosticStats`][topmark.diagnostic.model.DiagnosticStats] object
    can be used both for human summaries and for machine-readable reporting via `to_dict`.
    """
    return compute_diagnostic_stats(self.items)

has_info

has_info()

Return True if the MutableDiagnosticLog contains info diagnostics.

Source code in src/topmark/diagnostic/model.py
def has_info(self) -> bool:
    """Return True if the `MutableDiagnosticLog` contains info diagnostics."""
    return any(d.level == DiagnosticLevel.INFO for d in self.items)

has_warning

has_warning()

Return True if the MutableDiagnosticLog contains warning diagnostics.

Source code in src/topmark/diagnostic/model.py
def has_warning(self) -> bool:
    """Return True if the `MutableDiagnosticLog` contains warning diagnostics."""
    return any(d.level == DiagnosticLevel.WARNING for d in self.items)

has_error

has_error()

Return True if the MutableDiagnosticLog contains error diagnostics.

Source code in src/topmark/diagnostic/model.py
def has_error(self) -> bool:
    """Return True if the `MutableDiagnosticLog` contains error diagnostics."""
    return any(d.level == DiagnosticLevel.ERROR for d in self.items)

to_dict

to_dict()

Return a JSON-friendly mapping of counts by severity.

Returns:

Type Description
dict[str, int]

Mapping with keys "info", "warning", and "error"

dict[str, int]

reflecting the number of diagnostics at each level.

Source code in src/topmark/diagnostic/model.py
def to_dict(self) -> dict[str, int]:
    """Return a JSON-friendly mapping of counts by severity.

    Returns:
        Mapping with keys ``"info"``, ``"warning"``, and ``"error"``
        reflecting the number of diagnostics at each level.
    """
    return diagnostics_counts_to_dict(self.items)

FrozenDiagnosticLog dataclass

FrozenDiagnosticLog(*, items)

Immutable diagnostic container.

FrozenDiagnosticLog is the immutable counterpart to MutableDiagnosticLog. It is intended for storing diagnostics on immutable snapshots where mutation is not permitted.

thaw

thaw()

Return a mutable copy of this frozen diagnostic log.

Source code in src/topmark/diagnostic/model.py
def thaw(self) -> MutableDiagnosticLog:
    """Return a mutable copy of this frozen diagnostic log."""
    return MutableDiagnosticLog(items=list(self.items))

stats

stats()

Return aggregated per-level counts for the contained diagnostics.

Source code in src/topmark/diagnostic/model.py
def stats(self) -> DiagnosticStats:
    """Return aggregated per-level counts for the contained diagnostics."""
    return compute_diagnostic_stats(self.items)

to_dict

to_dict()

Return a JSON-friendly mapping of counts by severity.

Source code in src/topmark/diagnostic/model.py
def to_dict(self) -> dict[str, int]:
    """Return a JSON-friendly mapping of counts by severity."""
    return diagnostics_counts_to_dict(self.items)

compute_diagnostic_stats

compute_diagnostic_stats(diagnostics)

Return per-level counts for a sequence of diagnostics.

The returned DiagnosticStats object can be used both for human summaries and for machine-readable reporting via to_dict.

Parameters:

Name Type Description Default
diagnostics Iterable[Diagnostic]

the diagnostic log.

required

Returns:

Type Description
DiagnosticStats

Per-level counts for diagnostics in this log.

Source code in src/topmark/diagnostic/model.py
def compute_diagnostic_stats(diagnostics: Iterable[Diagnostic]) -> DiagnosticStats:
    """Return per-level counts for a sequence of diagnostics.

    The returned [`DiagnosticStats`][topmark.diagnostic.model.DiagnosticStats] object
    can be used both for human summaries and for machine-readable reporting via `to_dict`.

    Args:
        diagnostics: the diagnostic log.

    Returns:
        Per-level counts for diagnostics in this log.
    """
    n_info: int = sum(1 for d in diagnostics if d.level == DiagnosticLevel.INFO)
    n_warn: int = sum(1 for d in diagnostics if d.level == DiagnosticLevel.WARNING)
    n_err: int = sum(1 for d in diagnostics if d.level == DiagnosticLevel.ERROR)
    return DiagnosticStats(n_info=n_info, n_warning=n_warn, n_error=n_err)

diagnostics_counts_to_dict

diagnostics_counts_to_dict(diagnostics)

Return a JSON-friendly mapping of counts by severity for any iterable.

Source code in src/topmark/diagnostic/model.py
def diagnostics_counts_to_dict(diagnostics: Iterable[Diagnostic]) -> dict[str, int]:
    """Return a JSON-friendly mapping of counts by severity for any iterable."""
    stats: DiagnosticStats = compute_diagnostic_stats(diagnostics)
    return {
        "info": stats.n_info,
        "warning": stats.n_warning,
        "error": stats.n_error,
    }