provide setup for MLZ_Amagnet to be used @PSI soon
Also implement lots of fixes and improvements. fixes: #3381 Change-Id: Ibe6664da00756ae5813b90f190295045808b2ff0
This commit is contained in:
@ -23,6 +23,8 @@
|
||||
|
||||
# nothing here yet.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import code
|
||||
|
||||
|
||||
@ -47,16 +49,19 @@ class NameSpace(dict):
|
||||
dict.__delitem__(self, name)
|
||||
|
||||
|
||||
import ConfigParser
|
||||
try:
|
||||
import ConfigParser
|
||||
except ImportError:
|
||||
import configparser as ConfigParser
|
||||
|
||||
|
||||
def getClientOpts(cfgfile):
|
||||
parser = ConfigParser.SafeConfigParser()
|
||||
if not parser.read([cfgfile + '.cfg']):
|
||||
print "Error reading cfg file %r" % cfgfile
|
||||
print("Error reading cfg file %r" % cfgfile)
|
||||
return {}
|
||||
if not parser.has_section('client'):
|
||||
print "No Server section found!"
|
||||
print("No Server section found!")
|
||||
return dict(item for item in parser.items('client'))
|
||||
|
||||
|
||||
@ -83,7 +88,7 @@ class ClientConsole(object):
|
||||
|
||||
def helpCmd(self, arg=Ellipsis):
|
||||
if arg is Ellipsis:
|
||||
print "No help available yet"
|
||||
print("No help available yet")
|
||||
else:
|
||||
help(arg)
|
||||
|
||||
|
@ -21,12 +21,20 @@
|
||||
# *****************************************************************************
|
||||
"""Define Client side proxies"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import json
|
||||
import socket
|
||||
import serial
|
||||
from select import select
|
||||
import threading
|
||||
import Queue
|
||||
|
||||
# Py2/3
|
||||
try:
|
||||
import Queue
|
||||
except ImportError:
|
||||
import queue as Queue
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
import mlzlog
|
||||
@ -71,14 +79,14 @@ class TCPConnection(object):
|
||||
if dlist[0] in rlist + wlist:
|
||||
newdata = self._io.recv(1024)
|
||||
if dlist[0] in xlist:
|
||||
print "Problem: exception on socket, reconnecting!"
|
||||
print("Problem: exception on socket, reconnecting!")
|
||||
for cb, arg in self.callbacks:
|
||||
cb(arg)
|
||||
return
|
||||
except socket.timeout:
|
||||
pass
|
||||
except Exception as err:
|
||||
print err, "reconnecting"
|
||||
print(err, "reconnecting")
|
||||
for cb, arg in self.callbacks:
|
||||
cb(arg)
|
||||
return
|
||||
@ -260,7 +268,6 @@ class Client(object):
|
||||
if spec else "got expected reply '%s'" % msgtype)
|
||||
entry.extend([False, msgtype, spec, data])
|
||||
entry[0].set()
|
||||
return
|
||||
|
||||
def encode_message(self, requesttype, spec='', data=None):
|
||||
"""encodes the given message to a string
|
||||
@ -292,12 +299,17 @@ class Client(object):
|
||||
|
||||
def _handle_event(self, spec, data):
|
||||
"""handles event"""
|
||||
self.log.debug('handle_event %r %r' % (spec, data))
|
||||
# self.log.debug('handle_event %r %r' % (spec, data))
|
||||
if ':' not in spec:
|
||||
self.log.warning("deprecated specifier %r" % spec)
|
||||
spec = '%s:value' % spec
|
||||
modname, pname = spec.split(':', 1)
|
||||
previous = '<unset>'
|
||||
if modname in self._cache:
|
||||
if pname in self._cache:
|
||||
previous = self._cache[modname][pname]
|
||||
self._cache.setdefault(modname, {})[pname] = Value(*data)
|
||||
# self.log.info('cache: %s:%s=%r (was: %s)', modname, pname, data, previous)
|
||||
if spec in self.callbacks:
|
||||
for func in self.callbacks[spec]:
|
||||
try:
|
||||
@ -351,6 +363,12 @@ class Client(object):
|
||||
['parameters', 'commands'], module)
|
||||
|
||||
self.describing_data = describing_data
|
||||
# import pprint
|
||||
# def r(stuff):
|
||||
# if isinstance(stuff, dict):
|
||||
# return dict((k,r(v)) for k,v in stuff.items())
|
||||
# return stuff
|
||||
# pprint.pprint(r(describing_data))
|
||||
|
||||
for module, moduleData in self.describing_data['modules'].items():
|
||||
for parameter, parameterData in moduleData[
|
||||
@ -359,7 +377,7 @@ class Client(object):
|
||||
self.describing_data['modules'][module]['parameters'] \
|
||||
[parameter]['datatype'] = datatype
|
||||
except Exception as exc:
|
||||
print formatException(verbose=True)
|
||||
print(formatException(verbose=True))
|
||||
raise
|
||||
|
||||
def register_callback(self, module, parameter, cb):
|
||||
@ -402,6 +420,10 @@ class Client(object):
|
||||
if msgtype == "*IDN?":
|
||||
return self.secop_id
|
||||
|
||||
# sanitize input
|
||||
msgtype = str(msgtype)
|
||||
spec = str(spec)
|
||||
|
||||
if msgtype not in ('*IDN?', 'describe', 'activate', 'deactivate', 'do',
|
||||
'change', 'read', 'ping', 'help'):
|
||||
raise EXCEPTIONS['Protocol'](args=[
|
||||
@ -411,9 +433,7 @@ class Client(object):
|
||||
errorinfo='%r: No Such Messagetype defined!' % msgtype, ),
|
||||
])
|
||||
|
||||
# sanitize input + handle syntactic sugar
|
||||
msgtype = str(msgtype)
|
||||
spec = str(spec)
|
||||
# handle syntactic sugar
|
||||
if msgtype == 'change' and ':' not in spec:
|
||||
spec = spec + ':target'
|
||||
if msgtype == 'read' and ':' not in spec:
|
||||
@ -460,14 +480,6 @@ class Client(object):
|
||||
if self._thread and self._thread.is_alive():
|
||||
self.thread.join(self._thread)
|
||||
|
||||
def handle_async(self, msg):
|
||||
self.log.info("Got async update %r" % msg)
|
||||
device = msg.device
|
||||
param = msg.param
|
||||
value = msg.value
|
||||
self._cache.getdefault(device, {})[param] = value
|
||||
# XXX: further notification-callbacks needed ???
|
||||
|
||||
def startup(self, async=False):
|
||||
self._issueDescribe()
|
||||
# always fill our cache
|
||||
@ -524,7 +536,7 @@ class Client(object):
|
||||
return self.getModuleProperties(module)['interface']
|
||||
|
||||
def getCommands(self, module):
|
||||
return self.describing_data['modules'][module]['commands'].keys()
|
||||
return self.describing_data['modules'][module]['commands']
|
||||
|
||||
def getProperties(self, module, parameter):
|
||||
return self.describing_data['modules'][module]['parameters'][parameter]
|
||||
|
@ -32,6 +32,7 @@ __all__ = [
|
||||
"BoolType", "EnumType",
|
||||
"BLOBType", "StringType",
|
||||
"TupleOf", "ArrayOf", "StructOf",
|
||||
"Command",
|
||||
]
|
||||
|
||||
# base class for all DataTypes
|
||||
@ -39,6 +40,7 @@ __all__ = [
|
||||
|
||||
class DataType(object):
|
||||
as_json = ['undefined']
|
||||
IS_COMMAND = False
|
||||
|
||||
def validate(self, value):
|
||||
"""validate a external representation and return an internal one"""
|
||||
@ -139,7 +141,7 @@ class IntRange(DataType):
|
||||
return "IntRange(%d, %d)" % (self.min, self.max)
|
||||
if self.min is not None:
|
||||
return "IntRange(%d)" % self.min
|
||||
return "IntRange(%d)" % self.min
|
||||
return "IntRange()"
|
||||
|
||||
def export(self, value):
|
||||
"""returns a python object fit for serialisation"""
|
||||
@ -159,7 +161,6 @@ class EnumType(DataType):
|
||||
num = 0
|
||||
for arg in args:
|
||||
if not isinstance(arg, str):
|
||||
print arg, type(arg)
|
||||
raise ValueError('EnumType entries MUST be strings!')
|
||||
self.entries[num] = arg
|
||||
num += 1
|
||||
@ -172,8 +173,8 @@ class EnumType(DataType):
|
||||
v,
|
||||
self.entries[v])
|
||||
self.entries[v] = k
|
||||
if len(self.entries) == 0:
|
||||
raise ValueError('Empty enums ae not allowed!')
|
||||
# if len(self.entries) == 0:
|
||||
# raise ValueError('Empty enums ae not allowed!')
|
||||
self.reversed = {}
|
||||
for k, v in self.entries.items():
|
||||
if v in self.reversed:
|
||||
@ -442,7 +443,7 @@ class StructOf(DataType):
|
||||
if len(value.keys()) != len(self.named_subtypes.keys()):
|
||||
raise ValueError(
|
||||
'Illegal number of Arguments! Need %d arguments.', len(
|
||||
self.namd_subtypes.keys()))
|
||||
self.named_subtypes.keys()))
|
||||
# validate elements and return as dict
|
||||
return dict((str(k), self.named_subtypes[k].validate(v))
|
||||
for k, v in value.items())
|
||||
@ -463,6 +464,60 @@ class StructOf(DataType):
|
||||
return self.validate(dict(value))
|
||||
|
||||
|
||||
class Command(DataType):
|
||||
IS_COMMAND = True
|
||||
|
||||
def __init__(self, argtypes=[], resulttype=None):
|
||||
for arg in argsin:
|
||||
if not isinstance(arg, DataType):
|
||||
raise ValueError('Command: Argument types must be DataTypes!')
|
||||
if resulttype is not None:
|
||||
if not isinstance(resulttype, DataType):
|
||||
raise ValueError('Command: result type must be DataTypes!')
|
||||
self.argtypes = argtypes
|
||||
self.resulttype = resulttype
|
||||
|
||||
if resulttype is not None:
|
||||
self.as_json = ['command',
|
||||
[t.as_json for t in argtypes],
|
||||
resulttype.as_json]
|
||||
else:
|
||||
self.as_json = ['command',
|
||||
[t.as_json for t in argtypes],
|
||||
None] # XXX: or NoneType ???
|
||||
|
||||
def __repr__(self):
|
||||
argstr = ', '.join(repr(arg) for arg in self.argtypes)
|
||||
if self.resulttype is None:
|
||||
return 'Command(%s)' % argstr
|
||||
return 'Command(%s)->%s' % (argstr, repr(self.resulttype))
|
||||
|
||||
def validate(self, value):
|
||||
"""return the validated arguments value or raise"""
|
||||
try:
|
||||
if len(value) != len(self.argtypes):
|
||||
raise ValueError(
|
||||
'Illegal number of Arguments! Need %d arguments.', len(
|
||||
self.argtypes))
|
||||
# validate elements and return
|
||||
return [t.validate(v) for t, v in zip(self.argtypes, value)]
|
||||
except Exception as exc:
|
||||
raise ValueError('Can not validate %s: %s', repr(value), str(exc))
|
||||
|
||||
def export(self, value):
|
||||
"""returns a python object fit for serialisation"""
|
||||
if len(value) != len(self.argtypes):
|
||||
raise ValueError(
|
||||
'Illegal number of Arguments! Need %d arguments.' % len(
|
||||
self.argtypes))
|
||||
# return [t.export(v) for t,v in zip(self.argtypes, value)]
|
||||
|
||||
def from_string(self, text):
|
||||
import ast
|
||||
value = ast.literal_eval(text)
|
||||
return self.validate(value)
|
||||
|
||||
|
||||
# XXX: derive from above classes automagically!
|
||||
DATATYPES = dict(
|
||||
bool=lambda: BoolType(),
|
||||
@ -476,6 +531,7 @@ DATATYPES = dict(
|
||||
enum=lambda kwds: EnumType(**kwds),
|
||||
struct=lambda named_subtypes: StructOf(
|
||||
**dict((n, get_datatype(t)) for n, t in named_subtypes.items())),
|
||||
command=Command,
|
||||
)
|
||||
|
||||
|
||||
|
@ -39,42 +39,54 @@ class ProgrammingError(SECoPServerError):
|
||||
class SECoPError(SECoPServerError):
|
||||
errorclass = 'InternalError'
|
||||
|
||||
|
||||
class NoSuchModuleError(SECoPError):
|
||||
errorclass = 'NoSuchModule'
|
||||
|
||||
|
||||
class NoSuchParameterError(SECoPError):
|
||||
errorclass = 'NoSuchParameter'
|
||||
|
||||
|
||||
class NoSuchCommandError(SECoPError):
|
||||
errorclass = 'NoSuchCommand'
|
||||
|
||||
|
||||
class CommandFailedError(SECoPError):
|
||||
errorclass = 'CommandFailed'
|
||||
|
||||
|
||||
class CommandRunningError(SECoPError):
|
||||
errorclass = 'CommandRunning'
|
||||
|
||||
|
||||
class ReadOnlyError(SECoPError):
|
||||
errorclass = 'ReadOnly'
|
||||
|
||||
|
||||
class BadValueError(SECoPError):
|
||||
errorclass = 'BadValue'
|
||||
|
||||
|
||||
class CommunicationError(SECoPError):
|
||||
errorclass = 'CommunicationFailed'
|
||||
|
||||
|
||||
class TimeoutError(SECoPError):
|
||||
errorclass = 'CommunicationFailed' # XXX: add to SECop messages
|
||||
|
||||
|
||||
class HardwareError(SECoPError):
|
||||
errorclass = 'CommunicationFailed' # XXX: Add to SECoP messages
|
||||
|
||||
|
||||
class IsBusyError(SECoPError):
|
||||
errorclass = 'IsBusy'
|
||||
|
||||
|
||||
class IsErrorError(SECoPError):
|
||||
errorclass = 'IsError'
|
||||
|
||||
|
||||
class DisabledError(SECoPError):
|
||||
errorclass = 'Disabled'
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from PyQt4.QtGui import QMainWindow, QInputDialog, QTreeWidgetItem, QMessageBox
|
||||
from PyQt4.QtCore import pyqtSignature as qtsig, QObject, pyqtSignal
|
||||
|
||||
@ -91,7 +93,7 @@ class MainWindow(QMainWindow):
|
||||
try:
|
||||
self._addNode(host)
|
||||
except Exception as e:
|
||||
print e
|
||||
print(e)
|
||||
|
||||
@qtsig('')
|
||||
def on_actionAdd_SEC_node_triggered(self):
|
||||
@ -108,11 +110,11 @@ class MainWindow(QMainWindow):
|
||||
'Connecting to %s failed!' % host, str(e))
|
||||
|
||||
def on_validateCheckBox_toggled(self, state):
|
||||
print "validateCheckBox_toggled", state
|
||||
print("validateCheckBox_toggled", state)
|
||||
|
||||
def on_visibilityComboBox_activated(self, level):
|
||||
if level in ['user', 'admin', 'expert']:
|
||||
print "visibility Level now:", level
|
||||
print("visibility Level now:", level)
|
||||
|
||||
def on_treeWidget_currentItemChanged(self, current, previous):
|
||||
if current.type() == ITEM_TYPE_NODE:
|
||||
|
@ -21,38 +21,13 @@
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from PyQt4.QtGui import QWidget, QLabel, QMessageBox, QCheckBox
|
||||
from __future__ import print_function
|
||||
|
||||
from PyQt4.QtGui import QWidget, QLabel, QPushButton as QButton, QLineEdit, QMessageBox, QCheckBox, QSizePolicy
|
||||
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, target
|
||||
|
||||
def __init__(self,
|
||||
module,
|
||||
parameter,
|
||||
initval='',
|
||||
readonly=True,
|
||||
parent=None):
|
||||
super(ParameterButtons, self).__init__(parent)
|
||||
loadUi(self, 'parambuttons.ui')
|
||||
|
||||
self._module = module
|
||||
self._parameter = parameter
|
||||
|
||||
self.currentLineEdit.setText(str(initval))
|
||||
if readonly:
|
||||
self.setPushButton.setEnabled(False)
|
||||
self.setLineEdit.setEnabled(False)
|
||||
else:
|
||||
self.setLineEdit.returnPressed.connect(
|
||||
self.on_setPushButton_clicked)
|
||||
|
||||
def on_setPushButton_clicked(self):
|
||||
self.setRequested.emit(self._module, self._parameter,
|
||||
self.setLineEdit.text())
|
||||
from secop.gui.params import ParameterView
|
||||
|
||||
|
||||
class ParameterGroup(QWidget):
|
||||
@ -79,7 +54,7 @@ class ParameterGroup(QWidget):
|
||||
self._row += 1
|
||||
|
||||
def on_toggle_clicked(self):
|
||||
print "ParameterGroup.on_toggle_clicked"
|
||||
print("ParameterGroup.on_toggle_clicked")
|
||||
if self.paramGroupBox.isChecked():
|
||||
for w in self._widgets:
|
||||
w.show()
|
||||
@ -122,6 +97,9 @@ class ModuleCtrl(QWidget):
|
||||
if group is not None:
|
||||
allGroups.add(group)
|
||||
paramsByGroup.setdefault(group, []).append(param)
|
||||
# enforce reading initial value if not already in cache
|
||||
if param not in initValues:
|
||||
self._node.getParameter(self._module, param)
|
||||
|
||||
groupWidgets = {} # groupname -> CheckBoxWidget for (un)folding
|
||||
|
||||
@ -137,9 +115,12 @@ class ModuleCtrl(QWidget):
|
||||
|
||||
# check if there is a param of the same name too
|
||||
if group in params:
|
||||
datatype = self._node.getProperties(
|
||||
self._module, group).get(
|
||||
'datatype', None)
|
||||
# yes: create a widget for this as well
|
||||
labelstr, buttons = self._makeEntry(
|
||||
param, initValues[param].value, nolabel=True, checkbox=checkbox, invert=True)
|
||||
param, initValues[param].value, datatype=datatype, nolabel=True, checkbox=checkbox, invert=True)
|
||||
checkbox.setText(labelstr)
|
||||
|
||||
# add to Layout (yes: ignore the label!)
|
||||
@ -150,11 +131,19 @@ class ModuleCtrl(QWidget):
|
||||
row += 1
|
||||
|
||||
# loop over all params and insert and connect
|
||||
for param in paramsByGroup[param]:
|
||||
if param == group:
|
||||
for param_ in paramsByGroup[param]:
|
||||
if param_ == group:
|
||||
continue
|
||||
if param_ not in initValues:
|
||||
initval = None
|
||||
print("Warning: %r not in initValues!" % param_)
|
||||
else:
|
||||
initval = initValues[param_].value
|
||||
datatype = self._node.getProperties(
|
||||
self._module, param_).get(
|
||||
'datatype', None)
|
||||
label, buttons = self._makeEntry(
|
||||
param, initValues[param].value, checkbox=checkbox, invert=False)
|
||||
param_, initval, checkbox=checkbox, invert=False)
|
||||
|
||||
# add to Layout
|
||||
self.paramGroupBox.layout().addWidget(label, row, 0)
|
||||
@ -166,18 +155,43 @@ class ModuleCtrl(QWidget):
|
||||
# or is named after a group (otherwise its created above)
|
||||
props = self._node.getProperties(self._module, param)
|
||||
if props.get('group', param) == param:
|
||||
datatype = self._node.getProperties(
|
||||
self._module, param).get(
|
||||
'datatype', None)
|
||||
label, buttons = self._makeEntry(
|
||||
param, initValues[param].value)
|
||||
param, initValues[param].value, datatype=datatype)
|
||||
|
||||
# add to Layout
|
||||
self.paramGroupBox.layout().addWidget(label, row, 0)
|
||||
self.paramGroupBox.layout().addWidget(buttons, row, 1)
|
||||
row += 1
|
||||
|
||||
# also populate properties
|
||||
self._propWidgets = {}
|
||||
props = self._node.getModuleProperties(self._module)
|
||||
row = 0
|
||||
for prop in sorted(props):
|
||||
label = QLabel(prop + ':')
|
||||
label.setFont(self._labelfont)
|
||||
label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
|
||||
|
||||
# make 'display' label
|
||||
view = QLabel(str(props[prop]))
|
||||
view.setFont(self.font())
|
||||
view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||
view.setWordWrap(True)
|
||||
|
||||
self.propertyGroupBox.layout().addWidget(label, row, 0)
|
||||
self.propertyGroupBox.layout().addWidget(view, row, 1)
|
||||
row += 1
|
||||
|
||||
self._propWidgets[prop] = (label, view)
|
||||
|
||||
def _makeEntry(
|
||||
self,
|
||||
param,
|
||||
initvalue,
|
||||
datatype=None,
|
||||
nolabel=False,
|
||||
checkbox=None,
|
||||
invert=False):
|
||||
@ -194,8 +208,12 @@ class ModuleCtrl(QWidget):
|
||||
if checkbox and not invert:
|
||||
labelstr = ' ' + labelstr
|
||||
|
||||
buttons = ParameterButtons(
|
||||
self._module, param, initvalue, props['readonly'])
|
||||
buttons = ParameterView(
|
||||
self._module,
|
||||
param,
|
||||
datatype=datatype,
|
||||
initvalue=initvalue,
|
||||
readonly=props['readonly'])
|
||||
buttons.setRequested.connect(self._set_Button_pressed)
|
||||
|
||||
if description:
|
||||
@ -243,5 +261,4 @@ class ModuleCtrl(QWidget):
|
||||
def _updateValue(self, module, parameter, value):
|
||||
if module != self._module:
|
||||
return
|
||||
|
||||
self._paramWidgets[parameter][1].currentLineEdit.setText(str(value[0]))
|
||||
self._paramWidgets[parameter][1].updateValue(str(value[0]))
|
||||
|
@ -24,11 +24,12 @@
|
||||
import pprint
|
||||
import json
|
||||
|
||||
from PyQt4.QtGui import QWidget, QTextCursor, QFont, QFontMetrics
|
||||
from PyQt4.QtCore import pyqtSignature as qtsig, Qt
|
||||
from PyQt4.QtGui import QWidget, QTextCursor, QFont, QFontMetrics, QLabel, QPushButton, QLineEdit, QMessageBox, QCheckBox, QSizePolicy
|
||||
from PyQt4.QtCore import pyqtSignature as qtsig, Qt, pyqtSignal
|
||||
|
||||
from secop.gui.util import loadUi
|
||||
from secop.protocol.errors import SECOPError
|
||||
from secop.datatypes import StringType, EnumType
|
||||
|
||||
|
||||
class NodeCtrl(QWidget):
|
||||
@ -44,6 +45,9 @@ class NodeCtrl(QWidget):
|
||||
self.protocolVersionLabel.setText(self._node.protocolVersion)
|
||||
self._clearLog()
|
||||
|
||||
# now populate modules tab
|
||||
self._init_modules_tab()
|
||||
|
||||
@qtsig('')
|
||||
def on_sendPushButton_clicked(self):
|
||||
msg = self.msgLineEdit.text().strip()
|
||||
@ -118,3 +122,172 @@ class NodeCtrl(QWidget):
|
||||
# due to monospace)
|
||||
result = self.logTextBrowser.width() / fontMetrics.width('a')
|
||||
return result
|
||||
|
||||
def _init_modules_tab(self):
|
||||
self._moduleWidgets = []
|
||||
layout = self.scrollAreaWidgetContents.layout()
|
||||
labelfont = self.font()
|
||||
labelfont.setBold(True)
|
||||
row = 0
|
||||
for modname in sorted(self._node.modules):
|
||||
modprops = self._node.getModuleProperties(modname)
|
||||
baseclass = modprops['interface']
|
||||
description = modprops['interface']
|
||||
unit = self._node.getProperties(modname, 'value').get('unit', '')
|
||||
|
||||
if unit:
|
||||
labelstr = '%s (%s):' % (modname, unit)
|
||||
else:
|
||||
labelstr = '%s:' % (modname,)
|
||||
label = QLabel(labelstr)
|
||||
label.setFont(labelfont)
|
||||
|
||||
if baseclass == 'Driveable':
|
||||
widget = DriveableWidget(self._node, modname, self)
|
||||
elif baseclass == 'Readable':
|
||||
widget = ReadableWidget(self._node, modname, self)
|
||||
else:
|
||||
widget = QLabel('Unsupported Interfaceclass %r' % baseclass)
|
||||
|
||||
if description:
|
||||
widget.setToolTip(description)
|
||||
|
||||
layout.addWidget(label, row, 0)
|
||||
layout.addWidget(widget, row, 1)
|
||||
|
||||
row += 1
|
||||
self._moduleWidgets.extend((label, widget))
|
||||
|
||||
|
||||
class ReadableWidget(QWidget):
|
||||
|
||||
def __init__(self, node, module, parent=None):
|
||||
super(ReadableWidget, self).__init__(parent)
|
||||
self._node = node
|
||||
self._module = module
|
||||
|
||||
params = self._node.getProperties(self._module, 'value')
|
||||
datatype = params.get('datatype', StringType())
|
||||
self._is_enum = isinstance(datatype, EnumType)
|
||||
|
||||
loadUi(self, 'modulebuttons.ui')
|
||||
|
||||
# populate comboBox, keeping a mapping of Qt-index to EnumValue
|
||||
if self._is_enum:
|
||||
self._map = {} # maps QT-idx to name/value
|
||||
self._revmap = {} # maps value/name to QT-idx
|
||||
for idx, (val, name) in enumerate(
|
||||
sorted(datatype.entries.items())):
|
||||
self._map[idx] = (name, val)
|
||||
self._revmap[name] = idx
|
||||
self._revmap[val] = idx
|
||||
self.targetComboBox.addItem(name, val)
|
||||
|
||||
self._init_status_widgets()
|
||||
self._init_current_widgets()
|
||||
self._init_target_widgets()
|
||||
|
||||
self._node.newData.connect(self._updateValue)
|
||||
|
||||
def _get(self, pname, fallback=Ellipsis):
|
||||
params = self._node.queryCache(self._module)
|
||||
if pname in params:
|
||||
return params[pname].value
|
||||
try:
|
||||
return self._node.getParameter(self._module, pname)
|
||||
except Exception:
|
||||
self.log.exception()
|
||||
if fallback is not Ellipsis:
|
||||
return fallback
|
||||
raise
|
||||
|
||||
def _init_status_widgets(self):
|
||||
self.update_status(self._get('status', (999, '<not supported>')))
|
||||
# XXX: also connect update_status signal to LineEdit ??
|
||||
|
||||
def update_status(self, status, qualifiers={}):
|
||||
self.statusLineEdit.setText(str(status))
|
||||
# may change meaning of cmdPushButton
|
||||
|
||||
def _init_current_widgets(self):
|
||||
self.update_current(self._get('value', ''))
|
||||
|
||||
def update_current(self, value, qualifiers={}):
|
||||
self.currentLineEdit.setText(str(value))
|
||||
|
||||
def _init_target_widgets(self):
|
||||
# Readable has no target: disable widgets
|
||||
self.targetLineEdit.setHidden(True)
|
||||
self.targetComboBox.setHidden(True)
|
||||
self.cmdPushButton.setHidden(True)
|
||||
|
||||
def update_target(self, target, qualifiers={}):
|
||||
pass
|
||||
|
||||
def target_go(self, target):
|
||||
try:
|
||||
self._node.setParameter(self._module, 'target', target)
|
||||
except Exception as e:
|
||||
QMessageBox.warning(self.parent(), 'Operation failed', str(e))
|
||||
|
||||
def _updateValue(self, module, parameter, value):
|
||||
if module != self._module:
|
||||
return
|
||||
if parameter == 'status':
|
||||
self.update_status(*value)
|
||||
elif parameter == 'value':
|
||||
self.update_current(*value)
|
||||
elif parameter == 'target':
|
||||
self.update_target(*value)
|
||||
|
||||
|
||||
class DriveableWidget(ReadableWidget):
|
||||
|
||||
def _init_target_widgets(self):
|
||||
params = self._node.getProperties(self._module, 'target')
|
||||
if self._is_enum:
|
||||
# EnumType: disable Linedit
|
||||
self.targetLineEdit.setHidden(True)
|
||||
else:
|
||||
# normal types: disable Combobox
|
||||
self.targetComboBox.setHidden(True)
|
||||
target = self._get('target', None)
|
||||
if target:
|
||||
if isinstance(target, list) and isinstance(target[1], dict):
|
||||
self.update_target(target[0])
|
||||
else:
|
||||
self.update_target(target)
|
||||
|
||||
def update_current(self, value, qualifiers={}):
|
||||
if self._is_enum:
|
||||
self.currentLineEdit.setText(self._map[self._revmap[value]][0])
|
||||
else:
|
||||
self.currentLineEdit.setText(str(value))
|
||||
|
||||
def update_target(self, target, qualifiers={}):
|
||||
if self._is_enum:
|
||||
# update selected item
|
||||
if target in self._revmap:
|
||||
self.targetComboBox.setCurrentIndex(self._revmap[target])
|
||||
else:
|
||||
print(
|
||||
"%s: Got invalid target value %r!" %
|
||||
(self._module, target))
|
||||
else:
|
||||
self.targetLineEdit.setText(str(target))
|
||||
|
||||
def on_cmdPushButton_clicked(self, toggle=False):
|
||||
if toggled:
|
||||
return
|
||||
if self._is_enum:
|
||||
self.on_targetComboBox_activated()
|
||||
else:
|
||||
self.on_targetLineEdit_returnPressed()
|
||||
|
||||
def on_targetLineEdit_returnPressed(self):
|
||||
self.target_go(self.targetLineEdit.text())
|
||||
|
||||
def on_targetComboBox_activated(self, stuff=''):
|
||||
if isinstance(stuff, (str, unicode)):
|
||||
return
|
||||
self.target_go(self._map[self.targetComboBox.currentIndex()][0])
|
||||
|
182
secop/gui/params/__init__.py
Normal file
182
secop/gui/params/__init__.py
Normal file
@ -0,0 +1,182 @@
|
||||
# -*- 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:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from PyQt4.QtGui import QWidget, QLabel, QPushButton as QButton, QLineEdit, QMessageBox, QCheckBox, QSizePolicy
|
||||
from PyQt4.QtCore import pyqtSignature as qtsig, Qt, pyqtSignal
|
||||
|
||||
from secop.gui.util import loadUi
|
||||
from secop.datatypes import *
|
||||
|
||||
|
||||
class ParameterWidget(QWidget):
|
||||
setRequested = pyqtSignal(str, str, str) # module, parameter, target
|
||||
cmdRequested = pyqtSignal(str, str, list) # module, command, args
|
||||
|
||||
def __init__(self,
|
||||
module,
|
||||
paramcmd,
|
||||
datatype=None,
|
||||
initvalue=None,
|
||||
readonly=True,
|
||||
parent=None):
|
||||
super(ParameterWidget, self).__init__(parent)
|
||||
self._module = module
|
||||
self._paramcmd = paramcmd
|
||||
self._datatype = datatype
|
||||
self._readonly = readonly
|
||||
|
||||
self._load_ui(initvalue)
|
||||
|
||||
def _load_ui(self, initvalue):
|
||||
# load ui file, set initvalue to right widget
|
||||
pass
|
||||
|
||||
def updateValue(self, valuestr):
|
||||
# async !
|
||||
pass
|
||||
|
||||
|
||||
class GenericParameterWidget(ParameterWidget):
|
||||
|
||||
def _load_ui(self, initvalue):
|
||||
# using two QLineEdits for current and target value
|
||||
loadUi(self, 'parambuttons.ui')
|
||||
|
||||
if self._readonly:
|
||||
self.setPushButton.setEnabled(False)
|
||||
self.setLineEdit.setEnabled(False)
|
||||
else:
|
||||
self.setLineEdit.returnPressed.connect(
|
||||
self.on_setPushButton_clicked)
|
||||
self.updateValue(str(initvalue))
|
||||
|
||||
def on_setPushButton_clicked(self):
|
||||
self.setRequested.emit(self._module, self._paramcmd,
|
||||
self.setLineEdit.text())
|
||||
|
||||
def updateValue(self, valuestr):
|
||||
self.currentLineEdit.setText(valuestr)
|
||||
|
||||
|
||||
class EnumParameterWidget(GenericParameterWidget):
|
||||
|
||||
def _load_ui(self, initvalue):
|
||||
# using two QLineEdits for current and target value
|
||||
loadUi(self, 'parambuttons_select.ui')
|
||||
|
||||
# transfer allowed settings from datatype to comboBoxes
|
||||
self._map = {} # maps index to enumstring
|
||||
self._revmap = {} # maps enumstring to index
|
||||
index = 0
|
||||
for data, entry in sorted(self._datatype.entries.items()):
|
||||
self.setComboBox.addItem(entry, data)
|
||||
self._map[index] = entry
|
||||
self._revmap[entry] = index
|
||||
self._revmap[data] = index
|
||||
index += 1
|
||||
if self._readonly:
|
||||
self.setLabel.setEnabled(False)
|
||||
self.setComboBox.setEnabled(False)
|
||||
self.setLabel.setHidden(True)
|
||||
self.setComboBox.setHidden(True)
|
||||
else:
|
||||
self.setComboBox.activated.connect(self.on_setPushButton_clicked)
|
||||
|
||||
self.updateValue(str(initvalue))
|
||||
|
||||
def on_setPushButton_clicked(self):
|
||||
self.setRequested.emit(
|
||||
self._module, self._paramcmd, str(
|
||||
self._datatype.reversed[
|
||||
self._map[
|
||||
self.setComboBox.currentIndex()]]))
|
||||
|
||||
def updateValue(self, valuestr):
|
||||
try:
|
||||
self.currentLineEdit.setText(
|
||||
self._datatype.entries.get(
|
||||
int(valuestr), valuestr))
|
||||
except ValueError:
|
||||
self.currentLineEdit.setText('undefined Value: %r' % valuestr)
|
||||
|
||||
|
||||
class GenericCmdWidget(ParameterWidget):
|
||||
|
||||
def _load_ui(self, initvalue):
|
||||
# using two QLineEdits for current and target value
|
||||
loadUi(self, 'cmdbuttons.ui')
|
||||
|
||||
self.cmdLineEdit.setText('')
|
||||
self.cmdLineEdit.setEnabled(self.datatype.argtypes is not None)
|
||||
self.cmdLineEdit.returnPressed.connect(
|
||||
self.on_cmdPushButton_clicked)
|
||||
|
||||
def on_cmdPushButton_clicked(self):
|
||||
# wait until command complete before retrying
|
||||
self.cmdPushButton.setEnabled(False)
|
||||
self.cmdRequested.emit(
|
||||
self._module,
|
||||
self._paramcmd,
|
||||
self._datatype.from_string(
|
||||
self.cmdLineEdit.text()))
|
||||
|
||||
def updateValue(self, valuestr):
|
||||
# open dialog and show value, if any.
|
||||
# then re-activate the command button
|
||||
self.cmdPushButton.setEnabled(True)
|
||||
|
||||
|
||||
def ParameterView(module,
|
||||
paramcmd,
|
||||
datatype=None,
|
||||
initvalue=None,
|
||||
readonly=True,
|
||||
parent=None):
|
||||
# depending on datatype returns an initialized widget fit for display and
|
||||
# interaction
|
||||
|
||||
if datatype is not None:
|
||||
if datatype.IS_COMMAND:
|
||||
return GenericCmdWidget(
|
||||
module,
|
||||
paramcmd, # name of command
|
||||
datatype,
|
||||
initvalue, # not used for comands
|
||||
readonly, # not used for commands
|
||||
parent)
|
||||
if isinstance(datatype, EnumType):
|
||||
return EnumParameterWidget(
|
||||
module,
|
||||
paramcmd, # name of parameter
|
||||
datatype,
|
||||
initvalue,
|
||||
readonly,
|
||||
parent)
|
||||
|
||||
return GenericParameterWidget(
|
||||
module,
|
||||
paramcmd, # name of parameter
|
||||
datatype,
|
||||
initvalue,
|
||||
readonly,
|
||||
parent)
|
60
secop/gui/ui/cmdbuttons.ui
Normal file
60
secop/gui/ui/cmdbuttons.ui
Normal file
@ -0,0 +1,60 @@
|
||||
<?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>33</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>Arguments:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="cmdLineEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>256</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="cmdPushButton">
|
||||
<property name="text">
|
||||
<string>Go</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -29,6 +29,9 @@
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="visibilityComboBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>user</string>
|
||||
@ -61,6 +64,9 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="validateCheckBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Validate locally</string>
|
||||
</property>
|
||||
@ -104,7 +110,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1228</width>
|
||||
<height>23</height>
|
||||
<height>33</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
|
79
secop/gui/ui/modulebuttons.ui
Normal file
79
secop/gui/ui/modulebuttons.ui
Normal file
@ -0,0 +1,79 @@
|
||||
<?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>748</width>
|
||||
<height>74</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="currentLineEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>256</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="targetLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="targetComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="cmdPushButton">
|
||||
<property name="text">
|
||||
<string>Go</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLineEdit" name="statusLineEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -6,53 +6,15 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>230</width>
|
||||
<height>195</height>
|
||||
<width>257</width>
|
||||
<height>162</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">
|
||||
<item row="4" column="0">
|
||||
<widget class="QGroupBox" name="paramGroupBox">
|
||||
<property name="title">
|
||||
<string>Parameters:</string>
|
||||
@ -76,44 +38,7 @@
|
||||
</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>
|
||||
<item row="4" column="0">
|
||||
<widget class="QGroupBox" name="propertyGroupBox">
|
||||
<property name="title">
|
||||
<string>Properties:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_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>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="6" column="0">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@ -126,6 +51,54 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="propertyGroupBox">
|
||||
<property name="title">
|
||||
<string>Properties:</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3"/>
|
||||
</widget>
|
||||
</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="font">
|
||||
<font>
|
||||
<pointsize>18</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="commandGroupBox">
|
||||
<property name="title">
|
||||
<string>Commands:</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
@ -85,49 +85,91 @@
|
||||
</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">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="consoleTab">
|
||||
<attribute name="title">
|
||||
<string>Console</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<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>
|
||||
</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; 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; font-family:'Sans'; font-size:11pt;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="clearPushButton">
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="msgLineEdit"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>>>></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<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>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="modulesTab">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Modules</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>610</width>
|
||||
<height>324</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5"/>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>730</width>
|
||||
<height>33</height>
|
||||
<height>39</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -36,25 +36,15 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Current: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Set: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="targetValueComboBox"/>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QComboBox" name="comboBox_2"/>
|
||||
<widget class="QComboBox" name="setComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
@ -69,6 +59,30 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="currentLabel">
|
||||
<property name="text">
|
||||
<string>Current: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="setLabel">
|
||||
<property name="text">
|
||||
<string>Set: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="currentLineEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
@ -223,10 +223,10 @@ def getfqdn(name=''):
|
||||
return socket.getfqdn(name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "minimal testing: lib"
|
||||
d = attrdict(a=1, b=2)
|
||||
_ = d.a + d['b']
|
||||
d.c = 9
|
||||
d['d'] = 'c'
|
||||
assert d[d.d] == 9
|
||||
# if __name__ == '__main__':
|
||||
# print "minimal testing: lib"
|
||||
# d = attrdict(a=1, b=2)
|
||||
# _ = d.a + d['b']
|
||||
# d.c = 9
|
||||
# d['d'] = 'c'
|
||||
# assert d[d.d] == 9
|
||||
|
@ -177,7 +177,6 @@ class ArgsParser(object):
|
||||
self.length = len(string)
|
||||
|
||||
def setstring(self, string):
|
||||
print repr(string)
|
||||
self.string = string
|
||||
self.idx = 0
|
||||
self.length = len(string)
|
||||
@ -191,7 +190,6 @@ class ArgsParser(object):
|
||||
def get(self):
|
||||
res = self.peek()
|
||||
self.idx += 1
|
||||
print "get->", res
|
||||
return res
|
||||
|
||||
def skip(self):
|
||||
@ -222,17 +220,14 @@ class ArgsParser(object):
|
||||
idx = self.idx
|
||||
res = self.parse_array()
|
||||
if res:
|
||||
print "is Array"
|
||||
return res
|
||||
self.idx = idx
|
||||
res = self.parse_record()
|
||||
if res:
|
||||
print "is record"
|
||||
return res
|
||||
self.idx = idx
|
||||
res = self.parse_string()
|
||||
if res:
|
||||
print "is string"
|
||||
return res
|
||||
self.idx = idx
|
||||
return self.parse_number()
|
||||
@ -388,26 +383,26 @@ def parse_args(s):
|
||||
|
||||
__ALL__ = ['format_time', 'parse_time', 'parse_args']
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "minimal testing: lib/parsing:"
|
||||
print "time_formatting:",
|
||||
t = time.time()
|
||||
s = format_time(t)
|
||||
assert (abs(t - parse_time(s)) < 1e-6)
|
||||
print "OK"
|
||||
# if __name__ == '__main__':
|
||||
# print "minimal testing: lib/parsing:"
|
||||
# print "time_formatting:",
|
||||
# t = time.time()
|
||||
# s = format_time(t)
|
||||
# assert (abs(t - parse_time(s)) < 1e-6)
|
||||
# print "OK"#
|
||||
#
|
||||
# print "ArgsParser:"
|
||||
# a = ArgsParser()
|
||||
# print a.parse('[ "\'\\\"A" , "<>\'", \'",C\', [1.23e1, 123.0e-001] , ]')
|
||||
|
||||
print "ArgsParser:"
|
||||
a = ArgsParser()
|
||||
print a.parse('[ "\'\\\"A" , "<>\'", \'",C\', [1.23e1, 123.0e-001] , ]')
|
||||
# #import pdb
|
||||
# #pdb.run('print a.parse()', globals(), locals())
|
||||
|
||||
#import pdb
|
||||
#pdb.run('print a.parse()', globals(), locals())
|
||||
|
||||
print "args_formatting:",
|
||||
for obj in [1, 2.3, 'X', (1, 2, 3), [1, (3, 4), 'X,y']]:
|
||||
s = format_args(obj)
|
||||
p = a.parse(s)
|
||||
print p,
|
||||
assert (parse_args(format_args(obj)) == obj)
|
||||
print "OK"
|
||||
print "OK"
|
||||
# print "args_formatting:",
|
||||
# for obj in [1, 2.3, 'X', (1, 2, 3), [1, (3, 4), 'X,y']]:
|
||||
# s = format_args(obj)
|
||||
# p = a.parse(s)
|
||||
# print p,
|
||||
# assert (parse_args(format_args(obj)) == obj)
|
||||
# print "OK"
|
||||
# print "OK"
|
||||
|
@ -36,6 +36,7 @@ class Namespace(object):
|
||||
|
||||
|
||||
class Step(object):
|
||||
|
||||
def __init__(self, desc, waittime, func, *args, **kwds):
|
||||
self.desc = desc
|
||||
self.waittime = waittime
|
||||
@ -126,7 +127,7 @@ class SequencerMixin(object):
|
||||
"""Can be called to check if a sequence is currently running."""
|
||||
return self._seq_thread and self._seq_thread.isAlive()
|
||||
|
||||
def read_status(self):
|
||||
def read_status(self, maxage=0):
|
||||
if self.seq_is_alive():
|
||||
return status.BUSY, 'moving: ' + self._seq_phase
|
||||
elif self._seq_error:
|
||||
@ -138,7 +139,7 @@ class SequencerMixin(object):
|
||||
return status.ERROR, self._seq_stopped
|
||||
return status.WARN, self._seq_stopped
|
||||
if hasattr(self, 'read_hw_status'):
|
||||
return self.read_hw_status()
|
||||
return self.read_hw_status(maxage)
|
||||
return OK, ''
|
||||
|
||||
def do_stop(self):
|
||||
@ -151,6 +152,9 @@ class SequencerMixin(object):
|
||||
except Exception as e:
|
||||
self.log.exception('unhandled error in sequence thread: %s', e)
|
||||
self._seq_error = str(e)
|
||||
finally:
|
||||
self._seq_thread = None
|
||||
self.poll(0)
|
||||
|
||||
def _seq_thread_inner(self, seq, store_init):
|
||||
store = Namespace()
|
||||
@ -163,19 +167,24 @@ class SequencerMixin(object):
|
||||
try:
|
||||
while True:
|
||||
result = step.func(store, *step.args)
|
||||
if self._seq_.stopflag:
|
||||
if self._seq_stopflag:
|
||||
if result:
|
||||
self._seq_stopped = 'stopped while %s' % step.desc
|
||||
else:
|
||||
self._seq_stopped = 'stopped after %s' % step.desc
|
||||
cleanup_func = step.kwds.get('cleanup', None)
|
||||
if callable(cleanup_func):
|
||||
cleanup_func(store, *step.args)
|
||||
try:
|
||||
cleanup_func(store, result, *step.args)
|
||||
except Exception as e:
|
||||
self.log.exception(e)
|
||||
raise
|
||||
return
|
||||
sleep(step.waittime)
|
||||
if not result:
|
||||
break
|
||||
except Exception as e:
|
||||
self.log.exception('error in sequence step: %s', e)
|
||||
self.log.exception(
|
||||
'error in sequence step %r: %s', step.desc, e)
|
||||
self._seq_error = 'during %s: %s' % (step.desc, e)
|
||||
break
|
||||
|
@ -31,11 +31,11 @@ import types
|
||||
import inspect
|
||||
import threading
|
||||
|
||||
from secop.lib import formatExtendedStack
|
||||
from secop.lib import formatExtendedStack, mkthread
|
||||
from secop.lib.parsing import format_time
|
||||
from secop.errors import ConfigError, ProgrammingError
|
||||
from secop.protocol import status
|
||||
from secop.datatypes import DataType, EnumType, TupleOf, StringType, FloatRange, export_datatype
|
||||
from secop.datatypes import DataType, EnumType, TupleOf, StringType, FloatRange, export_datatype, get_datatype
|
||||
|
||||
|
||||
EVENT_ONLY_ON_CHANGED_VALUES = False
|
||||
@ -72,6 +72,7 @@ class PARAM(object):
|
||||
self.readonly = readonly
|
||||
self.export = export
|
||||
self.group = group
|
||||
|
||||
# note: auto-converts True/False to 1/0 which yield the expected
|
||||
# behaviour...
|
||||
self.poll = int(poll)
|
||||
@ -214,7 +215,9 @@ class DeviceMeta(type):
|
||||
else:
|
||||
# return cached value
|
||||
self.log.debug("rfunc(%s): return cached value" % pname)
|
||||
return self.PARAMS[pname].value
|
||||
value = self.PARAMS[pname].value
|
||||
setattr(self, pname, value)
|
||||
return value
|
||||
|
||||
if rfunc:
|
||||
wrapped_rfunc.__doc__ = rfunc.__doc__
|
||||
@ -300,10 +303,13 @@ class Device(object):
|
||||
'meaning': None, # XXX: ???
|
||||
'priority': None, # XXX: ???
|
||||
'visibility': None, # XXX: ????
|
||||
'description': "The manufacturer forgot to set a meaningful description. please nag him!",
|
||||
# what else?
|
||||
}
|
||||
# PARAMS and CMDS are auto-merged upon subclassing
|
||||
PARAMS = {}
|
||||
# PARAMS = {
|
||||
# 'description': PARAM('short description of this module and its function', datatype=StringType(), default='no specified'),
|
||||
# }
|
||||
CMDS = {}
|
||||
DISPATCHER = None
|
||||
|
||||
@ -318,6 +324,12 @@ class Device(object):
|
||||
params[k] = v.copy()
|
||||
|
||||
self.PARAMS = params
|
||||
# make local copies of PROPERTIES
|
||||
props = {}
|
||||
for k, v in self.PROPERTIES.items()[:]:
|
||||
props[k] = v
|
||||
|
||||
self.PROPERTIES = props
|
||||
|
||||
# check and apply properties specified in cfgdict
|
||||
# moduleproperties are to be specified as
|
||||
@ -347,7 +359,9 @@ class Device(object):
|
||||
paramname, propname = k.split('.', 1)
|
||||
if paramname in self.PARAMS:
|
||||
paramobj = self.PARAMS[paramname]
|
||||
if hasattr(paramobj, propname):
|
||||
if propname == 'datatype':
|
||||
paramobj.datatype = get_datatype(cfgdict.pop(k))
|
||||
elif hasattr(paramobj, propname):
|
||||
setattr(paramobj, propname, v)
|
||||
del cfgdict[k]
|
||||
|
||||
@ -355,8 +369,10 @@ class Device(object):
|
||||
# only accept config items specified in PARAMS
|
||||
for k, v in cfgdict.items():
|
||||
if k not in self.PARAMS:
|
||||
raise ConfigError('Device %s:config Parameter %r '
|
||||
'not unterstood!' % (self.name, k))
|
||||
raise ConfigError(
|
||||
'Device %s:config Parameter %r '
|
||||
'not unterstood! (use on of %r)' %
|
||||
(self.name, k, self.PARAMS.keys()))
|
||||
# complain if a PARAM entry has no default value and
|
||||
# is not specified in cfgdict
|
||||
for k, v in self.PARAMS.items():
|
||||
@ -385,6 +401,7 @@ class Device(object):
|
||||
v = datatype.validate(v)
|
||||
except (ValueError, TypeError) as e:
|
||||
self.log.exception(formatExtendedStack())
|
||||
raise
|
||||
raise ConfigError('Device %s: config parameter %r:\n%r' %
|
||||
(self.name, k, e))
|
||||
setattr(self, k, v)
|
||||
@ -393,6 +410,10 @@ class Device(object):
|
||||
def init(self):
|
||||
# may be overriden in derived classes to init stuff
|
||||
self.log.debug('empty init()')
|
||||
mkthread(self.late_init)
|
||||
|
||||
def late_init(self):
|
||||
self.log.debug('late init()')
|
||||
|
||||
|
||||
class Readable(Device):
|
||||
@ -402,7 +423,7 @@ class Readable(Device):
|
||||
"""
|
||||
PARAMS = {
|
||||
'value': PARAM('current value of the device', readonly=True, default=0.,
|
||||
datatype=FloatRange(), poll=True),
|
||||
datatype=FloatRange(), unit='', poll=True),
|
||||
'pollinterval': PARAM('sleeptime between polls', default=5,
|
||||
readonly=False, datatype=FloatRange(0.1, 120), ),
|
||||
'status': PARAM('current status of the device', default=(status.OK, ''),
|
||||
@ -427,25 +448,43 @@ class Readable(Device):
|
||||
def __pollThread(self):
|
||||
"""super simple and super stupid per-module polling thread"""
|
||||
i = 0
|
||||
fastpoll = True # first update should be quick
|
||||
while True:
|
||||
i = 1
|
||||
try:
|
||||
time.sleep(self.pollinterval)
|
||||
time.sleep(self.pollinterval * (0.1 if fastpoll else 1))
|
||||
except TypeError:
|
||||
time.sleep(max(self.pollinterval))
|
||||
try:
|
||||
self.poll(i)
|
||||
except Exception: # really ALL
|
||||
pass
|
||||
time.sleep(min(self.pollinterval)
|
||||
if fastpoll else max(self.pollinterval))
|
||||
fastpoll = self.poll(i)
|
||||
|
||||
def poll(self, nr):
|
||||
# poll status first
|
||||
fastpoll = False
|
||||
if 'status' in self.PARAMS:
|
||||
stat = self.read_status(0)
|
||||
# self.log.info('polling read_status -> %r' % (stat,))
|
||||
fastpoll = stat[0] == status.BUSY
|
||||
# if fastpoll:
|
||||
# self.log.info('fastpoll!')
|
||||
for pname, pobj in self.PARAMS.iteritems():
|
||||
if not pobj.poll:
|
||||
continue
|
||||
if 0 == nr % int(pobj.poll):
|
||||
if pname == 'status':
|
||||
# status was already polled above
|
||||
continue
|
||||
if ((int(pobj.poll) < 0) and fastpoll) or (
|
||||
0 == nr % abs(int(pobj.poll))):
|
||||
# poll always if pobj.poll is negative and fastpoll (i.e. device is busy)
|
||||
# otherwise poll every 'pobj.poll' iteration
|
||||
rfunc = getattr(self, 'read_' + pname, None)
|
||||
if rfunc:
|
||||
rfunc()
|
||||
try:
|
||||
# self.log.info('polling read_%s -> %r' % (pname, rfunc()))
|
||||
rfunc()
|
||||
except Exception: # really all!
|
||||
pass
|
||||
return fastpoll
|
||||
|
||||
|
||||
class Driveable(Readable):
|
||||
|
@ -269,7 +269,7 @@ class Dispatcher(object):
|
||||
|
||||
# now call func and wrap result as value
|
||||
# note: exceptions are handled in handle_request, not here!
|
||||
func = getattr(moduleobj, 'do' + command)
|
||||
func = getattr(moduleobj, 'do_' + command)
|
||||
res = func(*arguments)
|
||||
res = CommandReply(
|
||||
module=modulename,
|
||||
@ -319,12 +319,14 @@ class Dispatcher(object):
|
||||
# note: exceptions are handled in handle_request, not here!
|
||||
readfunc()
|
||||
if pobj.timestamp:
|
||||
return Value(
|
||||
res = Value(
|
||||
modulename,
|
||||
parameter=pname,
|
||||
value=pobj.export_value,
|
||||
t=pobj.timestamp)
|
||||
return Value(modulename, parameter=pname, value=pobj.export_value)
|
||||
else:
|
||||
res = Value(modulename, parameter=pname, value=pobj.export_value)
|
||||
return res
|
||||
|
||||
# now the (defined) handlers for the different requests
|
||||
def handle_Help(self, conn, msg):
|
||||
@ -404,6 +406,10 @@ class Dispatcher(object):
|
||||
unit=pobj.unit)
|
||||
if res.value != Ellipsis: # means we do not have a value at all so skip this
|
||||
self.broadcast_event(res)
|
||||
else:
|
||||
self.log.error(
|
||||
'activate: got no value for %s:%s!' %
|
||||
modulename, pname)
|
||||
conn.queue_async_reply(ActivateReply(**msg.as_dict()))
|
||||
return None
|
||||
|
||||
|
@ -39,12 +39,12 @@ class MessageEncoder(object):
|
||||
raise NotImplemented
|
||||
|
||||
|
||||
from demo_v2 import DemoEncoder as DemoEncoderV2
|
||||
from demo_v3 import DemoEncoder as DemoEncoderV3
|
||||
from demo_v4 import DemoEncoder as DemoEncoderV4
|
||||
from text import TextEncoder
|
||||
from pickle import PickleEncoder
|
||||
from simplecomm import SCPEncoder
|
||||
from .demo_v2 import DemoEncoder as DemoEncoderV2
|
||||
from .demo_v3 import DemoEncoder as DemoEncoderV3
|
||||
from .demo_v4 import DemoEncoder as DemoEncoderV4
|
||||
from .text import TextEncoder
|
||||
from .pickle import PickleEncoder
|
||||
from .simplecomm import SCPEncoder
|
||||
|
||||
ENCODERS = {
|
||||
'pickle': PickleEncoder,
|
||||
|
@ -24,6 +24,8 @@
|
||||
# implement as class as they may need some internal 'state' later on
|
||||
# (think compressors)
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from secop.protocol.encoding import MessageEncoder
|
||||
from secop.protocol import messages
|
||||
from secop.lib.parsing import *
|
||||
@ -43,9 +45,9 @@ class DemoEncoder(MessageEncoder):
|
||||
if match:
|
||||
novalue, devname, pname, propname, assign = match.groups()
|
||||
if assign:
|
||||
print "parsing", assign,
|
||||
print("parsing", assign,)
|
||||
assign = parse_args(assign)
|
||||
print "->", assign
|
||||
print("->", assign)
|
||||
return messages.DemoRequest(novalue, devname, pname, propname,
|
||||
assign)
|
||||
return messages.HelpRequest()
|
||||
@ -56,13 +58,13 @@ class DemoEncoder(MessageEncoder):
|
||||
handler_name = '_encode_' + msg.__class__.__name__
|
||||
handler = getattr(self, handler_name, None)
|
||||
if handler is None:
|
||||
print "Handler %s not yet implemented!" % handler_name
|
||||
print("Handler %s not yet implemented!" % handler_name)
|
||||
try:
|
||||
args = dict((k, msg.__dict__[k]) for k in msg.ARGS)
|
||||
result = handler(**args)
|
||||
except Exception as e:
|
||||
print "Error encoding %r with %r!" % (msg, handler)
|
||||
print e
|
||||
print("Error encoding %r with %r!" % (msg, handler))
|
||||
print(e)
|
||||
return '~InternalError~'
|
||||
return result
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
# implement as class as they may need some internal 'state' later on
|
||||
# (think compressors)
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from secop.protocol.encoding import MessageEncoder
|
||||
from secop.protocol.messages import *
|
||||
from secop.protocol.errors import ProtocolError
|
||||
@ -257,7 +259,7 @@ class DemoEncoder(MessageEncoder):
|
||||
mgroups['args'] = args
|
||||
|
||||
# reformat qualifiers
|
||||
print mgroups
|
||||
print(mgroups)
|
||||
quals = dict(
|
||||
qual.split('=', 1)
|
||||
for qual in helper(mgroups.pop('qualifiers', ';')))
|
||||
@ -306,9 +308,9 @@ class DemoEncoder(MessageEncoder):
|
||||
'read blub:c=14;t=3.3',
|
||||
]
|
||||
for m in testmsg:
|
||||
print repr(m)
|
||||
print self.decode(m)
|
||||
print
|
||||
print(repr(m))
|
||||
print(self.decode(m))
|
||||
print()
|
||||
|
||||
|
||||
DEMO_RE_MZ = re.compile(
|
||||
@ -326,7 +328,7 @@ class DemoEncoder_MZ(MessageEncoder):
|
||||
def decode(sef, encoded):
|
||||
m = DEMO_RE_MZ.match(encoded)
|
||||
if m:
|
||||
print "implement me !"
|
||||
print("implement me !")
|
||||
return HelpRequest()
|
||||
|
||||
def encode(self, msg):
|
||||
|
@ -24,6 +24,8 @@
|
||||
# implement as class as they may need some internal 'state' later on
|
||||
# (think compressors)
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from secop.lib.parsing import format_time
|
||||
from secop.protocol.encoding import MessageEncoder
|
||||
from secop.protocol.messages import *
|
||||
@ -235,7 +237,7 @@ class DemoEncoder(MessageEncoder):
|
||||
# first check beginning
|
||||
match = DEMO_RE.match(encoded)
|
||||
if not match:
|
||||
print repr(encoded), repr(IDENTREPLY)
|
||||
print(repr(encoded), repr(IDENTREPLY))
|
||||
if encoded == IDENTREPLY: # XXX:better just check the first 2 parts...
|
||||
return IdentifyReply(version_string=encoded)
|
||||
|
||||
@ -274,9 +276,9 @@ class DemoEncoder(MessageEncoder):
|
||||
origin=encoded)
|
||||
|
||||
def tests(self):
|
||||
print "---- Testing encoding -----"
|
||||
print("---- Testing encoding -----")
|
||||
for msgclass, parts in sorted(self.ENCODEMAP.items()):
|
||||
print msgclass
|
||||
print(msgclass)
|
||||
e = self.encode(
|
||||
msgclass(
|
||||
module='<module>',
|
||||
@ -289,17 +291,17 @@ class DemoEncoder(MessageEncoder):
|
||||
nonce='<nonce>',
|
||||
errorclass='InternalError',
|
||||
errorinfo='nix'))
|
||||
print e
|
||||
print self.decode(e)
|
||||
print
|
||||
print "---- Testing decoding -----"
|
||||
print(e)
|
||||
print(self.decode(e))
|
||||
print()
|
||||
print("---- Testing decoding -----")
|
||||
for msgtype, _ in sorted(self.DECODEMAP.items()):
|
||||
msg = '%s a:b 3' % msgtype
|
||||
if msgtype == EVENT:
|
||||
msg = '%s a:b [3,{"t":193868}]' % msgtype
|
||||
print msg
|
||||
print(msg)
|
||||
d = self.decode(msg)
|
||||
print d
|
||||
print self.encode(d)
|
||||
print
|
||||
print "---- Testing done -----"
|
||||
print(d)
|
||||
print(self.encode(d))
|
||||
print()
|
||||
print("---- Testing done -----")
|
||||
|
@ -91,9 +91,3 @@ EXCEPTIONS = dict(
|
||||
Readonly=ReadonlyError,
|
||||
CommandFailed=CommandFailedError,
|
||||
InvalidParam=InvalidParamValueError, )
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Minimal testing of errors....")
|
||||
|
||||
print "OK"
|
||||
print
|
||||
|
@ -45,10 +45,10 @@ class Framer(object):
|
||||
raise NotImplemented
|
||||
|
||||
# now some Implementations
|
||||
from null import NullFramer
|
||||
from eol import EOLFramer
|
||||
from rle import RLEFramer
|
||||
from demo import DemoFramer
|
||||
from .null import NullFramer
|
||||
from .eol import EOLFramer
|
||||
from .rle import RLEFramer
|
||||
from .demo import DemoFramer
|
||||
|
||||
FRAMERS = {
|
||||
'null': NullFramer,
|
||||
|
@ -22,6 +22,7 @@
|
||||
# *****************************************************************************
|
||||
"""Define helpers"""
|
||||
import os
|
||||
import ast
|
||||
import time
|
||||
import psutil
|
||||
import threading
|
||||
@ -154,9 +155,10 @@ class Server(object):
|
||||
devopts['value'] = devopts.pop('default')
|
||||
# strip '"
|
||||
for k, v in devopts.items():
|
||||
for d in ("'", '"'):
|
||||
if v.startswith(d) and v.endswith(d):
|
||||
devopts[k] = v[1:-1]
|
||||
try:
|
||||
devopts[k] = ast.literal_eval(v)
|
||||
except Exception:
|
||||
pass
|
||||
devobj = devclass(
|
||||
self.log.getChild(devname), devopts, devname, self._dispatcher)
|
||||
devs.append([devname, devobj, export])
|
||||
|
Reference in New Issue
Block a user