Source code for django_snapshots.storage.protocols
"""Storage protocol definitions for django-snapshots.
Two stacked protocols:
- ``SnapshotStorage``: minimum interface, satisfied by LocalFileSystemBackend
and DjangoStorageBackend.
- ``AdvancedSnapshotStorage``: extends with streaming/atomic operations,
satisfied by LocalFileSystemBackend and RcloneBackend.
Third-party backends use structural subtyping — no inheritance required.
"""
from __future__ import annotations
from typing import IO, Iterator, Protocol, runtime_checkable
from django_snapshots.exceptions import SnapshotStorageCapabilityError
[docs]
@runtime_checkable
class SnapshotStorage(Protocol):
"""Minimum storage interface.
``read`` and ``write`` use ``IO[bytes]`` file-like objects to avoid loading
entire artifacts into memory.
``list(prefix)`` returns all stored paths whose full path string starts with
*prefix*. Pass ``""`` to list everything.
"""
[docs]
def read(self, path: str) -> IO[bytes]: ...
[docs]
def write(self, path: str, content: IO[bytes]) -> None: ...
[docs]
def list(self, prefix: str) -> list[str]: ...
[docs]
def delete(self, path: str) -> None: ...
[docs]
def exists(self, path: str) -> bool: ...
[docs]
@runtime_checkable
class AdvancedSnapshotStorage(SnapshotStorage, Protocol):
"""Extended storage interface with streaming and atomic operations.
Required for ``snapshot_format="archive"`` and for future incremental
backup support.
"""
[docs]
def stream_read(self, path: str) -> Iterator[bytes]: ...
[docs]
def stream_write(self, path: str, chunks: Iterator[bytes]) -> None: ...
[docs]
def atomic_move(self, src: str, dst: str) -> None: ...
[docs]
def recursive_list(self, prefix: str) -> list[str]: ...
[docs]
def sync(self, src_prefix: str, dst_prefix: str) -> None: ...
[docs]
def requires_advanced_storage(backend: SnapshotStorage, operation: str) -> None:
"""Raise ``SnapshotStorageCapabilityError`` if *backend* is not an ``AdvancedSnapshotStorage``.
Call this at the start of any function that requires the extended interface.
"""
if not isinstance(backend, AdvancedSnapshotStorage):
raise SnapshotStorageCapabilityError(
f"Operation '{operation}' requires AdvancedSnapshotStorage, but "
f"{type(backend).__name__!r} only satisfies SnapshotStorage. "
"Use LocalFileSystemBackend or RcloneBackend for this feature."
)