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

@ -11,7 +11,7 @@ demo:
@ps aux|grep [s]ecop-server|awk '{print $$2}'|xargs kill @ps aux|grep [s]ecop-server|awk '{print $$2}'|xargs kill
build: build:
python setup.py build python3 setup.py build
clean: clean:
find . -name '*.pyc' -delete find . -name '*.pyc' -delete
@ -19,20 +19,20 @@ clean:
$(MAKE) -C doc clean $(MAKE) -C doc clean
install: build install: build
python setup.py install python3 setup.py install
test: test:
ifdef T ifdef T
python $(shell which pytest) -v test -l -k $(T) python3 $(shell which pytest) -v test -l -k $(T)
else else
python $(shell which pytest) -v test -l python3 $(shell which pytest) -v test -l
endif endif
test-verbose: test-verbose:
python $(shell which pytest) -v test -s python3 $(shell which pytest) -v test -s
test-coverage: test-coverage:
python $(shell which pytest) -v test --cov=secop python3 $(shell which pytest) -v test --cov=secop
doc: doc:
$(MAKE) -C doc html $(MAKE) -C doc html

View File

@ -21,7 +21,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
import os import os
from os import path from os import path

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# ***************************************************************************** # *****************************************************************************
# #

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# pylint: disable=invalid-name # pylint: disable=invalid-name
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# ***************************************************************************** # *****************************************************************************

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# ***************************************************************************** # *****************************************************************************
# #

View File

@ -21,19 +21,11 @@
# ***************************************************************************** # *****************************************************************************
"""basic validators (for properties)""" """basic validators (for properties)"""
from __future__ import division, print_function
import re import re
from secop.errors import ProgrammingError from secop.errors import ProgrammingError
try:
# py2
unicode
except NameError:
# py3
unicode = str # pylint: disable=redefined-builtin
def FloatProperty(value): def FloatProperty(value):
return float(value) return float(value)
@ -43,80 +35,80 @@ def PositiveFloatProperty(value):
value = float(value) value = float(value)
if value > 0: if value > 0:
return value return value
raise ValueError(u'Value must be >0 !') raise ValueError('Value must be >0 !')
def NonNegativeFloatProperty(value): def NonNegativeFloatProperty(value):
value = float(value) value = float(value)
if value >= 0: if value >= 0:
return value return value
raise ValueError(u'Value must be >=0 !') raise ValueError('Value must be >=0 !')
def IntProperty(value): def IntProperty(value):
if int(value) == float(value): if int(value) == float(value):
return int(value) return int(value)
raise ValueError(u'Can\'t convert %r to int!' % value) raise ValueError('Can\'t convert %r to int!' % value)
def PositiveIntProperty(value): def PositiveIntProperty(value):
value = IntProperty(value) value = IntProperty(value)
if value > 0: if value > 0:
return value return value
raise ValueError(u'Value must be >0 !') raise ValueError('Value must be >0 !')
def NonNegativeIntProperty(value): def NonNegativeIntProperty(value):
value = IntProperty(value) value = IntProperty(value)
if value >= 0: if value >= 0:
return value return value
raise ValueError(u'Value must be >=0 !') raise ValueError('Value must be >=0 !')
def BoolProperty(value): def BoolProperty(value):
try: try:
if value.lower() in [u'0', u'false', u'no', u'off',]: if value.lower() in ['0', 'false', 'no', 'off',]:
return False return False
if value.lower() in [u'1', u'true', u'yes', u'on', ]: if value.lower() in ['1', 'true', 'yes', 'on', ]:
return True return True
except AttributeError: # was no string except AttributeError: # was no string
if bool(value) == value: if bool(value) == value:
return value return value
raise ValueError(u'%r is no valid boolean: try one of True, False, "on", "off",...' % value) raise ValueError('%r is no valid boolean: try one of True, False, "on", "off",...' % value)
def StringProperty(value): def StringProperty(value):
return unicode(value) return str(value)
def UnitProperty(value): def UnitProperty(value):
# probably too simple! # probably too simple!
for s in unicode(value): for s in str(value):
if s.lower() not in u'°abcdefghijklmnopqrstuvwxyz': if s.lower() not in '°abcdefghijklmnopqrstuvwxyz':
raise ValueError(u'%r is not a valid unit!') raise ValueError('%r is not a valid unit!')
def FmtStrProperty(value, regexp=re.compile(r'^%\.?\d+[efg]$')): def FmtStrProperty(value, regexp=re.compile(r'^%\.?\d+[efg]$')):
value=unicode(value) value=str(value)
if regexp.match(value): if regexp.match(value):
return value return value
raise ValueError(u'%r is not a valid fmtstr!' % value) raise ValueError('%r is not a valid fmtstr!' % value)
def OneOfProperty(*args): def OneOfProperty(*args):
# literally oneof! # literally oneof!
if not args: if not args:
raise ProgrammingError(u'OneOfProperty needs some argumets to check against!') raise ProgrammingError('OneOfProperty needs some argumets to check against!')
def OneOfChecker(value): def OneOfChecker(value):
if value not in args: if value not in args:
raise ValueError(u'Value must be one of %r' % list(args)) raise ValueError('Value must be one of %r' % list(args))
return value return value
return OneOfChecker return OneOfChecker
def NoneOr(checker): def NoneOr(checker):
if not callable(checker): if not callable(checker):
raise ProgrammingError(u'NoneOr needs a basic validator as Argument!') raise ProgrammingError('NoneOr needs a basic validator as Argument!')
def NoneOrChecker(value): def NoneOrChecker(value):
if value is None: if value is None:
return None return None
@ -126,13 +118,13 @@ def NoneOr(checker):
def EnumProperty(**kwds): def EnumProperty(**kwds):
if not kwds: if not kwds:
raise ProgrammingError(u'EnumProperty needs a mapping!') raise ProgrammingError('EnumProperty needs a mapping!')
def EnumChecker(value): def EnumChecker(value):
if value in kwds: if value in kwds:
return kwds[value] return kwds[value]
if value in kwds.values(): if value in kwds.values():
return value return value
raise ValueError(u'Value must be one of %r' % list(kwds)) raise ValueError('Value must be one of %r' % list(kwds))
return EnumChecker return EnumChecker
def TupleProperty(*checkers): def TupleProperty(*checkers):
@ -140,16 +132,16 @@ def TupleProperty(*checkers):
checkers = [None] checkers = [None]
for c in checkers: for c in checkers:
if not callable(c): if not callable(c):
raise ProgrammingError(u'TupleProperty needs basic validators as Arguments!') raise ProgrammingError('TupleProperty needs basic validators as Arguments!')
def TupleChecker(values): def TupleChecker(values):
if len(values)==len(checkers): if len(values)==len(checkers):
return tuple(c(v) for c, v in zip(checkers, values)) return tuple(c(v) for c, v in zip(checkers, values))
raise ValueError(u'Value needs %d elements!' % len(checkers)) raise ValueError('Value needs %d elements!' % len(checkers))
return TupleChecker return TupleChecker
def ListOfProperty(checker): def ListOfProperty(checker):
if not callable(checker): if not callable(checker):
raise ProgrammingError(u'ListOfProperty needs a basic validator as Argument!') raise ProgrammingError('ListOfProperty needs a basic validator as Argument!')
def ListOfChecker(values): def ListOfChecker(values):
return [checker(v) for v in values] return [checker(v) for v in values]
return ListOfChecker return ListOfChecker

View File

@ -23,7 +23,6 @@
# nothing here yet. # nothing here yet.
from __future__ import print_function
import code import code
import socket import socket

View File

@ -21,9 +21,9 @@
# ***************************************************************************** # *****************************************************************************
"""Define Client side proxies""" """Define Client side proxies"""
from __future__ import division, print_function
import json import json
import queue
import socket import socket
import threading import threading
import time import time
@ -43,15 +43,6 @@ from secop.protocol.messages import BUFFERREQUEST, COMMANDREQUEST, \
HEARTBEATREQUEST, HELPREQUEST, IDENTREQUEST, READREPLY, \ HEARTBEATREQUEST, HELPREQUEST, IDENTREQUEST, READREPLY, \
READREQUEST, REQUEST2REPLY, WRITEREPLY, WRITEREQUEST READREQUEST, REQUEST2REPLY, WRITEREPLY, WRITEREQUEST
try:
# py3
import queue
except ImportError:
# py2
import Queue as queue
class TCPConnection(object): class TCPConnection(object):
# disguise a TCP connection as serial one # disguise a TCP connection as serial one

View File

@ -23,7 +23,6 @@
# pylint: disable=abstract-method # pylint: disable=abstract-method
from __future__ import division, print_function
from base64 import b64decode, b64encode from base64 import b64decode, b64encode
@ -31,22 +30,15 @@ from secop.errors import ProgrammingError, ProtocolError, BadValueError
from secop.lib.enum import Enum from secop.lib.enum import Enum
from secop.parse import Parser from secop.parse import Parser
try:
# py2
unicode
except NameError:
# py3
unicode = str # pylint: disable=redefined-builtin
# Only export these classes for 'from secop.datatypes import *' # Only export these classes for 'from secop.datatypes import *'
__all__ = [ __all__ = [
u'DataType', 'DataType',
u'FloatRange', u'IntRange', 'FloatRange', 'IntRange',
u'BoolType', u'EnumType', 'BoolType', 'EnumType',
u'BLOBType', u'StringType', 'BLOBType', 'StringType',
u'TupleOf', u'ArrayOf', u'StructOf', 'TupleOf', 'ArrayOf', 'StructOf',
u'CommandType', 'CommandType',
] ]
# *DEFAULT* limits for IntRange/ScaledIntegers transport serialisation # *DEFAULT* limits for IntRange/ScaledIntegers transport serialisation
@ -58,8 +50,8 @@ Parser = Parser()
# base class for all DataTypes # base class for all DataTypes
class DataType(object): class DataType(object):
IS_COMMAND = False IS_COMMAND = False
unit = u'' unit = ''
fmtstr = u'%r' fmtstr = '%r'
default = None default = None
def __call__(self, value): def __call__(self, value):
@ -90,7 +82,7 @@ class DataType(object):
return value return value
def format_value(self, value, unit=None): def format_value(self, value, unit=None):
"""format a value of this type into a unicode string """format a value of this type into a str string
This is intended for 'nice' formatting for humans and is NOT This is intended for 'nice' formatting for humans and is NOT
the opposite of :meth:`from_string` the opposite of :meth:`from_string`
@ -128,23 +120,23 @@ class FloatRange(DataType):
def __init__(self, minval=None, maxval=None, unit=None, fmtstr=None, def __init__(self, minval=None, maxval=None, unit=None, fmtstr=None,
absolute_resolution=None, relative_resolution=None,): absolute_resolution=None, relative_resolution=None,):
self._defaults = {} self._defaults = {}
self.set_prop('min', minval, float(u'-inf'), float) self.set_prop('min', minval, float('-inf'), float)
self.set_prop('max', maxval, float(u'+inf'), float) self.set_prop('max', maxval, float('+inf'), float)
self.set_prop('unit', unit, u'', unicode) self.set_prop('unit', unit, '', str)
self.set_prop('fmtstr', fmtstr, u'%g', unicode) self.set_prop('fmtstr', fmtstr, '%g', str)
self.set_prop('absolute_resolution', absolute_resolution, 0.0, float) self.set_prop('absolute_resolution', absolute_resolution, 0.0, float)
self.set_prop('relative_resolution', relative_resolution, 1.2e-7, float) self.set_prop('relative_resolution', relative_resolution, 1.2e-7, float)
self.default = 0 if self.min <= 0 <= self.max else self.min self.default = 0 if self.min <= 0 <= self.max else self.min
# check values # check values
if self.min > self.max: if self.min > self.max:
raise BadValueError(u'max must be larger then min!') raise BadValueError('max must be larger then min!')
if '%' not in self.fmtstr: if '%' not in self.fmtstr:
raise BadValueError(u'Invalid fmtstr!') raise BadValueError('Invalid fmtstr!')
if self.absolute_resolution < 0: if self.absolute_resolution < 0:
raise BadValueError(u'absolute_resolution MUST be >=0') raise BadValueError('absolute_resolution MUST be >=0')
if self.relative_resolution < 0: if self.relative_resolution < 0:
raise BadValueError(u'relative_resolution MUST be >=0') raise BadValueError('relative_resolution MUST be >=0')
def export_datatype(self): def export_datatype(self):
return self.get_info(type='double') return self.get_info(type='double')
@ -153,11 +145,11 @@ class FloatRange(DataType):
try: try:
value = float(value) value = float(value)
except Exception: except Exception:
raise BadValueError(u'Can not __call__ %r to float' % value) raise BadValueError('Can not __call__ %r to float' % value)
prec = max(abs(value * self.relative_resolution), self.absolute_resolution) prec = max(abs(value * self.relative_resolution), self.absolute_resolution)
if self.min - prec <= value <= self.max + prec: if self.min - prec <= value <= self.max + prec:
return min(max(value, self.min), self.max) return min(max(value, self.min), self.max)
raise BadValueError(u'%.14g should be a float between %.14g and %.14g' % raise BadValueError('%.14g should be a float between %.14g and %.14g' %
(value, self.min, self.max)) (value, self.min, self.max))
def __repr__(self): def __repr__(self):
@ -166,7 +158,7 @@ class FloatRange(DataType):
hints['minval'] = hints.pop('min') hints['minval'] = hints.pop('min')
if 'max' in hints: if 'max' in hints:
hints['maxval'] = hints.pop('max') hints['maxval'] = hints.pop('max')
return u'FloatRange(%s)' % (', '.join('%s=%r' % (k,v) for k,v in hints.items())) return 'FloatRange(%s)' % (', '.join('%s=%r' % (k,v) for k,v in hints.items()))
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
@ -184,7 +176,7 @@ class FloatRange(DataType):
if unit is None: if unit is None:
unit = self.unit unit = self.unit
if unit: if unit:
return u' '.join([self.fmtstr % value, unit]) return ' '.join([self.fmtstr % value, unit])
return self.fmtstr % value return self.fmtstr % value
@ -196,11 +188,11 @@ class IntRange(DataType):
self.max = DEFAULT_MAX_INT if maxval is None else int(maxval) self.max = DEFAULT_MAX_INT if maxval is None else int(maxval)
self.default = 0 if self.min <= 0 <= self.max else self.min self.default = 0 if self.min <= 0 <= self.max else self.min
# a unit on an int is now allowed in SECoP, but do we need them in Frappy? # a unit on an int is now allowed in SECoP, but do we need them in Frappy?
# self.set_prop('unit', unit, u'', unicode) # self.set_prop('unit', unit, '', str)
# check values # check values
if self.min > self.max: if self.min > self.max:
raise BadValueError(u'Max must be larger then min!') raise BadValueError('Max must be larger then min!')
def export_datatype(self): def export_datatype(self):
return dict(type='int', min=self.min, max=self.max) return dict(type='int', min=self.min, max=self.max)
@ -209,17 +201,17 @@ class IntRange(DataType):
try: try:
value = int(value) value = int(value)
if value < self.min: if value < self.min:
raise BadValueError(u'%r should be an int between %d and %d' % raise BadValueError('%r should be an int between %d and %d' %
(value, self.min, self.max or 0)) (value, self.min, self.max or 0))
if value > self.max: if value > self.max:
raise BadValueError(u'%r should be an int between %d and %d' % raise BadValueError('%r should be an int between %d and %d' %
(value, self.min or 0, self.max)) (value, self.min or 0, self.max))
return value return value
except Exception: except Exception:
raise BadValueError(u'Can not convert %r to int' % value) raise BadValueError('Can not convert %r to int' % value)
def __repr__(self): def __repr__(self):
return u'IntRange(%d, %d)' % (self.min, self.max) return 'IntRange(%d, %d)' % (self.min, self.max)
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
@ -234,7 +226,7 @@ class IntRange(DataType):
return self(value) return self(value)
def format_value(self, value, unit=None): def format_value(self, value, unit=None):
return u'%d' % value return '%d' % value
class ScaledInteger(DataType): class ScaledInteger(DataType):
@ -248,9 +240,9 @@ class ScaledInteger(DataType):
self._defaults = {} self._defaults = {}
self.scale = float(scale) self.scale = float(scale)
if not self.scale > 0: if not self.scale > 0:
raise BadValueError(u'Scale MUST be positive!') raise BadValueError('Scale MUST be positive!')
self.set_prop('unit', unit, u'', unicode) self.set_prop('unit', unit, '', str)
self.set_prop('fmtstr', fmtstr, u'%g', unicode) self.set_prop('fmtstr', fmtstr, '%g', str)
self.set_prop('absolute_resolution', absolute_resolution, self.scale, float) self.set_prop('absolute_resolution', absolute_resolution, self.scale, float)
self.set_prop('relative_resolution', relative_resolution, 1.2e-7, float) self.set_prop('relative_resolution', relative_resolution, 1.2e-7, float)
@ -260,13 +252,13 @@ class ScaledInteger(DataType):
# check values # check values
if self.min > self.max: if self.min > self.max:
raise BadValueError(u'Max must be larger then min!') raise BadValueError('Max must be larger then min!')
if '%' not in self.fmtstr: if '%' not in self.fmtstr:
raise BadValueError(u'Invalid fmtstr!') raise BadValueError('Invalid fmtstr!')
if self.absolute_resolution < 0: if self.absolute_resolution < 0:
raise BadValueError(u'absolute_resolution MUST be >=0') raise BadValueError('absolute_resolution MUST be >=0')
if self.relative_resolution < 0: if self.relative_resolution < 0:
raise BadValueError(u'relative_resolution MUST be >=0') raise BadValueError('relative_resolution MUST be >=0')
# Remark: Datatype.copy() will round min, max to a multiple of self.scale # Remark: Datatype.copy() will round min, max to a multiple of self.scale
# this should be o.k. # this should be o.k.
@ -279,13 +271,13 @@ class ScaledInteger(DataType):
try: try:
value = float(value) value = float(value)
except Exception: except Exception:
raise BadValueError(u'Can not convert %r to float' % value) raise BadValueError('Can not convert %r to float' % value)
prec = max(self.scale, abs(value * self.relative_resolution), prec = max(self.scale, abs(value * self.relative_resolution),
self.absolute_resolution) self.absolute_resolution)
if self.min - prec <= value <= self.max + prec: if self.min - prec <= value <= self.max + prec:
value = min(max(value, self.min), self.max) value = min(max(value, self.min), self.max)
else: else:
raise BadValueError(u'%g should be a float between %g and %g' % raise BadValueError('%g should be a float between %g and %g' %
(value, self.min, self.max)) (value, self.min, self.max))
intval = int((value + self.scale * 0.5) // self.scale) intval = int((value + self.scale * 0.5) // self.scale)
value = float(intval * self.scale) value = float(intval * self.scale)
@ -295,7 +287,7 @@ class ScaledInteger(DataType):
hints = self.get_info(scale='%g' % self.scale, hints = self.get_info(scale='%g' % self.scale,
min = int((self.min + self.scale * 0.5) // self.scale), min = int((self.min + self.scale * 0.5) // self.scale),
max = int((self.max + self.scale * 0.5) // self.scale)) max = int((self.max + self.scale * 0.5) // self.scale))
return u'ScaledInteger(%s)' % (', '.join('%s=%r' % kv for kv in hints.items())) return 'ScaledInteger(%s)' % (', '.join('%s=%r' % kv for kv in hints.items()))
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
@ -314,17 +306,17 @@ class ScaledInteger(DataType):
if unit is None: if unit is None:
unit = self.unit unit = self.unit
if unit: if unit:
return u' '.join([self.fmtstr % value, unit]) return ' '.join([self.fmtstr % value, unit])
return self.fmtstr % value return self.fmtstr % value
class EnumType(DataType): class EnumType(DataType):
def __init__(self, enum_or_name='', **kwds): def __init__(self, enum_or_name='', **kwds):
if u'members' in kwds: if 'members' in kwds:
kwds = dict(kwds) kwds = dict(kwds)
kwds.update(kwds[u'members']) kwds.update(kwds['members'])
kwds.pop(u'members') kwds.pop('members')
self._enum = Enum(enum_or_name, **kwds) self._enum = Enum(enum_or_name, **kwds)
self.default = self._enum[self._enum.members[0]] self.default = self._enum[self._enum.members[0]]
@ -336,7 +328,7 @@ class EnumType(DataType):
return {'type': 'enum', 'members':dict((m.name, m.value) for m in self._enum.members)} return {'type': 'enum', 'members':dict((m.name, m.value) for m in self._enum.members)}
def __repr__(self): def __repr__(self):
return u"EnumType(%r, %s)" % (self._enum.name, ', '.join(u'%s=%d' %(m.name, m.value) for m in self._enum.members)) return u"EnumType(%r, %s)" % (self._enum.name, ', '.join('%s=%d' %(m.name, m.value) for m in self._enum.members))
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
@ -351,13 +343,13 @@ class EnumType(DataType):
try: try:
return self._enum[value] return self._enum[value]
except (KeyError, TypeError): # TypeError will be raised when value is not hashable except (KeyError, TypeError): # TypeError will be raised when value is not hashable
raise BadValueError(u'%r is not a member of enum %r' % (value, self._enum)) raise BadValueError('%r is not a member of enum %r' % (value, self._enum))
def from_string(self, text): def from_string(self, text):
return self(text) return self(text)
def format_value(self, value, unit=None): def format_value(self, value, unit=None):
return u'%s<%s>' % (self._enum[value].name, self._enum[value].value) return '%s<%s>' % (self._enum[value].name, self._enum[value].value)
class BLOBType(DataType): class BLOBType(DataType):
@ -373,28 +365,28 @@ class BLOBType(DataType):
self.set_prop('minbytes', minbytes, 0, int) self.set_prop('minbytes', minbytes, 0, int)
self.maxbytes = int(maxbytes) self.maxbytes = int(maxbytes)
if self.minbytes < 0: if self.minbytes < 0:
raise BadValueError(u'sizes must be bigger than or equal to 0!') raise BadValueError('sizes must be bigger than or equal to 0!')
elif self.minbytes > self.maxbytes: elif self.minbytes > self.maxbytes:
raise BadValueError(u'maxbytes must be bigger than or equal to minbytes!') raise BadValueError('maxbytes must be bigger than or equal to minbytes!')
self.default = b'\0' * self.minbytes self.default = b'\0' * self.minbytes
def export_datatype(self): def export_datatype(self):
return self.get_info(type='blob', maxbytes=self.maxbytes) return self.get_info(type='blob', maxbytes=self.maxbytes)
def __repr__(self): def __repr__(self):
return u'BLOBType(%d, %d)' % (self.minbytes, self.maxbytes) return 'BLOBType(%d, %d)' % (self.minbytes, self.maxbytes)
def __call__(self, value): def __call__(self, value):
"""return the validated (internal) value or raise""" """return the validated (internal) value or raise"""
if not isinstance(value, bytes): if not isinstance(value, bytes):
raise BadValueError(u'%r has the wrong type!' % value) raise BadValueError('%r has the wrong type!' % value)
size = len(value) size = len(value)
if size < self.minbytes: if size < self.minbytes:
raise BadValueError( raise BadValueError(
u'%r must be at least %d bytes long!' % (value, self.minbytes)) '%r must be at least %d bytes long!' % (value, self.minbytes))
if size > self.maxbytes: if size > self.maxbytes:
raise BadValueError( raise BadValueError(
u'%r must be at most %d bytes long!' % (value, self.maxbytes)) '%r must be at most %d bytes long!' % (value, self.maxbytes))
return value return value
def export_value(self, value): def export_value(self, value):
@ -425,49 +417,49 @@ class StringType(DataType):
self.set_prop('maxchars', maxchars, self.MAXCHARS, int) self.set_prop('maxchars', maxchars, self.MAXCHARS, int)
self.set_prop('isUTF8', isUTF8, False, bool) self.set_prop('isUTF8', isUTF8, False, bool)
if self.minchars < 0: if self.minchars < 0:
raise BadValueError(u'sizes must be bigger than or equal to 0!') raise BadValueError('sizes must be bigger than or equal to 0!')
elif self.minchars > self.maxchars: elif self.minchars > self.maxchars:
raise BadValueError(u'maxchars must be bigger than or equal to minchars!') raise BadValueError('maxchars must be bigger than or equal to minchars!')
self.default = u' ' * self.minchars self.default = ' ' * self.minchars
def export_datatype(self): def export_datatype(self):
return self.get_info(type='string') return self.get_info(type='string')
def __repr__(self): def __repr__(self):
return u'StringType(%s)' % (', '.join('%s=%r' % kv for kv in self.get_info().items())) return 'StringType(%s)' % (', '.join('%s=%r' % kv for kv in self.get_info().items()))
def __call__(self, value): def __call__(self, value):
"""return the validated (internal) value or raise""" """return the validated (internal) value or raise"""
if type(value) not in (unicode, str): if not isinstance(value, str):
raise BadValueError(u'%r has the wrong type!' % value) raise BadValueError('%r has the wrong type!' % value)
if not self.isUTF8: if not self.isUTF8:
try: try:
value.encode('ascii') value.encode('ascii')
except UnicodeEncodeError: except UnicodeEncodeError:
raise BadValueError(u'%r contains non-ascii character!' % value) raise BadValueError('%r contains non-ascii character!' % value)
size = len(value) size = len(value)
if size < self.minchars: if size < self.minchars:
raise BadValueError( raise BadValueError(
u'%r must be at least %d bytes long!' % (value, self.minchars)) '%r must be at least %d bytes long!' % (value, self.minchars))
if size > self.maxchars: if size > self.maxchars:
raise BadValueError( raise BadValueError(
u'%r must be at most %d bytes long!' % (value, self.maxchars)) '%r must be at most %d bytes long!' % (value, self.maxchars))
if u'\0' in value: if '\0' in value:
raise BadValueError( raise BadValueError(
u'Strings are not allowed to embed a \\0! Use a Blob instead!') 'Strings are not allowed to embed a \\0! Use a Blob instead!')
return value return value
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
return u'%s' % value return '%s' % value
def import_value(self, value): def import_value(self, value):
"""returns a python object from serialisation""" """returns a python object from serialisation"""
# XXX: do we keep it as unicode str, or convert it to something else? (UTF-8 maybe?) # XXX: do we keep it as str str, or convert it to something else? (UTF-8 maybe?)
return unicode(value) return str(value)
def from_string(self, text): def from_string(self, text):
value = unicode(text) value = str(text)
return self(value) return self(value)
def format_value(self, value, unit=None): def format_value(self, value, unit=None):
@ -485,7 +477,7 @@ class TextType(StringType):
super(TextType, self).__init__(0, maxchars) super(TextType, self).__init__(0, maxchars)
def __repr__(self): def __repr__(self):
return u'TextType(%d, %d)' % (self.minchars, self.maxchars) return 'TextType(%d, %d)' % (self.minchars, self.maxchars)
def copy(self): def copy(self):
# DataType.copy will not work, because it is exported as 'string' # DataType.copy will not work, because it is exported as 'string'
@ -500,15 +492,15 @@ class BoolType(DataType):
return {'type': 'bool'} return {'type': 'bool'}
def __repr__(self): def __repr__(self):
return u'BoolType()' return 'BoolType()'
def __call__(self, value): def __call__(self, value):
"""return the validated (internal) value or raise""" """return the validated (internal) value or raise"""
if value in [0, u'0', u'False', u'false', u'no', u'off', False]: if value in [0, '0', 'False', 'false', 'no', 'off', False]:
return False return False
if value in [1, u'1', u'True', u'true', u'yes', u'on', True]: if value in [1, '1', 'True', 'true', 'yes', 'on', True]:
return True return True
raise BadValueError(u'%r is not a boolean value!' % value) raise BadValueError('%r is not a boolean value!' % value)
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
@ -539,7 +531,7 @@ class ArrayOf(DataType):
def __init__(self, members, minlen=0, maxlen=None, unit=None): def __init__(self, members, minlen=0, maxlen=None, unit=None):
if not isinstance(members, DataType): if not isinstance(members, DataType):
raise BadValueError( raise BadValueError(
u'ArrayOf only works with a DataType as first argument!') 'ArrayOf only works with a DataType as first argument!')
# one argument -> exactly that size # one argument -> exactly that size
# argument default to 100 # argument default to 100
if maxlen is None: if maxlen is None:
@ -551,11 +543,11 @@ class ArrayOf(DataType):
self.minlen = int(minlen) self.minlen = int(minlen)
self.maxlen = int(maxlen) self.maxlen = int(maxlen)
if self.minlen < 0: if self.minlen < 0:
raise BadValueError(u'sizes must be > 0') raise BadValueError('sizes must be > 0')
elif self.maxlen < 1: elif self.maxlen < 1:
raise BadValueError(u'Maximum size must be >= 1!') raise BadValueError('Maximum size must be >= 1!')
elif self.minlen > self.maxlen: elif self.minlen > self.maxlen:
raise BadValueError(u'maxlen must be bigger than or equal to minlen!') raise BadValueError('maxlen must be bigger than or equal to minlen!')
self.default = [members.default] * self.minlen self.default = [members.default] * self.minlen
def export_datatype(self): def export_datatype(self):
@ -563,7 +555,7 @@ class ArrayOf(DataType):
members=self.members.export_datatype()) members=self.members.export_datatype())
def __repr__(self): def __repr__(self):
return u'ArrayOf(%s, %s, %s)' % ( return 'ArrayOf(%s, %s, %s)' % (
repr(self.members), self.minlen, self.maxlen) repr(self.members), self.minlen, self.maxlen)
def __call__(self, value): def __call__(self, value):
@ -572,15 +564,15 @@ class ArrayOf(DataType):
# check number of elements # check number of elements
if self.minlen is not None and len(value) < self.minlen: if self.minlen is not None and len(value) < self.minlen:
raise BadValueError( raise BadValueError(
u'Array too small, needs at least %d elements!' % 'Array too small, needs at least %d elements!' %
self.minlen) self.minlen)
if self.maxlen is not None and len(value) > self.maxlen: if self.maxlen is not None and len(value) > self.maxlen:
raise BadValueError( raise BadValueError(
u'Array too big, holds at most %d elements!' % self.minlen) 'Array too big, holds at most %d elements!' % self.minlen)
# apply subtype valiation to all elements and return as list # apply subtype valiation to all elements and return as list
return [self.members(elem) for elem in value] return [self.members(elem) for elem in value]
raise BadValueError( raise BadValueError(
u'Can not convert %s to ArrayOf DataType!' % repr(value)) 'Can not convert %s to ArrayOf DataType!' % repr(value))
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
@ -593,13 +585,13 @@ class ArrayOf(DataType):
def from_string(self, text): def from_string(self, text):
value, rem = Parser.parse(text) value, rem = Parser.parse(text)
if rem: if rem:
raise ProtocolError(u'trailing garbage: %r' % rem) raise ProtocolError('trailing garbage: %r' % rem)
return self(value) return self(value)
def format_value(self, value, unit=None): def format_value(self, value, unit=None):
if unit is None: if unit is None:
unit = self.unit or self.members.unit unit = self.unit or self.members.unit
res = u'[%s]' % (', '.join([self.members.format_value(elem, u'') for elem in value])) res = '[%s]' % (', '.join([self.members.format_value(elem, '') for elem in value]))
if unit: if unit:
return ' '.join([res, unit]) return ' '.join([res, unit])
return res return res
@ -609,11 +601,11 @@ class TupleOf(DataType):
def __init__(self, *members): def __init__(self, *members):
if not members: if not members:
raise BadValueError(u'Empty tuples are not allowed!') raise BadValueError('Empty tuples are not allowed!')
for subtype in members: for subtype in members:
if not isinstance(subtype, DataType): if not isinstance(subtype, DataType):
raise BadValueError( raise BadValueError(
u'TupleOf only works with DataType objs as arguments!') 'TupleOf only works with DataType objs as arguments!')
self.members = members self.members = members
self.default = tuple(el.default for el in members) self.default = tuple(el.default for el in members)
@ -621,7 +613,7 @@ class TupleOf(DataType):
return dict(type='tuple', members=[subtype.export_datatype() for subtype in self.members]) return dict(type='tuple', members=[subtype.export_datatype() for subtype in self.members])
def __repr__(self): def __repr__(self):
return u'TupleOf(%s)' % u', '.join([repr(st) for st in self.members]) return 'TupleOf(%s)' % ', '.join([repr(st) for st in self.members])
def __call__(self, value): def __call__(self, value):
"""return the validated value or raise""" """return the validated value or raise"""
@ -629,13 +621,13 @@ class TupleOf(DataType):
try: try:
if len(value) != len(self.members): if len(value) != len(self.members):
raise BadValueError( raise BadValueError(
u'Illegal number of Arguments! Need %d arguments.' % 'Illegal number of Arguments! Need %d arguments.' %
(len(self.members))) (len(self.members)))
# validate elements and return as list # validate elements and return as list
return [sub(elem) return [sub(elem)
for sub, elem in zip(self.members, value)] for sub, elem in zip(self.members, value)]
except Exception as exc: except Exception as exc:
raise BadValueError(u'Can not validate:', unicode(exc)) raise BadValueError('Can not validate:', str(exc))
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
@ -648,11 +640,11 @@ class TupleOf(DataType):
def from_string(self, text): def from_string(self, text):
value, rem = Parser.parse(text) value, rem = Parser.parse(text)
if rem: if rem:
raise ProtocolError(u'trailing garbage: %r' % rem) raise ProtocolError('trailing garbage: %r' % rem)
return self(value) return self(value)
def format_value(self, value, unit=None): def format_value(self, value, unit=None):
return u'(%s)' % (', '.join([sub.format_value(elem) return '(%s)' % (', '.join([sub.format_value(elem)
for sub, elem in zip(self.members, value)])) for sub, elem in zip(self.members, value)]))
@ -661,19 +653,19 @@ class StructOf(DataType):
def __init__(self, optional=None, **members): def __init__(self, optional=None, **members):
self.members = members self.members = members
if not members: if not members:
raise BadValueError(u'Empty structs are not allowed!') raise BadValueError('Empty structs are not allowed!')
self.optional = list(optional or []) self.optional = list(optional or [])
for name, subtype in list(members.items()): for name, subtype in list(members.items()):
if not isinstance(subtype, DataType): if not isinstance(subtype, DataType):
raise ProgrammingError( raise ProgrammingError(
u'StructOf only works with named DataType objs as keyworded arguments!') 'StructOf only works with named DataType objs as keyworded arguments!')
if not isinstance(name, (unicode, str)): if not isinstance(name, str):
raise ProgrammingError( raise ProgrammingError(
u'StructOf only works with named DataType objs as keyworded arguments!') 'StructOf only works with named DataType objs as keyworded arguments!')
for name in self.optional: for name in self.optional:
if name not in members: if name not in members:
raise ProgrammingError( raise ProgrammingError(
u'Only members of StructOf may be declared as optional!') 'Only members of StructOf may be declared as optional!')
self.default = dict((k,el.default) for k, el in members.items()) self.default = dict((k,el.default) for k, el in members.items())
def export_datatype(self): def export_datatype(self):
@ -685,8 +677,8 @@ class StructOf(DataType):
def __repr__(self): def __repr__(self):
opt = self.optional if self.optional else '' opt = self.optional if self.optional else ''
return u'StructOf(%s%s)' % (u', '.join( return 'StructOf(%s%s)' % (', '.join(
[u'%s=%s' % (n, repr(st)) for n, st in list(self.members.items())]), opt) ['%s=%s' % (n, repr(st)) for n, st in list(self.members.items())]), opt)
def __call__(self, value): def __call__(self, value):
"""return the validated value or raise""" """return the validated value or raise"""
@ -694,40 +686,40 @@ class StructOf(DataType):
# XXX: handle optional elements !!! # XXX: handle optional elements !!!
if len(list(value.keys())) != len(list(self.members.keys())): if len(list(value.keys())) != len(list(self.members.keys())):
raise BadValueError( raise BadValueError(
u'Illegal number of Arguments! Need %d arguments.' % 'Illegal number of Arguments! Need %d arguments.' %
len(list(self.members.keys()))) len(list(self.members.keys())))
# validate elements and return as dict # validate elements and return as dict
return dict((unicode(k), self.members[k](v)) return dict((str(k), self.members[k](v))
for k, v in list(value.items())) for k, v in list(value.items()))
except Exception as exc: except Exception as exc:
raise BadValueError(u'Can not validate %s: %s' % (repr(value), unicode(exc))) raise BadValueError('Can not validate %s: %s' % (repr(value), str(exc)))
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
if len(list(value.keys())) != len(list(self.members.keys())): if len(list(value.keys())) != len(list(self.members.keys())):
raise BadValueError( raise BadValueError(
u'Illegal number of Arguments! Need %d arguments.' % len( 'Illegal number of Arguments! Need %d arguments.' % len(
list(self.members.keys()))) list(self.members.keys())))
return dict((unicode(k), self.members[k].export_value(v)) return dict((str(k), self.members[k].export_value(v))
for k, v in list(value.items())) for k, v in list(value.items()))
def import_value(self, value): def import_value(self, value):
"""returns a python object from serialisation""" """returns a python object from serialisation"""
if len(list(value.keys())) != len(list(self.members.keys())): if len(list(value.keys())) != len(list(self.members.keys())):
raise BadValueError( raise BadValueError(
u'Illegal number of Arguments! Need %d arguments.' % len( 'Illegal number of Arguments! Need %d arguments.' % len(
list(self.members.keys()))) list(self.members.keys())))
return dict((unicode(k), self.members[k].import_value(v)) return dict((str(k), self.members[k].import_value(v))
for k, v in list(value.items())) for k, v in list(value.items()))
def from_string(self, text): def from_string(self, text):
value, rem = Parser.parse(text) value, rem = Parser.parse(text)
if rem: if rem:
raise ProtocolError(u'trailing garbage: %r' % rem) raise ProtocolError('trailing garbage: %r' % rem)
return self(dict(value)) return self(dict(value))
def format_value(self, value, unit=None): def format_value(self, value, unit=None):
return u'{%s}' % (', '.join(['%s=%s' % (k, self.members[k].format_value(v)) for k, v in sorted(value.items())])) return '{%s}' % (', '.join(['%s=%s' % (k, self.members[k].format_value(v)) for k, v in sorted(value.items())]))
class CommandType(DataType): class CommandType(DataType):
@ -738,10 +730,10 @@ class CommandType(DataType):
def __init__(self, argument=None, result=None): def __init__(self, argument=None, result=None):
if argument is not None: if argument is not None:
if not isinstance(argument, DataType): if not isinstance(argument, DataType):
raise BadValueError(u'CommandType: Argument type must be a DataType!') raise BadValueError('CommandType: Argument type must be a DataType!')
if result is not None: if result is not None:
if not isinstance(result, DataType): if not isinstance(result, DataType):
raise BadValueError(u'CommandType: Result type must be a DataType!') raise BadValueError('CommandType: Result type must be a DataType!')
self.argument = argument self.argument = argument
self.result = result self.result = result
@ -757,23 +749,23 @@ class CommandType(DataType):
def __repr__(self): def __repr__(self):
argstr = repr(self.argument) if self.argument else '' argstr = repr(self.argument) if self.argument else ''
if self.result is None: if self.result is None:
return u'CommandType(%s)' % argstr return 'CommandType(%s)' % argstr
return u'CommandType(%s)->%s' % (argstr, repr(self.result)) return 'CommandType(%s)->%s' % (argstr, repr(self.result))
def __call__(self, value): def __call__(self, value):
"""return the validated argument value or raise""" """return the validated argument value or raise"""
return self.argument(value) return self.argument(value)
def export_value(self, value): def export_value(self, value):
raise ProgrammingError(u'values of type command can not be transported!') raise ProgrammingError('values of type command can not be transported!')
def import_value(self, value): def import_value(self, value):
raise ProgrammingError(u'values of type command can not be transported!') raise ProgrammingError('values of type command can not be transported!')
def from_string(self, text): def from_string(self, text):
value, rem = Parser.parse(text) value, rem = Parser.parse(text)
if rem: if rem:
raise ProtocolError(u'trailing garbage: %r' % rem) raise ProtocolError('trailing garbage: %r' % rem)
return self(value) return self(value)
def format_value(self, value, unit=None): def format_value(self, value, unit=None):
@ -789,7 +781,7 @@ class DataTypeType(DataType):
returns the value or raises an appropriate exception""" returns the value or raises an appropriate exception"""
if isinstance(value, DataType): if isinstance(value, DataType):
return value return value
raise ProgrammingError(u'%r should be a DataType!' % value) raise ProgrammingError('%r should be a DataType!' % value)
def export_value(self, value): def export_value(self, value):
"""if needed, reformat value for transport""" """if needed, reformat value for transport"""
@ -872,7 +864,7 @@ class LimitsType(StructOf):
def __call__(self, value): def __call__(self, value):
limits = StructOf.__call__(self, value) limits = StructOf.__call__(self, value)
if limits['max'] < limits['min']: if limits['max'] < limits['min']:
raise BadValueError(u'Maximum Value %s must be greater than minimum value %s!' % (limits['max'], limits['min'])) raise BadValueError('Maximum Value %s must be greater than minimum value %s!' % (limits['max'], limits['min']))
return limits return limits
@ -925,4 +917,4 @@ def get_datatype(json):
try: try:
return DATATYPES[base](**args) return DATATYPES[base](**args)
except (TypeError, AttributeError, KeyError): except (TypeError, AttributeError, KeyError):
raise BadValueError(u'invalid data descriptor: %r' % json) raise BadValueError('invalid data descriptor: %r' % json)

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""Define (internal) SECoP Errors""" """Define (internal) SECoP Errors"""
from __future__ import division, print_function
class SECoPError(RuntimeError): class SECoPError(RuntimeError):

View File

@ -21,16 +21,14 @@
# ***************************************************************************** # *****************************************************************************
"""Define Mixin Features for real Modules implemented in the server""" """Define Mixin Features for real Modules implemented in the server"""
from __future__ import division, print_function
from secop.datatypes import ArrayOf, BoolType, EnumType, \ from secop.datatypes import ArrayOf, BoolType, EnumType, \
FloatRange, StringType, StructOf, TupleOf FloatRange, StringType, StructOf, TupleOf
from secop.metaclass import ModuleMeta, add_metaclass from secop.metaclass import ModuleMeta
from secop.modules import Command, Parameter from secop.modules import Command, Parameter
@add_metaclass(ModuleMeta) class Feature(object, metaclass=ModuleMeta):
class Feature(object):
"""all things belonging to a small, predefined functionality influencing the working of a module""" """all things belonging to a small, predefined functionality influencing the working of a module"""
pass pass

View File

@ -20,7 +20,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import print_function
from os import path, listdir from os import path, listdir
import sys import sys
import inspect import inspect

View File

@ -20,7 +20,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import print_function
import os import os

View File

@ -21,7 +21,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
import sys import sys

View File

@ -22,7 +22,6 @@
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
from os import path from os import path

View File

@ -22,7 +22,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
from secop.gui.params import ParameterView from secop.gui.params import ParameterView
from secop.gui.qt import QCheckBox, QDialog, QLabel, \ from secop.gui.qt import QCheckBox, QDialog, QLabel, \
@ -30,20 +29,6 @@ from secop.gui.qt import QCheckBox, QDialog, QLabel, \
from secop.gui.util import loadUi from secop.gui.util import loadUi
from secop.gui.valuewidgets import get_widget from secop.gui.valuewidgets import get_widget
try:
# py2
unicode(u'')
except NameError:
# py3
unicode = str # pylint: disable=redefined-builtin
#from secop.datatypes import ...
class CommandDialog(QDialog): class CommandDialog(QDialog):
def __init__(self, cmdname, argument, parent=None): def __init__(self, cmdname, argument, parent=None):
@ -104,7 +89,7 @@ class ParameterGroup(QWidget):
self._row = 0 self._row = 0
self._widgets = [] self._widgets = []
self.paramGroupBox.setTitle('Group: ' + unicode(groupname)) self.paramGroupBox.setTitle('Group: ' + str(groupname))
self.paramGroupBox.toggled.connect(self.on_toggle_clicked) self.paramGroupBox.toggled.connect(self.on_toggle_clicked)
self.paramGroupBox.setChecked(False) self.paramGroupBox.setChecked(False)
@ -293,7 +278,7 @@ class ModuleCtrl(QWidget):
label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred) label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
# make 'display' label # make 'display' label
view = QLabel(unicode(props[prop])) view = QLabel(str(props[prop]))
view.setFont(self.font()) view.setFont(self.font())
view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
view.setWordWrap(True) view.setWordWrap(True)
@ -369,7 +354,7 @@ class ModuleCtrl(QWidget):
try: try:
self._node.setParameter(module, parameter, target) self._node.setParameter(module, parameter, target)
except Exception as e: except Exception as e:
QMessageBox.warning(self.parent(), 'Operation failed', unicode(e)) QMessageBox.warning(self.parent(), 'Operation failed', str(e))
def _updateValue(self, module, parameter, value): def _updateValue(self, module, parameter, value):
if module != self._module: if module != self._module:

View File

@ -21,7 +21,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
import json import json
import pprint import pprint
@ -33,15 +32,6 @@ from secop.gui.qt import QFont, QFontMetrics, QLabel, \
QMessageBox, QTextCursor, QWidget, pyqtSlot, toHtmlEscaped QMessageBox, QTextCursor, QWidget, pyqtSlot, toHtmlEscaped
from secop.gui.util import loadUi from secop.gui.util import loadUi
try:
# py2
unicode(u'')
except NameError:
unicode = str # pylint: disable=redefined-builtin
class NodeCtrl(QWidget): class NodeCtrl(QWidget):
@ -334,6 +324,6 @@ class DrivableWidget(ReadableWidget):
def on_targetLineEdit_returnPressed(self): def on_targetLineEdit_returnPressed(self):
self.target_go(self.targetLineEdit.text()) self.target_go(self.targetLineEdit.text())
@pyqtSlot(unicode) @pyqtSlot(str)
def on_targetComboBox_activated(self, selection): def on_targetComboBox_activated(self, selection):
self.target_go(selection) self.target_go(selection)

View File

@ -21,7 +21,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import print_function
from secop.datatypes import EnumType, FloatRange, IntRange from secop.datatypes import EnumType, FloatRange, IntRange
from secop.gui.qt import QPushButton as QButton from secop.gui.qt import QPushButton as QButton
@ -30,14 +29,6 @@ from secop.gui.qt import QCheckBox, QLabel, QLineEdit, \
from secop.gui.util import loadUi from secop.gui.util import loadUi
from secop.lib import formatExtendedStack from secop.lib import formatExtendedStack
try:
# py2
unicode(u'')
except NameError:
unicode = str # pylint: disable=redefined-builtin
class ParameterWidget(QWidget): class ParameterWidget(QWidget):
setRequested = pyqtSignal(str, str, object) # module, parameter, target setRequested = pyqtSignal(str, str, object) # module, parameter, target

View File

@ -21,19 +21,10 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
from secop.gui.qt import QLabel, QSizePolicy, QWidget from secop.gui.qt import QLabel, QSizePolicy, QWidget
from secop.gui.util import loadUi from secop.gui.util import loadUi
try:
# py2
unicode(u'')
except NameError:
# py3
unicode = str # pylint: disable=redefined-builtin
class ParameterView(QWidget): class ParameterView(QWidget):

View File

@ -22,7 +22,6 @@
"""Import needed stuff from PyQt4/PyQt5""" """Import needed stuff from PyQt4/PyQt5"""
# pylint: disable=unused-import # pylint: disable=unused-import
from __future__ import division, print_function
import sys import sys

View File

@ -21,7 +21,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
from os import path from os import path

View File

@ -21,7 +21,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
from secop.datatypes import ArrayOf, BLOBType, BoolType, EnumType, \ from secop.datatypes import ArrayOf, BLOBType, BoolType, EnumType, \
FloatRange, IntRange, StringType, StructOf, TupleOf, TextType FloatRange, IntRange, StringType, StructOf, TupleOf, TextType

View File

@ -32,21 +32,20 @@ import subprocess
import sys import sys
import threading import threading
import traceback import traceback
import unicodedata
from os import path from os import path
repodir = path.abspath(path.join(path.dirname(__file__), u'..', u'..')) repodir = path.abspath(path.join(path.dirname(__file__), '..', '..'))
CONFIG = { CONFIG = {
u'piddir': os.path.join(repodir, u'pid'), 'piddir': os.path.join(repodir, 'pid'),
u'logdir': os.path.join(repodir, u'log'), 'logdir': os.path.join(repodir, 'log'),
u'confdir': os.path.join(repodir, u'cfg'), 'confdir': os.path.join(repodir, 'etc'),
u'basedir': repodir, 'basedir': repodir,
} if os.path.exists(os.path.join(repodir, u'.git')) else { } if os.path.exists(os.path.join(repodir, '.git')) else {
u'piddir': u'/var/run/secop', 'piddir': '/var/run/secop',
u'logdir': u'/var/log', 'logdir': '/var/log',
u'confdir': u'/etc/secop', 'confdir': '/etc/secop',
u'basedir': repodir, 'basedir': repodir,
} }

View File

@ -22,15 +22,9 @@
# ***************************************************************************** # *****************************************************************************
"""Enum class""" """Enum class"""
from __future__ import division, print_function
__ALL__ = ['Enum'] __ALL__ = ['Enum']
try:
text_type = unicode # Py2
except NameError:
text_type = str # Py3
unicode = str # pylint: disable=redefined-builtin
class EnumMember(object): class EnumMember(object):
"""represents one member of an Enum """represents one member of an Enum
@ -49,7 +43,7 @@ class EnumMember(object):
def __cmp__(self, other): def __cmp__(self, other):
if isinstance(other, EnumMember): if isinstance(other, EnumMember):
other = other.value other = other.value
if isinstance(other, (str, unicode)): if isinstance(other, str):
if other in self.enum: if other in self.enum:
other = self.enum[other].value other = self.enum[other].value
try: try:
@ -73,7 +67,7 @@ class EnumMember(object):
if isinstance(other, int): if isinstance(other, int):
return other == self.value return other == self.value
# compare by name (for (in)equality only) # compare by name (for (in)equality only)
if isinstance(other, (str, unicode)): if isinstance(other, str):
if other in self.enum: if other in self.enum:
return self.name == other return self.name == other
return False return False
@ -114,8 +108,6 @@ class EnumMember(object):
return self.value.__sub__(other.value if isinstance(other, EnumMember) else other) return self.value.__sub__(other.value if isinstance(other, EnumMember) else other)
def __mul__(self, other): def __mul__(self, other):
return self.value.__mul__(other.value if isinstance(other, EnumMember) else other) return self.value.__mul__(other.value if isinstance(other, EnumMember) else other)
def __div__(self, other):
return self.value.__div__(other.value if isinstance(other, EnumMember) else other)
def __truediv__(self, other): def __truediv__(self, other):
return self.value.__truediv__(other.value if isinstance(other, EnumMember) else other) return self.value.__truediv__(other.value if isinstance(other, EnumMember) else other)
def __floordiv__(self, other): def __floordiv__(self, other):
@ -137,8 +129,6 @@ class EnumMember(object):
return self.value.__rsub__(other.value if isinstance(other, EnumMember) else other) return self.value.__rsub__(other.value if isinstance(other, EnumMember) else other)
def __rmul__(self, other): def __rmul__(self, other):
return self.value.__rmul__(other.value if isinstance(other, EnumMember) else other) return self.value.__rmul__(other.value if isinstance(other, EnumMember) else other)
def __rdiv__(self, other):
return self.value.__rdiv__(other.value if isinstance(other, EnumMember) else other)
def __rtruediv__(self, other): def __rtruediv__(self, other):
return self.value.__rtruediv__(other.value if isinstance(other, EnumMember) else other) return self.value.__rtruediv__(other.value if isinstance(other, EnumMember) else other)
def __rfloordiv__(self, other): def __rfloordiv__(self, other):
@ -181,10 +171,6 @@ class EnumMember(object):
def __float__(self): def __float__(self):
return self.value.__float__() return self.value.__float__()
#return NotImplemented # makes no sense #return NotImplemented # makes no sense
def __oct__(self):
return self.value.__oct__()
def __hex__(self):
return self.value.__hex__()
def __index__(self): def __index__(self):
return self.value.__index__() return self.value.__index__()
@ -234,7 +220,7 @@ class Enum(dict):
name=parent.name name=parent.name
# else: # else:
# raise TypeError('Enum instances need a name or an Enum parent!') # raise TypeError('Enum instances need a name or an Enum parent!')
if not isinstance(name, (str, text_type)): if not isinstance(name, str):
raise TypeError('1st argument to Enum must be a name or an Enum!') raise TypeError('1st argument to Enum must be a name or an Enum!')
names = set() names = set()

View File

@ -1,44 +0,0 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# 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>
#
# *****************************************************************************
"""Define metaclass helper"""
from __future__ import division, print_function
try:
# pylint: disable=unused-import
from six import add_metaclass # for py2/3 compat
except ImportError:
# copied from six v1.10.0
def add_metaclass(metaclass):
"""Class decorator for creating a class with a metaclass."""
def wrapper(cls):
orig_vars = cls.__dict__.copy()
slots = orig_vars.get('__slots__')
if slots is not None:
if isinstance(slots, str):
slots = [slots]
for slots_var in slots:
orig_vars.pop(slots_var)
orig_vars.pop('__dict__', None)
orig_vars.pop('__weakref__', None)
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""Define parsing helpers""" """Define parsing helpers"""
from __future__ import division, print_function
import re import re
import time import time
@ -144,7 +143,7 @@ def format_args(args):
return ','.join(format_args(arg) for arg in args).join('[]') return ','.join(format_args(arg) for arg in args).join('[]')
if isinstance(args, tuple): if isinstance(args, tuple):
return ','.join(format_args(arg) for arg in args).join('()') return ','.join(format_args(arg) for arg in args).join('()')
if isinstance(args, (str, unicode)): if isinstance(args, str):
# XXX: check for 'easy' strings only and omit the '' # XXX: check for 'easy' strings only and omit the ''
return repr(args) return repr(args)
return repr(args) # for floats/ints/... return repr(args) # for floats/ints/...

View File

@ -20,7 +20,6 @@
# #
# ***************************************************************************** # *****************************************************************************
"""Define pidfile helpers""" """Define pidfile helpers"""
from __future__ import division, print_function
import atexit import atexit
import os import os

View File

@ -23,7 +23,6 @@
"""Utilities for modules that require sequenced actions on value change.""" """Utilities for modules that require sequenced actions on value change."""
from __future__ import division, print_function
from time import sleep from time import sleep
@ -74,7 +73,7 @@ class SequencerMixin(object):
self._seq_fault_on_error = fault_on_error self._seq_fault_on_error = fault_on_error
self._seq_fault_on_stop = fault_on_stop self._seq_fault_on_stop = fault_on_stop
self._seq_stopflag = False self._seq_stopflag = False
self._seq_phase = u'' self._seq_phase = ''
self._seq_error = None self._seq_error = None
self._seq_stopped = None self._seq_stopped = None
@ -116,7 +115,7 @@ class SequencerMixin(object):
the default is to only go into ALARM. the default is to only go into ALARM.
""" """
if self.seq_is_alive(): if self.seq_is_alive():
raise IsBusyError(u'move sequence already in progress') raise IsBusyError('move sequence already in progress')
self._seq_stopflag = False self._seq_stopflag = False
self._seq_error = self._seq_stopped = None self._seq_error = self._seq_stopped = None
@ -129,7 +128,7 @@ class SequencerMixin(object):
def read_status(self): def read_status(self):
if self.seq_is_alive(): if self.seq_is_alive():
return self.Status.BUSY, u'moving: ' + self._seq_phase return self.Status.BUSY, 'moving: ' + self._seq_phase
elif self._seq_error: elif self._seq_error:
if self._seq_fault_on_error: if self._seq_fault_on_error:
return self.Status.ERROR, self._seq_error return self.Status.ERROR, self._seq_error
@ -138,9 +137,9 @@ class SequencerMixin(object):
if self._seq_fault_on_stop: if self._seq_fault_on_stop:
return self.Status.ERROR, self._seq_stopped return self.Status.ERROR, self._seq_stopped
return self.Status.WARN, self._seq_stopped return self.Status.WARN, self._seq_stopped
if hasattr(self, u'read_hw_status'): if hasattr(self, 'read_hw_status'):
return self.read_hw_status() return self.read_hw_status()
return self.Status.IDLE, u'' return self.Status.IDLE, ''
def do_stop(self): def do_stop(self):
if self.seq_is_alive(): if self.seq_is_alive():
@ -150,7 +149,7 @@ class SequencerMixin(object):
try: try:
self._seq_thread_inner(seq, store_init) self._seq_thread_inner(seq, store_init)
except Exception as e: except Exception as e:
self.log.exception(u'unhandled error in sequence thread: %s', e) self.log.exception('unhandled error in sequence thread: %s', e)
self._seq_error = str(e) self._seq_error = str(e)
finally: finally:
self._seq_thread = None self._seq_thread = None
@ -159,11 +158,11 @@ class SequencerMixin(object):
def _seq_thread_inner(self, seq, store_init): def _seq_thread_inner(self, seq, store_init):
store = Namespace() store = Namespace()
store.__dict__.update(store_init) store.__dict__.update(store_init)
self.log.debug(u'sequence: starting, values %s', store_init) self.log.debug('sequence: starting, values %s', store_init)
for step in seq: for step in seq:
self._seq_phase = step.desc self._seq_phase = step.desc
self.log.debug(u'sequence: entering phase: %s', step.desc) self.log.debug('sequence: entering phase: %s', step.desc)
try: try:
i = 0 i = 0
while True: while True:
@ -171,10 +170,10 @@ class SequencerMixin(object):
result = step.func(store, *step.args) result = step.func(store, *step.args)
if self._seq_stopflag: if self._seq_stopflag:
if result: if result:
self._seq_stopped = u'stopped while %s' % step.desc self._seq_stopped = 'stopped while %s' % step.desc
else: else:
self._seq_stopped = u'stopped after %s' % step.desc self._seq_stopped = 'stopped after %s' % step.desc
cleanup_func = step.kwds.get(u'cleanup', None) cleanup_func = step.kwds.get('cleanup', None)
if callable(cleanup_func): if callable(cleanup_func):
try: try:
cleanup_func(store, result, *step.args) cleanup_func(store, result, *step.args)
@ -188,6 +187,6 @@ class SequencerMixin(object):
i += 1 i += 1
except Exception as e: except Exception as e:
self.log.exception( self.log.exception(
u'error in sequence step %r: %s', step.desc, e) 'error in sequence step %r: %s', step.desc, e)
self._seq_error = u'during %s: %s' % (step.desc, e) self._seq_error = 'during %s: %s' % (step.desc, e)
break break

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""Define Metaclass for Modules/Features""" """Define Metaclass for Modules/Features"""
from __future__ import division, print_function
import time import time
from collections import OrderedDict from collections import OrderedDict

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""Define Baseclasses for real Modules implemented in the server""" """Define Baseclasses for real Modules implemented in the server"""
from __future__ import division, print_function
import sys import sys
import time import time
@ -33,7 +32,6 @@ from secop.errors import ConfigError, ProgrammingError
from secop.lib import formatException, \ from secop.lib import formatException, \
formatExtendedStack, mkthread, unset_value formatExtendedStack, mkthread, unset_value
from secop.lib.enum import Enum from secop.lib.enum import Enum
from secop.lib.metaclass import add_metaclass
from secop.metaclass import ModuleMeta from secop.metaclass import ModuleMeta
from secop.params import PREDEFINED_ACCESSIBLES, Command, Override, Parameter, Parameters, Commands from secop.params import PREDEFINED_ACCESSIBLES, Command, Override, Parameter, Parameters, Commands
from secop.properties import HasProperties, Property from secop.properties import HasProperties, Property
@ -45,8 +43,7 @@ from secop.properties import HasProperties, Property
# from these base classes (how to do this?) # from these base classes (how to do this?)
@add_metaclass(ModuleMeta) class Module(HasProperties, metaclass=ModuleMeta):
class Module(HasProperties):
"""Basic Module """Basic Module
ALL secop Modules derive from this ALL secop Modules derive from this
@ -205,7 +202,7 @@ class Module(HasProperties):
# (self.name, k, e)) # (self.name, k, e))
# note: this will call write_* methods which will # note: this will call write_* methods which will
# write to the hardware, if possible! # write to the hardware, if possible!
if k != u'value': if k != 'value':
setattr(self, k, v) setattr(self, k, v)
cfgdict.pop(k) cfgdict.pop(k)

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""Define classes for Parameters/Commands and Overriding them""" """Define classes for Parameters/Commands and Overriding them"""
from __future__ import division, print_function
from collections import OrderedDict from collections import OrderedDict
@ -30,11 +29,6 @@ from secop.datatypes import CommandType, DataType, StringType, BoolType, EnumTyp
from secop.errors import ProgrammingError from secop.errors import ProgrammingError
from secop.properties import HasProperties, Property from secop.properties import HasProperties, Property
try:
unicode
except NameError:
# pylint: disable=redefined-builtin
unicode = str # py3 compat
class CountedObj(object): class CountedObj(object):
ctr = [0] ctr = [0]
@ -54,8 +48,8 @@ class Accessible(HasProperties, CountedObj):
self.properties.update(kwds) self.properties.update(kwds)
def __repr__(self): def __repr__(self):
return u'%s_%d(%s)' % (self.__class__.__name__, self.ctr, ',\n\t'.join( return '%s_%d(%s)' % (self.__class__.__name__, self.ctr, ',\n\t'.join(
[u'%s=%r' % (k, self.properties.get(k, v.default)) for k, v in sorted(self.__class__.properties.items())])) ['%s=%r' % (k, self.properties.get(k, v.default)) for k, v in sorted(self.__class__.properties.items())]))
def copy(self): def copy(self):
# return a copy of ourselfs # return a copy of ourselfs
@ -92,26 +86,26 @@ class Parameter(Accessible):
""" """
properties = { properties = {
u'description': Property('Description of the Parameter', TextType(), 'description': Property('Description of the Parameter', TextType(),
extname=u'description', mandatory=True), extname='description', mandatory=True),
u'datatype': Property('Datatype of the Parameter', DataTypeType(), 'datatype': Property('Datatype of the Parameter', DataTypeType(),
extname=u'datainfo', mandatory=True), extname='datainfo', mandatory=True),
u'unit': Property('[legacy] unit of the parameter. This should now be on the datatype!', StringType(), 'unit': Property('[legacy] unit of the parameter. This should now be on the datatype!', StringType(),
extname=u'unit', default=''), # goodie, should be on the datatype! extname='unit', default=''), # goodie, should be on the datatype!
u'readonly': Property('Is the Parameter readonly? (vs. changeable via SECoP)', BoolType(), 'readonly': Property('Is the Parameter readonly? (vs. changeable via SECoP)', BoolType(),
extname=u'readonly', default=True), extname='readonly', default=True),
u'group': Property('Optional parameter group this parameter belongs to', StringType(), 'group': Property('Optional parameter group this parameter belongs to', StringType(),
extname=u'group', default=''), extname='group', default=''),
u'visibility': Property('Optional visibility hint', EnumType(u'visibility', user=1, advanced=2, expert=3), 'visibility': Property('Optional visibility hint', EnumType('visibility', user=1, advanced=2, expert=3),
extname=u'visibility', default=1), extname='visibility', default=1),
u'constant': Property('Optional constant value for constant parameters', ValueType(), 'constant': Property('Optional constant value for constant parameters', ValueType(),
extname=u'constant', default=None), extname='constant', default=None),
u'default': Property('Default (startup) value of this parameter if it can not be read from the hardware.', 'default': Property('Default (startup) value of this parameter if it can not be read from the hardware.',
ValueType(), export=False, default=None, mandatory=False), ValueType(), export=False, default=None, mandatory=False),
u'export': Property('Is this parameter accessible via SECoP? (vs. internal parameter)', 'export': Property('Is this parameter accessible via SECoP? (vs. internal parameter)',
OrType(BoolType(), StringType()), export=False, default=True), OrType(BoolType(), StringType()), export=False, default=True),
u'poll': Property('Polling indicator', ValueType(), export=False, default=True), # check default value! 'poll': Property('Polling indicator', ValueType(), export=False, default=True), # check default value!
u'optional': Property('[Internal] is this parameter optional?', BoolType(), export=False, default=False), 'optional': Property('[Internal] is this parameter optional?', BoolType(), export=False, default=False),
} }
value = None value = None
@ -127,27 +121,27 @@ class Parameter(Accessible):
datatype = datatype() datatype = datatype()
else: else:
raise ValueError( raise ValueError(
u'datatype MUST be derived from class DataType!') 'datatype MUST be derived from class DataType!')
kwds[u'description'] = description kwds['description'] = description
kwds[u'datatype'] = datatype kwds['datatype'] = datatype
super(Parameter, self).__init__(**kwds) super(Parameter, self).__init__(**kwds)
# note: auto-converts True/False to 1/0 which yield the expected # note: auto-converts True/False to 1/0 which yield the expected
# behaviour... # behaviour...
self.properties[u'poll'] = int(self.poll) self.properties['poll'] = int(self.poll)
if self.constant is not None: if self.constant is not None:
self.properties[u'readonly'] = True self.properties['readonly'] = True
# The value of the `constant` property should be the # The value of the `constant` property should be the
# serialised version of the constant, or unset # serialised version of the constant, or unset
constant = self.datatype(kwds[u'constant']) constant = self.datatype(kwds['constant'])
self.properties[u'constant'] = self.datatype.export_value(constant) self.properties['constant'] = self.datatype.export_value(constant)
# helper: unit should be set on the datatype, not on the parameter! # helper: unit should be set on the datatype, not on the parameter!
if self.unit: if self.unit:
self.datatype.unit = self.unit self.datatype.unit = self.unit
self.properties[u'unit'] = '' self.properties['unit'] = ''
# internal caching: value and timestamp of last change... # internal caching: value and timestamp of last change...
self.value = self.default self.value = self.default
@ -161,7 +155,7 @@ class Parameter(Accessible):
return self.datatype.unit return self.datatype.unit
def _set_unit_(self, unit): def _set_unit_(self, unit):
print(u'DeprecationWarning: setting unit on the parameter is going to be removed') print('DeprecationWarning: setting unit on the parameter is going to be removed')
self.datatype.unit = unit self.datatype.unit = unit
unit = property(_get_unit_, _set_unit_) unit = property(_get_unit_, _set_unit_)
@ -182,9 +176,9 @@ class Parameters(OrderedDict):
def __setitem__(self, key, value): def __setitem__(self, key, value):
if value.export: if value.export:
if isinstance(value, PREDEFINED_ACCESSIBLES.get(key, UnusedClass)): if isinstance(value, PREDEFINED_ACCESSIBLES.get(key, UnusedClass)):
value.properties[u'export'] = key value.properties['export'] = key
else: else:
value.properties[u'export'] = '_' + key value.properties['export'] = '_' + key
self.exported[value.export] = key self.exported[value.export] = key
super(Parameters, self).__setitem__(key, value) super(Parameters, self).__setitem__(key, value)
@ -216,22 +210,22 @@ class Override(CountedObj):
self.reorder = reorder self.reorder = reorder
# allow to override description without keyword # allow to override description without keyword
if description: if description:
self.kwds[u'description'] = description self.kwds['description'] = description
# for now, do not use the Override ctr # for now, do not use the Override ctr
# self.kwds['ctr'] = self.ctr # self.kwds['ctr'] = self.ctr
def __repr__(self): def __repr__(self):
return u'%s_%d(%s)' % (self.__class__.__name__, self.ctr, ', '.join( return '%s_%d(%s)' % (self.__class__.__name__, self.ctr, ', '.join(
[u'%s=%r' % (k, v) for k, v in sorted(self.kwds.items())])) ['%s=%r' % (k, v) for k, v in sorted(self.kwds.items())]))
def apply(self, obj): def apply(self, obj):
if isinstance(obj, Accessible): if isinstance(obj, Accessible):
props = obj.properties.copy() props = obj.properties.copy()
if isinstance(obj, Parameter): if isinstance(obj, Parameter):
if u'constant' in self.kwds: if 'constant' in self.kwds:
constant = obj.datatype(self.kwds.pop(u'constant')) constant = obj.datatype(self.kwds.pop('constant'))
self.kwds[u'constant'] = obj.datatype.export_value(constant) self.kwds['constant'] = obj.datatype.export_value(constant)
self.kwds[u'readonly'] = True self.kwds['readonly'] = True
props.update(self.kwds) props.update(self.kwds)
if self.reorder: if self.reorder:
@ -249,27 +243,27 @@ class Command(Accessible):
""" """
# datatype is not listed (handled separately) # datatype is not listed (handled separately)
properties = { properties = {
u'description': Property('Description of the Command', TextType(), 'description': Property('Description of the Command', TextType(),
extname=u'description', export=True, mandatory=True), extname='description', export=True, mandatory=True),
u'group': Property('Optional command group of the command.', StringType(), 'group': Property('Optional command group of the command.', StringType(),
extname=u'group', export=True, default=''), extname='group', export=True, default=''),
u'visibility': Property('Optional visibility hint', EnumType(u'visibility', user=1, advanced=2, expert=3), 'visibility': Property('Optional visibility hint', EnumType('visibility', user=1, advanced=2, expert=3),
extname=u'visibility', export=True, default=1), extname='visibility', export=True, default=1),
u'export': Property('[internal] Flag: is the command accessible via SECoP? (vs. pure internal use)', 'export': Property('[internal] Flag: is the command accessible via SECoP? (vs. pure internal use)',
OrType(BoolType(), StringType()), export=False, default=True), OrType(BoolType(), StringType()), export=False, default=True),
u'optional': Property('[internal] is The comamnd optional to implement? (vs. mandatory', 'optional': Property('[internal] is The comamnd optional to implement? (vs. mandatory',
BoolType(), export=False, default=False, settable=False), BoolType(), export=False, default=False, settable=False),
u'datatype': Property('[internal] datatype of the command, auto generated from \'argument\' and \'result\'', 'datatype': Property('[internal] datatype of the command, auto generated from \'argument\' and \'result\'',
DataTypeType(), extname=u'datainfo', mandatory=True), DataTypeType(), extname='datainfo', mandatory=True),
u'argument': Property('Datatype of the argument to the command, or None.', 'argument': Property('Datatype of the argument to the command, or None.',
NoneOr(DataTypeType()), export=False, mandatory=True), NoneOr(DataTypeType()), export=False, mandatory=True),
u'result': Property('Datatype of the result from the command, or None.', 'result': Property('Datatype of the result from the command, or None.',
NoneOr(DataTypeType()), export=False, mandatory=True), NoneOr(DataTypeType()), export=False, mandatory=True),
} }
def __init__(self, description, ctr=None, **kwds): def __init__(self, description, ctr=None, **kwds):
kwds[u'description'] = description kwds['description'] = description
kwds[u'datatype'] = CommandType(kwds.get('argument', None), kwds.get('result', None)) kwds['datatype'] = CommandType(kwds.get('argument', None), kwds.get('result', None))
super(Command, self).__init__(**kwds) super(Command, self).__init__(**kwds)
if ctr is not None: if ctr is not None:
self.ctr = ctr self.ctr = ctr
@ -289,10 +283,10 @@ class Command(Accessible):
# - readonly is mandatory for serialisation, but not for declaration in classes # - readonly is mandatory for serialisation, but not for declaration in classes
r = self.exportProperties() r = self.exportProperties()
# if isinstance(self, Parameter): # if isinstance(self, Parameter):
# if u'readonly' not in r: # if 'readonly' not in r:
# r[u'readonly'] = self.__class__.properties[u'readonly'].default # r['readonly'] = self.__class__.properties['readonly'].default
# if u'datatype' in r: # if 'datatype' in r:
# _d = r[u'datatype'] # _d = r['datatype']
# print(formatExtendedStack()) # for debug # print(formatExtendedStack()) # for debug
return r return r

View File

@ -36,7 +36,6 @@ text -> string
further convertions are done by the validator of the datatype.... further convertions are done by the validator of the datatype....
""" """
from __future__ import division, print_function
from collections import OrderedDict from collections import OrderedDict
@ -55,7 +54,7 @@ class Parser(object):
length = l length = l
l += 1 l += 1
except ValueError: except ValueError:
if text[l - 1] in u'eE+-': if text[l - 1] in 'eE+-':
l += 1 l += 1
continue continue
if number is None: if number is None:
@ -69,7 +68,7 @@ class Parser(object):
def parse_string(self, orgtext): def parse_string(self, orgtext):
# handle quoted and unquoted strings correctly # handle quoted and unquoted strings correctly
text = orgtext.strip() text = orgtext.strip()
if text[0] in (u'"', u"'"): if text[0] in ('"', u"'"):
# quoted string # quoted string
quote = text[0] quote = text[0]
idx = 0 idx = 0
@ -79,14 +78,14 @@ class Parser(object):
if idx == -1: if idx == -1:
return None, orgtext return None, orgtext
# check escapes! # check escapes!
if text[idx - 1] == u'\\': if text[idx - 1] == '\\':
continue continue
return text[1:idx], text[idx + 1:] return text[1:idx], text[idx + 1:]
# unquoted strings are terminated by comma or whitespace # unquoted strings are terminated by comma or whitespace
idx = 0 idx = 0
while idx < len(text): while idx < len(text):
if text[idx] in u'\x09 ,.;:()[]{}<>-+*/\\!"§$%&=?#~+*\'´`^°|-': if text[idx] in '\x09 ,.;:()[]{}<>-+*/\\!"§$%&=?#~+*\'´`^°|-':
break break
idx += 1 idx += 1
return text[:idx] or None, text[idx:] return text[:idx] or None, text[idx:]
@ -94,10 +93,10 @@ class Parser(object):
def parse_tuple(self, orgtext): def parse_tuple(self, orgtext):
text = orgtext.strip() text = orgtext.strip()
bra = text[0] bra = text[0]
if bra not in u'([<': if bra not in '([<':
return None, orgtext return None, orgtext
# convert to closing bracket # convert to closing bracket
bra = u')]>'[u'([<'.index(bra)] bra = ')]>'['([<'.index(bra)]
reslist = [] reslist = []
# search for cosing bracket, collecting results # search for cosing bracket, collecting results
text = text[1:] text = text[1:]
@ -111,7 +110,7 @@ class Parser(object):
if rem[0] == bra: if rem[0] == bra:
return tuple(reslist), rem[1:] return tuple(reslist), rem[1:]
# eat separator # eat separator
if rem[0] in u',;': if rem[0] in ',;':
text = rem[1:] text = rem[1:]
else: else:
return None, rem return None, rem
@ -119,19 +118,19 @@ class Parser(object):
def parse_dict(self, orgtext): def parse_dict(self, orgtext):
text = orgtext.strip() text = orgtext.strip()
if text[0] != u'{': if text[0] != '{':
return None, orgtext return None, orgtext
# keep ordering # keep ordering
result = OrderedDict() result = OrderedDict()
# search for cosing bracket, collecting results # search for cosing bracket, collecting results
# watch for key=value or key:value pairs, separated by , # watch for key=value or key:value pairs, separated by ,
text = text[1:] text = text[1:]
while u'}' in text: while '}' in text:
# first part is always a string # first part is always a string
key, rem = self.parse_string(text) key, rem = self.parse_string(text)
if not key: if not key:
return None, orgtext return None, orgtext
if rem[0] not in u':=': if rem[0] not in ':=':
return None, rem return None, rem
# eat separator # eat separator
text = rem[1:] text = rem[1:]
@ -139,10 +138,10 @@ class Parser(object):
if not value: if not value:
return None, orgtext return None, orgtext
result[key] = value result[key] = value
if rem[0] == u'}': if rem[0] == '}':
return result, rem[1:] return result, rem[1:]
if rem[0] not in u',;': if rem[0] not in ',;':
return None, rem return None, rem
# eat separator # eat separator
text = rem[1:] text = rem[1:]
@ -152,17 +151,17 @@ class Parser(object):
text = orgtext.strip() text = orgtext.strip()
if not text: if not text:
return None, orgtext return None, orgtext
if text[0] in u'+-.0123456789': if text[0] in '+-.0123456789':
return self.parse_number(orgtext) return self.parse_number(orgtext)
elif text[0] == u'{': elif text[0] == '{':
return self.parse_dict(orgtext) return self.parse_dict(orgtext)
elif text[0] in u'([<': elif text[0] in '([<':
return self.parse_tuple(orgtext) return self.parse_tuple(orgtext)
return self.parse_string(orgtext) return self.parse_string(orgtext)
def parse(self, orgtext): def parse(self, orgtext):
print("parsing %r" % orgtext) print("parsing %r" % orgtext)
res, rem = self.parse_sub(orgtext) res, rem = self.parse_sub(orgtext)
if rem and rem[0] in u',;': if rem and rem[0] in ',;':
return self.parse_sub(u'[%s]' % orgtext) return self.parse_sub('[%s]' % orgtext)
return res, rem return res, rem

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""Pathes. how to find what and where...""" """Pathes. how to find what and where..."""
from __future__ import division, print_function
import sys import sys
from os import path from os import path

View File

@ -21,14 +21,11 @@
# ***************************************************************************** # *****************************************************************************
"""Define validated data types.""" """Define validated data types."""
from __future__ import division, print_function
from collections import OrderedDict from collections import OrderedDict
from secop.datatypes import ValueType, DataType from secop.datatypes import ValueType, DataType
from secop.errors import ProgrammingError, ConfigError from secop.errors import ProgrammingError, ConfigError
from secop.lib.metaclass import add_metaclass
# storage for 'properties of a property' # storage for 'properties of a property'
@ -44,7 +41,7 @@ class Property(object):
# the VALUES of the properties are on the instances! # the VALUES of the properties are on the instances!
def __init__(self, description, datatype, default=None, extname='', export=False, mandatory=False, settable=True): def __init__(self, description, datatype, default=None, extname='', export=False, mandatory=False, settable=True):
if not callable(datatype): if not callable(datatype):
raise ValueError(u'datatype MUST be a valid DataType or a basic_validator') raise ValueError('datatype MUST be a valid DataType or a basic_validator')
self.description = description self.description = description
self.default = datatype.default if default is None else datatype(default) self.default = datatype.default if default is None else datatype(default)
self.datatype = datatype self.datatype = datatype
@ -54,7 +51,7 @@ class Property(object):
self.settable = settable or mandatory # settable means settable from the cfg file self.settable = settable or mandatory # settable means settable from the cfg file
def __repr__(self): def __repr__(self):
return u'Property(%s, %s, default=%r, extname=%r, export=%r, mandatory=%r)' % ( return 'Property(%s, %s, default=%r, extname=%r, export=%r, mandatory=%r)' % (
self.description, self.datatype, self.default, self.extname, self.export, self.mandatory) self.description, self.datatype, self.default, self.extname, self.export, self.mandatory)
@ -67,16 +64,16 @@ class Properties(OrderedDict):
""" """
def __setitem__(self, key, value): def __setitem__(self, key, value):
if not isinstance(value, Property): if not isinstance(value, Property):
raise ProgrammingError(u'setting property %r on classes is not supported!' % key) raise ProgrammingError('setting property %r on classes is not supported!' % key)
# make sure, extname is valid if export is True # make sure, extname is valid if export is True
if not value.extname and value.export: if not value.extname and value.export:
value.extname = u'_%s' % key # generate custom kex value.extname = '_%s' % key # generate custom kex
elif value.extname and not value.export: elif value.extname and not value.export:
value.export = True value.export = True
OrderedDict.__setitem__(self, key, value) OrderedDict.__setitem__(self, key, value)
def __delitem__(self, key): def __delitem__(self, key):
raise ProgrammingError(u'deleting Properties is not supported!') raise ProgrammingError('deleting Properties is not supported!')
class PropertyMeta(type): class PropertyMeta(type):
@ -112,13 +109,12 @@ class PropertyMeta(type):
return self.properties.get(pname, val) return self.properties.get(pname, val)
if k in attrs: if k in attrs:
if not isinstance(attrs[k], property): if not isinstance(attrs[k], property):
raise ProgrammingError(u'Name collision with property %r' % k) raise ProgrammingError('Name collision with property %r' % k)
setattr(newtype, k, property(getter)) setattr(newtype, k, property(getter))
return newtype return newtype
@add_metaclass(PropertyMeta) class HasProperties(object, metaclass=PropertyMeta):
class HasProperties(object):
properties = {} properties = {}
def __init__(self, supercall_init=True): def __init__(self, supercall_init=True):

View File

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

View File

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

View File

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

View File

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

View File

@ -21,12 +21,12 @@
# #
# ***************************************************************************** # *****************************************************************************
"""Define helpers""" """Define helpers"""
from __future__ import division, print_function
import ast
import os import os
import threading import ast
import time import time
import threading
import configparser
from collections import OrderedDict from collections import OrderedDict
from daemon import DaemonContext from daemon import DaemonContext
@ -34,19 +34,12 @@ from daemon import DaemonContext
from secop.errors import ConfigError from secop.errors import ConfigError
from secop.lib import formatException, get_class, getGeneralConfig from secop.lib import formatException, get_class, getGeneralConfig
try:
import configparser # py3
except ImportError:
import ConfigParser as configparser # py2
try: try:
import daemon.pidlockfile as pidlockfile import daemon.pidlockfile as pidlockfile
except ImportError: except ImportError:
import daemon.pidfile as pidlockfile import daemon.pidfile as pidlockfile
class Server(object): class Server(object):
# list allowed section prefixes # list allowed section prefixes
# if mapped dict does not exist -> section need a 'class' option # if mapped dict does not exist -> section need a 'class' option
@ -66,12 +59,12 @@ class Server(object):
if os.path.abspath(name) == name and os.path.exists(name) and \ if os.path.abspath(name) == name and os.path.exists(name) and \
name.endswith('.cfg'): name.endswith('.cfg'):
self._cfgfile = name self._cfgfile = name
self._pidfile = os.path.join(cfg[u'piddir'], self._pidfile = os.path.join(cfg['piddir'],
name[:-4].replace(os.path.sep, u'_') + u'.pid') name[:-4].replace(os.path.sep, '_') + '.pid')
name = os.path.basename(name[:-4]) name = os.path.basename(name[:-4])
else: else:
self._cfgfile = os.path.join(cfg[u'confdir'], name + u'.cfg') self._cfgfile = os.path.join(cfg['confdir'], name + '.cfg')
self._pidfile = os.path.join(cfg[u'piddir'], name + u'.pid') self._pidfile = os.path.join(cfg['piddir'], name + '.pid')
self._name = name self._name = name
@ -87,7 +80,7 @@ class Server(object):
pidfile = pidlockfile.TimeoutPIDLockFile(self._pidfile) pidfile = pidlockfile.TimeoutPIDLockFile(self._pidfile)
if pidfile.is_locked(): if pidfile.is_locked():
self.log.error(u'Pidfile already exists. Exiting') self.log.error('Pidfile already exists. Exiting')
with DaemonContext( with DaemonContext(
pidfile=pidfile, pidfile=pidfile,
@ -101,10 +94,10 @@ class Server(object):
print(formatException(verbose=True)) print(formatException(verbose=True))
raise raise
self.log.info(u'startup done, handling transport messages') self.log.info('startup done, handling transport messages')
self._threads = set() self._threads = set()
for ifname, ifobj in self.interfaces.items(): for ifname, ifobj in self.interfaces.items():
self.log.debug(u'starting thread for interface %r' % ifname) self.log.debug('starting thread for interface %r' % ifname)
t = threading.Thread(target=ifobj.serve_forever) t = threading.Thread(target=ifobj.serve_forever)
t.daemon = True t.daemon = True
t.start() t.start()
@ -113,78 +106,78 @@ class Server(object):
time.sleep(1) time.sleep(1)
for t in self._threads: for t in self._threads:
if not t.is_alive(): if not t.is_alive():
self.log.debug(u'thread %r died (%d still running)' % self.log.debug('thread %r died (%d still running)' %
(t, len(self._threads))) (t, len(self._threads)))
t.join() t.join()
self._threads.discard(t) self._threads.discard(t)
def _processCfg(self): def _processCfg(self):
self.log.debug(u'Parse config file %s ...' % self._cfgfile) self.log.debug('Parse config file %s ...' % self._cfgfile)
parser = configparser.SafeConfigParser() parser = configparser.SafeConfigParser()
parser.optionxform = str parser.optionxform = str
if not parser.read([self._cfgfile]): if not parser.read([self._cfgfile]):
self.log.error(u'Couldn\'t read cfg file !') self.log.error('Couldn\'t read cfg file !')
raise ConfigError(u'Couldn\'t read cfg file %r' % self._cfgfile) raise ConfigError('Couldn\'t read cfg file %r' % self._cfgfile)
for kind, devtype, classmapping in self.CFGSECTIONS: for kind, devtype, classmapping in self.CFGSECTIONS:
kinds = u'%ss' % kind kinds = '%ss' % kind
objs = OrderedDict() objs = OrderedDict()
self.__dict__[kinds] = objs self.__dict__[kinds] = objs
for section in parser.sections(): for section in parser.sections():
prefix = u'%s ' % kind prefix = '%s ' % kind
if section.lower().startswith(prefix): if section.lower().startswith(prefix):
name = section[len(prefix):] name = section[len(prefix):]
opts = dict(item for item in parser.items(section)) opts = dict(item for item in parser.items(section))
if u'class' in opts: if 'class' in opts:
cls = opts.pop(u'class') cls = opts.pop('class')
else: else:
if not classmapping: if not classmapping:
self.log.error(u'%s %s needs a class option!' % (kind.title(), name)) self.log.error('%s %s needs a class option!' % (kind.title(), name))
raise ConfigError(u'cfgfile %r: %s %s needs a class option!' % raise ConfigError('cfgfile %r: %s %s needs a class option!' %
(self._cfgfile, kind.title(), name)) (self._cfgfile, kind.title(), name))
type_ = opts.pop(u'type', devtype) type_ = opts.pop('type', devtype)
cls = classmapping.get(type_, None) cls = classmapping.get(type_, None)
if not cls: if not cls:
self.log.error(u'%s %s needs a type option (select one of %s)!' % self.log.error('%s %s needs a type option (select one of %s)!' %
(kind.title(), name, ', '.join(repr(r) for r in classmapping))) (kind.title(), name, ', '.join(repr(r) for r in classmapping)))
raise ConfigError(u'cfgfile %r: %s %s needs a type option (select one of %s)!' % raise ConfigError('cfgfile %r: %s %s needs a type option (select one of %s)!' %
(self._cfgfile, kind.title(), name, ', '.join(repr(r) for r in classmapping))) (self._cfgfile, kind.title(), name, ', '.join(repr(r) for r in classmapping)))
# MAGIC: transform \n.\n into \n\n which are normally stripped # MAGIC: transform \n.\n into \n\n which are normally stripped
# by the ini parser # by the ini parser
for k in opts: for k in opts:
v = opts[k] v = opts[k]
while u'\n.\n' in v: while '\n.\n' in v:
v = v.replace(u'\n.\n', u'\n\n') v = v.replace('\n.\n', '\n\n')
try: try:
opts[k] = ast.literal_eval(v) opts[k] = ast.literal_eval(v)
except Exception: except Exception:
opts[k] = v opts[k] = v
# try to import the class, raise if this fails # try to import the class, raise if this fails
self.log.debug(u'Creating %s %s ...' % (kind.title(), name)) self.log.debug('Creating %s %s ...' % (kind.title(), name))
# cls.__init__ should pop all used args from options! # cls.__init__ should pop all used args from options!
logname = u'dispatcher' if kind == u'node' else u'%s_%s' % (kind, name.lower()) logname = 'dispatcher' if kind == 'node' else '%s_%s' % (kind, name.lower())
obj = get_class(cls)(name, self.log.getChild(logname), opts, self) obj = get_class(cls)(name, self.log.getChild(logname), opts, self)
if opts: if opts:
raise ConfigError(u'%s %s: class %s: don\'t know how to handle option(s): %s' % raise ConfigError('%s %s: class %s: don\'t know how to handle option(s): %s' %
(kind, name, cls, u', '.join(opts))) (kind, name, cls, ', '.join(opts)))
# all went well so far # all went well so far
objs[name] = obj objs[name] = obj
# following line is the reason for 'node' beeing the first entry in CFGSECTIONS # following line is the reason for 'node' beeing the first entry in CFGSECTIONS
if len(self.nodes) != 1: if len(self.nodes) != 1:
raise ConfigError(u'cfgfile %r: needs exactly one node section!' % self._cfgfile) raise ConfigError('cfgfile %r: needs exactly one node section!' % self._cfgfile)
self.dispatcher, = tuple(self.nodes.values()) self.dispatcher, = tuple(self.nodes.values())
pollTable = dict() pollTable = dict()
# all objs created, now start them up and interconnect # all objs created, now start them up and interconnect
for modname, modobj in self.modules.items(): for modname, modobj in self.modules.items():
self.log.info(u'registering module %r' % modname) self.log.info('registering module %r' % modname)
self.dispatcher.register_module(modobj, modname, modobj.properties['export']) self.dispatcher.register_module(modobj, modname, modobj.properties['export'])
try: try:
modobj.pollerClass.add_to_table(pollTable, modobj) modobj.pollerClass.add_to_table(pollTable, modobj)
@ -208,8 +201,8 @@ class Server(object):
# poller.start must return either a timeout value or None (default 30 sec) # poller.start must return either a timeout value or None (default 30 sec)
timeout = poller.start(started_callback=event.set) or 30 timeout = poller.start(started_callback=event.set) or 30
start_events.append((time.time() + timeout, repr(poller), event)) start_events.append((time.time() + timeout, repr(poller), event))
self.log.info(u'waiting for modules and pollers being started') self.log.info('waiting for modules and pollers being started')
for deadline, name, event in sorted(start_events): for deadline, name, event in sorted(start_events):
if not event.wait(timeout=max(0, deadline - time.time())): if not event.wait(timeout=max(0, deadline - time.time())):
self.log.info('WARNING: timeout when starting %s' % name) self.log.info('WARNING: timeout when starting %s' % name)
self.log.info(u'all modules and pollers started') self.log.info('all modules and pollers started')

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""Define Simulation classes""" """Define Simulation classes"""
from __future__ import division, print_function
import random import random
from time import sleep from time import sleep

View File

@ -23,7 +23,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
import os.path import os.path
from subprocess import PIPE, Popen from subprocess import PIPE, Popen

View File

@ -20,7 +20,6 @@
# ***************************************************************************** # *****************************************************************************
"""playing implementation of a (simple) simulated cryostat""" """playing implementation of a (simple) simulated cryostat"""
from __future__ import division, print_function
import random import random
import time import time

View File

@ -20,7 +20,6 @@
# ***************************************************************************** # *****************************************************************************
"""testing devices""" """testing devices"""
from __future__ import division, print_function
import random import random
import threading import threading

View File

@ -20,7 +20,6 @@
# ***************************************************************************** # *****************************************************************************
"""testing devices""" """testing devices"""
from __future__ import division, print_function
import random import random
@ -28,15 +27,6 @@ from secop.datatypes import FloatRange, StringType
from secop.modules import Communicator, Drivable, Parameter, Readable, Override from secop.modules import Communicator, Drivable, Parameter, Readable, Override
from secop.params import Command from secop.params import Command
try:
# py2
unicode
except NameError:
# py3
unicode = str # pylint: disable=redefined-builtin
class LN2(Readable): class LN2(Readable):
"""Just a readable. """Just a readable.
@ -104,4 +94,4 @@ class Lower(Communicator):
'communicate': Command('lowercase a string', argument=StringType(), result=StringType(), export='communicate'), 'communicate': Command('lowercase a string', argument=StringType(), result=StringType(), export='communicate'),
} }
def do_communicate(self, request): def do_communicate(self, request):
return unicode(request).lower() return str(request).lower()

View File

@ -20,7 +20,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import absolute_import, division, print_function
from secop.datatypes import EnumType, FloatRange, StringType from secop.datatypes import EnumType, FloatRange, StringType
from secop.modules import Drivable, Parameter, Readable from secop.modules import Drivable, Parameter, Readable

View File

@ -25,7 +25,6 @@
# partially borrowed from nicos # partially borrowed from nicos
from __future__ import division, print_function
import math import math

View File

@ -27,7 +27,6 @@
Here we support devices which fulfill the official Here we support devices which fulfill the official
MLZ TANGO interface for the respective device classes. MLZ TANGO interface for the respective device classes.
""" """
from __future__ import division, print_function
import re import re
import threading import threading

View File

@ -22,7 +22,6 @@
# #
# ***************************************************************************** # *****************************************************************************
from __future__ import division, print_function
from glob import glob from glob import glob
from os import listdir, path from os import listdir, path

View File

@ -1,5 +1,4 @@
# content of conftest.py # content of conftest.py
from __future__ import division, print_function
import pytest import pytest

View File

@ -20,7 +20,6 @@
# #
# ***************************************************************************** # *****************************************************************************
"""test basic validators.""" """test basic validators."""
from __future__ import division, print_function
# no fixtures needed # no fixtures needed
import pytest import pytest
@ -42,9 +41,9 @@ class unprintable(object):
[PositiveIntProperty, ['x', 1.9, '-9', '1e-4'], [1, '1']], [PositiveIntProperty, ['x', 1.9, '-9', '1e-4'], [1, '1']],
[NonNegativeIntProperty, ['x', 1.9, '-9', '1e-6'], [0, '1']], [NonNegativeIntProperty, ['x', 1.9, '-9', '1e-6'], [0, '1']],
[BoolProperty, ['x', 3], ['on', 'off', True, False]], [BoolProperty, ['x', 3], ['on', 'off', True, False]],
[StringProperty, [unprintable()], [u'1', 1.2, [{}]]], [StringProperty, [unprintable()], ['1', 1.2, [{}]]],
[UnitProperty, [unprintable(), '3', 9], [u'mm', 'Gbarn', 'acre']], [UnitProperty, [unprintable(), '3', 9], ['mm', 'Gbarn', 'acre']],
[FmtStrProperty, [1, None, 'a', '%f'], [u'%.0e', u'%.3f','%.1g']], [FmtStrProperty, [1, None, 'a', '%f'], ['%.0e', '%.3f','%.1g']],
]) ])
def test_validators(validators_args): def test_validators(validators_args):
v, fails, oks = validators_args v, fails, oks = validators_args
@ -72,7 +71,7 @@ def test_checker_fails(checker_inits):
@pytest.mark.parametrize('checker_args', [ @pytest.mark.parametrize('checker_args', [
[OneOfProperty(1,2,3), ['x', None, 4], [1, 2, 3]], [OneOfProperty(1,2,3), ['x', None, 4], [1, 2, 3]],
[NoneOr(IntProperty), ['a', 1.2, '1.2'], [None, 1, '-1', '999999999999999']], [NoneOr(IntProperty), ['a', 1.2, '1.2'], [None, 1, '-1', '999999999999999']],
[EnumProperty(a=1, b=2), ['x', None, 3], [u'a', 'b', 1, 2]], [EnumProperty(a=1, b=2), ['x', None, 3], ['a', 'b', 1, 2]],
[TupleProperty(IntProperty, StringProperty), [1, 'a', ('x', 2)], [(1,'x')]], [TupleProperty(IntProperty, StringProperty), [1, 'a', ('x', 2)], [(1,'x')]],
]) ])
def test_checkers(checker_args): def test_checkers(checker_args):

View File

@ -20,7 +20,6 @@
# #
# ***************************************************************************** # *****************************************************************************
"""test base client.""" """test base client."""
from __future__ import division, print_function
from collections import OrderedDict from collections import OrderedDict

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""test data types.""" """test data types."""
from __future__ import division, print_function
# no fixtures needed # no fixtures needed
import pytest import pytest
@ -56,34 +55,34 @@ def test_FloatRange():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(-9) dt(-9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'XX') dt('XX')
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt([19, u'X']) dt([19, 'X'])
dt(1) dt(1)
dt(0) dt(0)
dt(13.14 - 10) # raises an error, if resolution is not handled correctly dt(13.14 - 10) # raises an error, if resolution is not handled correctly
assert dt.export_value(-2.718) == -2.718 assert dt.export_value(-2.718) == -2.718
assert dt.import_value(-2.718) == -2.718 assert dt.import_value(-2.718) == -2.718
with pytest.raises(ValueError): with pytest.raises(ValueError):
FloatRange(u'x', u'Y') FloatRange('x', 'Y')
# check that unit can be changed # check that unit can be changed
dt.unit = u'K' dt.unit = 'K'
assert dt.export_datatype() == {'type': 'double', 'min':-3.14, 'max':3.14, 'unit': u'K'} assert dt.export_datatype() == {'type': 'double', 'min':-3.14, 'max':3.14, 'unit': 'K'}
dt = FloatRange() dt = FloatRange()
copytest(dt) copytest(dt)
assert dt.export_datatype() == {'type': 'double'} assert dt.export_datatype() == {'type': 'double'}
dt = FloatRange(unit=u'X', fmtstr=u'%.2f', absolute_resolution=1, dt = FloatRange(unit='X', fmtstr='%.2f', absolute_resolution=1,
relative_resolution=0.1) relative_resolution=0.1)
copytest(dt) copytest(dt)
assert dt.export_datatype() == {'type': 'double', 'unit':'X', 'fmtstr':'%.2f', assert dt.export_datatype() == {'type': 'double', 'unit':'X', 'fmtstr':'%.2f',
'absolute_resolution':1.0, 'absolute_resolution':1.0,
'relative_resolution':0.1} 'relative_resolution':0.1}
assert dt(4) == 4 assert dt(4) == 4
assert dt.format_value(3.14) == u'3.14 X' assert dt.format_value(3.14) == '3.14 X'
assert dt.format_value(3.14, u'') == u'3.14' assert dt.format_value(3.14, '') == '3.14'
assert dt.format_value(3.14, u'#') == u'3.14 #' assert dt.format_value(3.14, '#') == '3.14 #'
def test_IntRange(): def test_IntRange():
@ -96,20 +95,20 @@ def test_IntRange():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(-9) dt(-9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'XX') dt('XX')
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt([19, u'X']) dt([19, 'X'])
dt(1) dt(1)
dt(0) dt(0)
with pytest.raises(ValueError): with pytest.raises(ValueError):
IntRange(u'xc', u'Yx') IntRange('xc', 'Yx')
dt = IntRange() dt = IntRange()
copytest(dt) copytest(dt)
assert dt.export_datatype()['type'] == 'int' assert dt.export_datatype()['type'] == 'int'
assert dt.export_datatype()['min'] < 0 < dt.export_datatype()['max'] assert dt.export_datatype()['min'] < 0 < dt.export_datatype()['max']
assert dt.export_datatype() == {'type': 'int', 'max': 16777216,u'min': -16777216} assert dt.export_datatype() == {'type': 'int', 'max': 16777216,'min': -16777216}
assert dt.format_value(42) == u'42' assert dt.format_value(42) == '42'
def test_ScaledInteger(): def test_ScaledInteger():
dt = ScaledInteger(0.01, -3, 3) dt = ScaledInteger(0.01, -3, 3)
@ -122,36 +121,36 @@ def test_ScaledInteger():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(-9) dt(-9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'XX') dt('XX')
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt([19, u'X']) dt([19, 'X'])
dt(1) dt(1)
dt(0) dt(0)
with pytest.raises(ValueError): with pytest.raises(ValueError):
ScaledInteger(u'xc', u'Yx') ScaledInteger('xc', 'Yx')
with pytest.raises(ValueError): with pytest.raises(ValueError):
ScaledInteger(scale=0, minval=1, maxval=2) ScaledInteger(scale=0, minval=1, maxval=2)
with pytest.raises(ValueError): with pytest.raises(ValueError):
ScaledInteger(scale=-10, minval=1, maxval=2) ScaledInteger(scale=-10, minval=1, maxval=2)
# check that unit can be changed # check that unit can be changed
dt.unit = u'A' dt.unit = 'A'
assert dt.export_datatype() == {'type': 'scaled', 'scale':0.01, 'min':-300, 'max':300, 'unit': 'A'} assert dt.export_datatype() == {'type': 'scaled', 'scale':0.01, 'min':-300, 'max':300, 'unit': 'A'}
assert dt.export_value(0.0001) == int(0) assert dt.export_value(0.0001) == int(0)
assert dt.export_value(2.71819) == int(272) assert dt.export_value(2.71819) == int(272)
assert dt.import_value(272) == 2.72 assert dt.import_value(272) == 2.72
dt = ScaledInteger(0.003, 0, 1, unit=u'X', fmtstr=u'%.1f', dt = ScaledInteger(0.003, 0, 1, unit='X', fmtstr='%.1f',
absolute_resolution=0.001, relative_resolution=1e-5) absolute_resolution=0.001, relative_resolution=1e-5)
copytest(dt) copytest(dt)
assert dt.export_datatype() == {'type': 'scaled', 'scale':0.003, 'min':0, 'max':333, assert dt.export_datatype() == {'type': 'scaled', 'scale':0.003, 'min':0, 'max':333,
u'unit':u'X', u'fmtstr':u'%.1f', 'unit':'X', 'fmtstr':'%.1f',
u'absolute_resolution':0.001, 'absolute_resolution':0.001,
u'relative_resolution':1e-5} 'relative_resolution':1e-5}
assert dt(0.4) == 0.399 assert dt(0.4) == 0.399
assert dt.format_value(0.4) == u'0.4 X' assert dt.format_value(0.4) == '0.4 X'
assert dt.format_value(0.4, u'') == u'0.4' assert dt.format_value(0.4, '') == '0.4'
assert dt.format_value(0.4, u'Z') == u'0.4 Z' assert dt.format_value(0.4, 'Z') == '0.4 Z'
assert dt(1.0029) == 0.999 assert dt(1.0029) == 0.999
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(1.004) dt(1.004)
@ -162,9 +161,9 @@ def test_EnumType():
with pytest.raises(TypeError): with pytest.raises(TypeError):
EnumType(1) EnumType(1)
with pytest.raises(TypeError): with pytest.raises(TypeError):
EnumType([u'b', 0]) EnumType(['b', 0])
dt = EnumType(u'dt', a=3, c=7, stuff=1) dt = EnumType('dt', a=3, c=7, stuff=1)
copytest(dt) copytest(dt)
assert dt.export_datatype() == {'type': 'enum', 'members': dict(a=3, c=7, stuff=1)} assert dt.export_datatype() == {'type': 'enum', 'members': dict(a=3, c=7, stuff=1)}
@ -173,28 +172,28 @@ def test_EnumType():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(-9) dt(-9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'XX') dt('XX')
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt([19, u'X']) dt([19, 'X'])
assert dt(u'a') == 3 assert dt('a') == 3
assert dt(u'stuff') == 1 assert dt('stuff') == 1
assert dt(1) == 1 assert dt(1) == 1
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(2) dt(2)
assert dt.export_value(u'c') == 7 assert dt.export_value('c') == 7
assert dt.export_value(u'stuff') == 1 assert dt.export_value('stuff') == 1
assert dt.export_value(1) == 1 assert dt.export_value(1) == 1
assert dt.import_value(u'c') == 7 assert dt.import_value('c') == 7
assert dt.import_value(u'a') == 3 assert dt.import_value('a') == 3
assert dt.import_value(u'stuff') == 1 assert dt.import_value('stuff') == 1
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt.export_value(2) dt.export_value(2)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt.import_value(u'A') dt.import_value('A')
assert dt.format_value(3) == u'a<3>' assert dt.format_value(3) == 'a<3>'
def test_BLOBType(): def test_BLOBType():
@ -217,13 +216,13 @@ def test_BLOBType():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(b'abcdefghijklmno') dt(b'abcdefghijklmno')
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'abcd') dt('abcd')
assert dt(b'abcd') == b'abcd' assert dt(b'abcd') == b'abcd'
assert dt.export_value(b'abcd') == u'YWJjZA==' assert dt.export_value(b'abcd') == 'YWJjZA=='
assert dt.export_value(b'abcd') == u'YWJjZA==' assert dt.export_value(b'abcd') == 'YWJjZA=='
# assert dt.export_value(u'abcd') == u'YWJjZA==' # assert dt.export_value('abcd') == 'YWJjZA=='
assert dt.import_value(u'YWJjZA==') == b'abcd' assert dt.import_value('YWJjZA==') == b'abcd'
# XXX: right? or different format? # XXX: right? or different format?
# to be added after migration to py3 # to be added after migration to py3
@ -246,9 +245,9 @@ def test_StringType():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(9) dt(9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'av') dt('av')
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'abcdefghijklmno') dt('abcdefghijklmno')
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt('abcdefg\0') dt('abcdefg\0')
assert dt('abcd') == 'abcd' assert dt('abcd') == 'abcd'
@ -271,7 +270,7 @@ def test_TextType():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(9) dt(9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'abcdefghijklmno') dt('abcdefghijklmno')
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt('abcdefg\0') dt('abcdefg\0')
assert dt('ab\n\ncd\n') == 'ab\n\ncd\n' assert dt('ab\n\ncd\n') == 'ab\n\ncd\n'
@ -292,20 +291,20 @@ def test_BoolType():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(9) dt(9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'av') dt('av')
assert dt(u'true') is True assert dt('true') is True
assert dt(u'off') is False assert dt('off') is False
assert dt(1) is True assert dt(1) is True
assert dt.export_value(u'false') is False assert dt.export_value('false') is False
assert dt.export_value(0) is False assert dt.export_value(0) is False
assert dt.export_value(u'on') is True assert dt.export_value('on') is True
assert dt.import_value(False) is False assert dt.import_value(False) is False
assert dt.import_value(True) is True assert dt.import_value(True) is True
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt.import_value(u'av') dt.import_value('av')
assert dt.format_value(0) == u"False" assert dt.format_value(0) == u"False"
assert dt.format_value(True) == u"True" assert dt.format_value(True) == u"True"
@ -323,7 +322,7 @@ def test_ArrayOf():
'members': {'type': 'int', 'min':-10, 'members': {'type': 'int', 'min':-10,
'max':10}} 'max':10}}
dt = ArrayOf(FloatRange(-10, 10, unit=u'Z'), 1, 3) dt = ArrayOf(FloatRange(-10, 10, unit='Z'), 1, 3)
copytest(dt) copytest(dt)
assert dt.export_datatype() == {'type': 'array', 'minlen':1, 'maxlen':3, assert dt.export_datatype() == {'type': 'array', 'minlen':1, 'maxlen':3,
'members':{'type': 'double', 'min':-10, 'members':{'type': 'double', 'min':-10,
@ -331,16 +330,16 @@ def test_ArrayOf():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(9) dt(9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(u'av') dt('av')
assert dt([1, 2, 3]) == [1, 2, 3] assert dt([1, 2, 3]) == [1, 2, 3]
assert dt.export_value([1, 2, 3]) == [1, 2, 3] assert dt.export_value([1, 2, 3]) == [1, 2, 3]
assert dt.import_value([1, 2, 3]) == [1, 2, 3] assert dt.import_value([1, 2, 3]) == [1, 2, 3]
assert dt.format_value([1,2,3]) == u'[1, 2, 3] Z' assert dt.format_value([1,2,3]) == '[1, 2, 3] Z'
assert dt.format_value([1,2,3], u'') == u'[1, 2, 3]' assert dt.format_value([1,2,3], '') == '[1, 2, 3]'
assert dt.format_value([1,2,3], u'Q') == u'[1, 2, 3] Q' assert dt.format_value([1,2,3], 'Q') == '[1, 2, 3] Q'
def test_TupleOf(): def test_TupleOf():
@ -373,7 +372,7 @@ def test_StructOf():
StructOf(IntRange=1) StructOf(IntRange=1)
dt = StructOf(a_string=StringType(0, 55), an_int=IntRange(0, 999), dt = StructOf(a_string=StringType(0, 55), an_int=IntRange(0, 999),
optional=[u'an_int']) optional=['an_int'])
copytest(dt) copytest(dt)
assert dt.export_datatype() == {'type': 'struct', assert dt.export_datatype() == {'type': 'struct',
'members':{'a_string': {'type': 'string', 'maxchars':55}, 'members':{'a_string': {'type': 'string', 'maxchars':55},
@ -383,18 +382,18 @@ def test_StructOf():
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(9) dt(9)
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt([99, u'X']) dt([99, 'X'])
with pytest.raises(ValueError): with pytest.raises(ValueError):
dt(dict(a_string=u'XXX', an_int=1811)) dt(dict(a_string='XXX', an_int=1811))
assert dt(dict(a_string=u'XXX', an_int=8)) == {u'a_string': u'XXX', assert dt(dict(a_string='XXX', an_int=8)) == {'a_string': 'XXX',
u'an_int': 8} 'an_int': 8}
assert dt.export_value({u'an_int': 13, u'a_string': u'WFEC'}) == { assert dt.export_value({'an_int': 13, 'a_string': 'WFEC'}) == {
u'a_string': u'WFEC', u'an_int': 13} 'a_string': 'WFEC', 'an_int': 13}
assert dt.import_value({u'an_int': 13, u'a_string': u'WFEC'}) == { assert dt.import_value({'an_int': 13, 'a_string': 'WFEC'}) == {
u'a_string': u'WFEC', u'an_int': 13} 'a_string': 'WFEC', 'an_int': 13}
assert dt.format_value({'an_int':2, u'a_string':'Z'}) == u"{a_string='Z', an_int=2}" assert dt.format_value({'an_int':2, 'a_string':'Z'}) == u"{a_string='Z', an_int=2}"
def test_Command(): def test_Command():
@ -418,11 +417,11 @@ def test_get_datatype():
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype(str) get_datatype(str)
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype({u'undefined': {}}) get_datatype({'undefined': {}})
assert isinstance(get_datatype({'type': 'bool'}), BoolType) assert isinstance(get_datatype({'type': 'bool'}), BoolType)
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype([u'bool']) get_datatype(['bool'])
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype({'type': 'int', 'min':-10}) # missing max get_datatype({'type': 'int', 'min':-10}) # missing max
@ -444,7 +443,7 @@ def test_get_datatype():
FloatRange) FloatRange)
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype([u'double']) get_datatype(['double'])
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype({'type': 'double', 'min':10, 'max':-10}) get_datatype({'type': 'double', 'min':10, 'max':-10})
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -462,7 +461,7 @@ def test_get_datatype():
assert get_datatype(dt.export_datatype()).export_datatype() == dt.export_datatype() assert get_datatype(dt.export_datatype()).export_datatype() == dt.export_datatype()
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype([u'scaled']) # dict missing get_datatype(['scaled']) # dict missing
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype({'type': 'scaled', 'min':-10, 'max':10}) # no scale get_datatype({'type': 'scaled', 'min':-10, 'max':10}) # no scale
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -471,7 +470,7 @@ def test_get_datatype():
get_datatype(['scaled', {'min':10, 'max':-10, 'scale': 1}, 2]) get_datatype(['scaled', {'min':10, 'max':-10, 'scale': 1}, 2])
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype([u'enum']) get_datatype(['enum'])
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype({'type': 'enum', 'a': -2}) get_datatype({'type': 'enum', 'a': -2})
assert isinstance(get_datatype({'type': 'enum', 'members':dict(a=-2)}), EnumType) assert isinstance(get_datatype({'type': 'enum', 'members':dict(a=-2)}), EnumType)
@ -498,13 +497,13 @@ def test_get_datatype():
get_datatype(['string', {'maxchars':-0}, 'x']) get_datatype(['string', {'maxchars':-0}, 'x'])
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype([u'array']) get_datatype(['array'])
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype({'type': 'array', 'members': [1]}) get_datatype({'type': 'array', 'members': [1]})
assert isinstance(get_datatype({'type': 'array', 'minlen':1, 'maxlen':1, assert isinstance(get_datatype({'type': 'array', 'minlen':1, 'maxlen':1,
'members':{'type': 'blob', 'maxbytes':1}} 'members':{'type': 'blob', 'maxbytes':1}}
), ArrayOf) ), ArrayOf)
assert isinstance(get_datatype({'type': 'array', 'minlen':1, u'maxlen':1, assert isinstance(get_datatype({'type': 'array', 'minlen':1, 'maxlen':1,
'members':{'type': 'blob', 'maxbytes':1}} 'members':{'type': 'blob', 'maxbytes':1}}
).members, BLOBType) ).members, BLOBType)
@ -528,7 +527,7 @@ def test_get_datatype():
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype({'type': 'tuple', 'members': {}}) get_datatype({'type': 'tuple', 'members': {}})
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype([u'tuple', 10, -10]) get_datatype(['tuple', 10, -10])
assert isinstance(get_datatype({'type': 'tuple', 'members':[{'type': 'blob', 'maxbytes':1}, assert isinstance(get_datatype({'type': 'tuple', 'members':[{'type': 'blob', 'maxbytes':1},
{'type': 'bool'}]}), TupleOf) {'type': 'bool'}]}), TupleOf)
@ -538,9 +537,9 @@ def test_get_datatype():
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype(['struct', [1], 2, 3]) get_datatype(['struct', [1], 2, 3])
assert isinstance(get_datatype({'type': 'struct', 'members': assert isinstance(get_datatype({'type': 'struct', 'members':
{u'name': {'type': 'blob', 'maxbytes':1}}}), StructOf) {'name': {'type': 'blob', 'maxbytes':1}}}), StructOf)
assert isinstance(get_datatype({'type': 'struct', 'members': assert isinstance(get_datatype({'type': 'struct', 'members':
{u'name': {'type': 'blob', 'maxbytes':1}}}).members[u'name'], BLOBType) {'name': {'type': 'blob', 'maxbytes':1}}}).members['name'], BLOBType)
with pytest.raises(ValueError): with pytest.raises(ValueError):
get_datatype({'type': 'struct', 'members': {}}) get_datatype({'type': 'struct', 'members': {}})

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""test Enum type.""" """test Enum type."""
from __future__ import division, print_function
# no fixtures needed # no fixtures needed
import pytest import pytest

View File

@ -20,7 +20,6 @@
# #
# ***************************************************************************** # *****************************************************************************
"""test data types.""" """test data types."""
from __future__ import division, print_function
# no fixtures needed # no fixtures needed
#import pytest #import pytest

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""test data types.""" """test data types."""
from __future__ import division, print_function
# no fixtures needed # no fixtures needed
import pytest import pytest
@ -31,24 +30,24 @@ from secop.params import Command, Override, Parameter, Parameters
def test_Command(): def test_Command():
cmd = Command(u'do_something') cmd = Command('do_something')
assert cmd.description == u'do_something' assert cmd.description == 'do_something'
assert cmd.ctr assert cmd.ctr
assert cmd.argument is None assert cmd.argument is None
assert cmd.result is None assert cmd.result is None
assert cmd.for_export() == {u'datainfo': {'type': 'command'}, assert cmd.for_export() == {'datainfo': {'type': 'command'},
u'description': u'do_something'} 'description': 'do_something'}
cmd = Command(u'do_something', argument=IntRange(-9,9), result=IntRange(-1,1)) cmd = Command('do_something', argument=IntRange(-9,9), result=IntRange(-1,1))
assert cmd.description assert cmd.description
assert isinstance(cmd.argument, IntRange) assert isinstance(cmd.argument, IntRange)
assert isinstance(cmd.result, IntRange) assert isinstance(cmd.result, IntRange)
assert cmd.for_export() == {u'datainfo': {'type': 'command', 'argument': {'type': 'int', 'min':-9, 'max':9}, assert cmd.for_export() == {'datainfo': {'type': 'command', 'argument': {'type': 'int', 'min':-9, 'max':9},
u'result': {'type': 'int', 'min':-1, 'max':1}}, 'result': {'type': 'int', 'min':-1, 'max':1}},
u'description': u'do_something'} 'description': 'do_something'}
assert cmd.exportProperties() == {u'datainfo': {'type': 'command', 'argument': {'type': 'int', 'max': 9, 'min': -9}, assert cmd.exportProperties() == {'datainfo': {'type': 'command', 'argument': {'type': 'int', 'max': 9, 'min': -9},
'result': {'type': 'int', 'max': 1, 'min': -1}}, 'result': {'type': 'int', 'max': 1, 'min': -1}},
u'description': u'do_something'} 'description': 'do_something'}
def test_Parameter(): def test_Parameter():

View File

@ -21,7 +21,6 @@
# ***************************************************************************** # *****************************************************************************
"""test data types.""" """test data types."""
from __future__ import division, print_function
from collections import OrderedDict from collections import OrderedDict

View File

@ -20,7 +20,6 @@
# #
# ***************************************************************************** # *****************************************************************************
"""test data types.""" """test data types."""
from __future__ import division, print_function
import pytest import pytest
@ -31,13 +30,13 @@ from secop.properties import Property, Properties, HasProperties
V_test_Property = [ V_test_Property = [
[(StringType(), 'default', 'extname', False, False), [(StringType(), 'default', 'extname', False, False),
dict(default=u'default', extname=u'extname', export=True, mandatory=False)], dict(default='default', extname='extname', export=True, mandatory=False)],
[(IntRange(), '42', '_extname', False, True), [(IntRange(), '42', '_extname', False, True),
dict(default=42, extname=u'_extname', export=True, mandatory=True)], dict(default=42, extname='_extname', export=True, mandatory=True)],
[(IntRange(), '42', '_extname', True, False), [(IntRange(), '42', '_extname', True, False),
dict(default=42, extname=u'_extname', export=True, mandatory=False)], dict(default=42, extname='_extname', export=True, mandatory=False)],
[(IntRange(), 42, '_extname', True, True), [(IntRange(), 42, '_extname', True, True),
dict(default=42, extname=u'_extname', export=True, mandatory=True)], dict(default=42, extname='_extname', export=True, mandatory=True)],
[(IntRange(), 0, '', True, True), [(IntRange(), 0, '', True, True),
dict(default=0, extname='', export=True, mandatory=True)], dict(default=0, extname='', export=True, mandatory=True)],
[(IntRange(), 0, '', True, False), [(IntRange(), 0, '', True, False),
@ -75,7 +74,7 @@ def test_Properties():
p['a'] = Property('', IntRange(), '42', export=True) p['a'] = Property('', IntRange(), '42', export=True)
assert p['a'].default == 42 assert p['a'].default == 42
assert p['a'].export is True assert p['a'].export is True
assert p['a'].extname == u'_a' assert p['a'].extname == '_a'
with pytest.raises(ProgrammingError): with pytest.raises(ProgrammingError):
p['a'] = 137 p['a'] = 137
with pytest.raises(ProgrammingError): with pytest.raises(ProgrammingError):

View File

@ -1,4 +1,3 @@
from __future__ import division, print_function
def test_assert(): def test_assert():