Source code for ralph.checkpoint.execution_history
"""Bounded checkpoint execution history models."""
from __future__ import annotations
from collections import deque
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ralph.checkpoint.execution_step import ExecutionStep
[docs]
@dataclass(frozen=True)
class ExecutionHistory:
"""Bounded execution history plus checkpoint-relevant file snapshots."""
steps: tuple[ExecutionStep, ...] = ()
file_snapshots: dict[str, str] = field(default_factory=dict)
[docs]
@classmethod
def new(cls, file_snapshots: dict[str, str] | None = None) -> ExecutionHistory:
"""Create an empty execution history."""
return cls(file_snapshots=file_snapshots or {})
[docs]
def add_step_bounded(self, step: ExecutionStep, limit: int) -> ExecutionHistory:
"""Return a copy with the step appended and bounded to the given limit."""
if limit <= 0:
bounded_steps: tuple[ExecutionStep, ...] = ()
else:
queue = deque(self.steps, maxlen=limit)
queue.append(step)
bounded_steps = tuple(queue)
return ExecutionHistory(
steps=bounded_steps,
file_snapshots=dict(self.file_snapshots),
)
[docs]
def clone_bounded(self, limit: int) -> ExecutionHistory:
"""Clone the history while keeping only the most recent steps."""
if limit <= 0:
bounded_steps: tuple[ExecutionStep, ...] = ()
else:
bounded_steps = self.steps[-limit:]
return ExecutionHistory(
steps=bounded_steps,
file_snapshots=dict(self.file_snapshots),
)
[docs]
def to_dict(self) -> dict[str, object]:
"""Return a JSON-safe dictionary representation."""
return {
"steps": [step.to_dict() for step in self.steps],
"file_snapshots": dict(self.file_snapshots),
}