fix and improved Attached
- Attached checks now for proper base class - fixes an error in Attached: attached saved in attachedModules dict instead on the Attached object (which sits on the class!) + fix: in testonly mode errors must be logged before returning + fix: use repr of exception in poll to check for repeated errors Change-Id: I141fa107fed48e58b55ddf1e071987656c0f618f Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27913 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
parent
8767be2aac
commit
fda1939324
@ -280,6 +280,7 @@ class Module(HasAccessibles):
|
|||||||
|
|
||||||
# reference to the dispatcher (used for sending async updates)
|
# reference to the dispatcher (used for sending async updates)
|
||||||
DISPATCHER = None
|
DISPATCHER = None
|
||||||
|
attachedModules = None
|
||||||
|
|
||||||
def __init__(self, name, logger, cfgdict, srv):
|
def __init__(self, name, logger, cfgdict, srv):
|
||||||
# remember the dispatcher object (for the async callbacks)
|
# remember the dispatcher object (for the async callbacks)
|
||||||
@ -649,11 +650,11 @@ class Module(HasAccessibles):
|
|||||||
self.log.info('recovered after %d calls to doPoll (%r)', error_count, last_error)
|
self.log.info('recovered after %d calls to doPoll (%r)', error_count, last_error)
|
||||||
last_error = None
|
last_error = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if type(e) != last_error:
|
if repr(e) != last_error:
|
||||||
error_count = 0
|
error_count = 0
|
||||||
self.log.error('error in doPoll: %r', e)
|
self.log.error('error in doPoll: %r', e)
|
||||||
error_count += 1
|
error_count += 1
|
||||||
last_error = e
|
last_error = repr(e)
|
||||||
now = time.time()
|
now = time.time()
|
||||||
# find ONE due slow poll and call it
|
# find ONE due slow poll and call it
|
||||||
loop = True
|
loop = True
|
||||||
@ -803,14 +804,15 @@ class Attached(Property):
|
|||||||
assign a module name to this property in the cfg file,
|
assign a module name to this property in the cfg file,
|
||||||
and the server will create an attribute with this module
|
and the server will create an attribute with this module
|
||||||
"""
|
"""
|
||||||
module = None
|
def __init__(self, basecls=Module, description='attached module'):
|
||||||
|
self.basecls = basecls
|
||||||
def __init__(self, description='attached module'):
|
|
||||||
super().__init__(description, StringType(), mandatory=False)
|
super().__init__(description, StringType(), mandatory=False)
|
||||||
|
|
||||||
def __get__(self, obj, owner):
|
def __get__(self, obj, owner):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
return self
|
return self
|
||||||
if self.module is None:
|
if obj.attachedModules is None:
|
||||||
self.module = obj.DISPATCHER.get_module(super().__get__(obj, owner))
|
# return the name of the module (called from Server on startup)
|
||||||
return self.module
|
return super().__get__(obj, owner)
|
||||||
|
# return the module (called after startup)
|
||||||
|
return obj.attachedModules[self.name]
|
||||||
|
@ -30,10 +30,11 @@ import sys
|
|||||||
import traceback
|
import traceback
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from secop.errors import ConfigError
|
from secop.errors import ConfigError, SECoPError
|
||||||
from secop.lib import formatException, get_class, generalConfig
|
from secop.lib import formatException, get_class, generalConfig
|
||||||
from secop.lib.multievent import MultiEvent
|
from secop.lib.multievent import MultiEvent
|
||||||
from secop.params import PREDEFINED_ACCESSIBLES
|
from secop.params import PREDEFINED_ACCESSIBLES
|
||||||
|
from secop.modules import Attached
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from daemon import DaemonContext
|
from daemon import DaemonContext
|
||||||
@ -275,6 +276,23 @@ class Server:
|
|||||||
missing_super.add('%s was not called, probably missing super call'
|
missing_super.add('%s was not called, probably missing super call'
|
||||||
% modobj.earlyInit.__qualname__)
|
% modobj.earlyInit.__qualname__)
|
||||||
|
|
||||||
|
# handle attached modules
|
||||||
|
for modname, modobj in self.modules.items():
|
||||||
|
attached_modules = {}
|
||||||
|
for propname, propobj in modobj.propertyDict.items():
|
||||||
|
if isinstance(propobj, Attached):
|
||||||
|
try:
|
||||||
|
attname = getattr(modobj, propname)
|
||||||
|
attobj = self.dispatcher.get_module(attname)
|
||||||
|
if isinstance(attobj, propobj.basecls):
|
||||||
|
attached_modules[propname] = attobj
|
||||||
|
else:
|
||||||
|
errors.append('attached module %s=%r must inherit from %r'
|
||||||
|
% (propname, attname, propobj.basecls.__qualname__))
|
||||||
|
except SECoPError as e:
|
||||||
|
errors.append('module %s, attached %s: %s' % (modname, propname, str(e)))
|
||||||
|
modobj.attachedModules = attached_modules
|
||||||
|
|
||||||
# call init on each module after registering all
|
# call init on each module after registering all
|
||||||
for modname, modobj in self.modules.items():
|
for modname, modobj in self.modules.items():
|
||||||
try:
|
try:
|
||||||
@ -287,8 +305,7 @@ class Server:
|
|||||||
failure_traceback = traceback.format_exc()
|
failure_traceback = traceback.format_exc()
|
||||||
errors.append('error initializing %s: %r' % (modname, e))
|
errors.append('error initializing %s: %r' % (modname, e))
|
||||||
|
|
||||||
if self._testonly:
|
if not self._testonly:
|
||||||
return
|
|
||||||
start_events = MultiEvent(default_timeout=30)
|
start_events = MultiEvent(default_timeout=30)
|
||||||
for modname, modobj in self.modules.items():
|
for modname, modobj in self.modules.items():
|
||||||
# startModule must return either a timeout value or None (default 30 sec)
|
# startModule must return either a timeout value or None (default 30 sec)
|
||||||
@ -297,8 +314,8 @@ class Server:
|
|||||||
if not modobj.startModuleDone:
|
if not modobj.startModuleDone:
|
||||||
missing_super.add('%s was not called, probably missing super call'
|
missing_super.add('%s was not called, probably missing super call'
|
||||||
% modobj.startModule.__qualname__)
|
% modobj.startModule.__qualname__)
|
||||||
|
|
||||||
errors.extend(missing_super)
|
errors.extend(missing_super)
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
for errtxt in errors:
|
for errtxt in errors:
|
||||||
for line in errtxt.split('\n'):
|
for line in errtxt.split('\n'):
|
||||||
@ -310,6 +327,8 @@ class Server:
|
|||||||
sys.stderr.write(failure_traceback)
|
sys.stderr.write(failure_traceback)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if self._testonly:
|
||||||
|
return
|
||||||
self.log.info('waiting for modules being started')
|
self.log.info('waiting for modules being started')
|
||||||
start_events.name = None
|
start_events.name = None
|
||||||
if not start_events.wait():
|
if not start_events.wait():
|
||||||
|
@ -75,4 +75,6 @@ def test_attach():
|
|||||||
assert m.propertyValues['att'] == 'a'
|
assert m.propertyValues['att'] == 'a'
|
||||||
srv.dispatcher.register_module(a, 'a')
|
srv.dispatcher.register_module(a, 'a')
|
||||||
srv.dispatcher.register_module(m, 'm')
|
srv.dispatcher.register_module(m, 'm')
|
||||||
|
assert m.att == 'a'
|
||||||
|
m.attachedModules = {'att': a}
|
||||||
assert m.att == a
|
assert m.att == a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user