Source code for simvx.core.assets.source

"""Source protocol: abstract storage backend that yields bytes for a URI.

Sources do *not* parse: they just resolve a URI to bytes (and optional
versioning metadata). Loaders parse those bytes into typed assets.

URI schemes supported by built-in Sources:

* ``pkg://<package>/<path>``: Python package resource (importlib.resources).
* ``file:///<absolute path>``: filesystem.
* Bare relative path: also routed to ``FileSource`` for ergonomics.
* ``http://...`` / ``https://...``: network (HttpSource).
* ``mem://<key>``: in-memory test source.

User code rarely touches Sources directly; the
:class:`~simvx.core.assets.server.AssetServer` looks up the right Source
from a URI's scheme.
"""

from __future__ import annotations

from collections.abc import Iterable
from typing import Protocol, runtime_checkable


[docs] @runtime_checkable class Source(Protocol): """Storage backend mapped to a URI scheme. Implementations should be cheap to construct and stateless beyond configuration; the ``AssetServer`` shares one instance per scheme. """ scheme: str # e.g. "pkg", "file", "https"
[docs] def read_bytes(self, uri: str) -> bytes: """Resolve *uri* and return the contents as raw bytes. Should raise :class:`FileNotFoundError`, :class:`OSError`, or a source-specific exception on failure. Network sources may raise :class:`ConnectionError` or :class:`TimeoutError`. """ ...
[docs] def version(self, uri: str) -> str | None: """Return a version hint (etag/mtime/None) for cache invalidation. Implementations that don't support versioning return ``None``. ``AssetServer`` uses the value as part of the cache key. """ ...
[docs] def list(self, uri: str) -> Iterable[str]: """List child URIs under *uri* (folder enumeration). Sources that cannot list (e.g. HTTP without directory indexing) should raise :class:`NotImplementedError`. """ ...