sunflare.engine
#
- class sunflare.engine.Status(*, timeout=None, settle_time=0)#
Track the status of a potentially-lengthy action like moving or triggering.
- Parameters:
timeout (float, optional) – The amount of time to wait before marking the Status as failed. If
None
(default) wait forever. It is strongly encouraged to set a finite timeout. If settle_time below is set, that time is added to the effective timeout.settle_time (float, optional) – The amount of time to wait between the caller specifying that the status has completed to running callbacks. Default is 0.
Notes
Theory of operation:
This employs two
threading.Event
objects, one thread that runs for (timeout + settle_time) seconds, and one thread that runs for settle_time seconds (if settle_time is nonzero).At __init__ time, a timeout and settle_time are specified. A thread is started, on which user callbacks, registered after __init__ time via
add_callback()
, will eventually be run. The thread waits on an Event be set or (timeout + settle_time) seconds to pass, whichever happens first.If (timeout + settle_time) expires and the Event has not been set, an internal Exception is set to
StatusTimeoutError
, and a second Event is set, marking the Status as done and failed. The callbacks are run.If a callback is registered after the Status is done, it will be run immediately.
If the first Event is set before (timeout + settle_time) expires, then the second Event is set and no internal Exception is set, marking the Status as done and successful. The callbacks are run.
There are two methods that directly set the first Event. One, :meth:set_exception, sets it directly after setting the internal Exception. The other,
set_finished()
, starts athreading.Timer
that will set it after a delay (the settle_time). One of these methods may be called, and at most once. If one is called twice or if both are called,InvalidState
is raised. If they are called too late to prevent aStatusTimeoutError
, they are ignored but one call is still allowed. Thus, an external callback, e.g. pyepics, may reports success or failure after the Status object has expired, but to no effect because the callbacks have already been called and the program has moved on.- property timeout: float | None#
The timeout for this action.
This is set when the Status is created, and it cannot be changed.
- property settle_time: float#
A delay between when
set_finished()
is when the Status is done.This is set when the Status is created, and it cannot be changed.
- property done: bool#
Boolean indicating whether associated operation has completed.
This is set to True at __init__ time or by calling
set_finished()
,set_exception()
. Once True, it can never become False.
- property success: bool#
Boolean indicating whether associated operation has completed.
This is set to True at __init__ time or by calling
set_finished()
,set_exception()
. Once True, it can never become False.
- set_exception(exc)#
Mark as finished but failed with the given Exception.
This method should generally not be called by the recipient of this Status object, but only by the object that created and returned it.
- Parameters:
exc (Exception)
- Return type:
None
- set_finished()#
Mark as finished successfully.
This method should generally not be called by the recipient of this Status object, but only by the object that created and returned it.
- Return type:
None
- exception(timeout=None)#
Return the exception raised by the action.
If the action has completed successfully, return
None
. If it has finished in error, return the exception.- Parameters:
timeout (Union[Number, None], optional) – If None (default) wait indefinitely until the status finishes.
- Returns:
The exception raised by the action. If the action has completed successfully, return
None
.- Return type:
Exception
- Raises:
WaitTimeoutError – If the status has not completed within
timeout
(starting from when this method was called, not from the beginning of the action).
- wait(timeout=None)#
Block until the action completes.
When the action has finished succesfully, return
None
. If the action has failed, raise the exception.- Parameters:
timeout (
float
, optional) – IfNone
(default) wait indefinitely until the status finishes.- Raises:
WaitTimeoutError – If the status has not completed within
timeout
(starting from when this method was called, not from the beginning of the action).StatusTimeoutError – If the status has failed because the timeout that it was initialized with has expired.
Exception – This is
status.exception()
, raised if the status has finished with an error. This may includeTimeoutError
, which indicates that the action itself raisedTimeoutError
, distinct fromWaitTimeoutError
above.
- Return type:
None
- property callbacks: deque[Callable[[Status], None]]#
Callbacks to be run when the status is marked as finished.
- add_callback(callback)#
Register a callback to be called once when the Status finishes.
The callback will be called exactly once. If the Status is finished before a callback is added, it will be called immediately. This is threadsafe. The callback will be called regardless of success of failure. The callback has access to this status object, so it can distinguish success or failure by inspecting the object.
- Parameters:
callback (
Callable[[Status], None]
) –The callback to be called when the status is marked as finished.
def callback(status: Status) -> None: # Do something with the status object ...
- Return type:
None
- class sunflare.engine.RunEngine(*args, **kwargs)#
Subclass of
bluesky.run_engine.RunEngine
to allow execution in a separate thread.Additional features:
socket
: A ZMQ socket to send messages to a remote endpoint;socket_prefix
: A prefix to be used in the ZMQ topic when sending messages.
When launching a plan, the
RunEngine
, the__call__
method returns aFuture
object. This allows to set a callback on the future to retrieve the result of the execution. Alternatively, the result can be accessed directly from theresult
attribute when the future is done.Suppressed features:
context_managers
: The context managers are forced to be an empty list to avoid the use of the built-inSignalHandler
context manager.
The rationale is that the original implementation is meant for interactive usage (e.g., Jupyter notebooks, scripts) and not for applications relying on an event loop.
pause_msg
: Overridden to be an empty string.during_task
: Overridden toDuringTask
, so theRunEngine
does not interact with any possible event loop in the main thread.
For the original class initializer signature, refer to the
RunEngine
documentation.- Parameters:
socket_prefix (
str
, keyword-only, optional) – Prefix to be used in the ZMQ topic when sending messages. Default isRE{N}
, where{N}
is a counter that increments for each instance.socket (
zmq.Socket[bytes]
, keyword-only, optional) – ZMQ socket to send messages to a remote endpoint. Default isNone
(no messages are sent).args (Any)
kwargs (Any)
- emit_sync(name, doc)#
Emit a document synchronously.
Reimplemented to send documents also through a ZMQ socket.
Warning
This method is not meant to be used directly. The
RunEngine
will emit documents automatically during the execution of a plan. Any subscriber will receive the documents.- Parameters:
name (DocumentNames)
doc (dict[str, Any])
- Return type:
None
- class sunflare.engine.RunEngineResult(run_start_uids, plan_result, exit_status, interrupted, reason, exception)#
Information about the plan that was run
- Parameters:
run_start_uids (tuple[str, ...])
plan_result (Any)
exit_status (str)
interrupted (bool)
reason (str)
exception (Exception | None)
- run_start_uids#
A list of the UIDs generated during the plan (if any)
- Type:
list
- plan_result#
The return value of the top-level plan that was run
- Type:
Any
- exit_status#
- Type:
str
- interrupted#
True if the plan was halted, stopped or aborted
- Type:
bool
- reason#
A text description of the reason why the plan was aborted (if aborted)
- Type:
str
- exception#
The exception generated by the plan, if any
- Type:
Exception | None