From 5f640ce2997476985bb31f9bf62310b378a85842 Mon Sep 17 00:00:00 2001 From: Enrico Faulhaber Date: Tue, 31 Jul 2018 16:37:36 +0200 Subject: [PATCH] [server.py] rename initialisation steps for better clarity initialisation occurs in this order: - object creeation (via __init__ which should consume the cfg values it knows about) - registering each object with the dispatcher - calling init_module() on each module (for connecting to other modules, checking hw, creating threads....) - calling start_module(cb) on each module. after the module finished startup it should call cb(self) once. This is the right place to do initialisation of hw which is not needed to read from the hw. (uploading curves, polling/re-setting all parameters, etc.) Change-Id: Ieaf9df5876e764634836861241f58ab986027f44 Reviewed-on: https://forge.frm2.tum.de/review/18566 Tested-by: JenkinsCodeReview Reviewed-by: Markus Zolliker Reviewed-by: Enrico Faulhaber --- secop/modules.py | 19 +++++++---------- secop/server.py | 11 +++++----- secop/simulation.py | 2 +- secop_demo/cryo.py | 2 +- secop_demo/modules.py | 4 ++-- secop_mlz/amagnet.py | 4 ++-- secop_mlz/entangle.py | 32 ++++++++++++++-------------- test/test_modules.py | 19 ++++++++++++++--- test/{test_blubb.py => test_test.py} | 0 9 files changed, 52 insertions(+), 41 deletions(-) rename test/{test_blubb.py => test_test.py} (100%) diff --git a/secop/modules.py b/secop/modules.py index 20eacc62..e6c7a7b8 100644 --- a/secop/modules.py +++ b/secop/modules.py @@ -189,21 +189,21 @@ class Module(object): v.unit = v.unit.replace('$', self.accessibles['value'].unit) - def init(self): + def early_init(self): # may be overriden in derived classes to init stuff - self.log.debug('empty init()') + self.log.debug('empty early_init()') - def postinit(self): - self.log.debug('empty postinit()') + def init_module(self): + self.log.debug('empty init_module()') - def late_init(self, started_callback): - '''runs after postinit of all modules + def start_module(self, started_callback): + '''runs after init of all modules started_callback to be called when thread spawned by late_init or, if not implmemented, immediately ''' - self.log.debug('empty late init()') + self.log.debug('empty start_module()') started_callback(self) @@ -238,10 +238,7 @@ class Readable(Module): ), } - def init(self): - Module.init(self) - - def late_init(self, started_callback): + def start_module(self, started_callback): '''start polling thread''' mkthread(self.__pollThread, started_callback) diff --git a/secop/server.py b/secop/server.py index 4bd4de66..66fe2085 100644 --- a/secop/server.py +++ b/secop/server.py @@ -214,16 +214,16 @@ class Server(object): for devname, devobj, export in devs: self.log.info(u'registering module %r' % devname) self._dispatcher.register_module(devobj, devname, export) - # also call init on the modules - devobj.init() - # call postinit on each module after registering all + # also call early_init on the modules + devobj.early_init() + # call init on each module after registering all for _devname, devobj, _export in devs: - devobj.postinit() + devobj.init_module() starting_modules = set() finished_modules = Queue() for _devname, devobj, _export in devs: starting_modules.add(devobj) - devobj.late_init(started_callback=finished_modules.put) + devobj.start_module(started_callback=finished_modules.put) # remark: it is the module implementors responsibility to call started_callback # within reasonable time (using timeouts). If we find later, that this is not # enough, we might insert checking for a timeout here, and somehow set the remaining @@ -233,6 +233,7 @@ class Server(object): self.log.info(u'%s has started' % finished.name) # use discard instead of remove here, catching the case when started_callback is called twice starting_modules.discard(finished) + finished_modules.task_done() def _processInterfaceOptions(self, interfaceopts): # eval interfaces diff --git a/secop/simulation.py b/secop/simulation.py index e956885e..6ae0a8e4 100644 --- a/secop/simulation.py +++ b/secop/simulation.py @@ -55,7 +55,7 @@ class SimBase(object): return newval setattr(self, 'write_' + k, writer) - def late_init(self): + def init_module(self): self._sim_thread = mkthread(self._sim) def _sim(self): diff --git a/secop_demo/cryo.py b/secop_demo/cryo.py index 77a30af6..29b4ba50 100644 --- a/secop_demo/cryo.py +++ b/secop_demo/cryo.py @@ -129,7 +129,7 @@ class Cryostat(CryoBase): None), ) - def init(self): + def init_module(self): self._stopflag = False self._thread = mkthread(self.thread) diff --git a/secop_demo/modules.py b/secop_demo/modules.py index 96db9eb0..6c01afe5 100644 --- a/secop_demo/modules.py +++ b/secop_demo/modules.py @@ -115,7 +115,7 @@ class MagneticField(Drivable): ), } - def init(self): + def init_module(self): self._state = Enum('state', idle=1, switch_on=2, switch_off=3, ramp=4).idle self._heatswitch = self.DISPATCHER.get_module(self.heatswitch) _thread = threading.Thread(target=self._thread) @@ -211,7 +211,7 @@ class SampleTemp(Drivable): ), } - def init(self): + def init_module(self): _thread = threading.Thread(target=self._thread) _thread.daemon = True _thread.start() diff --git a/secop_mlz/amagnet.py b/secop_mlz/amagnet.py index 35926663..720b3253 100644 --- a/secop_mlz/amagnet.py +++ b/secop_mlz/amagnet.py @@ -132,8 +132,8 @@ class GarfieldMagnet(SequencerMixin, Drivable): raise ConfigError(self, '_current2field polynome not monotonic!') - def init(self): - super(GarfieldMagnet, self).init() + def init_module(self): + super(GarfieldMagnet, self).init_module() self._enable = self.DISPATCHER.get_module(self.subdev_enable) self._symmetry = self.DISPATCHER.get_module(self.subdev_symmetry) self._polswitch = self.DISPATCHER.get_module(self.subdev_polswitch) diff --git a/secop_mlz/entangle.py b/secop_mlz/entangle.py index fe2cc0df..d9ab6074 100644 --- a/secop_mlz/entangle.py +++ b/secop_mlz/entangle.py @@ -210,12 +210,12 @@ class PyTangoDevice(Module): self._com_warn(tries, name, err, info) sleep(self.comdelay) - def init(self): + def early_init(self): # Wrap PyTango client creation (so even for the ctor, logging and # exception mapping is enabled). self._createPyTangoDevice = self._applyGuardToFunc( self._createPyTangoDevice, 'constructor') - super(PyTangoDevice, self).init() + super(PyTangoDevice, self).early_init() @lazy_property def _dev(self): @@ -379,8 +379,8 @@ class AnalogInput(PyTangoDevice, Readable): The AnalogInput handles all devices only delivering an analogue value. """ - def late_init(self, started_callback): - super(AnalogInput, self).late_init(started_callback) + def start_module(self, started_callback): + super(AnalogInput, self).start_module(started_callback) # query unit from tango and update value property attrInfo = self._dev.attribute_query('value') # prefer configured unit if nothing is set on the Tango device, else @@ -456,14 +456,14 @@ class AnalogOutput(PyTangoDevice, Drivable): _timeout = None _moving = False - def init(self): - super(AnalogOutput, self).init() + def init_module(self): + super(AnalogOutput, self).init_module() # init history self._history = [] # will keep (timestamp, value) tuple self._timeout = None # keeps the time at which we will timeout, or None - def late_init(self, started_callback): - super(AnalogOutput, self).late_init(started_callback) + def start_module(self, started_callback): + super(AnalogOutput, self).start_module(started_callback) # query unit from tango and update value property attrInfo = self._dev.attribute_query('value') # prefer configured unit if nothing is set on the Tango device, else @@ -801,8 +801,8 @@ class NamedDigitalInput(DigitalInput): datatype=StringType(), export=False), # XXX:!!! } - def init(self): - super(NamedDigitalInput, self).init() + def init_module(self): + super(NamedDigitalInput, self).init_module() try: # pylint: disable=eval-used self.accessibles['value'].datatype = EnumType('value', **eval(self.mapping)) @@ -826,8 +826,8 @@ class PartialDigitalInput(NamedDigitalInput): datatype=IntRange(0), default=1), } - def init(self): - super(PartialDigitalInput, self).init() + def init_module(self): + super(PartialDigitalInput, self).init_module() self._mask = (1 << self.bitwidth) - 1 # self.accessibles['value'].datatype = IntRange(0, self._mask) @@ -868,8 +868,8 @@ class NamedDigitalOutput(DigitalOutput): datatype=StringType(), export=False), } - def init(self): - super(NamedDigitalOutput, self).init() + def init_module(self): + super(NamedDigitalOutput, self).init_module() try: # pylint: disable=eval-used self.accessibles['value'].datatype = EnumType('value', **eval(self.mapping)) @@ -896,8 +896,8 @@ class PartialDigitalOutput(NamedDigitalOutput): datatype=IntRange(0), default=1), } - def init(self): - super(PartialDigitalOutput, self).init() + def init_module(self): + super(PartialDigitalOutput, self).init_module() self._mask = (1 << self.bitwidth) - 1 # self.accessibles['value'].datatype = IntRange(0, self._mask) # self.accessibles['target'].datatype = IntRange(0, self._mask) diff --git a/test/test_modules.py b/test/test_modules.py index 014dd7c0..da83093f 100644 --- a/test/test_modules.py +++ b/test/test_modules.py @@ -28,6 +28,10 @@ sys.path.insert(0, sys.path[0] + '/..') # no fixtures needed import pytest +try: + import Queue as queue +except ImportError: + import queue as queue from secop.datatypes import BoolType, EnumType @@ -47,7 +51,11 @@ def test_Communicator(): ))() o = Communicator(logger, {}, 'o1', dispatcher) - o.init() + o.early_init() + o.init_module() + q = queue.Queue() + o.start_module(q.put) + q.get() def test_ModuleMeta(): newclass = ModuleMeta.__new__(ModuleMeta, 'TestReadable', (Drivable, Writable, Readable, Module), { @@ -100,5 +108,10 @@ def test_ModuleMeta(): params_found.add(o) assert o.ctr not in ctr_found ctr_found.add(o.ctr) - o1.init() - o2.init() + o1.early_init() + o2.early_init() + o1.init_module() + o2.init_module() + q = queue.Queue() + o1.start_module(q.put) + o2.start_module(q.put) diff --git a/test/test_blubb.py b/test/test_test.py similarity index 100% rename from test/test_blubb.py rename to test/test_test.py