Generate Configuration Using Configuration Schemas#

This guide shows how to use ConfigurationSchema to create a configuration. This allows to program the configuration if you prefer instead of using any of the options based on a JSON Schema.

Discover Schemas#

First create the registry and discover available schemas.

from pyaml.validation import SchemaRegistry

registry = SchemaRegistry()
registry.discover()

Create Configuration for Accelerator#

To create a configuration for an accelerator start by extracting the schema for it from the registry. You can see the required fields and their description using describe().

Unfortunately static type checking does not work since the schema is generated dynamically.

accelerator_schema = registry["pyaml.accelerator.Accelerator"]
print(accelerator_schema.describe())
AcceleratorConfigurationSchema(
    class_path: str — Fully qualified class path.
    facility: str
    machine: str
    energy: float
    alphac: float | None
    harmonic_number: int | None
    controls: list[pyaml.control.controlsystem.ControlSystemConfigurationSchema] | None
    simulators: list[pyaml.lattice.simulator.SimulatorConfigurationSchema] | None
    arrays: list[pyaml.arrays.array.ArrayConfigConfigurationSchema] | None
    devices: list[pyaml.common.element.ElementConfigurationSchema] | None
    data_folder: str | None
    description: str | None
)

For the subschemas, you can list available subclasses that are available in the registry.

from pprint import pprint

control_system_schema = registry["pyaml.control.controlsystem.ControlSystem"]

subclasses = registry.subclasses_of(control_system_schema)

pprint(subclasses)
{'pyaml_cs_oa.controlsystem.OphydAsyncControlSystem': <class 'pyaml_cs_oa.controlsystem.OphydAsyncControlSystemConfigurationSchema'>,
 'tango.pyaml.controlsystem.TangoControlSystem': <class 'tango.pyaml.controlsystem.TangoControlSystemConfigurationSchema'>}

You can list the required fields for them in the same way as before.

tango_schema = registry["tango.pyaml.controlsystem.TangoControlSystem"]
print(tango_schema.describe())
TangoControlSystemConfigurationSchema(
    class_path: str — Fully qualified class path.
    name: str
    tango_host: str | None
    catalog: tango.pyaml.catalog.CatalogConfigurationSchema | None
    debug_level: str | int | None
    lazy_devices: bool
    timeout_ms: int
)

Since ConfigurationSchema inherits from Pydantic BaseModel the configuration is validated for each object you create, meaning you can validate the configuration step-by-step instead of validating the whole nested structure in one step.

live_mode = tango_schema(
    class_path = "tango.pyaml.controlsystem.TangoControlSystem",
    name = "live",
    )

print(type(live_mode))
print(live_mode)
<class 'tango.pyaml.controlsystem.TangoControlSystemConfigurationSchema'>
class_path='tango.pyaml.controlsystem.TangoControlSystem' name='live' tango_host=None catalog=None debug_level=None lazy_devices=True timeout_ms=3000
accelerator = accelerator_schema(
    class_path='pyaml.accelerator.Accelerator',
    facility = 'pyaml_facility',
    machine = 'storage_ring',
    energy = 1e6,
    controls = [live_mode]
    )

print(type(accelerator))
print(accelerator)
<class 'pyaml.accelerator.AcceleratorConfigurationSchema'>
class_path='pyaml.accelerator.Accelerator' facility='pyaml_facility' machine='storage_ring' energy=1000000.0 alphac=None harmonic_number=None controls=[TangoControlSystemConfigurationSchema(class_path='tango.pyaml.controlsystem.TangoControlSystem', name='live', tango_host=None, catalog=None, debug_level=None, lazy_devices=True, timeout_ms=3000)] simulators=None arrays=None devices=None data_folder=None description=None

You have now created a Pydantic BaseModel which describes the configuration and can dump it to a dictionary or JSON using Pydantic functionality depending on what you prefer.

print(accelerator.model_dump())
{'class_path': 'pyaml.accelerator.Accelerator', 'facility': 'pyaml_facility', 'machine': 'storage_ring', 'energy': 1000000.0, 'alphac': None, 'harmonic_number': None, 'controls': [{'class_path': 'tango.pyaml.controlsystem.TangoControlSystem', 'name': 'live', 'tango_host': None, 'catalog': None, 'debug_level': None, 'lazy_devices': True, 'timeout_ms': 3000}], 'simulators': None, 'arrays': None, 'devices': None, 'data_folder': None, 'description': None}
print(accelerator.model_dump_json(indent=2))
{
  "class_path": "pyaml.accelerator.Accelerator",
  "facility": "pyaml_facility",
  "machine": "storage_ring",
  "energy": 1000000.0,
  "alphac": null,
  "harmonic_number": null,
  "controls": [
    {
      "class_path": "tango.pyaml.controlsystem.TangoControlSystem",
      "name": "live",
      "tango_host": null,
      "catalog": null,
      "debug_level": null,
      "lazy_devices": true,
      "timeout_ms": 3000
    }
  ],
  "simulators": null,
  "arrays": null,
  "devices": null,
  "data_folder": null,
  "description": null
}