an.genres.registry#
The core’s open registries: action kinds, entity kinds, semantic checks, md sugar, compile passes.
ADR 0001 decision 2 (“the IR is open at the type level; genres register, never
edit”) and decision 4 (the first batch of registries). Each registry is a plain
name-keyed table with an owner per entry, so the core can tell its own
entries from a genre’s (the timing contract does the same, review-237 S3), and a
test can take every genre out and put it back (snapshot() /
restore()).
This module imports nothing from an.ir: the schema consults it while it
validates (a document’s kind: play is looked up here), so it must sit below
the schema in the import graph. That is also why an entry holds its model class
and hooks as plain values: the registry never needs to know what they are.
>>> isinstance(action_kind("tween"), ActionKind) # core kinds register on import of the IR
True
>>> "play" in action_kind_names(owner=CORE_OWNER) # a genre's kind is never the core's
False
Module Attributes
The owner of every entry the core registers itself. |
|
the natural length of a leaf. |
|
once before the shots, once per shot, once after them. |
|
The bracket pairs a GENRE may claim on a |
Functions
|
The registered kind called |
|
Registered action-kind names in registration order; |
|
|
|
|
|
Who registered the check |
|
The registered checks of |
|
|
|
Who registered the compile pass |
|
The registered passes of |
|
The sugar registered for the bracket |
|
|
|
|
|
|
|
|
|
The modules whose code the genres' registered hooks run, sorted and unique. |
|
Every owner with at least one entry, the core first. |
|
Register an action kind. |
|
Register a semantic-validation check (run by |
|
Register a compile pass (or an entity builder) under its name. |
|
Register |
|
Register an entity kind (a value |
|
Register runtime code for an engine (a genre's visual kinds). |
|
Register a named service a genre offers the core (an#225). |
|
The registered service |
|
|
|
The scripts registered for |
|
The registered service |
|
|
|
The state of every table, for |
|
Remove every entry |
Classes
|
One kind of action: its model, how it occupies time, how |
|
One step a genre adds to an engine's COMPILER (shot -> compiled document). |
|
|
|
One kind of entity ( |
|
JavaScript a genre adds to an engine's RUNTIME (an#247; ADR 0001 decision 4, second batch): for the stage, code that registers visual kinds with |
|
One semantic-validation check: |
|
What one entity's descriptor declares for the stage compiler's swap vocabulary. |
Exceptions
A registration is malformed or collides with one already made. |
|
The core asked a genre for a service nobody registered. |
|
|
A document names a kind no loaded genre registered. |
- class an.genres.registry.ActionKind(name, model, duration=None, flatten=None, children=None, read_md=None, write_md=None, md_start=True, description='', version='1', lowering=None)[source]#
Bases:
objectOne kind of action: its model, how it occupies time, how
scene.mdspells it.modelvalidates a document’s action of this kind. A genre’s model subclassesan.ir.schema.ExtensionAction; the core’s are the static members of the schema’s union.durationis a LEAF’s natural length; a leaf flattens to oneFlatActionon[t, t + duration]and advances asequenceby it.flattenreplaces that default for kinds that place themselves differently (setdoes not advance the cursor) or that hold children (sequence):flatten(action, t, ctx) -> new cursor, wherectxisan.ir.compose.FlattenContext.childrenlists a composite’s child actions, so generic walkers (validation) reach every leaf without knowing the kind.read_md/write_mdare thescene.mdyaml actionshooks:read_md(item, index=i) -> action(start:already removed whenmd_start) andwrite_md(action) -> dict(withoutstart). A kind with noread_mdhas noscene.mdform.
- lowering: Any = None#
How the STAGE compiler turns an action of this kind into clips, for a kind that is not a plain tween or set (the cut-out
play): an object withextent_resolver(vocab, *, products),expand(flat_list, *, vocab, fps, step_hz, default_easing, resolutions, products),view_of(entity_swaps, vocab, *, duration)andclip(action, *, anim_id, vocab, fps, view)– seean.stage.compile.ActionLowering.None: the compiler has nothing kind-specific to do. (an#225: this is how the compiler stops namingplay.)
- version: str = '1'#
bump when what an action of this kind compiles to changes for the same fields, so the shots that use it re-render visibly (
an.semanticfolds it into the shot digest).- Type:
The kind’s vocabulary version (ADR 0003)
- an.genres.registry.CORE_OWNER: str = 'an'#
The owner of every entry the core registers itself. A genre registers under its own name (
an.genres.Genre.name).
- an.genres.registry.CheckStage#
once before the shots, once per shot, once after them.
- Type:
When a check runs
alias of
Literal[‘scene’, ‘shot’, ‘finish’]
- class an.genres.registry.CompilePass(name, run, order=0.0, compiler='stage', builds=None, description='', replace=False)[source]#
Bases:
objectOne step a genre adds to an engine’s COMPILER (shot -> compiled document).
A compiler (
compiler: today"stage",an.stage.compile) runs its own passes plus every registered one, inorder. A pass withbuildsset is an ENTITY BUILDER instead: the compiler’s scene pass calls it for each entity of that kind (the cut-out genre’srigbuilds acharacter); builders with a lowerorderbuild all their entities first (the stage’s backdrop before the cast), equal orders in entity order.runis the callable, or"module:function", resolved on first use – so a genre is inspectable (an.genres.available()) without importing the engine its passes target. Whatrunreceives is the compiler’s business (the stage hands a pass itsCompileState, a builder the entity and the scene being built); the core never calls it.
- an.genres.registry.DIALOGUE_BRACKETS: dict[str, str] = {'[': ']'}#
The bracket pairs a GENRE may claim on a
scene.mddialogue line. The line grammar has three:(…)(timing) and{…}(delivery direction) are the core’s own and never registered;[…]is the one left for sugar.
- class an.genres.registry.DialogueSugar(name, opener, field, parse, format, description='', fields=())[source]#
Bases:
objectscene.mdsugar on a dialogue line: one bracket pair, oneDialoguefield (and, declared infields, the parameters it may carry).parse(content) -> valueturns what is between the brackets into the field’s value (raiseValueError(why)to refuse it);format(line) -> str | Noneis the inverse (the content, without brackets, orNonewhen the line carries none). The cut-out genre’s[emotion]is one.A sugar that also sets other
Dialoguefields ([angry 0.4]: the emotion and itsemotion_intensity, an#253) names them infields; itsparsethen returns{field name: value}overfieldand any offields, andformatwrites them back.
- an.genres.registry.DurationHook#
the natural length of a leaf.
extentis the caller’s per-call resolver for a leaf that has no explicit duration (the compiler andan validatepass one bound to the entity’s descriptor), orNone.- Type:
(action, extent) -> seconds
- class an.genres.registry.EntityKind(name, space=None, store=None, description='', version='1', swap_declaration=None, descriptor_kind=None, placeholder_on_missing=False, swap_checks=None, specimen=None)[source]#
Bases:
objectOne kind of entity (
AssetRef.kind): what its nodes’ properties are.spacenames the registeredan.timing.spaces.PropertySpaceits nodes’ properties live in (None: the entity has no animatable nodes, as a voice);storeis the project-mall store itsrefkeys into.- descriptor_kind: str | None = None#
The
kindtag of the descriptor documentstoreholds for this kind ("CharacterDescriptor"): what makes the validator treat the entity as a rig whose declared asset sets it can check (an#246).
- placeholder_on_missing: bool = False#
A missing
refis NOT an error because the compiler draws a placeholder instead; the genre reports it with its own (warning) check.
- specimen: Callable[[Any], Any] | None = None#
a short shot showing one entity of this kind on its own, the one
refcasts — whatan library sheetdraws for a version of it (an#347).None: the sheet shows a labelled placeholder.- Type:
(ref: AssetRef) -> Shot
- swap_checks: Any = None#
an object with
missing_set_hint(prop) -> str(appended to “names no declared asset set”) andwhole_entity(action, desc, prop, keys, entity_id, *, where, report, art_exists) -> bool(judge a swap on the entity ITSELF;Truewhen handled).None: the generic per-node rule only.- Type:
Extra swap-reference checks for this kind
- swap_declaration: Callable[[Any, Any], SwapDeclaration | None] | None = None#
what the entity’s descriptor declares for the stage compiler’s swap vocabulary (an#87).
None: the kind declares nothing (its built nodes’ sets ARE its declaration).- Type:
(entity, mall) -> SwapDeclaration | None
- version: str = '1'#
The kind’s vocabulary version (ADR 0003), as
ActionKind.version.
- exception an.genres.registry.RegistryError[source]#
Bases:
ValueErrorA registration is malformed or collides with one already made.
- class an.genres.registry.RuntimeScript(name, source, engine='stage', description='')[source]#
Bases:
objectJavaScript a genre adds to an engine’s RUNTIME (an#247; ADR 0001 decision 4, second batch): for the stage, code that registers visual kinds with
window.anRegisterVisual(kind, make)– how the cut-out mouth and eye leaveruntime.jsforcutan(P8).sourceis"package:relative/path.js", read withimportlib.resourceswhen the engine stages its runtime, so it ships in the genre’s wheel. The staged code is part of the shot cache’s key.
- class an.genres.registry.SemanticCheck(name, run, stage='shot', order=0.0, description='')[source]#
Bases:
objectOne semantic-validation check:
run(ctx)adds findings toctx.report.ctxisan.ir.validate.ValidationContext; ashotcheck is called once per shot withctx.shotset. Within a stage, checks run byorder(then registration order), so a genre’s check lands exactly where it belongs in the report.
- exception an.genres.registry.ServiceMissingError[source]#
Bases:
RegistryError,ImportErrorThe core asked a genre for a service nobody registered.
- class an.genres.registry.SwapDeclaration(sets, descriptor=None, art_exists=None, scale=1.0)[source]#
Bases:
objectWhat one entity’s descriptor declares for the stage compiler’s swap vocabulary.
setsis{set name: {KEY: attachment name}}as declared;descriptoris the (migrated) document the declaration came from, kept for the kind’s own lowering;art_existsanswersrel_path -> art on disk(Nonewhen the store cannot say);scaleis the factor from the entity’s view box to scene pixels.
- exception an.genres.registry.UnregisteredKindError(what, name, *, known=(), providers=(), where='')[source]#
Bases:
RegistryErrorA document names a kind no loaded genre registered.
The message names the installed genres that could provide it (read from their declarations, which are inspectable without loading them), so the fix is one line:
an.genres.load(), or installing the package named.
- an.genres.registry.action_kind(name)[source]#
The registered kind called
name, orNone.- Return type:
- an.genres.registry.action_kind_names(*, owner=None)[source]#
Registered action-kind names in registration order;
owner’s only when given.
- an.genres.registry.check_owner(name)[source]#
Who registered the check
name(CORE_OWNERfor the core’s), orNone.
- an.genres.registry.checks(stage)[source]#
The registered checks of
stage, in run order (order, then registration).- Return type:
- an.genres.registry.compile_pass_owner(name)[source]#
Who registered the compile pass
name(a genre’s name), orNone.
- an.genres.registry.compile_passes(compiler)[source]#
The registered passes of
compiler(builders excluded), in run order.- Return type:
- an.genres.registry.dialogue_sugar(opener)[source]#
The sugar registered for the bracket
opener, orNone.- Return type:
- an.genres.registry.entity_builders(compiler)[source]#
{entity kind: builder}registered forcompiler.- Return type:
- an.genres.registry.hook_modules(*, exclude_owner='an')[source]#
The modules whose code the genres’ registered hooks run, sorted and unique.
Compile passes, lowerings, entity hooks, checks, services and runtime scripts of every owner but
exclude_owner(the core’s own are walked from the renderer already). The shot cache’s code key starts its walk here for the packages outsidean, so a change to a genre’s code changes the key (an#294): the genre is reached by REGISTRATION, not by an import froman.>>> isinstance(hook_modules(), tuple) True
- an.genres.registry.register_action_kind(kind, *, owner='an', replace=False)[source]#
Register an action kind. Its model’s
kindmust default to its name.- Return type:
>>> from pydantic import BaseModel >>> class Bad(BaseModel): ... kind: str = "other" >>> register_action_kind(ActionKind("wave", Bad), owner="demo") Traceback (most recent call last): ... an.genres.registry.RegistryError: action kind 'wave': ...
- an.genres.registry.register_check(check, *, owner='an', replace=False)[source]#
Register a semantic-validation check (run by
an.ir.validate.validate_semantic).- Return type:
- an.genres.registry.register_compile_pass(compile_pass, *, owner='an', replace=False)[source]#
Register a compile pass (or an entity builder) under its name.
- Return type:
- an.genres.registry.register_dialogue_sugar(sugar, *, owner='an', replace=False)[source]#
Register
scene.mddialogue sugar. One sugar per bracket pair.- Return type:
- an.genres.registry.register_entity_kind(kind, *, owner='an', replace=False)[source]#
Register an entity kind (a value
AssetRef.kindmay take).- Return type:
- an.genres.registry.register_runtime_script(script, *, owner='an', replace=False)[source]#
Register runtime code for an engine (a genre’s visual kinds).
- Return type:
- an.genres.registry.register_service(name, target, *, owner='an', replace=False)[source]#
Register a named service a genre offers the core (an#225).
The seam for the places where the core needs a genre’s code only when that genre is installed: a CLI namespace (
cli.character), a provider factory (lipsync.offline), a licence lookup.targetis the object itself or"module:attr"(imported on first use, so declaring a service imports no engine). The names a genre may use are the core’s contract, listed with their callers inmisc/docs/architecture_as_built.md.- Return type:
- an.genres.registry.require_service(name, *, what='', extra='cutout')[source]#
The registered service
name; a typed error naming the install when absent.- Return type:
- an.genres.registry.runtime_scripts(engine)[source]#
The scripts registered for
engine, by name (a stable order).- Return type:
- an.genres.registry.service(name, default=None)[source]#
The registered service
name, resolved, ordefaultwhen none is.- Return type:
>>> service("no.such.service") is None True