#####################################################################
# #
# /plugins/__init__.py #
# #
# Copyright 2013, Monash University #
# #
# This file is part of the program BLACS, in the labscript suite #
# (see http://labscriptsuite.org), and is licensed under the #
# Simplified BSD License. See the license.txt file in the root of #
# the project for the full license. #
# #
#####################################################################
import os
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')
default_plugins = ['connection_table', 'general', 'theme']
logger = logging.getLogger('BLACS.plugins')
DEFAULT_PRIORITY = 10
[docs]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"""
[docs] 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)
[docs]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:
[docs] def __init__(self, priority=DEFAULT_PRIORITY):
self.priority = priority
# Call the decorator
def __call__(self, func):
return Callback(func, self.priority)
[docs]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:
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')
modules = {}
for module_name in os.listdir(PLUGINS_DIR):
if os.path.isdir(os.path.join(PLUGINS_DIR, module_name)) and module_name != '__pycache__':
# is it a new plugin?
# If so lets add it to the config
if not module_name in [name for name, val in exp_config.items('BLACS/plugins')]:
exp_config.set('BLACS/plugins', module_name, str(module_name in default_plugins))
# only load activated plugins
if exp_config.getboolean('BLACS/plugins', module_name):
try:
module = importlib.import_module('blacs.plugins.'+module_name)
except Exception:
logger.exception('Could not import plugin \'%s\'. Skipping.'%module_name)
else:
modules[module_name] = module