Skip to content

topmark.core.machine.schemas

topmark / core / machine / schemas

Canonical schema primitives for TopMark machine-readable output.

This module centralizes: - canonical keys used in JSON envelopes and NDJSON records (MachineKey) - canonical NDJSON kinds (MachineKind) - canonical diagnostic domains (MachineDomain) - helper types used across machine-readable formats (MetaPayload, CommandSummary) - payload normalization (normalize_payload)

Design goals: - Pure (no Click / no Console / no serialization side-effects). - Stable, shared constants to avoid "stringly-typed" drift across commands. - Conservative normalization to keep payload shaping predictable.

Normalization rules: - Path -> str - Enum -> Enum.name - objects with .to_dict() -> normalize of that mapping - mappings -> dict with stringified keys and normalized values - sequences/sets -> lists of normalized values

MachineKey

Bases: str, Enum

Stable keys shared by all machine-readable output envelopes.

These keys are intentionally limited to the shared envelope layer and other cross-domain fields that multiple machine-readable output domains rely on. Domain- specific payload keys belong in the corresponding *.machine.schemas module.

Attributes:

Name Type Description
KIND

Top-level record kind key used by NDJSON records.

META

Top-level metadata key shared by JSON and NDJSON machine-readable output.

DOMAIN

Stable diagnostic domain key used by diagnostic payloads.

COMMAND

Top-level command name for command-summary style payloads.

SUBCOMMAND

Optional subcommand name for command-summary style payloads.

MachineMetaKey

Bases: str, Enum

Stable keys for the shared machine-readable output metadata payload.

Attributes:

Name Type Description
TOOL

Executable/tool name.

VERSION

TopMark version string.

PLATFORM

Execution platform identifier.

MachineDomain

Bases: str, Enum

Stable diagnostic domains shared across machine-readable output emitters.

These values are used as the payload value for the envelope-level MachineKey.DOMAIN key when emitting machine-readable diagnostics.

Attributes:

Name Type Description
CONFIG

Diagnostics originating from config discovery or validation.

PIPELINE

Diagnostics originating from processing-pipeline execution.

REGISTRY

Diagnostics originating from registry inspection commands.

VERSION

Diagnostics originating from version computation/rendering.

DetailLevel

Bases: str, Enum

Enumeration of supported machine-readable output detail levels.

These values describe how much information is included in a payload and are intended for machine consumers.

Attributes:

Name Type Description
BRIEF

Minimal representation (default CLI behavior).

LONG

Expanded representation including additional identity and descriptive fields (triggered via --long).

Notes
  • This is a machine-facing concept; it should not be confused with human-facing verbosity levels.
  • Consumers should rely on this field instead of inferring structure from payload shape.

CommandSummary dataclass

CommandSummary(*, command, subcommand=None)

Identifies the TopMark command context for a machine-readable output record.

Attributes:

Name Type Description
command str

Top-level command name (e.g. "config", "check", "strip").

subcommand str | None

Optional subcommand name (e.g. "check" under "config").

MetaPayload

Bases: TypedDict

Base metadata describing the TopMark runtime environment for machine-readable output.

This payload is process-stable and shared across all machine-readable output commands.

Attributes:

Name Type Description
tool str

Name of the tool (e.g. "topmark").

version str

Tool version string.

platform str

Execution platform (e.g. "darwin", "linux").

DetailedMetaPayload

Bases: MetaPayload

Extended metadata for machine-readable output envelopes and records.

This structure extends [MetaPayload] with fields that vary per command invocation (e.g. --long).

Attributes:

Name Type Description
detail_level DetailLevel

Indicates whether the payload represents a brief or detailed projection of the underlying data.

Notes

Inherits the base metadata fields from MetaPayload: tool, version, and platform.

normalize_payload

normalize_payload(obj)

Normalize a payload into JSON-serializable structures.

Conversions
  • Path -> str
  • Enum:
  • str-backed Enum (e.g. StrEnum) -> value
  • other Enum -> name
  • object with callable .to_dict() -> normalize(.to_dict())
  • Mapping -> dict[str, normalized value]
  • list/tuple/set/frozenset -> list[normalized item]
Notes
  • This function is intentionally conservative. It does not attempt arbitrary dataclass conversion; payload objects should implement to_dict() if they want custom serialization.
  • Mapping keys are stringified to keep JSON object keys valid.

Parameters:

Name Type Description Default
obj object

The payload object to normalize.

required

Returns:

Type Description
object

A JSON-serializable representation of obj.

Source code in src/topmark/core/machine/schemas.py
def normalize_payload(obj: object) -> object:
    """Normalize a payload into JSON-serializable structures.

    Conversions:
      - `Path` -> `str`
      - `Enum`:
        - `str`-backed Enum (e.g. StrEnum) -> `value`
        - other Enum -> `name`
      - object with callable `.to_dict()` -> normalize(`.to_dict()`)
      - `Mapping` -> `dict[str, normalized value]`
      - `list/tuple/set/frozenset` -> `list[normalized item]`

    Notes:
      - This function is intentionally conservative. It does not attempt arbitrary
        dataclass conversion; payload objects should implement `to_dict()` if they
        want custom serialization.
      - Mapping keys are stringified to keep JSON object keys valid.

    Args:
        obj: The payload object to normalize.

    Returns:
        A JSON-serializable representation of `obj`.
    """
    if isinstance(obj, Path):
        return str(obj)

    if isinstance(obj, Enum):
        if isinstance(obj, str):
            # StrEnum → use value (already a str)
            return obj
        # non-str Enum → use name
        return obj.name

    to_dict_obj: object = getattr(obj, "to_dict", None)
    if callable(to_dict_obj):
        to_dict_func: Callable[[], object] = to_dict_obj
        return normalize_payload(to_dict_func())

    if isinstance(obj, Mapping):
        mapping = cast("Mapping[object, object]", obj)
        return {str(key): normalize_payload(value) for key, value in mapping.items()}

    if isinstance(obj, list | tuple | set | frozenset):
        values = cast("Iterable[object]", obj)
        return [normalize_payload(value) for value in values]

    return obj