angee.compose.runtime
Build-time runtime source rendering and emission.
Runtime is the composer's emitter: it reads the discovered addons' abstract source models and renders the concrete Django apps under runtime/<label>/ that each source addon then adopts (see angee.compose.apps and docs/composer.md). render_sources is the seam — everything reaching it is generic plugin composition (discover, order, drift, clean); everything inside it is Angee's concrete emission.
ModelContributions
class ModelContributions(NamedTuple)Abstract source models one addon contributes, split by composition role.
owned
Models emitted as concrete runtime classes under the addon's label.
extensions
Same-row extensions that merge fields into another addon's model.
Runtime
class Runtime()Owner for Angee runtime rendering, emission, checks, and cleanup.
One object owns the whole build-time lifecycle so the plan and the emit travel together (docs/backend/guidelines.md → compose-onto-classes):
render_sources— the seam: returns{relative path: text}for the whole runtime. Every other entry point renders through it.emit— write that map toruntime_dirduring the explicitangee buildpass (resets, prunes orphans).is_current/check/_drift— disk vs the rendered map.reset/clean— delete generated files behind theGENERATED_SENTINELgate while preserving*/migrations/.
Construction groups source models by emitted label, resolves extends extensions, and fails fast on field collisions, so an invalid composition never reaches emission.
__init__
def __init__(addons: Iterable[AppConfig],
*,
runtime_dir: Path,
runtime_module: str = "runtime") -> NoneCreate a runtime renderer for addons and runtime_dir.
from_django
@classmethod
def from_django(cls) -> RuntimeReturn a runtime using installed addons and Django settings.
ANGEE_RUNTIME_DIR is the single owner of where the runtime lives. angee.compose.settings always sets it. A host that installs the composer without it is misconfigured, so fail loudly here rather than let a caller silently skip emission and surface a cryptic missing-model error later in app population.
render_sources
def render_sources() -> dict[Path, str]Return generated runtime source files keyed by relative path.
The composition seam. The returned map (path relative to runtime_dir → file text) is the single source of truth that emit writes and _drift compares against disk. It contains the generated package __init__ plus, per label, an empty app/migrations __init__ and a models.py. Migrations themselves are never rendered here — Django's makemigrations owns runtime/<label>/migrations/ (redirected via MIGRATION_MODULES), and cleanup preserves it.
emit
def emit() -> NoneReset the runtime and write all sources (destructive; explicit).
Used by the angee build command: it runs the _ensure_cleanable gate and prunes stale files (e.g. a removed addon's leftover label), then rewrites.
import_generated_models
def import_generated_models() -> NoneImport generated concrete model modules for all emitted labels.
emit_if_stale
def emit_if_stale() -> boolWrite the runtime when it drifts from the sources, on every boot.
Called from the composer's import_models in app-populate phase 2. Write-only and idempotent: it never resets or cleans, so a present-but- stale runtime is healed file by file and a corrupted or non-Angee directory can never abort app population through the destructive _ensure_cleanable gate. Orphaned files from a removed addon are pruned by the explicit angee build (which calls emit). Returning early when current keeps boots fast and avoids churning files the running process (and Django's autoreloader) already imported.
configure_migration_modules
def configure_migration_modules() -> RuntimeRedirect migrations for emitted runtime app labels.
is_current
def is_current() -> boolReturn whether the on-disk runtime matches the rendered sources.
check
def check() -> NoneRaise when generated runtime sources differ from disk.
reset
def reset() -> NoneClear generated runtime sources while preserving migrations.
clean
def clean() -> NoneDelete generated runtime files while preserving migrations.
model_contributions
def model_contributions(app_config: AppConfig) -> ModelContributionsReturn source models and extensions declared by one Django app config.
Runtime owns this scan because addons deliberately remain plain Django AppConfig classes with no shared Angee base method to delegate to.