Decorators¶
Module: alienbio.spec_lang
Python decorators for registering functions and classes in the ABIO system. All decorators and YAML tag implementations live in the spec_lang module.
Type Registration¶
Type registration is done via Entity subclassing, not decorators:
- Subclassing
Entitymakes a class a biotype automatically - Entity subclasses are hydratable/dehydratable via
to_dict()/from_dict()methods - On load:
{"_type": "Chemistry", ...}→Chemistry(...) - On save:
Chemistry(...)→{"_type": "Chemistry", ...}
See Entity for details on the Entity base class.
Function Decorators¶
All function decorators inherit from @fn and share common metadata.
@fn¶
Base decorator for all functions. Stores metadata for documentation, plots, and tooling.
@fn(summary="One-liner for plots/tables",
range=(0.0, 1.0),
category="scoring.process", # arbitrary additional metadata
reference="Author, Year")
def function_name(args):
"""Detailed docstring for documentation."""
...
| Metadata | Required | Description |
|---|---|---|
summary |
Yes | Short description for plots/tables |
range |
Yes* | Expected output range (*not required for actions) |
| (other) | No | Arbitrary kwargs stored as fn.meta[key] |
@scoring¶
Evaluation metrics for scenarios. Used by sim.results() to compute final scores.
@scoring(summary="Population health of protected species",
range=(0.0, 1.0),
higher_is_better=True)
def population_health(timeline, species):
"""Measures final population health."""
...
| Metadata | Description |
|---|---|
higher_is_better |
Direction of optimization |
@action¶
Agent actions that modify simulation state. Called via sim.action(name, ...).
@action(summary="Add feedstock molecules to a region",
targets="regions",
reversible=False,
cost=1.0)
def add_feedstock(sim, region, molecule, amount):
"""Add molecules from feedstock to substrate."""
...
| Metadata | Description |
|---|---|
targets |
What the action operates on (regions, organisms, etc.) |
reversible |
Whether effects can be undone |
cost |
Resource cost of taking this action |
@measurement¶
Agent observations that read simulation state. Called via sim.measure(name, ...).
@measurement(summary="Sample substrate concentrations",
targets="regions",
cost="none")
def sample_substrate(sim, region):
"""Get molecule concentrations in a region."""
return sim.get_concentrations(region)
| Metadata | Description |
|---|---|
targets |
What can be observed (regions, organisms, etc.) |
returns |
Description of return value structure |
cost |
Resource cost of taking this measurement |
@rate¶
Reaction rate laws for chemistry. Used in reaction definitions.
@rate(summary="Mass action rate law",
range=(0.0, float('inf')))
def mass_action(ctx, k=0.1):
"""Derives rate from equation using Law of Mass Action."""
...
Future: Rate functions will be JIT-compiled via JAX for GPU acceleration.
@factory¶
Registers an implementation class for a protocol. Multiple implementations can exist for each protocol.
@factory(name="reference", protocol=Simulator)
class ReferenceSimulatorImpl(Simulator):
"""Reference implementation - accurate but slow."""
def __init__(self, spec=None):
self.chemistry = spec
...
@factory(name="fast", protocol=Simulator)
class FastSimulatorImpl(Simulator):
"""Optimized implementation - faster but approximations."""
...
| Parameter | Description |
|---|---|
name |
Implementation name (e.g., "reference", "fast") |
protocol |
Protocol class this implements |
Creating instances with bio.create():
from alienbio import bio
# Create with default implementation
sim = bio.create(Simulator, spec=chemistry)
# Create with specific implementation
sim = bio.create(Simulator, name="fast", spec=chemistry)
# Assign to pegboard for global access
bio.sim = bio.create(Simulator, spec=chemistry)
# Ensure pattern (only create if not set)
bio.sim = bio.sim or bio.create(Simulator, spec=chemistry)
Resolution order:
nameparameter — explicit programmatic choice- Config default —
~/.config/alienbio/defaults.yaml - Error — no silent fallback
Config defaults:
See Factory Pegboard API for full documentation.
Summary Table¶
| Decorator/Pattern | Purpose | Registration | Called via |
|---|---|---|---|
Entity subclass |
Class hydration | automatic | Bio.fetch() |
@fn |
Base function | — | direct call |
@scoring |
Evaluation metrics | scoring registry | sim.results() |
@action |
Agent actions | action registry | sim.action() |
@measurement |
Agent observations | measurement registry | sim.measure() |
@rate |
Reaction rates | rate registry | reaction evaluation |
@factory |
Multiple implementations | factory registry | bio.create() |
FnMeta Class¶
All function decorators wrap their functions in FnMeta, which stores metadata and delegates calls to the original function.
from alienbio.spec_lang import scoring
@scoring(summary="Test score", range=(0.0, 1.0))
def test_fn():
return 0.5
# Access metadata
test_fn.meta["summary"] # "Test score"
test_fn.meta["range"] # (0.0, 1.0)
test_fn.meta["higher_is_better"] # True (default for @scoring)
# Call function normally
result = test_fn() # 0.5
| Property/Method | Description |
|---|---|
meta |
Dict of all metadata (summary, range, etc.) |
func |
The original unwrapped function |
__call__(*args, **kwargs) |
Delegates to original function |
Registry Access Functions¶
Look up registered functions by name. All raise KeyError if not found.
from alienbio.spec_lang import get_action, get_measurement, get_scoring, get_rate
# Look up registered functions
action_fn = get_action("add_feedstock")
measure_fn = get_measurement("sample_substrate")
score_fn = get_scoring("population_health")
rate_fn = get_rate("mass_action")
# Access their metadata
action_fn.meta["cost"] # 1.0
score_fn.meta["higher_is_better"] # True
| Function | Registry | Returns |
|---|---|---|
get_action(name) |
action_registry |
Action function |
get_measurement(name) |
measurement_registry |
Measurement function |
get_scoring(name) |
scoring_registry |
Scoring function |
get_rate(name) |
rate_registry |
Rate function |
Implementation Notes¶
All decorators assume the decorated functions/classes are loaded into the environment before use. This happens via:
- spec.include("functions.py") — loads Python file, decorators register automatically
- Direct import in Python code
The registries are global singletons. Registration happens at decoration time (module load), not at call time.
See Also¶
- [[Spec Language]] — YAML syntax and tags (
!ev,!ref,!include) - Bio — Loading and hydration
- Entity — Base class for hydratable types
- Factory Pegboard API — Factory pattern and Bio pegboard