Source code for ncarnate.convert.models

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''

The convert data models: stdlib dataclasses describing how a
manifest-driven convert run behaves (``ConvertOptions``) and what it did
(``ConvertResult`` — the per-file ``ConvertRecord`` outcomes).

``ConvertOptions`` mirrors the ``recompress`` encoding flags (design
§Per-status conversion parameters) so a manifest run and the legacy
positional form encode identically, and defaults to the safety-first
posture the spec pins: only the ``ready`` status is converted (KD8) and the
archive is never mutated unless ``in_place`` is set (KD3).

Copyright (c) 2020-2026 Erick Edward Shepherd. MIT License — see the
top-level LICENSE file.

'''

from __future__ import annotations

# Standard library imports.
from dataclasses import dataclass, field


[docs] @dataclass class ConvertOptions: ''' How a manifest-driven convert run behaves. ``out_dir`` is the mirrored output root (the non-destructive default, KD3); ``in_place`` opts into recompressing sources where they sit. ``statuses`` selects which audited statuses to act on and defaults to ``{"ready"}`` only (KD8) — the operator widens it after reading the report. ``allow_unverified`` relaxes the mandatory sha256 gate (KD2) for a ``null``-hash record; ``skip_existing`` makes an ``out_dir`` run resumable; ``root`` is the operator-supplied containment base a source path resolves under (§Risks); ``allow_manifest_root`` opts into trusting the manifest's own recorded ``root`` as that base when ``root`` is not given — untrusted by default, since the manifest is untrusted input. The encoding flags (``zlib``/``shuffle``/``complevel``/``geolocation``) share ``recompress``'s defaults. ''' out_dir : str | None = None statuses : set[str] = field(default_factory=lambda: {"ready"}) allow_unverified : bool = False in_place : bool = False skip_existing : bool = False root : str | None = None allow_manifest_root : bool = False zlib : bool = True shuffle : bool = True complevel : int = 7 geolocation : bool = True
@dataclass class ConvertRecord: ''' One file's outcome. ``path`` is the manifest-relative source path; ``reason`` explains a skip or failure (a converted file needs none, so it defaults to ``None``). ''' path : str reason : str | None = None @dataclass class ConvertResult: ''' The end-of-run tally: the files ``converted``, those ``skipped`` (a status not selected, a blocker, an already-present output), and those ``failed`` (a sha256 mismatch, a containment rejection, a conversion error). The exit code is non-zero iff ``failed`` is non-empty. ''' converted : list[ConvertRecord] = field(default_factory=list) skipped : list[ConvertRecord] = field(default_factory=list) failed : list[ConvertRecord] = field(default_factory=list) @property def exit_code(self) -> int: ''' The process exit code: non-zero **iff any selected record failed** (§The per-record loop). A skip — a blocker or a non-selected status — is not a failure and never sets it, mirroring the audit's ``main`` returning an ``int``. ''' return 1 if self.failed else 0