Source code for algomancy_scenario.result

"""Scenario result containers.

``BaseScenarioResult`` mirrors :class:`algomancy_data.datasource.BaseDataSource`:
subclasses MUST implement ``to_json`` / ``from_json`` to participate in
database persistence. Subclasses whose state decomposes into one or more
DataFrames can additionally implement
:class:`algomancy_scenario.persistence.protocols.SqlResultLayout` to land each
DataFrame in a real, externally queryable SQL table.
"""

from __future__ import annotations

import json
from abc import ABC, abstractmethod
from datetime import datetime
from typing import TypeVar


[docs] class BaseScenarioResult(ABC): def __init__(self, data_id: str): self.data_id = data_id self.completed_at = datetime.now()
[docs] @abstractmethod def to_dict(self) -> dict: raise NotImplementedError("Abstract method")
[docs] @abstractmethod def to_json(self) -> str: """Serialise the full result to a JSON string. The output must round-trip through :meth:`from_json`. Used as the JSON-blob fallback path by ``SqlScenarioRepository`` when the subclass does not implement ``SqlResultLayout``. """ raise NotImplementedError("Abstract method")
[docs] @classmethod @abstractmethod def from_json(cls, json_string: str) -> "BaseScenarioResult": """Reconstruct an instance from the string produced by :meth:`to_json`.""" raise NotImplementedError("Abstract method")
BASE_RESULT_BOUND = TypeVar("BASE_RESULT_BOUND", bound=BaseScenarioResult)
[docs] class ScenarioResult(BaseScenarioResult): """Bundled minimal result: carries only ``data_id`` and ``completed_at``.""" def __init__(self, data_id: str): super().__init__(data_id)
[docs] def to_dict(self) -> dict: return { "scenario_id": self.data_id, "completed_at": self.completed_at, }
[docs] def to_json(self) -> str: return json.dumps( { "data_id": self.data_id, "completed_at": self.completed_at.isoformat(), } )
[docs] @classmethod def from_json(cls, json_string: str) -> "ScenarioResult": payload = json.loads(json_string) inst = cls(data_id=payload["data_id"]) completed_at = payload.get("completed_at") if completed_at: inst.completed_at = datetime.fromisoformat(completed_at) return inst