Skip to content

Tips for BLISS programming

cleanup

cleanup context manager feature allows to restore parameters of objects after the execution of code block which involves them. Objects supporting this functionality are:

  • motors: Axis objects
  • camera: lima objects

after the execution means:

  • on a Control-c
  • in case of exception while code is being executed
  • at the normal end of the code block

Devices to consider are defined in first parameter of cleanup function.

Parameters to restore are defined in restore_list.

In order to deal with errors and not normal ending, error_cleanup() acts similar but is executed:

  • on a Control-c
  • in case of exception while code is being executed

Motors

For Motors, this context manager would guarantee that they will be stopped in any case, or even returned to their initial position if axis.POS is in restore_list.

There is the possibility to restore:

  • the velocity (axis.VEL)
  • the acceleration (axis.ACC)
  • the limits (axis.LIM).

All motors in the context will be waited.

Example from bliss/common/scans.py:

axis = enum.Enum("axis", "POS VEL ACC LIM")

Usage example from bliss/common/scans.py:

from bliss.common.cleanup import cleanup, axis as cleanup_axis

...

with cleanup(motor, restore_list=(cleanup_axis.POS,)):
    scan = ascan(motor, start, stop, intervals, count_time, *counter_args, **kwargs)

return scan

Exceptions

Bliss and Python exceptions

PDF version: Exceptions

Exceptions

capture_exceptions() context manager

capture_exceptions() is a context manager to capture and manage multiple exceptions.

Usage:

with capture_exceptions() as capture:
    with capture():
        do_A()
    with capture():
        do_B()
    with capture():
        do_C()

The inner contexts (with capture()) protect the execution by capturing any exception raised. This allows the next contexts to run. When leaving the main context (with capture_exceptions()), the last exception (potentially raised by by do_C() here) is raised, if any.

If the raise_index argument is set to 0, the first exception is raised instead. This behavior can also be disabled by setting raise_index to None.

The other exceptions are processed through the given excepthook, which defaults to sys.excepthook.

A list containing the information about the raised exception can be retreived using the exception_infos attribute of the capture object or the raised exception.

Example:

print("-------------------- capture_exc START ------------------")

def my_exc_handler(exc_type, exc_value, exc_traceback):
    print("     +++ FBF:", "exc_type=", exc_type,
                           "exc_value=", exc_value,
                           "exc_traceback=", exc_traceback, flush=True)


with capture_exceptions(raise_index=None, excepthook=my_exc_handler) as capture:
    with capture():
        print("try to print 123/0", flush=True)
        print(123/0)

    print("")
    with capture():
        print("try to decode a str", flush=True)
        print("ee".decode())

    if capture.failed:
        print("oh no, you cannot decode a str")
        exc_type, exc_value, exc_traceback = capture.exception_infos[-1]
        print(f"it has raised a '{exc_type}' exception")

    print("")
    with capture():
        print("try to print toto (not def)", flush=True)
        print(toto)

print("-------------------- capture_exc END ------------------", flush=True)

The previous example produce this (long lines are wrapped for clarity) at execution:

raised is set to None so no exception is raised.

-------------------- capture_exc START ------------------
try to print 123/0
     +++ FBF: exc_type= <class 'ZeroDivisionError'>
              exc_value= division by zero
              exc_traceback= <traceback object at 0x7faa58be65f0>

try to decode a str
     +++ FBF: exc_type= <class 'AttributeError'>
              exc_value= 'str' object has no attribute 'decode'
              exc_traceback= <traceback object at 0x7faa58be6230>
oh no, you cannot decode a str
it has raised a '<class 'AttributeError'>' exception

try to print toto (not def)
     +++ FBF: exc_type= <class 'NameError'>
              exc_value= name 'toto' is not defined
              exc_traceback= <traceback object at 0x7faa58c267d0>
-------------------- capture_exc END ------------------

informing the user

bliss.common.user_status_info provides a mechanism to send information to the user while a sequence is running.

example

from bliss.common.user_status_info import status_message
import gevent
import time

def is_finished():
    return (time.perf_counter() - t0) > 5

def my_seq():
    gevent.sleep(0.2)

t0 = time.perf_counter()

with status_message() as p:
    while(not is_finished()):
        my_seq()
        p("salut")

Beamline root config

To read “root beamline config”, usualy located in file:
~/local/beamline_configuration/__init__.yml
such a piece of code can be used:

from bliss import current_session

if current_session.config.root.get("display_initialized_objects"):
    print("bla bla")