class documentation

class TextChangeRenderer(ChangeRenderer):

View In Hierarchy

Render Changes as a human-readable plain-text changelog (the text format).

Layout:

Schema changes (N):
+ ClassName [new class]
+ ClassName [new subclass of Parent] (+M inherited)
- ClassName [removed]
~ ClassName [modified]
  field: before -> after
~ ClassName [reordered]
  properties reordered: [p1, p2, ...]
~ ClassName [renamed from OldName]
  field: before -> after
  + newProp [added]
  ~ dose: dosage -> dose [renamed]; isOptional: true -> false
  - oldProp [removed]

N counts only the top-level class/metadata entries (not individual property-level lines).

Unlike the flat records format, text output is hierarchical: property changes nest under their owning class's block. render owns that grouping/emission orchestration; per-op line shaping is delegated through the _CLASS_HEADERS / _PROP_LINES dispatch tables so that adding a new op is one table entry rather than another conditional branch.

Every method is side-effect-free — it returns its lines rather than mutating shared state — so each renders in isolation and composes cleanly.

Method __init__ Undocumented
Method render Render changes as a deterministic plain-text changelog string.
Static Method _detail_lines Indented continuation lines for an entry's semantic annotations.
Static Method _metadata_line The single ~ target: before -> after line for a metadata Change.
Static Method _modified_prop_line Undocumented
Static Method _owning_class The class name owning a property Change ("Class" from "Class.prop").
Static Method _renamed_prop_line Undocumented
Static Method _subclass_created_header Undocumented
Static Method _summary_header The Schema changes (N): header, or None when there is nothing.
Method _class_block Render ALL class-level Changes for cls_name, then its property lines.
Method _class_header Build the single class-level header line, dispatched on ch.op.
Method _one_class_change Header line + field/reorder/detail continuation lines for one class Change.
Method _prop_change Property change line plus any annotation continuation lines.
Method _prop_line Single indented property-change line, dispatched on pch.op.
Instance Variable _CLASS_HEADERS Undocumented
Instance Variable _PROP_LINES Undocumented
def __init__(self):

Undocumented

def render(self, changes: list[Change]) -> str:

Render changes as a deterministic plain-text changelog string.

Parameters
changes:list[Change]Ordered Change instances (already sorted).
Returns
strDeterministic plain-text changelog string.
@staticmethod
def _detail_lines(ch: Change, indent: str) -> list[str]:

Indented continuation lines for an entry's semantic annotations.

The default (text) output MUST surface every detail dimension the records format carries, or the two renderings describe different logical changes and the cross-format invariant policing them is blind to the gap. The five published detail dimensions (applied_to_subclasses, label_property, order, parent, inherited) each render on their own continuation line.

List/string values are JSON-encoded (not naively joined on a comma) so a value containing the delimiter (e.g. a class name with a comma) round-trips unambiguously and cannot fool the invariant's text-side parser. The order/parent/inherited lines are continuation detail emitted in addition to the human-readable header summary (which keeps the familiar [new subclass of P] (+N inherited) / [reordered] shape), so the text contract gains content without losing its existing form.

Parameters
ch:ChangeThe change whose detail to render.
indent:strLeading whitespace (two spaces at class level, four at property level) so the line nests under its owning block.
Returns
list[str]Zero or more annotation lines.
@staticmethod
def _metadata_line(ch: Change) -> str:

The single ~ target: before -> after line for a metadata Change.

@staticmethod
def _modified_prop_line(pch: Change, prop_name: str) -> str:

Undocumented

@staticmethod
def _owning_class(ch: Change) -> str:

The class name owning a property Change ("Class" from "Class.prop").

@staticmethod
def _renamed_prop_line(pch: Change, prop_name: str) -> str:

Undocumented

@staticmethod
def _subclass_created_header(ch: Change) -> str:

Undocumented

@staticmethod
def _summary_header(changes: list[Change]) -> str | None:

The Schema changes (N): header, or None when there is nothing.

N counts one entry per metadata change plus one per distinct owning class that has any change (property-only changed classes count once); individual property lines are not counted.

def _class_block(self, cls_name: str, class_chs: list[Change], prop_chs: list[Change]) -> list[str]:

Render ALL class-level Changes for cls_name, then its property lines.

FIX VR-B1: a class may legitimately carry MORE THAN ONE class-level Change (a recycled name yields renamed + removed; a concurrent reorder yields modified/renamed + reordered). Every such Change must render — the renderer must not silently drop a destructive removed or a reordered after the first block, or the text output would lie while records stay correct. A class with only property-level changes gets a synthesised ~ header.

def _class_header(self, ch: Change) -> str:

Build the single class-level header line, dispatched on ch.op.

def _one_class_change(self, ch: Change) -> list[str]:

Header line + field/reorder/detail continuation lines for one class Change.

def _prop_change(self, pch: Change) -> list[str]:

Property change line plus any annotation continuation lines.

A modified property carrying neither field changes nor renderable detail is content-free noise (it would print ~ prop asserting a change while showing none) and is skipped (B2). The corresponding records entry is likewise contentless, so both formats agree.

def _prop_line(self, pch: Change) -> str:

Single indented property-change line, dispatched on pch.op.

_CLASS_HEADERS: dict[str, Callable[[Change], str]] =

Undocumented

_PROP_LINES: dict[str, Callable[[Change, str], str]] =

Undocumented