niess.dispatch¶
The registry mechanism every conversion target shares: three-tier resolution keyed on niess provenance or the McStas component type, for a live niess object or for an assembled instance.
niess.provenance is the record it resolves against — written onto every emitted McStas
component, and read back by whatever has only the emitted file.
dispatch
¶
Target-neutral registry dispatch over the assembled Instance tree.
Conversion targets (STEP/CAD geometry in :mod:niess.brep, NeXus Structure JSON
in :mod:niess.nexus) resolve a builder for each mccode_antlr Instance
using three tiers, most specific first:
- the niess
source_typerecorded in the instance's provenance metadata, - the niess
rolerecorded there, - the raw McCode component-type name, which every
Instancecarries whether or not niess produced it.
The registry only resolves builders; each target invokes them with whatever
signature it needs. Keeping resolution and invocation separate lets a caller
distinguish "no builder registered" from "a builder ran and declined to emit
anything" -- a distinction :mod:niess.nexus depends on for group suppression.
Classes:
-
NiessRegistry–Three-tier builder lookup keyed on provenance metadata or component type.
-
ClassHooks–Lets a class describe its own conversion, next to the fields it converts.
Functions:
-
expr_float–A plain float out of a McCode
Expr, orValueErrorif it is not one. -
merged_params–Instance parameters evaluated to floats, layered over
params.
NiessRegistry
¶
NiessRegistry(parent: 'NiessRegistry[B] | None' = None, hooks: str | None = None)
Bases: Generic[B]
Three-tier builder lookup keyed on provenance metadata or component type.
A registry may extend another by naming it as parent: lookups that find
nothing locally fall through to the parent's own three tiers. That is how an
instrument-specific registry adds its translators without touching the shared
default one, so which translators apply is a property of a single conversion
rather than of whatever the process happened to import.
Methods:
-
register–Register against a niess class (or its dotted
source_typename). -
register_role–Register against a provenance
role. -
register_component_type–Register against one or more raw McCode component-type names.
-
resolve_builder–Return the builder for
instance, orNoneif none is registered. -
resolve_for_object–Return the builder for a niess object, or
Noneif none is registered. -
registered_component_types–Component-type names this registry handles, inherited ones included.
Source code in src/niess/dispatch.py
register
¶
Register against a niess class (or its dotted source_type name).
Source code in src/niess/dispatch.py
register_component_type
¶
register_component_type(*comp_type_names: str)
Register against one or more raw McCode component-type names.
Source code in src/niess/dispatch.py
resolve_builder
¶
Return the builder for instance, or None if none is registered.
This registry's own three tiers are tried first, in full, before any parent is consulted: the more specific registry wins outright.
None means unhandled -- it never means "handled, emit nothing".
Callers that need that distinction must invoke the returned builder
themselves and interpret its return value.
Source code in src/niess/dispatch.py
resolve_for_object
¶
Return the builder for a niess object, or None if none is registered.
The companion to :meth:resolve_builder, which resolves against an emitted
McStas instance. Same tiers, read off the object rather than off a metadata blob
it left behind, most specific first:
- a translator registered for the object's exact class,
- the object's own hooks for this target, if it has any (see
:class:
ClassHooks) -- as specific as (1), because a class describing its own conversion is describing its conversion, - a translator registered for an ancestor class, nearest first,
- a translator registered for the object's role.
A registration for a base class does not beat a hook on the class itself:
registering something for Component says what to do with components in
general, and a component that says what to do with itself is more specific than
that.
There is no McCode-component-type tier: a type name is something an object acquires by being emitted, and nothing here has been.
As everywhere else, None means unhandled; it never means "handled, emit
nothing".
Source code in src/niess/dispatch.py
registered_component_types
¶
Component-type names this registry handles, inherited ones included.
Source code in src/niess/dispatch.py
ClassHooks
¶
ClassHooks(obj, prefix: str)
Lets a class describe its own conversion, next to the fields it converts.
A registry created with hooks='mccode' finds __mccode_enter__,
__mccode_leaf__ and __mccode_exit__ on a class and uses them as its
translator, so nothing has to be registered for the ordinary case. One with
hooks='nexus' does the same for __nexus_*__.
Both idioms are available for every target. Which suits depends on the target: a format with imperative scaffolding to place -- McStas, with its coordinate frames and per-particle state -- reads well as a method on the composite that needs it, while one that is mostly a table of per-type mappings reads better registered.
Source code in src/niess/dispatch.py
expr_float
¶
A plain float out of a McCode Expr, or ValueError if it is not one.
hasattr(expr, 'value') is not the test it looks like: Expr.value is a property
that raises for anything not constant, and hasattr only swallows
AttributeError, so asking whether an expression has a value used to raise
NotImplementedError straight through every caller. Every caller catches
TypeError/ValueError -- that is what "this names a run-time parameter, skip it"
is spelled as throughout niess -- so an expression that does not reduce says so that
way.
Source code in src/niess/dispatch.py
merged_params
¶
Instance parameters evaluated to floats, layered over params.
Parameters that cannot be reduced to a float (they depend on a runtime instrument parameter, say) are skipped rather than raising.
Source code in src/niess/dispatch.py
provenance
¶
What niess wrote a component from, recorded on the component it emitted.
Every McStas instance niess emits carries a niess_provenance METADATA block naming the
niess class and instance behind it. This module is both halves of that: writing it during
emission, and reading it back when something that has only the emitted instrument needs to
know what it came from.
The namespace string in that block is literally this module's own name, and
niess_source_type is what puts a class's __module__ into the emitted file -- so the
frozen .instr goldens in tests/data/baseline pin the import path of every component
class. Moving niess/components/guide.py changes emitted text; moving this module changes
the namespace every previously-written file is recognised by. Neither is a rename to make
casually.
Below niess.dispatch, which resolves a translator from what it reads here, and therefore
below every target. Writing happens through add_niess_metadata, called from the
components themselves.
Functions:
-
add_visit_metadata–Write provenance for one emitted instance, unless this emission opted out.
add_visit_metadata
¶
Write provenance for one emitted instance, unless this emission opted out.
Every McStas emitter on the walk goes through here rather than calling
add_niess_metadata directly, so that "emit without the niess METADATA blocks" is
one decision made once at to_mccode rather than a flag each of seven call sites
has to remember to honour -- and so that a translator added later cannot forget it.