Picarones / picarones /pipeline /cache_protocol.py
Claude
feat(sprint-H.3)!: renommage reports_v2/ → reports/
9011070 unverified
Raw
History Blame
2.82 kB
"""``ArtifactCachePort`` — port (Protocol) consommé par ``PipelineExecutor``.
Sprint A14-S47 — inversion de dépendance pour le branchement
``ArtifactStore`` dans le pipeline.
Pourquoi ce Protocol
--------------------
La couche ``pipeline/`` est plus interne que ``adapters/`` dans la
hiérarchie documentée du rewrite (``domain → formats → evaluation
→ pipeline → adapters → app → reports → interfaces``). Importer
depuis ``adapters/`` dans ``pipeline/`` violerait la règle de
dépendance.
On applique l'inversion de dépendance (pattern hexagonal /
ports-and-adapters) :
- ``pipeline/`` définit le **port** ``ArtifactCachePort`` (ce
module) — ce que le pipeline a besoin de consommer.
- ``adapters/storage/artifact_store.ArtifactStore`` (S29) est
l'**adapter** qui satisfait ce port par duck typing.
- Toute autre implémentation tierce (Redis, S3, GCS, ...) qui
implémente ces 5 méthodes est compatible.
Convention duck typing
----------------------
``StoredArtifact`` est aussi exposé comme Protocol minimal pour
éviter d'importer la dataclass concrète depuis ``adapters/``.
Les implémentations réelles fournissent une dataclass plus riche ;
``pipeline/`` ne consomme que ``stored.artifact`` et
``stored.artifact.uri``.
"""
from __future__ import annotations
from typing import Protocol, runtime_checkable
from picarones.domain.artifacts import Artifact
@runtime_checkable
class CachedArtifactRef(Protocol):
"""Port minimal consommé par ``read_cached_outputs``.
Les implémentations concrètes peuvent porter des champs
supplémentaires (``payload``, ``key``, …) ; ``pipeline/``
n'utilise que l'``Artifact`` reconstitué.
"""
@property
def artifact(self) -> Artifact: # pragma: no cover — Protocol
...
@runtime_checkable
class ArtifactCachePort(Protocol):
"""Contrat minimal d'un cache d'artefacts consommable par
``PipelineExecutor`` pour la reprise par hash.
Les méthodes correspondent **exactement** à l'API publique de
``ArtifactStore`` (S29) — ``ArtifactStore`` est donc compatible
par duck typing sans rien changer.
Pas d'``isinstance(store, ArtifactCachePort)`` requis : Python
type-checke à l'usage (les méthodes manquantes lèvent
``AttributeError`` au runtime). Le ``@runtime_checkable``
autorise un test ``isinstance`` côté caller s'il veut une
validation explicite.
"""
def get(self, key: str) -> CachedArtifactRef | None: # pragma: no cover
...
def put(
self,
key: str,
artifact: Artifact,
payload: bytes | None = None,
) -> None: # pragma: no cover
...
def __contains__(self, key: str) -> bool: # pragma: no cover
...
__all__ = ["ArtifactCachePort", "CachedArtifactRef"]