Source code for bacommon.assetref._wrapper

# Released under the MIT License. See LICENSE for details.
#
"""Runtime accessor for generated asset-reference wrapper packages.

A generated wrapper module exposes per-kind roots (``textures``,
``meshes``, ...) built from a compact nested kind-code tree; its precise
types live in the module's ``if TYPE_CHECKING`` shadow (a ``FooGroup``
class per subdir, each asset a typed property). This drives the *runtime*
side: a leaf reads as a property yielding the kind's reference type, a
subdir is a nested :class:`AssetRefDir`.

This mirrors the client-side asset wrappers (``bauiv1._assetwrap.AssetDir``)
except it yields a language-independent *reference* (:class:`TextureRef` /
:class:`MeshRef`) rather than loading the actual engine asset -- so the
same ergonomics (``pkg.textures.zoe_icon``) work server-side where no real
assets exist.
"""

from __future__ import annotations  # Docs-generation hack.

from bacommon.assetref._core import TextureRef, MeshRef

#: A node in a wrapper's kind-code tree: each key is one path segment; a
#: ``dict`` value is a subdirectory and a ``str`` value is a leaf asset
#: whose string is its single-char kind code (see :func:`_make`).
type AssetRefTree = dict[str, 'str | AssetRefTree']


[docs] class AssetRefDir: """Dynamic accessor for one subdirectory of an asset-package's refs. Attribute access resolves against the wrapper's nested kind-code tree: a subdirectory yields another :class:`AssetRefDir`; a leaf yields the reference for its kind. All real type information lives in the wrapper's ``if TYPE_CHECKING:`` shadow, so callers never type-check through this class. """ __slots__ = ('_apverid', '_node', '_prefix') def __init__(self, apverid: str, node: AssetRefTree, prefix: str) -> None: self._apverid = apverid self._node = node self._prefix = prefix def __getattr__(self, name: str) -> 'AssetRefDir | TextureRef | MeshRef': try: child = self._node[name] except KeyError: raise AttributeError(name) from None path = f'{self._prefix}/{name}' if self._prefix else name if isinstance(child, dict): return AssetRefDir(self._apverid, child, path) return _make(self._apverid, path, child)
def _make(apverid: str, path: str, kind: str) -> TextureRef | MeshRef: """Build a single leaf reference by its single-char kind code.""" if kind == 't': return TextureRef(apverid, path) if kind == 'm': return MeshRef(apverid, path) raise ValueError(f'Invalid asset-ref kind {kind!r} for {apverid}:{path}.') # Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum