diff --git a/.pylintrc b/.pylintrc index daa9688..21527bf 100644 --- a/.pylintrc +++ b/.pylintrc @@ -162,7 +162,7 @@ max-line-length=132 no-space-check=trailing-comma,dict-separator # Maximum number of lines in a module -max-module-lines=1200 +max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). diff --git a/doc/source/reference.rst b/doc/source/reference.rst index 9326ba2..77491e6 100644 --- a/doc/source/reference.rst +++ b/doc/source/reference.rst @@ -7,7 +7,7 @@ Module Base Classes .. autodata:: secop.modules.Done .. autoclass:: secop.modules.Module - :members: earlyInit, initModule, startModule, pollerClass + :members: earlyInit, initModule, startModule .. autoclass:: secop.modules.Readable :members: Status diff --git a/secop/core.py b/secop/core.py index be3d338..1da4370 100644 --- a/secop/core.py +++ b/secop/core.py @@ -31,7 +31,7 @@ from secop.datatypes import ArrayOf, BLOBType, BoolType, EnumType, \ from secop.iohandler import IOHandler, IOHandlerBase from secop.lib.enum import Enum from secop.modules import Attached, Communicator, \ - Done, Drivable, Module, Readable, Writable + Done, Drivable, Module, Readable, Writable, HasAccessibles from secop.params import Command, Parameter from secop.properties import Property from secop.proxy import Proxy, SecNode, proxy_class @@ -39,3 +39,8 @@ from secop.io import HasIO, StringIO, BytesIO, HasIodev # TODO: remove HasIodev from secop.persistent import PersistentMixin, PersistentParam from secop.rwhandler import ReadHandler, WriteHandler, CommonReadHandler, \ CommonWriteHandler, nopoll + +ERROR = Drivable.Status.ERROR +WARN = Drivable.Status.WARN +BUSY = Drivable.Status.BUSY +IDLE = Drivable.Status.IDLE diff --git a/secop/datatypes.py b/secop/datatypes.py index 12ce4ec..f5c31c1 100644 --- a/secop/datatypes.py +++ b/secop/datatypes.py @@ -22,7 +22,7 @@ # ***************************************************************************** """Define validated data types.""" -# pylint: disable=abstract-method +# pylint: disable=abstract-method, too-many-lines import sys @@ -454,7 +454,10 @@ class EnumType(DataType): super().__init__() if members is not None: kwds.update(members) - self._enum = Enum(enum_or_name, **kwds) + if isinstance(enum_or_name, str): + self._enum = Enum(enum_or_name, kwds) # allow 'self' as name + else: + self._enum = Enum(enum_or_name, **kwds) self.default = self._enum[self._enum.members[0]] def copy(self): diff --git a/secop/lib/statemachine.py b/secop/lib/statemachine.py index f24f00e..1742ff8 100644 --- a/secop/lib/statemachine.py +++ b/secop/lib/statemachine.py @@ -178,7 +178,9 @@ class StateMachine: if self.stop_exc: raise self.stop_exc except Exception as e: - self.log.info('%r raised in state %r', e, self.status_string) + # Stop and Restart are not unusual -> no warning + log = self.log.debug if isinstance(e, Stop) else self.log.warning + log('%r raised in state %r', e, self.status_string) self.last_error = e ret = self.cleanup(self) self.log.debug('cleanup %r %r %r', self.cleanup, self.last_error, ret) diff --git a/secop/modules.py b/secop/modules.py index 6a7f2d9..322fd0e 100644 --- a/secop/modules.py +++ b/secop/modules.py @@ -161,8 +161,8 @@ class HasAccessibles(HasProperties): new_rfunc.wrapped = True # indicate to subclasses that no more wrapping is needed setattr(cls, 'read_' + pname, new_rfunc) - if not pobj.readonly: - wfunc = getattr(cls, 'write_' + pname, None) + wfunc = getattr(cls, 'write_' + pname, None) + if not pobj.readonly or wfunc: # allow write_ method even when pobj is not readonly wrapped = getattr(wfunc, 'wrapped', False) # meaning: wrapped or auto generated if (wfunc is None or wrapped) and pobj.handler: # ignore the handler, if a write function is present @@ -392,9 +392,8 @@ class Module(HasAccessibles): continue if pname in cfgdict: - if not pobj.readonly and pobj.initwrite is not False: + if pobj.initwrite is not False and hasattr(self, 'write_' + pname): # parameters given in cfgdict have to call write_ - # TODO: not sure about readonly (why not a parameter which can only be written from config?) try: pobj.value = pobj.datatype(cfgdict[pname]) self.writeDict[pname] = pobj.value @@ -417,10 +416,8 @@ class Module(HasAccessibles): except BadValueError as e: # this should not happen, as the default is already checked in Parameter raise ProgrammingError('bad default for %s:%s: %s' % (name, pname, e)) from None - if pobj.initwrite and not pobj.readonly: + if pobj.initwrite and hasattr(self, 'write_' + pname): # we will need to call write_ - # if this is not desired, the default must not be given - # TODO: not sure about readonly (why not a parameter which can only be written from config?) pobj.value = value self.writeDict[pname] = value else: diff --git a/secop/persistent.py b/secop/persistent.py index 0360b84..63ce5a1 100644 --- a/secop/persistent.py +++ b/secop/persistent.py @@ -75,7 +75,7 @@ class PersistentMixin(HasAccessibles): self.initData = {} for pname in self.parameters: pobj = self.parameters[pname] - if not pobj.readonly and getattr(pobj, 'persistent', 0): + if hasattr(self, 'write_' + pname) and getattr(pobj, 'persistent', 0): self.initData[pname] = pobj.value if pobj.persistent == 'auto': def cb(value, m=self): diff --git a/secop/proxy.py b/secop/proxy.py index 7189fa8..2c25838 100644 --- a/secop/proxy.py +++ b/secop/proxy.py @@ -23,8 +23,7 @@ from secop.client import SecopClient, decode_msg, encode_msg_frame from secop.datatypes import StringType -from secop.errors import BadValueError, \ - CommunicationFailedError, ConfigError, make_secop_error +from secop.errors import BadValueError, CommunicationFailedError, ConfigError from secop.lib import get_class from secop.modules import Drivable, Module, Readable, Writable from secop.params import Command, Parameter @@ -47,8 +46,6 @@ class ProxyModule(HasIO, Module): if parameter not in self.parameters: return # ignore unknown parameters # should be done here: deal with clock differences - if readerror: - readerror = make_secop_error(*readerror) self.announceUpdate(parameter, value, readerror, timestamp) def initModule(self): @@ -201,7 +198,7 @@ def proxy_class(remote_class, name=None): def wfunc(self, value, pname=aname): value, _, readerror = self._secnode.setParameter(self.name, pname, value) if readerror: - raise make_secop_error(*readerror) + raise readerror return value attrs['write_' + aname] = wfunc diff --git a/secop_psi/ccu4.py b/secop_psi/ccu4.py index e263537..e1b4801 100644 --- a/secop_psi/ccu4.py +++ b/secop_psi/ccu4.py @@ -72,7 +72,7 @@ class HeLevel(HasIO, Readable): """ name, txtvalue = self.communicate(cmd).split('=') assert name == cmd.split('=')[0] # check that we got a reply to our command - return txtvalue # Frappy will automatically convert the string to the needed data type + return float(txtvalue) def read_value(self): return self.query('h') diff --git a/test/test_lib_enum.py b/test/test_lib_enum.py index 78016fa..97228e1 100644 --- a/test/test_lib_enum.py +++ b/test/test_lib_enum.py @@ -64,6 +64,7 @@ def test_EnumMember(): assert a != 3 assert a == 1 + def test_Enum(): e1 = Enum('e1') e2 = Enum('e2', e1, a=1, b=3) @@ -75,3 +76,4 @@ def test_Enum(): assert e2.b > e3.a assert e3.c >= e2.a assert e3.b <= e2.b + assert Enum({'self': 0, 'other': 1})('self') == 0