update to changes from mlz repo

- bug fixes in error.py
- add from * to raise statements
- fix py35 compatibility
- finalize omit_unchanged_within feature
- fix follwup bug (missing Param.override) in proxy.py

Change-Id: I621c01a0d5e1ec6696fb06f39666f3316fb53649
This commit is contained in:
2021-11-10 13:44:14 +01:00
parent 7690481938
commit 41ce909172
13 changed files with 43 additions and 58 deletions

View File

@ -25,7 +25,7 @@
class SECoPError(RuntimeError): class SECoPError(RuntimeError):
def __init__(self, *args, **kwds): def __init__(self, *args, **kwds):
RuntimeError.__init__(self) super().__init__()
self.args = args self.args = args
for k, v in list(kwds.items()): for k, v in list(kwds.items()):
setattr(self, k, v) setattr(self, k, v)
@ -151,7 +151,8 @@ EXCEPTIONS = dict(
IsError=IsErrorError, IsError=IsErrorError,
Disabled=DisabledError, Disabled=DisabledError,
SyntaxError=ProtocolError, SyntaxError=ProtocolError,
NotImplementedError=NotImplementedError, NotImplemented=NotImplementedError,
ProtocolError=ProtocolError,
InternalError=InternalError, InternalError=InternalError,
# internal short versions (candidates for spec) # internal short versions (candidates for spec)
Protocol=ProtocolError, Protocol=ProtocolError,

View File

@ -39,7 +39,7 @@ COMMENT = 'comment'
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
def __init__(self, file_path=None, parent=None): def __init__(self, file_path=None, parent=None):
QMainWindow.__init__(self, parent) super().__init__(parent)
loadUi(self, 'mainwindow.ui') loadUi(self, 'mainwindow.ui')
self.tabWidget.currentChanged.connect(self.tab_relevant_btns_disable) self.tabWidget.currentChanged.connect(self.tab_relevant_btns_disable)
if file_path is None: if file_path is None:

View File

@ -26,7 +26,7 @@ from secop.gui.qt import QHBoxLayout, QSizePolicy, QSpacerItem, Qt, QWidget
class NodeDisplay(QWidget): class NodeDisplay(QWidget):
def __init__(self, file_path=None, parent=None): def __init__(self, file_path=None, parent=None):
QWidget.__init__(self, parent) super().__init__(parent)
loadUi(self, 'node_display.ui') loadUi(self, 'node_display.ui')
self.saved = bool(file_path) self.saved = bool(file_path)
self.created = self.tree_widget.set_file(file_path) self.created = self.tree_widget.set_file(file_path)

View File

@ -44,7 +44,7 @@ class TreeWidgetItem(QTreeWidgetItem):
the datatype passed onto ValueWidget should be on of secop.datatypes""" the datatype passed onto ValueWidget should be on of secop.datatypes"""
# TODO: like stated in docstring the datatype for parameters and # TODO: like stated in docstring the datatype for parameters and
# properties must be found out through their object # properties must be found out through their object
QTreeWidgetItem.__init__(self, parent) super().__init__(parent)
self.kind = kind self.kind = kind
self.name = name self.name = name
self.class_object = class_object self.class_object = class_object
@ -129,7 +129,7 @@ class ValueWidget(QWidget):
def __init__(self, name='', value='', datatype=None, kind='', parent=None): def __init__(self, name='', value='', datatype=None, kind='', parent=None):
# TODO: implement: change module/interface class # TODO: implement: change module/interface class
QWidget.__init__(self, parent) super().__init__(parent)
self.datatype = datatype self.datatype = datatype
self.layout = QVBoxLayout() self.layout = QVBoxLayout()
self.name_label = QLabel(name) self.name_label = QLabel(name)
@ -205,7 +205,7 @@ class ValueWidget(QWidget):
class ChangeNameDialog(QDialog): class ChangeNameDialog(QDialog):
def __init__(self, current_name='', invalid_names=None, parent=None): def __init__(self, current_name='', invalid_names=None, parent=None):
QWidget.__init__(self, parent) super().__init__(parent)
loadUi(self, 'change_name_dialog.ui') loadUi(self, 'change_name_dialog.ui')
self.invalid_names = invalid_names self.invalid_names = invalid_names
self.name.setText(current_name) self.name.setText(current_name)

View File

@ -31,7 +31,7 @@ from secop.gui.cfg_editor.utils import get_all_items, \
get_props, loadUi, set_name_edit_style, setActionIcon get_props, loadUi, set_name_edit_style, setActionIcon
from secop.gui.qt import QComboBox, QDialog, QDialogButtonBox, QLabel, \ from secop.gui.qt import QComboBox, QDialog, QDialogButtonBox, QLabel, \
QLineEdit, QMenu, QPoint, QSize, QStandardItem, QStandardItemModel, \ QLineEdit, QMenu, QPoint, QSize, QStandardItem, QStandardItemModel, \
Qt, QTabBar, QTextEdit, QTreeView, QTreeWidget, QWidget, pyqtSignal Qt, QTabBar, QTextEdit, QTreeView, QTreeWidget, pyqtSignal
NODE = 'node' NODE = 'node'
MODULE = 'module' MODULE = 'module'
@ -47,7 +47,7 @@ class TreeWidget(QTreeWidget):
add_canceled = pyqtSignal() add_canceled = pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
QTreeWidget.__init__(self, parent) super().__init__(parent)
self.file_path = None self.file_path = None
self.setIconSize(QSize(24, 24)) self.setIconSize(QSize(24, 24))
self.setSelectionMode(QTreeWidget.SingleSelection) self.setSelectionMode(QTreeWidget.SingleSelection)
@ -335,7 +335,7 @@ class AddDialog(QDialog):
"""Notes: """Notes:
self.get_value: is mapped to the specific method for getting self.get_value: is mapped to the specific method for getting
the value from self.value""" the value from self.value"""
QWidget.__init__(self, parent) super().__init__(parent)
loadUi(self, 'add_dialog.ui') loadUi(self, 'add_dialog.ui')
self.setWindowTitle('add %s' % kind) self.setWindowTitle('add %s' % kind)
self.kind = kind self.kind = kind
@ -402,7 +402,7 @@ class AddDialog(QDialog):
class TabBar(QTabBar): class TabBar(QTabBar):
def __init__(self, parent=None): def __init__(self, parent=None):
QTabBar.__init__(self, parent) super().__init__(parent)
self.setContextMenuPolicy(Qt.CustomContextMenu) self.setContextMenuPolicy(Qt.CustomContextMenu)
self.context_pos = QPoint(0, 0) self.context_pos = QPoint(0, 0)
self.menu = QMenu() self.menu = QMenu()
@ -436,7 +436,7 @@ class TabBar(QTabBar):
class TreeComboBox(QComboBox): class TreeComboBox(QComboBox):
def __init__(self, value_dict, parent=None): def __init__(self, value_dict, parent=None):
QComboBox.__init__(self, parent) super().__init__(parent)
self.tree_view = QTreeView() self.tree_view = QTreeView()
self.tree_view.setHeaderHidden(True) self.tree_view.setHeaderHidden(True)
self.tree_view.expanded.connect(self.resize_length) self.tree_view.expanded.connect(self.resize_length)

View File

@ -44,7 +44,7 @@ class QSECNode(QObject):
logEntry = pyqtSignal(str) logEntry = pyqtSignal(str)
def __init__(self, uri, parent=None): def __init__(self, uri, parent=None):
QObject.__init__(self, parent) super().__init__(parent)
self.conn = conn = secop.client.SecopClient(uri) self.conn = conn = secop.client.SecopClient(uri)
conn.validate_data = True conn.validate_data = True
self.log = conn.log self.log = conn.log
@ -83,10 +83,7 @@ class QSECNode(QObject):
return self.conn.getParameter(module, parameter, True) return self.conn.getParameter(module, parameter, True)
def execCommand(self, module, command, argument): def execCommand(self, module, command, argument):
try:
return self.conn.execCommand(module, command, argument) return self.conn.execCommand(module, command, argument)
except Exception as e:
return 'ERROR: %r' % e, {}
def queryCache(self, module): def queryCache(self, module):
return {k: Value(*self.conn.cache[(module, k)]) return {k: Value(*self.conn.cache[(module, k)])
@ -115,7 +112,7 @@ class QSECNode(QObject):
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
def __init__(self, hosts, parent=None): def __init__(self, hosts, parent=None):
super(MainWindow, self).__init__(parent) super().__init__(parent)
loadUi(self, 'mainwindow.ui') loadUi(self, 'mainwindow.ui')

View File

@ -160,7 +160,7 @@ class MiniPlotFitCurve(MiniPlotCurve):
return float('-inf') return float('-inf')
def __init__(self, formula, params): def __init__(self, formula, params):
super(MiniPlotFitCurve, self).__init__() super().__init__()
self.formula = formula self.formula = formula
self.params = params self.params = params
@ -193,7 +193,7 @@ class MiniPlot(QWidget):
autoticky = True autoticky = True
def __init__(self, parent=None): def __init__(self, parent=None):
QWidget.__init__(self, parent) super().__init__(parent)
self.xmin = self.xmax = None self.xmin = self.xmax = None
self.ymin = self.ymax = None self.ymin = self.ymax = None
self.curves = [] self.curves = []

View File

@ -32,7 +32,7 @@ from secop.gui.valuewidgets import get_widget
class CommandDialog(QDialog): class CommandDialog(QDialog):
def __init__(self, cmdname, argument, parent=None): def __init__(self, cmdname, argument, parent=None):
super(CommandDialog, self).__init__(parent) super().__init__(parent)
loadUi(self, 'cmddialog.ui') loadUi(self, 'cmddialog.ui')
self.setWindowTitle('Arguments for %s' % cmdname) self.setWindowTitle('Arguments for %s' % cmdname)
@ -58,7 +58,7 @@ class CommandDialog(QDialog):
return True, self.widgets[0].get_value() return True, self.widgets[0].get_value()
def exec_(self): def exec_(self):
if super(CommandDialog, self).exec_(): if super().exec_():
return self.get_value() return self.get_value()
return None return None
@ -71,16 +71,17 @@ def showCommandResultDialog(command, args, result, extras=''):
m.exec_() m.exec_()
def showErrorDialog(error): def showErrorDialog(command, args, error):
m = QMessageBox() m = QMessageBox()
m.setText('Error %r' % error) args = '' if args is None else repr(args)
m.setText('calling: %s(%s)\nraised %r' % (command, args, error))
m.exec_() m.exec_()
class ParameterGroup(QWidget): class ParameterGroup(QWidget):
def __init__(self, groupname, parent=None): def __init__(self, groupname, parent=None):
super(ParameterGroup, self).__init__(parent) super().__init__(parent)
loadUi(self, 'paramgroup.ui') loadUi(self, 'paramgroup.ui')
self._groupname = groupname self._groupname = groupname
@ -112,7 +113,7 @@ class ParameterGroup(QWidget):
class CommandButton(QPushButton): class CommandButton(QPushButton):
def __init__(self, cmdname, cmdinfo, cb, parent=None): def __init__(self, cmdname, cmdinfo, cb, parent=None):
super(CommandButton, self).__init__(parent) super().__init__(parent)
self._cmdname = cmdname self._cmdname = cmdname
self._argintype = cmdinfo['datatype'].argument # single datatype self._argintype = cmdinfo['datatype'].argument # single datatype
@ -140,7 +141,7 @@ class CommandButton(QPushButton):
class ModuleCtrl(QWidget): class ModuleCtrl(QWidget):
def __init__(self, node, module, parent=None): def __init__(self, node, module, parent=None):
super(ModuleCtrl, self).__init__(parent) super().__init__(parent)
loadUi(self, 'modulectrl.ui') loadUi(self, 'modulectrl.ui')
self._node = node self._node = node
self._module = module self._module = module
@ -161,10 +162,9 @@ class ModuleCtrl(QWidget):
try: try:
result, qualifiers = self._node.execCommand( result, qualifiers = self._node.execCommand(
self._module, command, args) self._module, command, args)
except TypeError: except Exception as e:
result = None showErrorDialog(command, args, e)
qualifiers = {} return
# XXX: flag missing data report as error
if result is not None: if result is not None:
showCommandResultDialog(command, args, result, qualifiers) showCommandResultDialog(command, args, result, qualifiers)

View File

@ -39,7 +39,7 @@ class ParameterWidget(QWidget):
initvalue=None, initvalue=None,
readonly=True, readonly=True,
parent=None): parent=None):
super(ParameterWidget, self).__init__(parent) super().__init__(parent)
self._module = module self._module = module
self._paramcmd = paramcmd self._paramcmd = paramcmd
self._datatype = datatype self._datatype = datatype
@ -82,7 +82,6 @@ class GenericParameterWidget(ParameterWidget):
else: else:
value = fmtstr % (value.value,) value = fmtstr % (value.value,)
self.currentLineEdit.setText(value) self.currentLineEdit.setText(value)
# self.currentLineEdit.setText(str(value))
class EnumParameterWidget(GenericParameterWidget): class EnumParameterWidget(GenericParameterWidget):

View File

@ -24,24 +24,12 @@
import inspect import inspect
import sys
from secop.errors import BadValueError, ConfigError, ProgrammingError from secop.errors import BadValueError, ConfigError, ProgrammingError
from secop.lib.py35compat import Object
class HasDescriptorMeta(type): class HasDescriptors(Object):
def __new__(cls, name, bases, attrs):
newtype = type.__new__(cls, name, bases, attrs)
if sys.version_info < (3, 6):
# support older python versions
for key, attr in attrs.items():
if hasattr(attr, '__set_name__'):
attr.__set_name__(newtype, key)
newtype.__init_subclass__()
return newtype
class HasDescriptors(metaclass=HasDescriptorMeta):
@classmethod @classmethod
def __init_subclass__(cls): def __init_subclass__(cls):
# when migrating old style declarations, sometimes the trailing comma is not removed # when migrating old style declarations, sometimes the trailing comma is not removed
@ -142,12 +130,6 @@ class HasProperties(HasDescriptors):
@classmethod @classmethod
def __init_subclass__(cls): def __init_subclass__(cls):
super().__init_subclass__() super().__init_subclass__()
# raise an error when an attribute is a tuple with one single descriptor as element
# when migrating old style declarations, sometimes the trailing comma is not removed
bad = [k for k, v in cls.__dict__.items()
if isinstance(v, tuple) and len(v) == 1 and hasattr(v[0], '__set_name__')]
if bad:
raise ProgrammingError('misplaced trailing comma after %s.%s' % (cls.__name__, '/'.join(bad)))
properties = {} properties = {}
# using cls.__bases__ and base.propertyDict for this would fail on some multiple inheritance cases # using cls.__bases__ and base.propertyDict for this would fail on some multiple inheritance cases
for base in reversed(cls.__mro__): for base in reversed(cls.__mro__):

View File

@ -60,12 +60,11 @@ def make_update(modulename, pobj):
class Dispatcher: class Dispatcher:
OMIT_UNCHANGED_WITHIN = 1 # do not send unchanged updates within 1 sec
def __init__(self, name, logger, options, srv): def __init__(self, name, logger, options, srv):
# to avoid errors, we want to eat all options here # to avoid errors, we want to eat all options here
self.equipment_id = options.pop('id', name) self.equipment_id = options.pop('id', name)
# time interval for omitting updates of unchanged values
self.omit_unchanged_within = options.pop('omit_unchanged_within', 0.1)
self.nodeprops = {} self.nodeprops = {}
for k in list(options): for k in list(options):
self.nodeprops[k] = options.pop(k) self.nodeprops[k] = options.pop(k)
@ -84,7 +83,6 @@ class Dispatcher:
self._subscriptions = {} self._subscriptions = {}
self._lock = threading.RLock() self._lock = threading.RLock()
self.restart = srv.restart self.restart = srv.restart
self.shutdown = srv.shutdown
def broadcast_event(self, msg, reallyall=False): def broadcast_event(self, msg, reallyall=False):
"""broadcasts a msg to all active connections """broadcasts a msg to all active connections

View File

@ -202,3 +202,11 @@ class TCPServer(socketserver.ThreadingTCPServer):
if ntry: if ntry:
self.log.warning('tried again %d times after "Address already in use"' % ntry) self.log.warning('tried again %d times after "Address already in use"' % ntry)
self.log.info("TCPServer initiated") self.log.info("TCPServer initiated")
# py35 compatibility
if not hasattr(socketserver.ThreadingTCPServer, '__exit__'):
def __enter__(self):
return self
def __exit__(self, *args):
self.server_close()

View File

@ -182,7 +182,7 @@ def proxy_class(remote_class, name=None):
for aname, aobj in rcls.accessibles.items(): for aname, aobj in rcls.accessibles.items():
if isinstance(aobj, Parameter): if isinstance(aobj, Parameter):
pobj = aobj.override(poll=False, handler=None, needscfg=False) pobj = aobj.merge(dict(poll=False, handler=None, needscfg=False))
attrs[aname] = pobj attrs[aname] = pobj
def rfunc(self, pname=aname): def rfunc(self, pname=aname):