Template Device for Labscript

README

naqs_devices_template_device

This repository is both a template to follow for a labscript-device belonging to a namespace (here naqs_devices) as well as a github template repository. Use the green Use this template button above to copy the files and structure of this repository to fit your new device. You will need to modify at least pyproject.toml, README.md, index.rst, conf.py, and everything in src/.

Directory structure

└── naqs_devices_template_device/
    ├── .gitignore
    ├── pyproject.toml
    ├── README.md
    ├── LICENSE.txt # Choose a license, labscript uses BSD
    ├── CITATION.cff # Optional to define citation for citing the device repository
    ├── docs/
    │   ├── conf.py
    │   ├── make.bat
    │   ├── Makefile
    │   └── index.rst
    └── src/naqs_devices/ # note: must be same as in the parent naqs_devices repo to be in the same namespace
        └── TemplateDevice/
            ├── __init__.py
            ├── blacs_tabs.py
            ├── blacs_workers.py
            ├── labscript_devices.py
            ├── register_classes.py
            └── runviewer_parsers.py

How to document your device

To work within the labscript paradigm, we enforce that you write all specification related documentation in the top-level README.md (here). Then, any API related documentation should go in the docs/index.rst. The project is structured and has the machinery so that the device can be hosted on Read The Docs. This is optional and requires extra configuration steps as outlined in the RTD Docs.

API Documentation

class naqs_devices.TemplateDevice.labscript_devices.TemplateDevice(name='template_device', BLACS_connection='template_connection', **kwargs)[source]

Bases: Device

Creates a Device.

Parameters:
  • name (str) – python variable name to assign this device to.

  • parent_device (Device) – Parent of this device.

  • connection (str) – Connection on this device that links to parent.

  • call_parents_add_device (bool, optional) – Flag to command device to call its parent device’s add_device when adding a device.

  • added_properties (dict, optional)

  • gui

  • worker

  • start_order (int, optional) – Priority when starting, sorted with all devices.

  • stop_order (int, optional) – Priority when stopping, sorted with all devices.

  • **kwargs – Other options to pass to parent.

description = 'Template Device, minimal example'

Brief description of the device.

allowed_children = [<class 'naqs_devices.TemplateDevice.labscript_devices._TemplateChildDevice'>]

Defines types of devices that are allowed to be children of this device.

Type:

list

max_instructions = 100000.0
generate_code(hdf5_file)[source]

Writes instructions to an h5 file to be processed by other labscript components. As an example, we generate 3 columns of random data and use h5py to save the data to the shotfile. Labscript commonly makes use of numpy structured arrays to explicitly specify types.

Parameters:
  • hdf5_file (str) – The path to the shot-file, passed in by labscript

  • components.

add_device(device)

Adds a child device to this device.

Parameters:

device (Device) – Device to add.

Raises:

LabscriptError – If device is not an allowed child of this device.

get_all_children()

Get all children devices for this device.

Returns:

List of children Device.

Return type:

list

get_all_outputs()

Get all children devices that are outputs.

Recursively calls get_all_outputs() on each child device. Output’s will return a list containing just themselves.

Returns:

List of children Output.

Return type:

list

get_properties(location=None)

Get all properties in location.

Parameters:

location (str, optional) – Location to get properties from. If None, return all properties.

Returns:

Dictionary of properties.

Return type:

dict

get_property(name, location=None, *args, **kwargs)

Method to get a property of this device already set using Device.set_property().

If the property is not already set, a default value will be returned if specified as the argument after ‘name’, if there is only one argument after ‘name’ and the argument is either not a keyword argurment or is a keyword argument with the name ‘default’.

Parameters:
  • name (str) – Name of property to get.

  • location (str, optional) – If not None, only search for name in location.

  • default – The default value. If not provided, an exception is raised if the value is not set.

Returns:

Property value.

Raises:

LabscriptError – If property not set and default not provided, or default conventions not followed.

Examples

Examples of acceptable signatures:

>>> get_property('example')             # 'example' will be returned if set, or an exception raised
>>> get_property('example', 7)          # 7 returned if 'example' is not set
>>> get_property('example', default=7)  # 7 returnd if 'example' is not set

Example signatures that WILL ALWAYS RAISE AN EXCEPTION:

>>> get_property('example', 7, 8)
>>> get_property('example', 7, default=9)
>>> get_property('example', default=7, x=9)
init_device_group(hdf5_file)

Creates the device group in the shot file.

Parameters:

hdf5_file (h5py:h5py.File) – File handle to create the group in.

Returns:

Created group handle.

Return type:

h5py:h5py.Group

property parent_clock_line

Stores the clocking clockline, which may be itself.

Type:

ClockLine

property pseudoclock_device

Stores the clocking pseudoclock, which may be itself.

Type:

PseudoclockDevice

quantise_to_pseudoclock(times)

Quantises times to the resolution of the controlling pseudoclock.

Parameters:

times (numpy:numpy.ndarray or list or set or float) – Time, in seconds, to quantise.

Returns:

Quantised times.

Return type:

same type as times

set_properties(properties_dict, property_names, overwrite=False)

Add one or a bunch of properties packed into properties_dict

Parameters:
  • properties_dict (dict) – Dictionary of properties and their values.

  • property_names (dict) – Is a dictionary {key:val, …} where each val is a list [var1, var2, …] of variables to be pulled from properties_dict and added to the property localtion with name key

  • overwrite (bool, optional) – Toggles overwriting of existing properties.

set_property(name, value, location=None, overwrite=False)

Method to set a property for this device.

Property will be stored in the connection table and used during connection table comparisons.

Value must satisfy eval(repr(value)) == value.

Parameters:
  • name (str) – Name to save property value to.

  • value – Value to set property to.

  • location (str, optional) – Specify a location to save property to, such as ‘device_properties’ or ‘connection_table_properties’.

  • overwrite (bool, optional) – If True, allow overwriting a property already set.

Raises:

LabscriptError – If ‘location’ is not valid or trying to overwrite an existing property with ‘overwrite’=False.

property t0

The earliest time output can be commanded from this device at the start of the experiment. This is nonzero on secondary pseudoclock devices due to triggering delays.

Type:

float

class naqs_devices.TemplateDevice.blacs_tabs.TemplateDeviceTab(notebook, settings, restart=False)[source]

Bases: DeviceTab

show_widgets = True
initialise_GUI()[source]

Required to place GUI widgets and contains options for remote value checking and smart cache capability.

initialise_workers()[source]

Starts the workers, which handle communications between front panel, shot-file, and labscript instructions.

start_run(*args, **kwargs)[source]
wait_until_done(*args, **kwargs)[source]
ICON_BUSY = ':/qtutils/fugue/hourglass'
ICON_ERROR = ':/qtutils/fugue/exclamation'
ICON_FATAL_ERROR = ':/qtutils/fugue/exclamation-red'
ICON_OK = ':/qtutils/fugue/tick'
abort_buffered(*args, **kwargs)
abort_transition_to_buffered(*args, **kwargs)
add_secondary_worker(worker)
auto_create_widgets()
auto_place_widgets(*args)
check_remote_values(*args, **kwargs)
check_time()
clean_ui_on_restart()
close_tab(finalise=True)

Close the tab, terminate subprocesses and join the mainloop thread. If finalise=False, then do not terminate subprocesses or join the mainloop. In this case, callers must manually call finalise_close_tab() to perform these potentially blocking operations

connect_restart_receiver(function)
continue_restart(currentpage)

Called in a thread for the stages of restarting that may be blocking, so as to not block the main thread. Calls subsequent GUI operations in the main thread once finished blocking.

create_analog_outputs(analog_properties)
create_analog_widgets(channel_properties)
create_dds_outputs(dds_properties)
create_dds_widgets(channel_properties)
create_digital_outputs(digital_properties)
create_digital_widgets(channel_properties)
create_image_outputs(image_properties)
create_image_widgets(channel_properties)
create_worker(name, WorkerClass, workerargs=None)

Set up a worker process. WorkerClass can either be a subclass of Worker, or a string containing a fully qualified import path to a worker. The latter is useful if the worker class is in a separate file with global imports or other import-time behaviour that is undesirable to have run in the main process, for example if the imports may not be available to the main process (as may be the case once remote worker processes are implemented and the worker may be on a separate computer). The worker process will not be started immediately, it will be started once the state machine mainloop begins running. This way errors in startup will be handled using the normal state machine machinery.

property device_name
disconnect_restart_receiver(function)
property error_message
finalise_close_tab(currentpage)
finalise_restart(currentpage)
property force_full_buffered_reprogram
get_all_save_data()
get_builtin_save_data()

Get builtin settings to be restored like whether the terminal is visible. Not to be overridden.

get_channel(channel)
get_child_from_connection_table(parent_device_name, port)
get_front_panel_values()
get_save_data()
get_tab_layout()
hide_error()
mainloop()
property mode
on_force_full_buffered_reprogram()
on_resolve_value_inconsistency()
property primary_worker
program_device(*args, **kwargs)
queue_work(worker_process, worker_function, *args, **kwargs)
restart(*args)
restore_builtin_save_data(data)

Restore builtin settings to be restored like whether the terminal is visible. Not to be overridden.

restore_save_data(data)
set_tab_icon_and_colour()

Set the tab icon and the colour of its text to the values of self._tab_icon and self._tab_text_colour respectively

set_terminal_visible(visible)
shutdown_workers(*args, **kwargs)
property state
statemachine_timeout_add(delay, statefunction, *args, **kwargs)
statemachine_timeout_remove(statefunction)
statemachine_timeout_remove_all()
supports_remote_value_check(support)
supports_smart_programming(support)
transition_to_buffered(*args, **kwargs)
transition_to_manual(*args, **kwargs)
update_from_settings(settings)
class naqs_devices.TemplateDevice.blacs_workers.TemplateDeviceInterface[source]

Bases: object

This optional class holds the functions / methods for logic processing or commands that go between the device hardware and the front panel. It is automatically called by BLACS.

class naqs_devices.TemplateDevice.blacs_workers.TemplateDeviceWorker(*args, **kwargs)[source]

Bases: Worker

Handles processing of data between a shot’s h5file and the Device. Every Device’s Worker should generally implement the methods defined in this TemplateDeviceWorker.

Parameters:

Worker (Process) – Inherited from blacs.tab_base_classes.py.

init()[source]

Initialises communications with the device. Not to be confused with the standard python class __init__ method.

program_manual(values)[source]

Allows for user control of the device via the BLACS_tab, setting outputs to the values set in the BLACS_tab widgets.

Parameters:

values (dict) – dictionary of values to update front panel.

Returns:

returns are of dictionary shape to allow use from other methods.

Return type:

dict

check_remote_values()[source]

Queries and reads current settings of the device, updating the BLACS_tab widgets to reflect these values.

Returns:

returns an empty dictionary, can be populated depending on level of device feedback.

Return type:

dict

transition_to_buffered(device_name: str, h5file: str, initial_values: dict, fresh)[source]

This method transitions the device from buffered to manual mode. It does any necessary configuration to take the device out of buffered mode and is used to read any measurements and save them to the shot h5 file as results.

Parameters:
  • device_name (str) – Name of the device in labscript.

  • h5file (str) – path to shot file to run.

  • initial_values (dict) – Dictionary of output states at shot start

  • fresh (bool)

Returns:

Dictionary of expected final output states.

Return type:

dict

transition_to_manual()[source]

Logic that runs after buffered execution to return control to the user/front panel. May need to call abort_buffered() to handle behavior such as timeouts.

Returns:

returns True for internal logic.

Return type:

Bool

shutdown()[source]

Ends communication with the device. Often calls upon a close method.

abort_transition_to_buffered()[source]
abort_buffered()[source]

Called when the user presses the abort button during buffered execution. Here returns to initial values, since buffered execution needed to be stopped.

interrupt_startup(reason='Process.interrupt_startup() called')

Called from the parent process. Interrupt all blocking operations on starting the child process, causing Process.start() to raise Interrupted(reason). After interruption, self.child may be None if startup was interrupted before the child was started, otherwise self.child will be the child Popen object, which could be at any stage of setting up its connection with the parent. This method may be called multiple times without raising an exception, it will simply do nothing if startup has previously been interrupted

mainloop()
run(worker_name, device_name, extraargs)

The method that gets called in the subprocess. To be overridden by subclasses

start(*args, **kwargs)

Call in the parent process to start a subprocess. Passes args and kwargs to the run() method

terminate(wait_timeout=None, **kwargs)

Interrupt process startup if not already done, ensuring self.child exists or is None if startup was interrupted before the process was created. Then if the child is not None, call Popen.terminate() and Popen.wait() on it.

class naqs_devices.TemplateDevice.runviewer_parsers.TemplateDeviceParser(path, device)[source]

Bases: object