redsun.presenter¶
Positioner¶
PositionerPresenter
dataclass
¶
PositionerPresenter(
name: str,
*,
devices: DeviceMapping,
include: list[str] | None = None,
timeout: float = 10.0,
)
Bases: Loggable
Move the axes of devices by hand, one move at a time per device.
Axes are grouped by the device holding them: an axis is a row of the box
of its parent, or a box of its own when it has none. Every box is kept, or
only those named in include. Each axis is described and followed from
the start, and its readbacks are relayed on sig_readback; an axis that
cannot be, within timeout, is left out with a warning.
A step starts from the setpoint, so steps add up exactly, and from the
readback after a stop or a failure, when the setpoint no longer says
where the axis is. Every target passes
check before it is sent.
The limits of an axis are read again after each configuration write to
its device and after a move that is refused or fails, and before each move
of an axis that is not Checkable; a change is reported on sig_limits.
sig_readback
class-attribute
instance-attribute
¶
Device, axis and position, whenever the axis reads back.
sig_moving
class-attribute
instance-attribute
¶
Device, and whether it starts or ends a move.
sig_failed
class-attribute
instance-attribute
¶
Device, and why a move or a stop failed.
sig_configuration
class-attribute
instance-attribute
¶
Key and value of a configuration signal, whenever it changes and after a write.
sig_limits
class-attribute
instance-attribute
¶
Device, axis, and its new low and high limits; None for no bound.
devices
class-attribute
instance-attribute
¶
Devices of the session, searched for axes, with the devices below them.
include
class-attribute
instance-attribute
¶
Names of the boxes to keep; None keeps every box.
timeout
class-attribute
instance-attribute
¶
Seconds an axis may take to be described and followed at the start.
axes
property
¶
The axes of each box, by row, by the name of the device holding them.
configuration
property
¶
The configuration of every axis.
An entry whose signal cannot be written has :readonly appended to
its source.
check
¶
Refuse target for axis of device, or return.
A target that is not a finite number, or that falls outside the limits
the axis last reported, is refused. A subclass refusing more calls
super().check first.
Raises:
| Type | Description |
|---|---|
ValueError
|
With the reason, if the target is refused. |
move
async
¶
Move axis of device by delta, in the axis' units.
Skipped while device is still moving, so steps asked faster than the device moves do not queue up behind it.
Raises:
| Type | Description |
|---|---|
KeyError
|
If the presenter does not hold device. |
move_to
async
¶
Move the axes of device in positions there, one after another.
Waits for a move of device already running, and is dropped if device is stopped, or taken by a plan, meanwhile.
Raises:
| Type | Description |
|---|---|
KeyError
|
If the presenter does not hold device. |
stop
async
¶
Stop device and each of its axes that can be stopped.
Every one is asked at once, and one that fails does not keep the rest
from stopping: the failures are reported on sig_failed. A move
ended this way is not reported as failed, and a go-to waiting for
device is dropped.
Raises:
| Type | Description |
|---|---|
KeyError
|
If the presenter does not hold device. |
set_locked
¶
Hold the devices in names, and every device below them, for a plan.
No hand move, waiting go-to or configuration write reaches a held axis.
DescribesAxes
¶
Acquisition¶
AcquisitionPresenter
dataclass
¶
Bases: Loggable
Run the plans the components of a session offer, one at a time.
The plans of every component with a plan_map are gathered in setup;
one whose signature no plan widget can show is left out with a warning.
A run gets the callbacks its plan lists, then those attached to it. Its
files are named after the plan while it runs. Its end is reported on
sig_plan_done when it finishes, on sig_plan_stopped when it is
stopped, or on sig_plan_failed, with the error logged, when it raises.
sig_plan_started
class-attribute
instance-attribute
¶
Plan, and the values it was launched with, once the engine has started it.
sig_plan_done
class-attribute
instance-attribute
¶
Plan, once it has finished.
sig_plan_stopped
class-attribute
instance-attribute
¶
Plan, once it has been stopped.
sig_plan_failed
class-attribute
instance-attribute
¶
Plan, and why it failed.
sig_progress
class-attribute
instance-attribute
¶
Every progress scope of the running plan, as the engine reports them.
sig_locks_changed
class-attribute
instance-attribute
¶
Names of the devices the running plan holds, whenever they change.
sig_action_changed
class-attribute
instance-attribute
¶
Action and its state, from the actions of every component.
sig_base_dir_changed
class-attribute
instance-attribute
¶
The directory runs now write under.
devices
class-attribute
instance-attribute
¶
Devices of the session, which plan arguments name.
callbacks
property
¶
The document callbacks a user may attach to a run, by name.
plan_callbacks
property
¶
The document callbacks each plan runs with, by plan name.
engine
¶
Return the engine every plan runs on, shared with any component asking for one.
deferrals
¶
Return the deferrals of the engine, shared with any component asking for them.
setup
¶
setup(
plan_sources: Mapping[str, HasPlans],
callbacks: Mapping[str, CallbackType],
paths: SessionPathProvider,
) -> None
Gather the plans of every provider, the callbacks, and the path provider.
launch
¶
Run plan with the parameter values, attaching the callbacks named.
Refused, with a warning, while another plan runs. Values that cannot
be turned into the plan's arguments are reported on sig_plan_failed.
request_action
¶
Ask for action of the running plan, or ask it to end.
set_label
¶
Lead the file names of every later run with label; empty for none.
shutdown
¶
Abort a running or paused plan, reporting neither its end nor a failure.
Returns once the plan's cleanup has run, or after ten seconds.
DescribesPlans
¶
Lights¶
LightPresenter
dataclass
¶
LightPresenter(
name: str,
*,
devices: DevicesOf[Light],
include: list[str] | None = None,
timeout: float = 10.0,
)
Bases: Loggable
Switch light sources on and off, and set their intensity.
Every light is described and followed from the start; one that cannot be,
within timeout, is left out with a warning. Writes to a light a plan
holds are refused. While an intensity is being written, only the newest
one asked for meanwhile is written after it.
sig_enabled
class-attribute
instance-attribute
¶
Device, and whether it is on, whenever it reads back.
sig_intensity
class-attribute
instance-attribute
¶
Device and intensity, whenever it reads back.
sig_failed
class-attribute
instance-attribute
¶
Device, and why a write was refused or failed.
sig_configuration
class-attribute
instance-attribute
¶
Key and value of a configuration signal, when it changes and after a write.
devices
class-attribute
instance-attribute
¶
Devices of the session with an enabled signal.
include
class-attribute
instance-attribute
¶
Names of the lights to keep; None keeps every light.
timeout
class-attribute
instance-attribute
¶
Seconds a light may take to be described, followed, or written.
lights
property
¶
Each light's state and intensity range, by device name.
configuration
property
¶
The configuration of every light.
An entry whose signal cannot be written has :readonly appended to
its source.
set_enabled
async
¶
set_intensity
async
¶
Set the intensity of device, in its units.
Raises:
| Type | Description |
|---|---|
KeyError
|
If the presenter does not hold device. |
configure
async
¶
Write value to the configuration signal key, then report it.
Raises:
| Type | Description |
|---|---|
KeyError
|
If key names no writable configuration signal. |
set_locked
¶
Hold the lights in names, or below a device in it, for a plan.
No write reaches a held light.
DescribesLights
¶
Shared parts¶
DeviceConfiguration
¶
Bases: Loggable
The configuration of a set of devices: read, followed, and written.
Each device is added under an owner, the name the session knows it by,
and every key it holds belongs to that owner. A value changed on a device,
or read back after a write, is reported on sig_changed.
Hold no device yet; name names the owner in log records.
sig_changed
class-attribute
instance-attribute
¶
Key and value of a configuration signal, when it changes and after a write.
configuration
property
¶
Everything added so far.
An entry whose signal cannot be written has :readonly appended to
its source.
add
async
¶
add(
owner: str,
device: AsyncConfigurable,
*,
owner_device: Device | None = None,
) -> Configuration
Read device's configuration, follow its signals, and file it under owner.
Returns the configuration of device alone. Nothing is kept when reading fails or the call is cancelled. A key already added is followed once, and stays with its first owner.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
owner_device
|
Device | None
|
The device owner names, when it is not device. |
None
|
configure
async
¶
Write value to key, report what it reads back, and return its owner.
A write to a signal that is held, or that sits below a held device, is not made, and the value is still read back and reported.
Raises:
| Type | Description |
|---|---|
KeyError
|
If key names no writable configuration signal. |
set_locked
¶
Refuse writes to the signals in names and below the devices in it.
Plan specification¶
Describe a plan's signature as a PlanSpec.
create_plan_spec inspects a bluesky MsgGenerator function and returns
a PlanSpec describing its parameters, from which a view builds the controls
of the plan.
_fields_from_annotation turns a Literal or device annotation into
ParamDescription fields (choices, device_proto, multiselect).
ParamKind
¶
Bases: IntEnum
inspect._ParameterKind as a public IntEnum.
Usable in match/case without importing private standard library
names.
UnresolvableAnnotationError
¶
create_plan_spec
¶
create_plan_spec(
plan: Callable[..., Generator[Any, Any, Any]],
devices: Mapping[str, Device],
) -> PlanSpec
Inspect plan and return a PlanSpec with one ParamDescription per parameter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plan
|
Callable[..., Generator[Any, Any, Any]]
|
The plan function or bound method, a generator function annotated to
return a |
required |
devices
|
Mapping[str, Device]
|
The session's devices, giving |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
If plan is not a generator function or its return type is not a
|
UnresolvableAnnotationError
|
If an annotation names something missing at runtime, or no view can build a control for it. |
ValueError
|
If plan declares two actions of one name, or a parameter's default breaks its own limits. |
collect_arguments
¶
collect_arguments(
spec: PlanSpec, values: Mapping[str, Any]
) -> tuple[tuple[Any, ...], dict[str, Any]]
Build the (args, kwargs) calling a plan, from its PlanSpec.
A positional parameter with no value takes its default when a later positional argument is given, so every argument keeps its place.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
Mapping[str, Any]
|
Resolved values by parameter name. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a positional parameter with no value and no default comes before a positional argument that is given. |
Notes
POSITIONAL_ONLYandPOSITIONAL_OR_KEYWORD->args, in declaration order.KEYWORD_ONLY->kwargs.VAR_POSITIONAL(*args) -> sequence expanded intoargs.VAR_KEYWORD(**kwargs) -> mapping merged intokwargs.
resolve_arguments
¶
resolve_arguments(
spec: PlanSpec,
param_values: Mapping[str, Any],
devices: Mapping[str, Device],
) -> dict[str, Any]
Turn parameter values from the interface into values a plan takes.
- Action parameters are filled from the spec when the interface lacks them.
- Hidden parameters get their default, so the parameters after them keep their places.
- Device parameters: names become
OADeviceinstances fromdevices. - Everything else passes unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
PlanSpec
|
The plan specification. |
required |
param_values
|
Mapping[str, Any]
|
Parameter values from the interface. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a value breaks its parameter's limits, naming every one. |
ParamDescription
dataclass
¶
ParamDescription(
name: str,
kind: ParamKind,
annotation: Any,
default: Any,
choices: list[Any] | None = None,
labels: dict[str, str] = dict(),
multiselect: bool = False,
hidden: bool = False,
actions: Sequence[PlanAction]
| PlanAction
| None = None,
device_proto: type[Any] | None = None,
annotated: Any = _empty,
)
Description of one plan parameter.
default
instance-attribute
¶
Default value of the parameter, or inspect.Parameter.empty if none.
choices
class-attribute
instance-attribute
¶
Selectable values: a Literal's own values, or device names.
labels
class-attribute
instance-attribute
¶
What a view shows for each device name in choices, such as scope / xy.
multiselect
class-attribute
instance-attribute
¶
Whether several values can be selected, as for Sequence[OADevice].
hidden
class-attribute
instance-attribute
¶
Whether no input can show the parameter.
A view leaves a hidden parameter out, and the plan keeps its default.
actions
class-attribute
instance-attribute
¶
Actions taken from the parameter's default value, if any.
device_proto
class-attribute
instance-attribute
¶
Device class or runtime-checkable protocol of a device parameter, used to look devices up when resolving arguments.
annotated
class-attribute
instance-attribute
¶
The full annotation, Annotated metadata kept at every level; annotation when not given.
problems
¶
Return a line for each limit value breaks, located inside it: points[2]: ....
Empty when the annotation carries no limit. Each item of a *args
given as a list or tuple, and each value of a **kwargs given as a
mapping, is checked on its own.
PlanSpec
dataclass
¶
PlanSpec(
name: str,
docs: str,
parameters: list[ParamDescription],
continuous: bool = False,
pausable: bool = False,
)
Description of a plan's signature and type hints.
How an annotation is read¶
Annotations map to ParamDescription fields, first match wins:
Literal["a", "b"]->choices=["a", "b"]Sequence[MyDevice]-> multi-select,choices=<matching device names>*args: MyDevice(VAR_POSITIONAL) -> multi-selectMyDevice(bare protocol) -> single-select- Everything else -> a plain value, left to the view layer to render
Step 5 accepts an annotation an input can show:
| Annotation | Shown when |
|---|---|
int, float, str, bool, bytes, range, Path, datetime, date, time, timedelta, an Enum, a Literal |
always |
list[T], Sequence[T], Iterable[T], tuple[T, ...], set[T], frozenset[T], or any one-element container a list, tuple, set or frozenset satisfies |
T can be shown |
tuple[A, B] of fixed length |
every member can be shown |
dict[K, V], Mapping[K, V], or any mapping a dict satisfies |
K is a plain type, an Enum or a Literal, and V can be shown |
X \| None |
X can be shown |
A \| B |
every member can be shown |
Annotated metadata is set aside when deciding, at every level, so
list[Annotated[float, ...]] is read as list[float]. A device inside any of these shapes cannot be shown, and neither can Any, a
Callable, a container without type arguments, or a container no built-in
satisfies, such as deque[T] or OrderedDict[K, V]: the plan would receive
a list or a dict, not the class it names.
annotated-types limits in the metadata are kept in
ParamDescription.annotated and checked by ParamDescription.problems; see
Limit the values a parameter takes.
| Parameter | Outcome |
|---|---|
| an input can show it | an input, starting from the default |
| no input can show it, and it has a default | hidden=True: a view leaves it out and the plan keeps its default |
| no input can show it, and it has no default | UnresolvableAnnotationError |
The inputs each annotation gets are pictured in How to choose the inputs of a plan.
From the values to a call¶
Once the user fills in the plan widget, the presenter turns the values into a plan call:
from redsun.presenter.plan_spec import collect_arguments, resolve_arguments
# 1. Resolve: string device names -> live device instances, hidden parameters -> their defaults
resolved = resolve_arguments(spec, widget_values, devices)
# 2. Collect: build (args, kwargs) matching the plan signature
args, kwargs = collect_arguments(spec, resolved)
# 3. Run
engine(my_plan(*args, **kwargs))
Utilities¶
Predicates and helpers inspecting plan parameters.
create_plan_spec uses them to classify annotations, and resolve_arguments
to turn device names into Device instances.
device_class
¶
Return what devices are checked against for ann: its origin when it has type arguments.
Readable[Any] gives Readable, since isinstance takes no type
arguments; any other annotation is returned unchanged.
get_choice_list
¶
isdeviceset
¶
Return True if ann is Set[T] (or AbstractSet[T], FrozenSet[T]) where T is a Device subtype.
issequence
¶
Return True if ann is a Sequence[...] generic alias.
Notes
str and bytes are sequences, but not generic aliases
(get_origin(str) is None), so they are excluded.