Source code for simvx.core.assets.sources.pkg
"""Package-resource source: resolves ``pkg://<package>/<path>`` URIs."""
from __future__ import annotations
import importlib.resources
from collections.abc import Iterable
from importlib.resources.abc import Traversable
[docs]
class PkgSource:
"""Reads bytes from a Python package via :mod:`importlib.resources`.
URI form: ``pkg://<package>/<path>`` where path may contain forward
slashes for nested files (``pkg://game/textures/player.png``).
"""
scheme = "pkg"
def _resolve(self, uri: str) -> Traversable:
package, _, path = self._split(uri)
root = importlib.resources.files(package)
if not path:
return root
node = root
for part in path.split("/"):
if not part:
continue
node = node / part
return node
@staticmethod
def _split(uri: str) -> tuple[str, str, str]:
if not uri.startswith("pkg://"):
raise ValueError(f"PkgSource expects pkg:// URI, got {uri!r}")
rest = uri[len("pkg://"):]
if "/" in rest:
package, path = rest.split("/", 1)
else:
package, path = rest, ""
return package, "/", path
[docs]
def read_bytes(self, uri: str) -> bytes:
return self._resolve(uri).read_bytes()
[docs]
def version(self, uri: str) -> str | None:
# Package resources are immutable across a Python session; no version hint.
return None
[docs]
def list(self, uri: str) -> Iterable[str]:
node = self._resolve(uri)
if not node.is_dir():
raise NotADirectoryError(f"PkgSource.list expects a directory URI, got {uri!r}")
package, _, path = self._split(uri)
prefix = f"pkg://{package}/" + (f"{path}/" if path else "")
for child in node.iterdir():
yield prefix + child.name