Skip to content

topmark.toml.schema

topmark / toml / schema

Static TOML schema metadata and validation helpers for TopMark.

This module defines the explicit, typed schema used to validate the structure of TopMark TOML documents before value-level parsing. It complements topmark.toml.keys, which remains the canonical registry for user-facing TOML section/key names while this module owns structural schema metadata and validation rules.

The schema layer focuses on shape validation
  • known top-level sections,
  • allowed keys inside closed sections,
  • open sections such as [fields],
  • nested policy subtables such as [policy_by_type.<filetype>],
  • dump/provenance-only keys that should not appear in ordinary input mode.
Malformed-section handling policy
  • unknown sections/keys are reported as warnings and ignored,
  • known sections with invalid shapes (for example a scalar where a table is required) are reported as warnings and ignored,
  • malformed nested child sections such as [policy_by_type.<filetype>] follow the same warning-and-ignore policy,
  • missing known sections are reported as informational diagnostics so callers can distinguish absent sections from malformed-present sections.

TomlSection

Bases: str, Enum

Known top-level TOML sections owned by TopMark.

TomlValidationMode

Bases: str, Enum

Validation modes for TopMark TOML documents.

INPUT validates user-authored configuration. PROVENANCE additionally allows dump-only keys emitted by commands such as topmark config dump --show-origin.

TomlSchemaSection dataclass

TomlSchemaSection(
    *,
    name,
    allowed_keys,
    open_keys=False,
    dump_only_keys=frozenset(),
)

Schema metadata for a named top-level TOML section.

Attributes:

Name Type Description
name TomlSection

Canonical top-level section name.

allowed_keys frozenset[str]

Keys accepted directly inside this section.

open_keys bool

Whether arbitrary user-defined keys are allowed.

dump_only_keys frozenset[str]

Extra keys valid only in provenance/dump mode.

keys_for_mode

keys_for_mode(mode)

Return the effective allowed keys for the given validation mode.

Parameters:

Name Type Description Default
mode TomlValidationMode

Validation mode to evaluate.

required

Returns:

Type Description
frozenset[str]

Allowed keys, including dump-only keys in provenance mode.

Source code in src/topmark/toml/schema.py
def keys_for_mode(self, mode: TomlValidationMode) -> frozenset[str]:
    """Return the effective allowed keys for the given validation mode.

    Args:
        mode: Validation mode to evaluate.

    Returns:
        Allowed keys, including dump-only keys in provenance mode.
    """
    if mode is TomlValidationMode.PROVENANCE:
        return self.allowed_keys | self.dump_only_keys
    return self.allowed_keys

TomlNestedSchema dataclass

TomlNestedSchema(
    *, parent, allowed_child_keys, child_label
)

Schema metadata for dynamic nested TOML subtables.

This is used for structures such as [policy_by_type.<filetype>], where the child table names are dynamic but the keys inside each child table are fixed.

Attributes:

Name Type Description
parent TomlSection

Parent top-level section containing dynamic child subtables.

allowed_child_keys frozenset[str]

Keys accepted in each child subtable.

child_label str

Human-readable label for the dynamic child name.

TomlSchema dataclass

TomlSchema(*, sections, policy_by_type_nested=None)

Static schema for TopMark TOML document shape validation.

The schema owns section-level structure and emits TomlValidationIssue instances for unknown keys, wrong section shapes, and nested-policy shape mismatches.

Attributes:

Name Type Description
sections dict[TomlSection, TomlSchemaSection]

Mapping of known top-level sections to their schema metadata.

policy_by_type_nested TomlNestedSchema | None

Optional nested schema for [policy_by_type.<filetype>] subtables.

validate_top_level_keys

validate_top_level_keys(table, *, mode)

Validate top-level entries and section table shapes.

Top-level TopMark TOML entries are expected to be named sections such as [config] or [files]. Unknown top-level tables are therefore reported as unknown sections, while unknown non-table entries are reported as misplaced top-level keys.

Known sections must be TOML tables. When a known section is present with the wrong shape, the validator emits a warning and the malformed section is ignored by later parsing. Missing sections are not diagnosed by this helper; they are reported later during full-schema validation.

Parameters:

Name Type Description Default
table TomlTable

Top-level TOML table to validate.

required
mode TomlValidationMode

Validation mode controlling context-specific allowances.

required

Returns:

Type Description
TomlValidationIssue

Structured validation issues for unknown top-level entries and

...

invalid top-level section types.

Source code in src/topmark/toml/schema.py
def validate_top_level_keys(
    self,
    table: TomlTable,
    *,
    mode: TomlValidationMode,
) -> tuple[TomlValidationIssue, ...]:
    """Validate top-level entries and section table shapes.

    Top-level TopMark TOML entries are expected to be named sections such as
    `[config]` or `[files]`. Unknown top-level tables are therefore reported
    as unknown sections, while unknown non-table entries are reported as
    misplaced top-level keys.

    Known sections must be TOML tables. When a known section is present with
    the wrong shape, the validator emits a warning and the malformed section
    is ignored by later parsing. Missing sections are not diagnosed by this
    helper; they are reported later during full-schema validation.

    Args:
        table: Top-level TOML table to validate.
        mode: Validation mode controlling context-specific allowances.

    Returns:
        Structured validation issues for unknown top-level entries and
        invalid top-level section types.
    """
    del mode

    issues: list[TomlValidationIssue] = []
    known_names: frozenset[str] = frozenset(section.value for section in self.sections)

    for key, value in table.items():
        if key not in known_names:
            suggestion: str | None = _suggest_key(key, known_names)
            if isinstance(value, dict):
                code: TomlDiagnosticCode = TomlDiagnosticCode.UNKNOWN_TOP_LEVEL_SECTION
                message: str = f"Unknown TOML section [{key}] (ignored)."
                if suggestion is not None:
                    message = f"{message[:-1]} Did you mean [{suggestion}]?"
            else:
                # Policy: malformed known sections are warning-and-ignore, not fatal.
                code = TomlDiagnosticCode.UNKNOWN_TOP_LEVEL_KEY
                message = f"Unknown top-level key '{key}' in TopMark TOML (ignored)."
                if suggestion is not None:
                    message = (
                        f"{message[:-1]} Did you mean section [{suggestion}] "
                        "or key under that section?"
                    )
            issues.append(
                TomlValidationIssue(
                    code=code,
                    level=DiagnosticLevel.WARNING,
                    message=message,
                    path=(key,),
                    section=None,
                    key=key,
                    allowed_keys=tuple(sorted(known_names)),
                    suggestion=suggestion,
                )
            )
            continue

        if not isinstance(value, dict):
            issues.append(
                TomlValidationIssue(
                    code=TomlDiagnosticCode.INVALID_SECTION_TYPE,
                    level=DiagnosticLevel.WARNING,
                    message=(
                        f"TOML section [{key}] must be a table; "
                        f"got {type(value).__name__} (ignored)."
                    ),
                    path=(key,),
                    section=key,
                    key=None,
                )
            )

    return tuple(issues)

validate_section_keys

validate_section_keys(section, table, *, mode)

Validate keys inside a known top-level TOML section.

Parameters:

Name Type Description Default
section TomlSection

Known section being validated.

required
table TomlTable

Section table contents.

required
mode TomlValidationMode

Validation mode controlling dump-only-key allowances.

required

Returns:

Type Description
tuple[TomlValidationIssue, ...]

Structured validation issues for unknown or context-disallowed keys.

Source code in src/topmark/toml/schema.py
def validate_section_keys(
    self,
    section: TomlSection,
    table: TomlTable,
    *,
    mode: TomlValidationMode,
) -> tuple[TomlValidationIssue, ...]:
    """Validate keys inside a known top-level TOML section.

    Args:
        section: Known section being validated.
        table: Section table contents.
        mode: Validation mode controlling dump-only-key allowances.

    Returns:
        Structured validation issues for unknown or context-disallowed keys.
    """
    schema_section: TomlSchemaSection = self.sections[section]
    if schema_section.open_keys:
        return ()

    issues: list[TomlValidationIssue] = []
    allowed_for_mode: frozenset[str] = schema_section.keys_for_mode(mode)

    for key in table:
        if key in allowed_for_mode:
            continue

        suggestion_pool: frozenset[str] = allowed_for_mode
        suggestion: str | None = _suggest_key(key, suggestion_pool)

        if mode is TomlValidationMode.INPUT and key in schema_section.dump_only_keys:
            message: str = (
                f'Key "{key}" is only valid in [{section.value}] when '
                "reading provenance/dump output (ignored)."
            )
            issues.append(
                TomlValidationIssue(
                    code=TomlDiagnosticCode.DUMP_ONLY_KEY_IN_INPUT,
                    level=DiagnosticLevel.WARNING,
                    message=message,
                    path=(section.value, key),
                    section=section.value,
                    key=key,
                    allowed_keys=tuple(sorted(allowed_for_mode)),
                    suggestion=None,
                )
            )
            continue

        message = f'Unknown key "{key}" in [{section.value}] (ignored).'
        if suggestion is not None:
            message = f'{message[:-1]} Did you mean "{suggestion}"?'
        issues.append(
            TomlValidationIssue(
                code=TomlDiagnosticCode.UNKNOWN_SECTION_KEY,
                level=DiagnosticLevel.WARNING,
                message=message,
                path=(section.value, key),
                section=section.value,
                key=key,
                allowed_keys=tuple(sorted(suggestion_pool)),
                suggestion=suggestion,
            )
        )

    return tuple(issues)

validate

validate(table, *, mode)

Validate a complete TopMark TOML table against the static schema.

This performs shape validation for the full TopMark TOML fragment, including top-level entries, fixed-key sections, open sections, and nested policy-by-type child tables.

The validator is intentionally non-fatal for malformed sections: warnings are emitted, malformed sections are ignored by later parsing, and validation continues so callers can accumulate a complete issue set. Missing known sections are reported as informational diagnostics.

Parameters:

Name Type Description Default
table TomlTable

Top-level TOML table to validate.

required
mode TomlValidationMode

Validation mode controlling dump-only-key allowances.

required

Returns:

Type Description
tuple[TomlValidationIssue, ...]

Structured TOML validation issues.

Source code in src/topmark/toml/schema.py
def validate(
    self,
    table: TomlTable,
    *,
    mode: TomlValidationMode,
) -> tuple[TomlValidationIssue, ...]:
    """Validate a complete TopMark TOML table against the static schema.

    This performs shape validation for the full TopMark TOML fragment,
    including top-level entries, fixed-key sections, open sections, and
    nested policy-by-type child tables.

    The validator is intentionally non-fatal for malformed sections:
    warnings are emitted, malformed sections are ignored by later parsing,
    and validation continues so callers can accumulate a complete issue set.
    Missing known sections are reported as informational diagnostics.

    Args:
        table: Top-level TOML table to validate.
        mode: Validation mode controlling dump-only-key allowances.

    Returns:
        Structured TOML validation issues.
    """
    issues: list[TomlValidationIssue] = []
    issues.extend(self.validate_top_level_keys(table, mode=mode))

    for section in self.sections:
        raw_section: TomlValue | None = table.get(section.value)
        if raw_section is None:
            issues.append(
                TomlValidationIssue(
                    code=TomlDiagnosticCode.MISSING_SECTION,
                    level=DiagnosticLevel.INFO,
                    message=(
                        f"TOML section [{section.value}] is not present; "
                        "defaults/empty semantics apply."
                    ),
                    path=(section.value,),
                    section=section.value,
                    key=None,
                )
            )
            continue

        # Present-but-malformed sections were already recorded by
        # `validate_top_level_keys()` and are skipped here.
        if not isinstance(raw_section, dict):
            continue

        issues.extend(self.validate_section_keys(section, raw_section, mode=mode))

        if section is TomlSection.POLICY_BY_TYPE and self.policy_by_type_nested is not None:
            issues.extend(
                self._validate_nested_section(
                    raw_section,
                    nested=self.policy_by_type_nested,
                    mode=mode,
                )
            )

    return tuple(issues)