diff --git a/doc/source/tutorial_helevel.rst b/doc/source/tutorial_helevel.rst index f073cf8..77aadea 100644 --- a/doc/source/tutorial_helevel.rst +++ b/doc/source/tutorial_helevel.rst @@ -23,7 +23,7 @@ CCU4 luckily has a very simple and logical protocol: # the most common Frappy classes can be imported from secop.core from secop.core import Readable, Parameter, FloatRange, BoolType, StringIO, HasIodev - + class CCU4IO(StringIO): """communication with CCU4""" @@ -39,7 +39,7 @@ CCU4 luckily has a very simple and logical protocol: # Readable as a base class defines the value and status parameters class HeLevel(HasIodev, Readable): """He Level channel of CCU4""" - + # define the communication class to create the IO module iodevClass = CCU4IO @@ -99,11 +99,11 @@ the status codes from the hardware to the standard SECoP status codes. full_length = Parameter('warm length when full', FloatRange(0, 2000, unit='mm'), readonly=False) sample_rate = Parameter('sample rate', EnumType(slow=0, fast=1), readonly=False) - + ... - + Status = Readable.Status - + # conversion of the code from the CCU4 parameter 'hsf' STATUS_MAP = { 0: (Status.IDLE, 'sensor ok'), @@ -113,17 +113,17 @@ the status codes from the hardware to the standard SECoP status codes. 4: (Status.ERROR, 'not yet read'), 5: (Status.DISABLED, 'disabled'), } - + def read_status(self): name, txtvalue = self._iodev.communicate('hsf').split('=') assert name == 'hsf' return self.STATUS_MAP(int(txtvalue)) - + def read_empty_length(self): name, txtvalue = self._iodev.communicate('hem').split('=') assert name == 'hem' return txtvalue - + def write_empty_length(self, value): name, txtvalue = self._iodev.communicate('hem=%g' % value).split('=') assert name == 'hem' @@ -135,7 +135,7 @@ the status codes from the hardware to the standard SECoP status codes. Here we start to realize, that we will repeat similar code for other parameters, which means it might be worth to create a *query* method, and then the *read_* and *write_* methods will become shorter: - + .. code:: python ... diff --git a/secop/modules.py b/secop/modules.py index 6e89030..32f798e 100644 --- a/secop/modules.py +++ b/secop/modules.py @@ -89,16 +89,18 @@ class HasAccessibles(HasProperties): if isinstance(pobj, Command): # nothing to do for now continue - rfunc = cls.__dict__.get('read_' + pname, None) + rfunc = getattr(cls, 'read_' + pname, None) rfunc_handler = pobj.handler.get_read_func(cls, pname) if pobj.handler else None + wrapped = hasattr(rfunc, '__wrapped__') if rfunc_handler: - if rfunc: + if rfunc and not wrapped: raise ProgrammingError("parameter '%s' can not have a handler " "and read_%s" % (pname, pname)) rfunc = rfunc_handler + wrapped = False # create wrapper except when read function is already wrapped - if rfunc is None or getattr(rfunc, '__wrapped__', False) is False: + if not wrapped: def wrapped_rfunc(self, pname=pname, rfunc=rfunc): if rfunc: @@ -126,11 +128,14 @@ class HasAccessibles(HasProperties): if not pobj.readonly: wfunc = getattr(cls, 'write_' + pname, None) - if wfunc is None: # ignore the handler, if a write function is present - wfunc = pobj.handler.get_write_func(pname) if pobj.handler else None + wrapped = hasattr(wfunc, '__wrapped__') + if (wfunc is None or wrapped) and pobj.handler: + # ignore the handler, if a write function is present + wfunc = pobj.handler.get_write_func(pname) + wrapped = False # create wrapper except when write function is already wrapped - if wfunc is None or getattr(wfunc, '__wrapped__', False) is False: + if not wrapped: def wrapped_wfunc(self, value, pname=pname, wfunc=wfunc): self.log.debug("check validity of %s = %r" % (pname, value)) diff --git a/secop/proxy.py b/secop/proxy.py index 7320e82..325091c 100644 --- a/secop/proxy.py +++ b/secop/proxy.py @@ -122,6 +122,8 @@ class ProxyModule(HasIodev, Module): self.announceUpdate(pname, None, readerror) self.announceUpdate('status', newstatus) + def checkProperties(self): + pass # skip class ProxyReadable(ProxyModule, Readable): pass