Source code for percival.detector.interface

'''
The detector interface module contains a number of abstract interface definitions
which are to be implemented by classes that support control and communication
with detectors.

The interface classes do not implement any real functionality, but are used to define
the methods (and their args) and properties, required to support a certain
interface.

The interface classes rely on the python :mod:`abc` module to support Abstract Base
Classes
'''
from __future__ import unicode_literals, absolute_import
from future.utils import with_metaclass
import logging
logger = logging.getLogger(__name__)

import abc
from inspect import ismethod, getargspec
from . import parameter

[docs]class IABCMeta(object): ''' Abstract Base Meta Class which implements checking for required methods and properties, even when the class is not directly subclassed. The Interface class which uses this metaclass will need to define a property called :py:attr:`_iface_requirements` which is a list of properties that must be implemented. This class is intended to work together with the :py:class:`abc.ABCMeta` class: Subclass :class:`IABCMeta` into your own class and set the :py:const:`__metaclass__` = :py:class:`abc.ABCMeta` The :py:meth:`__subclasshook__` will automatically be called when a class interface need to be verified. ''' _iface_requirements = [] '''Interface requirements list. The memebers listed here must be implemented by subclasses''' @classmethod def __subclasshook__(cls, C): '''Iterate through the :py:attr:`_iface_requirements` list of members and check whether they are implemented by the current class or parent. For requirement functions: Check if the functions arguments match the required arguments of the interface function. Rules for implementation of interface functions: 1) Must have at least the main (non-defaulted) named args 2) Can extend the list of arguments Default value arguments are discouraged in interfaces as the interface does not implement any functionality. Implementations can assign default values to the arguments if desired. ''' if not cls._iface_requirements: return NotImplemented checks = [] for req in cls._iface_requirements: has_req = any(req in B.__dict__ for B in C.__mro__) result = has_req if has_req: if ismethod(getattr(cls, req)): # Check if the functions arguments match the required arguments interface_func_args = getargspec( getattr(cls, req) ).args impl_func_args = getargspec(getattr(C,req)).args try: result = interface_func_args == impl_func_args[:len(interface_func_args)] except: result = False checks.append(result) return not False in checks
[docs]class IDetector(with_metaclass(abc.ABCMeta, IABCMeta)): ''' Abstract Interface to a detector class ''' #__metaclass__ = abc.ABCMeta __iproperties__ = ['exposure'] __imethods__ = ['acquire'] _iface_requirements = __imethods__ + __iproperties__ @property def exposure(self): raise NotImplementedError @abc.abstractmethod
[docs] def acquire(self, exposure, nframes): ''' Start the detector acquiring data ''' raise NotImplementedError
[docs]class IParameter(with_metaclass(abc.ABCMeta, object)): '''Base class interface to describe a detector parameter The :obj:`value` object is a :class:`detector.parameter.Observable` instance to which callbacks can be registerred to provide notification updates ''' #__metaclass__ = abc.ABCMeta value = parameter.Observable('value')
class IControl(with_metaclass(abc.ABCMeta, IABCMeta)): #__metaclass__ = abc.ABCMeta @abc.abstractmethod def start_acquisition(self, exposure, nframes): raise NotImplementedError @abc.abstractmethod def stop_acquisition(self): raise NotImplementedError @abc.abstractmethod def get_nframes(self): raise NotImplementedError class IData(with_metaclass(abc.ABCMeta, IABCMeta)): #__metaclass__ = abc.ABCMeta def get_filename(self): return self.filename def set_filename(self, fname): self.filename = fname filename = abc.abstractproperty(get_filename, set_filename) def get_datasetname(self): return self.datasetname def set_datasetname(self): return self.datasetname datasetname = abc.abstractproperty(get_datasetname, set_datasetname) @abc.abstractmethod def start_capture(self, filename, nframes): ''' Start capturing data frames into a filename. :param filename: Name of file to capture and store frames in. :param nframes: Numbef of frames, expected to be acquired and stored. ''' raise NotImplementedError @abc.abstractmethod def wait_complete(self, timeout): ''' Wait and return once the current capture session has completed. This function will return when the required number of frames has been captured into the file - or throw Timeout exception after a timeout. :param timeout: Number of seconds to block before timing out. ''' raise NotImplementedError