Skip to content

Commit

Permalink
Merged in cbillington/blacs/callback_priorities (pull request labscri…
Browse files Browse the repository at this point in the history
…pt-suite#49)

Plugin callback priorities
  • Loading branch information
chrisjbillington committed Sep 14, 2018
2 parents 0471c04 + e5b90a9 commit 12f334a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 31 deletions.
40 changes: 9 additions & 31 deletions experiment_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
from labscript_utils.connections import ConnectionTable

from blacs.tab_base_classes import MODE_MANUAL, MODE_TRANSITION_TO_BUFFERED, MODE_TRANSITION_TO_MANUAL, MODE_BUFFERED
import blacs.plugins as plugins


FILEPATH_COLUMN = 0

Expand Down Expand Up @@ -154,8 +156,6 @@ def __init__(self, BLACS, ui):
self.manager.daemon=True
self.manager.start()

self._callbacks = None

def _create_headers(self):
self._model.setHorizontalHeaderItem(FILEPATH_COLUMN, QStandardItem('Filepath'))

Expand Down Expand Up @@ -251,26 +251,6 @@ def manager_repeat_mode(self, value):
elif value == self.REPEAT_LAST:
button.setIcon(QIcon(self.ICON_REPEAT_LAST))

@inmain_decorator(True)
def get_callbacks(self, name, update_cache=False):
if update_cache or self._callbacks is None:
self._callbacks = {}
try:
for plugin in self.BLACS.plugins.values():
callbacks = plugin.get_callbacks()
if isinstance(callbacks, dict):
for callback_name, callback in callbacks.items():
if callback_name not in self._callbacks:
self._callbacks[callback_name] = []
self._callbacks[callback_name].append(callback)
except Exception as e:
self._logger.exception('A Error occurred during get_callbacks.')

if name in self._callbacks:
return self._callbacks[name]
else:
return []

def on_add_shots_triggered(self):
shot_files = QFileDialog.getOpenFileNames(self._ui, 'Select shot files',
self.last_opened_shots_folder,
Expand Down Expand Up @@ -904,7 +884,7 @@ def restart_function(device_name):

# check for analysis Filters in Plugins
send_to_analysis = True
for callback in self.get_callbacks('analysis_cancel_send'):
for callback in plugins.get_callbacks('analysis_cancel_send'):
try:
if callback(path):
send_to_analysis = False
Expand All @@ -919,20 +899,18 @@ def restart_function(device_name):
##########################################################################################################################################
# Plugin callbacks #
##########################################################################################################################################
for plugin in self.BLACS.plugins.values():
callbacks = plugin.get_callbacks()
if isinstance(callbacks, dict) and 'shot_complete' in callbacks:
try:
callbacks['shot_complete'](path)
except Exception:
logger.exception("Plugin callback raised an exception")
for callback in plugins.get_callbacks('shot_complete'):
try:
callback(path)
except Exception:
logger.exception("Plugin callback raised an exception")

##########################################################################################################################################
# Repeat Experiment? #
##########################################################################################################################################
# check for repeat Filters in Plugins
repeat_shot = self.manager_repeat
for callback in self.get_callbacks('shot_ignore_repeat'):
for callback in plugins.get_callbacks('shot_ignore_repeat'):
try:
if callback(path):
repeat_shot = False
Expand Down
56 changes: 56 additions & 0 deletions plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import sys
import logging
import importlib
from types import MethodType
from collections import defaultdict
from labscript_utils.labconfig import LabConfig
from blacs import BLACS_DIR
PLUGINS_DIR = os.path.join(BLACS_DIR, 'plugins')
Expand All @@ -24,6 +26,60 @@

logger = logging.getLogger('BLACS.plugins')

DEFAULT_PRIORITY = 10

class Callback(object):
"""Class wrapping a callable. At present only differs from a regular
function in that it has a "priority" attribute - lower numbers means
higher priority. If there are multiple callbacks triggered by the same
event, they will be returned in order of priority by get_callbacks"""
def __init__(self, func, priority=DEFAULT_PRIORITY):
self.priority = priority
self.func = func

def __get__(self, instance, class_):
"""Make sure our callable binds like an instance method. Otherwise
__call__ doesn't get the instance argument."""
if instance is None:
return self
else:
return MethodType(self, instance)

def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)


class callback(object):
"""Decorator to turn a function into a Callback object. Presently
optional, and only required if the callback needs to have a non-default
priority set"""
# Instantiate the decorator:
def __init__(self, priority=DEFAULT_PRIORITY):
self.priority = priority
# Call the decorator
def __call__(self, func):
return Callback(func, self.priority)


def get_callbacks(name):
"""Return all the callbacks for a particular name, in order of priority"""
import __main__
BLACS = __main__.app
callbacks = []
for plugin in BLACS.plugins.values():
try:
plugin_callbacks = plugin.get_callbacks()
if plugin_callbacks is not None:
if name in plugin_callbacks:
callbacks.append(plugin_callbacks[name])
except Exception as e:
logger.exception('Error getting callbacks from %s.' % str(plugin))

# Sort all callbacks by priority:
callbacks.sort(key=lambda callback: getattr(callback, 'priority', DEFAULT_PRIORITY))
return callbacks


exp_config = LabConfig()
if not exp_config.has_section('BLACS/plugins'):
exp_config.add_section('BLACS/plugins')
Expand Down

0 comments on commit 12f334a

Please sign in to comment.