Remove py2 support

Change-Id: Ieeaeb3b8efcae004e94aea6c1d2703c9782a8650
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/21320
Tested-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
This commit is contained in:
Enrico Faulhaber
2019-09-25 17:45:26 +02:00
parent 04032079d7
commit 70a9c42a7a
59 changed files with 458 additions and 667 deletions

View File

@ -36,7 +36,6 @@ Interface to the modules:
- remove_module(modulename_or_obj): removes the module (during shutdown)
"""
from __future__ import division, print_function
import threading
from collections import OrderedDict
@ -50,12 +49,6 @@ from secop.protocol.messages import COMMANDREPLY, DESCRIPTIONREPLY, \
DISABLEEVENTSREPLY, ENABLEEVENTSREPLY, ERRORPREFIX, EVENTREPLY, \
HEARTBEATREPLY, IDENTREPLY, IDENTREQUEST, READREPLY, WRITEREPLY
try:
unicode
except NameError:
# no unicode on py3
unicode = str # pylint: disable=redefined-builtin
class Dispatcher(object):
@ -101,7 +94,7 @@ class Dispatcher(object):
"""called by modules param setters to notify subscribers of new values
"""
# argument pname is no longer used here - should we remove it?
msg = (EVENTREPLY, u'%s:%s' % (moduleobj.name, pobj.export),
msg = (EVENTREPLY, '%s:%s' % (moduleobj.name, pobj.export),
[pobj.export_value(), dict(t=pobj.timestamp)])
self.broadcast_event(msg)
@ -113,7 +106,7 @@ class Dispatcher(object):
# argument pname is no longer used here - should we remove it?
if not isinstance(err, SECoPError):
err = InternalError(err)
msg = (ERRORPREFIX + EVENTREPLY, u'%s:%s' % (moduleobj.name, pobj.export),
msg = (ERRORPREFIX + EVENTREPLY, '%s:%s' % (moduleobj.name, pobj.export),
# error-report !
[err.name, repr(err), dict(t=currenttime())])
self.broadcast_event(msg)
@ -125,7 +118,7 @@ class Dispatcher(object):
if not ':' in eventname:
# also remove 'more specific' subscriptions
for k, v in self._subscriptions.items():
if k.startswith(u'%s:' % eventname):
if k.startswith('%s:' % eventname):
v.discard(conn)
if eventname in self._subscriptions:
self._subscriptions[eventname].discard(conn)
@ -143,7 +136,7 @@ class Dispatcher(object):
self._active_connections.discard(conn)
def register_module(self, moduleobj, modulename, export=True):
self.log.debug(u'registering module %r as %s (export=%r)' %
self.log.debug('registering module %r as %s (export=%r)' %
(moduleobj, modulename, export))
self._modules[modulename] = moduleobj
if export:
@ -154,7 +147,7 @@ class Dispatcher(object):
return self._modules[modulename]
elif modulename in list(self._modules.values()):
return modulename
raise NoSuchModuleError(u'Module does not exist on this SEC-Node!')
raise NoSuchModuleError('Module does not exist on this SEC-Node!')
def remove_module(self, modulename_or_obj):
moduleobj = self.get_module(modulename_or_obj)
@ -163,7 +156,7 @@ class Dispatcher(object):
self._export.remove(modulename)
self._modules.pop(modulename)
self._subscriptions.pop(modulename, None)
for k in [k for k in self._subscriptions if k.startswith(u'%s:' % modulename)]:
for k in [kk for kk in self._subscriptions if kk.startswith('%s:' % modulename)]:
self._subscriptions.pop(k, None)
def list_module_names(self):
@ -171,52 +164,52 @@ class Dispatcher(object):
return self._export[:]
def export_accessibles(self, modulename):
self.log.debug(u'export_accessibles(%r)' % modulename)
self.log.debug('export_accessibles(%r)' % modulename)
if modulename in self._export:
# omit export=False params!
res = OrderedDict()
for aobj in self.get_module(modulename).accessibles.values():
if aobj.export:
res[aobj.export] = aobj.for_export()
self.log.debug(u'list accessibles for module %s -> %r' %
self.log.debug('list accessibles for module %s -> %r' %
(modulename, res))
return res
self.log.debug(u'-> module is not to be exported!')
self.log.debug('-> module is not to be exported!')
return OrderedDict()
def get_descriptive_data(self):
"""returns a python object which upon serialisation results in the descriptive data"""
# XXX: be lazy and cache this?
result = {u'modules': OrderedDict()}
result = {'modules': OrderedDict()}
for modulename in self._export:
module = self.get_module(modulename)
if not module.properties.get('export', False):
continue
# some of these need rework !
mod_desc = {u'accessibles': self.export_accessibles(modulename)}
mod_desc = {'accessibles': self.export_accessibles(modulename)}
mod_desc.update(module.exportProperties())
mod_desc.pop('export', False)
result[u'modules'][modulename] = mod_desc
result[u'equipment_id'] = self.equipment_id
result[u'firmware'] = u'FRAPPY - The Python Framework for SECoP'
result[u'version'] = u'2019.08'
result['modules'][modulename] = mod_desc
result['equipment_id'] = self.equipment_id
result['firmware'] = 'FRAPPY - The Python Framework for SECoP'
result['version'] = '2019.08'
result.update(self.nodeprops)
return result
def _execute_command(self, modulename, exportedname, argument=None):
moduleobj = self.get_module(modulename)
if moduleobj is None:
raise NoSuchModuleError(u'Module does not exist on this SEC-Node!')
raise NoSuchModuleError('Module does not exist on this SEC-Node!')
cmdname = moduleobj.commands.exported.get(exportedname, None)
if cmdname is None:
raise NoSuchCommandError(u'Module has no command %r on this SEC-Node!' % exportedname)
raise NoSuchCommandError('Module has no command %r on this SEC-Node!' % exportedname)
cmdspec = moduleobj.commands[cmdname]
if argument is None and cmdspec.datatype.argument is not None:
raise BadValueError(u'Command needs an argument!')
raise BadValueError('Command needs an argument!')
if argument is not None and cmdspec.datatype.argument is None:
raise BadValueError(u'Command takes no argument!')
raise BadValueError('Command takes no argument!')
if cmdspec.datatype.argument:
# validate!
@ -224,7 +217,7 @@ class Dispatcher(object):
# now call func
# note: exceptions are handled in handle_request, not here!
func = getattr(moduleobj, u'do_' + cmdname)
func = getattr(moduleobj, 'do_' + cmdname)
res = func(argument) if argument else func()
# pipe through cmdspec.datatype.result
@ -236,20 +229,20 @@ class Dispatcher(object):
def _setParameterValue(self, modulename, exportedname, value):
moduleobj = self.get_module(modulename)
if moduleobj is None:
raise NoSuchModuleError(u'Module does not exist on this SEC-Node!')
raise NoSuchModuleError('Module does not exist on this SEC-Node!')
pname = moduleobj.parameters.exported.get(exportedname, None)
if pname is None:
raise NoSuchParameterError(u'Module has no parameter %r on this SEC-Node!' % exportedname)
raise NoSuchParameterError('Module has no parameter %r on this SEC-Node!' % exportedname)
pobj = moduleobj.parameters[pname]
if pobj.constant is not None:
raise ReadOnlyError(u'This parameter is constant and can not be accessed remotely.')
raise ReadOnlyError('This parameter is constant and can not be accessed remotely.')
if pobj.readonly:
raise ReadOnlyError(u'This parameter can not be changed remotely.')
raise ReadOnlyError('This parameter can not be changed remotely.')
# validate!
value = pobj.datatype(value)
writefunc = getattr(moduleobj, u'write_%s' % pname, None)
writefunc = getattr(moduleobj, 'write_%s' % pname, None)
# note: exceptions are handled in handle_request, not here!
if writefunc:
# return value is ignored here, as it is automatically set on the pobj and broadcast
@ -261,18 +254,18 @@ class Dispatcher(object):
def _getParameterValue(self, modulename, exportedname):
moduleobj = self.get_module(modulename)
if moduleobj is None:
raise NoSuchModuleError(u'Module does not exist on this SEC-Node!')
raise NoSuchModuleError('Module does not exist on this SEC-Node!')
pname = moduleobj.parameters.exported.get(exportedname, None)
if pname is None:
raise NoSuchParameterError(u'Module has no parameter %r on this SEC-Node!' % exportedname)
raise NoSuchParameterError('Module has no parameter %r on this SEC-Node!' % exportedname)
pobj = moduleobj.parameters[pname]
if pobj.constant is not None:
# really needed? we could just construct a readreply instead....
#raise ReadOnlyError(u'This parameter is constant and can not be accessed remotely.')
#raise ReadOnlyError('This parameter is constant and can not be accessed remotely.')
return pobj.datatype.export_value(pobj.constant)
readfunc = getattr(moduleobj, u'read_%s' % pname, None)
readfunc = getattr(moduleobj, 'read_%s' % pname, None)
if readfunc:
# should also update the pobj (via the setter from the metaclass)
# note: exceptions are handled in handle_request, not here!
@ -288,7 +281,7 @@ class Dispatcher(object):
will call 'queue_async_reply(data)' on conn or return reply
"""
self.log.debug(u'Dispatcher: handling msg: %s' % repr(msg))
self.log.debug('Dispatcher: handling msg: %s' % repr(msg))
# play thread safe !
# XXX: ONLY ONE REQUEST (per dispatcher) AT A TIME
@ -298,8 +291,8 @@ class Dispatcher(object):
if action == IDENTREQUEST:
action, specifier, data = '_ident', None, None
self.log.debug(u'Looking for handle_%s' % action)
handler = getattr(self, u'handle_%s' % action, None)
self.log.debug('Looking for handle_%s' % action)
handler = getattr(self, 'handle_%s' % action, None)
if handler:
return handler(conn, specifier, data)
@ -319,28 +312,28 @@ class Dispatcher(object):
def handle_read(self, conn, specifier, data):
if data:
raise ProtocolError('read requests don\'t take data!')
modulename, pname = specifier, u'value'
modulename, pname = specifier, 'value'
if ':' in specifier:
modulename, pname = specifier.split(':', 1)
# XXX: trigger polling and force sending event ???
return (READREPLY, specifier, list(self._getParameterValue(modulename, pname)))
def handle_change(self, conn, specifier, data):
modulename, pname = specifier, u'value'
modulename, pname = specifier, 'value'
if ':' in specifier:
modulename, pname = specifier.split(u':', 1)
modulename, pname = specifier.split(':', 1)
return (WRITEREPLY, specifier, list(self._setParameterValue(modulename, pname, data)))
def handle_do(self, conn, specifier, data):
# XXX: should this be done asyncron? we could just return the reply in
# that case
modulename, cmd = specifier.split(u':', 1)
modulename, cmd = specifier.split(':', 1)
return (COMMANDREPLY, specifier, list(self._execute_command(modulename, cmd, data)))
def handle_ping(self, conn, specifier, data):
if data:
raise ProtocolError('ping requests don\'t take data!')
return (HEARTBEATREPLY, specifier, [None, {u't':currenttime()}])
return (HEARTBEATREPLY, specifier, [None, {'t':currenttime()}])
def handle_activate(self, conn, specifier, data):
if data:
@ -348,7 +341,7 @@ class Dispatcher(object):
if specifier:
modulename, exportedname = specifier, None
if ':' in specifier:
modulename, exportedname = specifier.split(u':', 1)
modulename, exportedname = specifier.split(':', 1)
if modulename not in self._export:
raise NoSuchModuleError('Module does not exist on this SEC-Node!')
moduleobj = self.get_module(modulename)
@ -373,7 +366,7 @@ class Dispatcher(object):
moduleobj = self._modules.get(modulename, None)
if pname:
pobj = moduleobj.accessibles[pname]
updmsg = (EVENTREPLY, u'%s:%s' % (modulename, pobj.export),
updmsg = (EVENTREPLY, '%s:%s' % (modulename, pobj.export),
[pobj.export_value(), dict(t=pobj.timestamp)])
conn.queue_async_reply(updmsg)
continue
@ -383,7 +376,7 @@ class Dispatcher(object):
if not pobj.export:
continue
# can not use announce_update here, as this will send to all clients
updmsg = (EVENTREPLY, u'%s:%s' % (modulename, pobj.export),
updmsg = (EVENTREPLY, '%s:%s' % (modulename, pobj.export),
[pobj.export_value(), dict(t=pobj.timestamp)])
conn.queue_async_reply(updmsg)
return (ENABLEEVENTSREPLY, specifier, None) if specifier else (ENABLEEVENTSREPLY, None, None)

View File

@ -28,7 +28,7 @@ SPACE = b' '
def encode_msg_frame(action, specifier=None, data=None):
""" encode a msg_tripel into an msg_frame, ready to be sent
action (and optional specifier) are unicode strings,
action (and optional specifier) are str strings,
data may be an json-yfied python object"""
action = action.encode('utf-8')
if specifier is None:
@ -54,7 +54,7 @@ def get_msg(_bytes):
def decode_msg(msg):
"""decode the (binary) msg into a (unicode) msg_tripel"""
"""decode the (binary) msg into a (str) msg_tripel"""
# check for leading/trailing CR and remove it
res = msg.split(b' ', 2)
action = res[0].decode('utf-8')

View File

@ -19,11 +19,11 @@
#
# *****************************************************************************
"""provides tcp interface to the SECoP Server"""
from __future__ import division, print_function
import collections
import socket
import sys
import socket
import collections
import socketserver
from secop.datatypes import StringType, IntRange, BoolType
from secop.errors import SECoPError
@ -34,17 +34,10 @@ from secop.protocol.interface import decode_msg, encode_msg_frame, get_msg
from secop.protocol.messages import ERRORPREFIX, \
HELPREPLY, HELPREQUEST, HelpMessage
try:
import socketserver # py3
except ImportError:
import SocketServer as socketserver # py2
DEF_PORT = 10767
MESSAGE_READ_SIZE = 1024
CR = b'\r'
SPACE = b' '

View File

@ -21,7 +21,6 @@
# *****************************************************************************
"""provide a zmq server"""
from __future__ import division, print_function
# tbd.

View File

@ -20,50 +20,49 @@
#
# *****************************************************************************
"""Define SECoP Messages"""
from __future__ import division, print_function
# allowed actions:
IDENTREQUEST = u'*IDN?' # literal
IDENTREQUEST = '*IDN?' # literal
# literal! first part is fixed!
IDENTREPLY = u'SINE2020&ISSE,SECoP,V2019-08-20,v1.0 RC2'
IDENTREPLY = 'SINE2020&ISSE,SECoP,V2019-08-20,v1.0 RC2'
DESCRIPTIONREQUEST = u'describe' # literal
DESCRIPTIONREPLY = u'describing' # +<id> +json
DESCRIPTIONREQUEST = 'describe' # literal
DESCRIPTIONREPLY = 'describing' # +<id> +json
ENABLEEVENTSREQUEST = u'activate' # literal + optional spec
ENABLEEVENTSREPLY = u'active' # literal + optional spec, is end-of-initial-data-transfer
ENABLEEVENTSREQUEST = 'activate' # literal + optional spec
ENABLEEVENTSREPLY = 'active' # literal + optional spec, is end-of-initial-data-transfer
DISABLEEVENTSREQUEST = u'deactivate' # literal + optional spec
DISABLEEVENTSREPLY = u'inactive' # literal + optional spec
DISABLEEVENTSREQUEST = 'deactivate' # literal + optional spec
DISABLEEVENTSREPLY = 'inactive' # literal + optional spec
COMMANDREQUEST = u'do' # +module:command +json args (if needed)
COMMANDREQUEST = 'do' # +module:command +json args (if needed)
# +module:command +json args (if needed) # send after the command finished !
COMMANDREPLY = u'done'
COMMANDREPLY = 'done'
# +module[:parameter] +json_value
WRITEREQUEST = u'change'
WRITEREQUEST = 'change'
# +module[:parameter] +json_value # send with the read back value
WRITEREPLY = u'changed'
WRITEREPLY = 'changed'
# +module[:parameter] +json_value
BUFFERREQUEST = u'buffer'
BUFFERREQUEST = 'buffer'
# +module[:parameter] +json_value # send with the read back value
BUFFERREPLY = u'buffered'
BUFFERREPLY = 'buffered'
# +module[:parameter] -> NO direct reply, calls POLL internally!
READREQUEST = u'read'
READREPLY = u'reply' # See Issue 54
READREQUEST = 'read'
READREPLY = 'reply' # See Issue 54
EVENTREPLY = u'update' # +module[:parameter] +json_value (value, qualifiers_as_dict)
EVENTREPLY = 'update' # +module[:parameter] +json_value (value, qualifiers_as_dict)
HEARTBEATREQUEST = u'ping' # +nonce_without_space
HEARTBEATREPLY = u'pong' # +nonce_without_space
HEARTBEATREQUEST = 'ping' # +nonce_without_space
HEARTBEATREPLY = 'pong' # +nonce_without_space
ERRORPREFIX = u'error_' # + specifier + json_extended_info(error_report)
ERRORPREFIX = 'error_' # + specifier + json_extended_info(error_report)
HELPREQUEST = u'help' # literal
HELPREPLY = u'helping' # +line number +json_text
HELPREQUEST = 'help' # literal
HELPREPLY = 'helping' # +line number +json_text
# helper mapping to find the REPLY for a REQUEST
REQUEST2REPLY = {