Stub debug client gui.
Change-Id: Ib422c66bc36245e1fc3c450765d7555da5c8dda0
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,3 +3,5 @@ html/*
|
|||||||
*.pyc
|
*.pyc
|
||||||
pid/*
|
pid/*
|
||||||
|
|
||||||
|
# ide
|
||||||
|
.idea
|
||||||
|
53
bin/secop-gui
Executable file
53
bin/secop-gui
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
# Add import path for inplace usage
|
||||||
|
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
|
||||||
|
|
||||||
|
from secop.gui.mainwindow import MainWindow
|
||||||
|
from secop import loggers
|
||||||
|
|
||||||
|
from PyQt4.QtGui import QApplication
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv
|
||||||
|
|
||||||
|
loggers.initLogging('gui', 'debug')
|
||||||
|
|
||||||
|
app = QApplication(argv)
|
||||||
|
|
||||||
|
win = MainWindow()
|
||||||
|
win.show()
|
||||||
|
|
||||||
|
return app.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv))
|
||||||
|
|
@ -0,0 +1,26 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
import sip
|
||||||
|
sip.setapi('QString', 2)
|
||||||
|
sip.setapi('QVariant', 2)
|
||||||
|
@ -29,6 +29,7 @@ import threading
|
|||||||
import Queue
|
import Queue
|
||||||
|
|
||||||
from secop import loggers
|
from secop import loggers
|
||||||
|
from secop.validators import validator_from_str
|
||||||
from secop.lib import mkthread
|
from secop.lib import mkthread
|
||||||
from secop.lib.parsing import parse_time, format_time
|
from secop.lib.parsing import parse_time, format_time
|
||||||
from secop.protocol.encoding import ENCODERS
|
from secop.protocol.encoding import ENCODERS
|
||||||
@ -137,7 +138,7 @@ class Client(object):
|
|||||||
describing_data = {}
|
describing_data = {}
|
||||||
stopflag = False
|
stopflag = False
|
||||||
|
|
||||||
def __init__(self, opts):
|
def __init__(self, opts, autoconnect=True):
|
||||||
self.log = loggers.log.getChild('client', True)
|
self.log = loggers.log.getChild('client', True)
|
||||||
self._cache = dict()
|
self._cache = dict()
|
||||||
if 'device' in opts:
|
if 'device' in opts:
|
||||||
@ -164,13 +165,15 @@ class Client(object):
|
|||||||
# mapping the modulename to a dict mapping the parameter names to their values
|
# mapping the modulename to a dict mapping the parameter names to their values
|
||||||
# note: the module value is stored as the value of the parameter value
|
# note: the module value is stored as the value of the parameter value
|
||||||
# of the module
|
# of the module
|
||||||
self.cache = dict()
|
|
||||||
|
|
||||||
self._syncLock = threading.RLock()
|
self._syncLock = threading.RLock()
|
||||||
self._thread = threading.Thread(target=self._run)
|
self._thread = threading.Thread(target=self._run)
|
||||||
self._thread.daemon = True
|
self._thread.daemon = True
|
||||||
self._thread.start()
|
self._thread.start()
|
||||||
|
|
||||||
|
if autoconnect:
|
||||||
|
self.startup()
|
||||||
|
|
||||||
def _run(self):
|
def _run(self):
|
||||||
while not self.stopflag:
|
while not self.stopflag:
|
||||||
try:
|
try:
|
||||||
@ -247,7 +250,7 @@ class Client(object):
|
|||||||
self.log.warning("deprecated specifier %r" % spec)
|
self.log.warning("deprecated specifier %r" % spec)
|
||||||
spec = '%s:value' % spec
|
spec = '%s:value' % spec
|
||||||
modname, pname = spec.split(':', 1)
|
modname, pname = spec.split(':', 1)
|
||||||
self.cache.setdefault(modname, {})[pname] = Value(*data)
|
self._cache.setdefault(modname, {})[pname] = Value(*data)
|
||||||
if spec in self.callbacks:
|
if spec in self.callbacks:
|
||||||
for func in self.callbacks[spec]:
|
for func in self.callbacks[spec]:
|
||||||
try:
|
try:
|
||||||
@ -265,6 +268,22 @@ class Client(object):
|
|||||||
run.add(func)
|
run.add(func)
|
||||||
self.single_shots[spec].difference_update(run)
|
self.single_shots[spec].difference_update(run)
|
||||||
|
|
||||||
|
def _getDescribingModuleData(self, module):
|
||||||
|
return self.describingModulesData[module]
|
||||||
|
|
||||||
|
def _getDescribingParameterData(self, module, parameter):
|
||||||
|
return self._getDescribingModuleData(module)['parameters'][parameter]
|
||||||
|
|
||||||
|
def _issueDescribe(self):
|
||||||
|
_, self.equipment_id, self.describing_data = self.communicate(
|
||||||
|
'describe')
|
||||||
|
|
||||||
|
for module, moduleData in self.describing_data['modules'].items():
|
||||||
|
for parameter, parameterData in moduleData['parameters'].items():
|
||||||
|
validator = validator_from_str(parameterData['validator'])
|
||||||
|
self.describing_data['modules'][module]['parameters'] \
|
||||||
|
[parameter]['validator'] = validator
|
||||||
|
|
||||||
def register_callback(self, module, parameter, cb):
|
def register_callback(self, module, parameter, cb):
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
'registering callback %r for %s:%s' %
|
'registering callback %r for %s:%s' %
|
||||||
@ -343,14 +362,36 @@ class Client(object):
|
|||||||
# XXX: further notification-callbacks needed ???
|
# XXX: further notification-callbacks needed ???
|
||||||
|
|
||||||
def startup(self, async=False):
|
def startup(self, async=False):
|
||||||
_, self.equipment_id, self.describing_data = self.communicate(
|
self._issueDescribe()
|
||||||
'describe')
|
|
||||||
# always fill our cache
|
# always fill our cache
|
||||||
self.communicate('activate')
|
self.communicate('activate')
|
||||||
# deactivate updates if not wanted
|
# deactivate updates if not wanted
|
||||||
if not async:
|
if not async:
|
||||||
self.communicate('deactivate')
|
self.communicate('deactivate')
|
||||||
|
|
||||||
|
def queryCache(self, module, parameter=None):
|
||||||
|
result = self._cache.get(module, {})
|
||||||
|
|
||||||
|
if parameter is not None:
|
||||||
|
result = result[parameter]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def setParameter(self, module, parameter, value):
|
||||||
|
validator = self._getDescribingParameterData(module,
|
||||||
|
parameter)['validator']
|
||||||
|
|
||||||
|
value = validator(value)
|
||||||
|
self.communicate('change', '%s:%s' % (module, parameter), value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def describingData(self):
|
||||||
|
return self.describing_data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def describingModulesData(self):
|
||||||
|
return self.describingData['modules']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def equipmentId(self):
|
def equipmentId(self):
|
||||||
return self.equipment_id
|
return self.equipment_id
|
||||||
|
@ -74,7 +74,8 @@ class PARAM(object):
|
|||||||
readonly=self.readonly,
|
readonly=self.readonly,
|
||||||
value=self.value,
|
value=self.value,
|
||||||
timestamp=self.timestamp,
|
timestamp=self.timestamp,
|
||||||
validator=repr(self.validator),
|
validator=str(self.validator) if not isinstance(
|
||||||
|
self.validator, type) else self.validator.__name__
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
0
secop/gui/__init__.py
Normal file
0
secop/gui/__init__.py
Normal file
136
secop/gui/mainwindow.py
Normal file
136
secop/gui/mainwindow.py
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
from PyQt4.QtGui import QMainWindow, QInputDialog, QTreeWidgetItem
|
||||||
|
from PyQt4.QtCore import pyqtSignature as qtsig, QObject, pyqtSignal
|
||||||
|
|
||||||
|
from secop.gui.util import loadUi
|
||||||
|
from secop.gui.nodectrl import NodeCtrl
|
||||||
|
from secop.gui.modulectrl import ModuleCtrl
|
||||||
|
from secop.client.baseclient import Client as SECNode
|
||||||
|
|
||||||
|
ITEM_TYPE_NODE = QTreeWidgetItem.UserType + 1
|
||||||
|
ITEM_TYPE_MODULE = QTreeWidgetItem.UserType + 2
|
||||||
|
ITEM_TYPE_PARAMETER = QTreeWidgetItem.UserType + 3
|
||||||
|
|
||||||
|
|
||||||
|
class QSECNode(SECNode, QObject):
|
||||||
|
newData = pyqtSignal(str, str, object) # module, parameter, data
|
||||||
|
|
||||||
|
def __init__(self, opts, autoconnect=False, parent=None):
|
||||||
|
SECNode.__init__(self, opts, autoconnect)
|
||||||
|
QObject.__init__(self, parent)
|
||||||
|
|
||||||
|
self.startup(True)
|
||||||
|
self._subscribeCallbacks()
|
||||||
|
|
||||||
|
def _subscribeCallbacks(self):
|
||||||
|
for module in self.modules:
|
||||||
|
self._subscribeModuleCallback(module)
|
||||||
|
|
||||||
|
def _subscribeModuleCallback(self, module):
|
||||||
|
for parameter in self.getParameters(module):
|
||||||
|
self._subscribeParameterCallback(module, parameter)
|
||||||
|
|
||||||
|
def _subscribeParameterCallback(self, module, parameter):
|
||||||
|
self.register_callback(module, parameter, self._newDataReceived)
|
||||||
|
|
||||||
|
def _newDataReceived(self, module, parameter, data):
|
||||||
|
self.newData.emit(module, parameter, data)
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(MainWindow, self).__init__(parent)
|
||||||
|
|
||||||
|
loadUi(self, 'mainwindow.ui')
|
||||||
|
|
||||||
|
self.splitter.setStretchFactor(0, 1)
|
||||||
|
self.splitter.setStretchFactor(1, 70)
|
||||||
|
|
||||||
|
self._nodes = {}
|
||||||
|
self._nodeCtrls = {}
|
||||||
|
self._currentWidget = self.splitter.widget(1).layout().takeAt(0)
|
||||||
|
|
||||||
|
# add localhost if available
|
||||||
|
self._addNode('localhost')
|
||||||
|
|
||||||
|
@qtsig('')
|
||||||
|
def on_actionAdd_SEC_node_triggered(self):
|
||||||
|
host, ok = QInputDialog.getText(self, 'Add SEC node',
|
||||||
|
'Enter SEC node hostname:')
|
||||||
|
|
||||||
|
if not ok:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._addNode(host)
|
||||||
|
|
||||||
|
def on_treeWidget_currentItemChanged(self, current, previous):
|
||||||
|
if current.type() == ITEM_TYPE_NODE:
|
||||||
|
self._displayNode(current.text(0))
|
||||||
|
elif current.type() == ITEM_TYPE_MODULE:
|
||||||
|
self._displayModule(current.parent().text(0), current.text(0))
|
||||||
|
|
||||||
|
def _addNode(self, host):
|
||||||
|
|
||||||
|
# create client
|
||||||
|
port = 10767
|
||||||
|
if ':' in host:
|
||||||
|
host, port = host.split(':', 1)
|
||||||
|
port = int(port)
|
||||||
|
node = QSECNode({'connectto':host, 'port':port}, parent=self)
|
||||||
|
host = '%s:%d' % (host, port)
|
||||||
|
|
||||||
|
self._nodes[host] = node
|
||||||
|
|
||||||
|
# fill tree
|
||||||
|
nodeItem = QTreeWidgetItem(None, [host], ITEM_TYPE_NODE)
|
||||||
|
|
||||||
|
for module in sorted(node.modules):
|
||||||
|
moduleItem = QTreeWidgetItem(nodeItem, [module], ITEM_TYPE_MODULE)
|
||||||
|
for param in sorted(node.getParameters(module)):
|
||||||
|
paramItem = QTreeWidgetItem(moduleItem, [param],
|
||||||
|
ITEM_TYPE_PARAMETER)
|
||||||
|
|
||||||
|
self.treeWidget.addTopLevelItem(nodeItem)
|
||||||
|
|
||||||
|
def _displayNode(self, node):
|
||||||
|
|
||||||
|
ctrl = self._nodeCtrls.get(node, None)
|
||||||
|
|
||||||
|
if ctrl is None:
|
||||||
|
ctrl = self._nodeCtrls[node] = NodeCtrl(self._nodes[node])
|
||||||
|
|
||||||
|
self._replaceCtrlWidget(ctrl)
|
||||||
|
|
||||||
|
def _displayModule(self, node, module):
|
||||||
|
self._replaceCtrlWidget(ModuleCtrl(self._nodes[node], module))
|
||||||
|
|
||||||
|
def _replaceCtrlWidget(self, new):
|
||||||
|
old = self.splitter.widget(1).layout().takeAt(0)
|
||||||
|
if old:
|
||||||
|
old.widget().hide()
|
||||||
|
self.splitter.widget(1).layout().addWidget(new)
|
||||||
|
new.show()
|
||||||
|
self._currentWidget = new
|
86
secop/gui/modulectrl.py
Normal file
86
secop/gui/modulectrl.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
from PyQt4.QtGui import QWidget, QLabel
|
||||||
|
from PyQt4.QtCore import pyqtSignature as qtsig, Qt, pyqtSignal
|
||||||
|
|
||||||
|
from secop.gui.util import loadUi
|
||||||
|
|
||||||
|
class ParameterButtons(QWidget):
|
||||||
|
setRequested = pyqtSignal(str, str, str) # module, parameter, setpoint
|
||||||
|
|
||||||
|
def __init__(self, module, parameter, initval='', parent=None):
|
||||||
|
super(ParameterButtons, self).__init__(parent)
|
||||||
|
loadUi(self, 'parambuttons.ui')
|
||||||
|
|
||||||
|
self._module = module
|
||||||
|
self._parameter = parameter
|
||||||
|
|
||||||
|
self.currentLineEdit.setText(str(initval))
|
||||||
|
|
||||||
|
def on_setPushButton_clicked(self):
|
||||||
|
self.setRequested.emit(self._module, self._parameter,
|
||||||
|
self.setLineEdit.text())
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleCtrl(QWidget):
|
||||||
|
def __init__(self, node, module, parent=None):
|
||||||
|
super(ModuleCtrl, self).__init__(parent)
|
||||||
|
loadUi(self, 'modulectrl.ui')
|
||||||
|
self._node = node
|
||||||
|
self._module = module
|
||||||
|
|
||||||
|
self._paramWidgets = {} # widget cache do avoid garbage collection
|
||||||
|
|
||||||
|
self.moduleNameLabel.setText(module)
|
||||||
|
self._initModuleWidgets()
|
||||||
|
|
||||||
|
self._node.newData.connect(self._updateValue)
|
||||||
|
|
||||||
|
def _initModuleWidgets(self):
|
||||||
|
initValues = self._node.queryCache(self._module)
|
||||||
|
row = 0
|
||||||
|
|
||||||
|
font = self.font()
|
||||||
|
font.setBold(True)
|
||||||
|
|
||||||
|
for param in sorted(self._node.getParameters(self._module)):
|
||||||
|
label = QLabel(param + ':')
|
||||||
|
label.setFont(font)
|
||||||
|
|
||||||
|
buttons = ParameterButtons(self._module, param,
|
||||||
|
initValues[param].value)
|
||||||
|
buttons.setRequested.connect(self._node.setParameter)
|
||||||
|
|
||||||
|
self.paramGroupBox.layout().addWidget(label, row, 0)
|
||||||
|
self.paramGroupBox.layout().addWidget(buttons, row, 1)
|
||||||
|
|
||||||
|
self._paramWidgets[param] = (label, buttons)
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
|
||||||
|
def _updateValue(self, module, parameter, value):
|
||||||
|
if module != self._module:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._paramWidgets[parameter][1].currentLineEdit.setText(str(value[0]))
|
92
secop/gui/nodectrl.py
Normal file
92
secop/gui/nodectrl.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
from PyQt4.QtGui import QWidget, QTextCursor, QFont, QFontMetrics
|
||||||
|
from PyQt4.QtCore import pyqtSignature as qtsig, Qt
|
||||||
|
|
||||||
|
from secop.gui.util import loadUi
|
||||||
|
|
||||||
|
class NodeCtrl(QWidget):
|
||||||
|
def __init__(self, node, parent=None):
|
||||||
|
super(NodeCtrl, self).__init__(parent)
|
||||||
|
loadUi(self, 'nodectrl.ui')
|
||||||
|
|
||||||
|
self._node = node
|
||||||
|
|
||||||
|
self.contactPointLabel.setText(self._node.contactPoint)
|
||||||
|
self.equipmentIdLabel.setText(self._node.equipmentId)
|
||||||
|
self.protocolVersionLabel.setText(self._node.protocolVersion)
|
||||||
|
self._clearLog()
|
||||||
|
|
||||||
|
@qtsig('')
|
||||||
|
def on_sendPushButton_clicked(self):
|
||||||
|
msg = self.msgLineEdit.text().strip()
|
||||||
|
|
||||||
|
if not msg:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._addLogEntry('<span style="font-weight:bold">Request:</span> '
|
||||||
|
'%s:' % msg, raw=True)
|
||||||
|
msg = msg.split(' ', 2)
|
||||||
|
reply = self._node.syncCommunicate(*msg)
|
||||||
|
self._addLogEntry(reply, newline=True, pretty=True)
|
||||||
|
|
||||||
|
@qtsig('')
|
||||||
|
def on_clearPushButton_clicked(self):
|
||||||
|
self._clearLog()
|
||||||
|
|
||||||
|
def _clearLog(self):
|
||||||
|
self.logTextBrowser.clear()
|
||||||
|
|
||||||
|
self._addLogEntry('SECoP Communication Shell')
|
||||||
|
self._addLogEntry('=========================')
|
||||||
|
self._addLogEntry('', newline=True)
|
||||||
|
|
||||||
|
def _addLogEntry(self, msg, newline=False, pretty=False, raw=False):
|
||||||
|
|
||||||
|
if pretty:
|
||||||
|
msg = pprint.pformat(msg, width=self._getLogWidth())
|
||||||
|
|
||||||
|
if not raw:
|
||||||
|
msg = '<pre>%s</pre>' % Qt.escape(str(msg)).replace('\n', '<br />')
|
||||||
|
|
||||||
|
content = ''
|
||||||
|
if self.logTextBrowser.toPlainText():
|
||||||
|
content = self.logTextBrowser.toHtml()
|
||||||
|
content += msg
|
||||||
|
|
||||||
|
if newline:
|
||||||
|
content += '<br />'
|
||||||
|
|
||||||
|
self.logTextBrowser.setHtml(content)
|
||||||
|
self.logTextBrowser.moveCursor(QTextCursor.End)
|
||||||
|
|
||||||
|
def _getLogWidth(self):
|
||||||
|
fontMetrics = QFontMetrics(QFont('Monospace'))
|
||||||
|
# calculate max avail characters by using an a (which is possible
|
||||||
|
# due to monospace)
|
||||||
|
result = self.logTextBrowser.width() / fontMetrics.width('a')
|
||||||
|
return result
|
||||||
|
|
118
secop/gui/ui/mainwindow.ui
Normal file
118
secop/gui/ui/mainwindow.ui
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1228</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>secop-gui</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="layoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeWidget" name="treeWidget">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>200</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">1</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1228</width>
|
||||||
|
<height>25</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionAdd_SEC_node"/>
|
||||||
|
<addaction name="actionExit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuHelp">
|
||||||
|
<property name="title">
|
||||||
|
<string>Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionAbout"/>
|
||||||
|
<addaction name="actionAbout_Qt"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menuHelp"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<widget class="QToolBar" name="toolBar">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>toolBar</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="actionAdd_SEC_node"/>
|
||||||
|
</widget>
|
||||||
|
<action name="actionAdd_SEC_node">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add SEC node</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Exit</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout">
|
||||||
|
<property name="text">
|
||||||
|
<string>About</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout_Qt">
|
||||||
|
<property name="text">
|
||||||
|
<string>About Qt</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
99
secop/gui/ui/modulectrl.ui
Normal file
99
secop/gui/ui/modulectrl.ui
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>230</width>
|
||||||
|
<height>121</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="3" column="0">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<italic>false</italic>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Module name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="moduleNameLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QGroupBox" name="paramGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Parameters:</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
153
secop/gui/ui/nodectrl.ui
Normal file
153
secop/gui/ui/nodectrl.ui
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>652</width>
|
||||||
|
<height>490</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>652</width>
|
||||||
|
<height>490</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Contact point:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="contactPointLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Equipment ID:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="equipmentIdLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Protocol version:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="protocolVersionLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="msgLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>>>></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="sendPushButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Send</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<widget class="QPushButton" name="clearPushButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="4">
|
||||||
|
<widget class="QTextBrowser" name="logTextBrowser">
|
||||||
|
<property name="html">
|
||||||
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
</style></head><body style=" font-family:'Sans'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>msgLineEdit</sender>
|
||||||
|
<signal>returnPressed()</signal>
|
||||||
|
<receiver>sendPushButton</receiver>
|
||||||
|
<slot>animateClick()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>387</x>
|
||||||
|
<y>459</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>498</x>
|
||||||
|
<y>462</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
74
secop/gui/ui/parambuttons.ui
Normal file
74
secop/gui/ui/parambuttons.ui
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>730</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="verticalSpacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Current: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="currentLineEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>256</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QLineEdit" name="setLineEdit">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>256</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="4">
|
||||||
|
<widget class="QPushButton" name="setPushButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
33
secop/gui/util.py
Normal file
33
secop/gui/util.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
from PyQt4 import uic
|
||||||
|
|
||||||
|
|
||||||
|
uipath = path.dirname(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
def loadUi(widget, uiname, subdir='ui'):
|
||||||
|
uic.loadUi(path.join(uipath, subdir, uiname), widget)
|
@ -61,6 +61,7 @@ def mkthread(func, *args, **kwds):
|
|||||||
t.start()
|
t.start()
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print "minimal testing: lib"
|
print "minimal testing: lib"
|
||||||
d = attrdict(a=1, b=2)
|
d = attrdict(a=1, b=2)
|
||||||
|
@ -278,7 +278,7 @@ class Dispatcher(object):
|
|||||||
def _getParamValue(self, modulename, pname):
|
def _getParamValue(self, modulename, pname):
|
||||||
moduleobj = self.get_module(modulename)
|
moduleobj = self.get_module(modulename)
|
||||||
if moduleobj is None:
|
if moduleobj is None:
|
||||||
raise NoSuchmoduleError(module=modulename)
|
raise NoSuchModuleError(module=modulename)
|
||||||
|
|
||||||
pobj = moduleobj.PARAMS.get(pname, None)
|
pobj = moduleobj.PARAMS.get(pname, None)
|
||||||
if pobj is None:
|
if pobj is None:
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
# if a validator does a mapping, it normally maps to the external representation (used for print/log/protocol/...)
|
# if a validator does a mapping, it normally maps to the external representation (used for print/log/protocol/...)
|
||||||
# to get the internal representation (for the code), call method convert
|
# to get the internal representation (for the code), call method convert
|
||||||
|
|
||||||
|
|
||||||
class ProgrammingError(Exception):
|
class ProgrammingError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -156,7 +157,7 @@ class vector(object):
|
|||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
self.validators = args
|
self.validators = args
|
||||||
self.argstr = ', '.join([repr(e) for e in args])
|
self.argstr = ', '.join([validator_to_str(e) for e in args])
|
||||||
|
|
||||||
def __call__(self, args):
|
def __call__(self, args):
|
||||||
if len(args) != len(self.validators):
|
if len(args) != len(self.validators):
|
||||||
@ -173,7 +174,7 @@ class record(object):
|
|||||||
|
|
||||||
def __init__(self, **kwds):
|
def __init__(self, **kwds):
|
||||||
self.validators = args
|
self.validators = args
|
||||||
self.argstr = ', '.join([repr(e) for e in kwds.items()])
|
self.argstr = ', '.join([validator_to_str(e) for e in kwds.items()])
|
||||||
|
|
||||||
def __call__(self, arg):
|
def __call__(self, arg):
|
||||||
if len(args) != len(self.validators):
|
if len(args) != len(self.validators):
|
||||||
@ -190,7 +191,7 @@ class oneof(object):
|
|||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
self.oneof = args
|
self.oneof = args
|
||||||
self.argstr = ', '.join([repr(e) for e in args])
|
self.argstr = ', '.join([validator_to_str(e) for e in args])
|
||||||
|
|
||||||
def __call__(self, arg):
|
def __call__(self, arg):
|
||||||
for v in self.oneof:
|
for v in self.oneof:
|
||||||
@ -247,3 +248,12 @@ class enum(object):
|
|||||||
|
|
||||||
def convert(self, arg):
|
def convert(self, arg):
|
||||||
return self.mapping.get(arg, arg)
|
return self.mapping.get(arg, arg)
|
||||||
|
|
||||||
|
|
||||||
|
def validator_to_str(validator):
|
||||||
|
return str(validator) if not isinstance(validator, type) \
|
||||||
|
else validator.__name__
|
||||||
|
|
||||||
|
|
||||||
|
def validator_from_str(validator_str):
|
||||||
|
return eval(validator_str)
|
||||||
|
Reference in New Issue
Block a user