migrated secop_psi drivers to new syntax
- includes all changes up to 'fix inheritance order' from git_mlz
6a32ecf342
Change-Id: Ie3ceee3dbd0a9284b47b1d5b5dbe262eebe8f283
This commit is contained in:
@@ -21,13 +21,13 @@
|
||||
# *****************************************************************************
|
||||
"""Define helpers"""
|
||||
|
||||
import importlib
|
||||
import linecache
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import importlib
|
||||
from os import path, environ
|
||||
from os import environ, path
|
||||
|
||||
repodir = path.abspath(path.join(path.dirname(__file__), '..', '..'))
|
||||
|
||||
@@ -58,6 +58,7 @@ CONFIG['basedir'] = repodir
|
||||
|
||||
unset_value = object()
|
||||
|
||||
|
||||
class lazy_property:
|
||||
"""A property that calculates its value only once."""
|
||||
|
||||
|
||||
@@ -28,16 +28,18 @@ support for asynchronous communication, but may be used also for
|
||||
synchronous IO (see secop.stringio.StringIO)
|
||||
"""
|
||||
|
||||
import socket
|
||||
import select
|
||||
import time
|
||||
import ast
|
||||
import select
|
||||
import socket
|
||||
import time
|
||||
|
||||
from secop.errors import CommunicationFailedError, ConfigError
|
||||
from secop.lib import closeSocket, parseHostPort, tcpSocket
|
||||
|
||||
try:
|
||||
from serial import Serial
|
||||
except ImportError:
|
||||
Serial = None
|
||||
from secop.lib import parseHostPort, tcpSocket, closeSocket
|
||||
from secop.errors import ConfigError, CommunicationFailedError
|
||||
|
||||
|
||||
class ConnectionClosed(ConnectionError):
|
||||
@@ -60,10 +62,10 @@ class AsynConn:
|
||||
except (ValueError, TypeError, AssertionError):
|
||||
if 'COM' in uri:
|
||||
raise ValueError("the correct uri for a COM port is: "
|
||||
"'serial://COM<i>[?<option>=<value>[+<option>=value ...]]'" )
|
||||
"'serial://COM<i>[?<option>=<value>[+<option>=value ...]]'")
|
||||
if '/dev' in uri:
|
||||
raise ValueError("the correct uri for a serial port is: "
|
||||
"'serial:///dev/<tty>[?<option>=<value>[+<option>=value ...]]'" )
|
||||
"'serial:///dev/<tty>[?<option>=<value>[+<option>=value ...]]'")
|
||||
raise ValueError('invalid uri: %s' % uri)
|
||||
iocls = cls.SCHEME_MAP['tcp']
|
||||
uri = 'tcp://%s:%d' % host_port
|
||||
|
||||
@@ -20,57 +20,168 @@
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from inspect import cleandoc
|
||||
from textwrap import indent
|
||||
|
||||
from secop.modules import Command, HasProperties, Module, Parameter, Property
|
||||
|
||||
|
||||
def indent_description(p):
|
||||
"""indent lines except first one"""
|
||||
return indent(p.description, ' ').replace(' ', '', 1)
|
||||
return indent(p.description, ' ').replace(' ', '', 1)
|
||||
|
||||
|
||||
def append_to_doc(cls, name, title, attrname, newitems, fmtfunc):
|
||||
def fmt_param(name, param):
|
||||
desc = indent_description(param)
|
||||
if '(' in desc[0:2]:
|
||||
dtinfo = ''
|
||||
else:
|
||||
dtinfo = [short_doc(param.datatype), 'rd' if param.readonly else 'wr',
|
||||
None if param.export else 'hidden']
|
||||
dtinfo = '*(%s)* ' % ', '.join(filter(None, dtinfo))
|
||||
return '- **%s** - %s%s\n' % (name, dtinfo, desc)
|
||||
|
||||
|
||||
def fmt_command(name, command):
|
||||
desc = indent_description(command)
|
||||
if '(' in desc[0:2]:
|
||||
dtinfo = '' # note: we expect that desc contains argument list
|
||||
else:
|
||||
dtinfo = '*%s*' % short_doc(command.datatype) + ' -%s ' % ('' if command.export else ' *(hidden)*')
|
||||
return '- **%s**\\ %s%s\n' % (name, dtinfo, desc)
|
||||
|
||||
|
||||
def fmt_property(name, prop):
|
||||
desc = indent_description(prop)
|
||||
if '(' in desc[0:2]:
|
||||
dtinfo = ''
|
||||
else:
|
||||
dtinfo = [short_doc(prop.datatype), None if prop.export else 'hidden']
|
||||
dtinfo = ', '.join(filter(None, dtinfo))
|
||||
if dtinfo:
|
||||
dtinfo = '*(%s)* ' % dtinfo
|
||||
return '- **%s** - %s%s\n' % (name, dtinfo, desc)
|
||||
|
||||
|
||||
SIMPLETYPES = {
|
||||
'FloatRange': 'float',
|
||||
'ScaledInteger': 'float',
|
||||
'IntRange': 'int',
|
||||
'BlobType': 'bytes',
|
||||
'StringType': 'str',
|
||||
'TextType': 'str',
|
||||
'BoolType': 'bool',
|
||||
'StructOf': 'dict',
|
||||
}
|
||||
|
||||
|
||||
def short_doc(datatype):
|
||||
# pylint: disable=possibly-unused-variable
|
||||
|
||||
def doc_EnumType(dt):
|
||||
return 'one of %s' % str(tuple(dt._enum.keys()))
|
||||
|
||||
def doc_ArrayOf(dt):
|
||||
return 'array of %s' % short_doc(dt.members)
|
||||
|
||||
def doc_TupleOf(dt):
|
||||
return 'tuple of (%s)' % ', '.join(short_doc(m) for m in dt.members)
|
||||
|
||||
def doc_CommandType(dt):
|
||||
argument = short_doc(dt.argument) if dt.argument else ''
|
||||
result = ' -> %s' % short_doc(dt.result) if dt.result else ''
|
||||
return '(%s)%s' % (argument, result) # return argument list only
|
||||
|
||||
def doc_NoneOr(dt):
|
||||
other = short_doc(dt.other)
|
||||
return '%s or None' % other if other else None
|
||||
|
||||
def doc_OrType(dt):
|
||||
types = [short_doc(t) for t in dt.types]
|
||||
if None in types: # type is anyway broad: no doc
|
||||
return None
|
||||
return ' or '.join(types)
|
||||
|
||||
def doc_Stub(dt):
|
||||
return dt.name.replace('Type', '').replace('Range', '').lower()
|
||||
|
||||
clsname = datatype.__class__.__name__
|
||||
result = SIMPLETYPES.get(clsname)
|
||||
if result:
|
||||
return result
|
||||
fun = locals().get('doc_' + clsname)
|
||||
if fun:
|
||||
return fun(datatype)
|
||||
return None # broad type like ValueType: no doc
|
||||
|
||||
|
||||
def append_to_doc(cls, lines, itemcls, name, attrname, fmtfunc):
|
||||
"""add information about some items to the doc
|
||||
|
||||
:param cls: the class with the doc string to be extended
|
||||
:param name: the name of the attribute dict to be used
|
||||
:param title: the title to be used
|
||||
:param newitems: the set of new items defined for this class
|
||||
:param lines: content of the docstring, as lines
|
||||
:param itemcls: the class of the attribute to be collected, a tuple of classes is also allowed.
|
||||
:param attrname: the name of the attribute dict to look for
|
||||
:param name: the name of the items to be collected (used for the title and for the tags)
|
||||
:param fmtfunc: a function returning a formatted item to be displayed, including line feed at end
|
||||
or an empty string to suppress output for this item
|
||||
:type fmtfunc: function(key, value)
|
||||
|
||||
rules, assuming name='properties':
|
||||
|
||||
- if the docstring contains ``{properties}``, new properties are inserted here
|
||||
- if the docstring contains ``{all properties}``, all properties are inserted here
|
||||
- if the docstring contains ``{no properties}``, no properties are inserted
|
||||
|
||||
only the first appearance of a tag above is considered
|
||||
"""
|
||||
doc = cleandoc(cls.__doc__ or '')
|
||||
doc = '\n'.join(lines)
|
||||
title = 'SECoP %s' % name.title()
|
||||
allitems = getattr(cls, attrname, {})
|
||||
fmtdict = {n: fmtfunc(n, p) or ' - **%s** *removed*\n' % n for n, p in allitems.items()}
|
||||
fmtdict = {n: fmtfunc(n, p) for n, p in allitems.items() if isinstance(p, itemcls)}
|
||||
head, _, tail = doc.partition('{all %s}' % name)
|
||||
clsset = set()
|
||||
if tail: # take all
|
||||
inherited = set()
|
||||
fmted = ''.join(fmtdict.values())
|
||||
fmted = fmtdict.values()
|
||||
else:
|
||||
inherited = {n: p for n, p in allitems.items() if fmtdict.get(n) and n not in newitems}
|
||||
fmted = ''.join(' ' + v for k, v in fmtdict.items() if k in newitems)
|
||||
head, _, tail = doc.partition('{%s}' % name)
|
||||
if not tail:
|
||||
head, _, tail = doc.partition('{no %s}' % name)
|
||||
if tail: # add no information
|
||||
return
|
||||
# no tag found: append to the end
|
||||
if fmted:
|
||||
clsset = set()
|
||||
for name in inherited:
|
||||
p = allitems[name]
|
||||
refcls = cls
|
||||
|
||||
fmted = []
|
||||
for key, formatted_item in fmtdict.items():
|
||||
if not formatted_item:
|
||||
continue
|
||||
# find where item is defined or modified
|
||||
refcls = None
|
||||
for base in cls.__mro__:
|
||||
dp = getattr(base, attrname, {}).get(name)
|
||||
if dp:
|
||||
if dp == p:
|
||||
p = getattr(base, attrname, {}).get(key)
|
||||
if isinstance(p, itemcls):
|
||||
if fmtfunc(key, p) == formatted_item:
|
||||
refcls = base
|
||||
else:
|
||||
break
|
||||
clsset.add(refcls)
|
||||
clsset.discard(cls)
|
||||
if refcls == cls:
|
||||
# definition in cls is new or modified
|
||||
fmted.append(formatted_item)
|
||||
else:
|
||||
# definition of last modification in refcls
|
||||
clsset.add(refcls)
|
||||
if fmted:
|
||||
if clsset:
|
||||
fmted += ' - see also %s\n' % (', '.join(':class:`%s.%s`' % (c.__module__, c.__name__)
|
||||
for c in cls.__mro__ if c in clsset))
|
||||
cls.__doc__ = '%s\n\n:%s: %s\n%s' % (head, title, fmted, tail)
|
||||
fmted.append('- see also %s\n' % (', '.join(':class:`%s.%s`' % (c.__module__, c.__name__)
|
||||
for c in cls.__mro__ if c in clsset)))
|
||||
|
||||
doc = '%s\n\n:%s: %s\n\n%s' % (head, title, ' '.join(fmted), tail)
|
||||
lines[:] = doc.split('\n')
|
||||
|
||||
|
||||
def class_doc_handler(app, what, name, cls, options, lines):
|
||||
if what == 'class':
|
||||
if issubclass(cls, HasProperties):
|
||||
append_to_doc(cls, lines, Property, 'properties', 'propertyDict', fmt_property)
|
||||
if issubclass(cls, Module):
|
||||
append_to_doc(cls, lines, Parameter, 'parameters', 'accessibles', fmt_param)
|
||||
append_to_doc(cls, lines, Command, 'commands', 'accessibles', fmt_command)
|
||||
|
||||
@@ -32,6 +32,7 @@ class EnumMember:
|
||||
has an int-type value and attributes 'name' and 'value'
|
||||
"""
|
||||
__slots__ = ['name', 'value', 'enum']
|
||||
|
||||
def __init__(self, enum, name, value):
|
||||
if not isinstance(enum, Enum):
|
||||
raise TypeError('1st Argument must be an instance of class Enum()')
|
||||
@@ -49,7 +50,7 @@ class EnumMember:
|
||||
try:
|
||||
other = int(other)
|
||||
except Exception:
|
||||
#raise TypeError('%r can not be compared to %r!' %(other, self))
|
||||
# raise TypeError('%r can not be compared to %r!' %(other, self))
|
||||
return -1 # XXX:!
|
||||
if self.value < other:
|
||||
return -1
|
||||
@@ -59,10 +60,12 @@ class EnumMember:
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.__cmp__(other.value if isinstance(other, EnumMember) else other) == -1
|
||||
|
||||
def __le__(self, other):
|
||||
return self.__cmp__(other.value if isinstance(other, EnumMember) else other) < 1
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, (EnumMember)):
|
||||
if isinstance(other, EnumMember):
|
||||
return other.value == self.value
|
||||
if isinstance(other, int):
|
||||
return other == self.value
|
||||
@@ -72,10 +75,13 @@ class EnumMember:
|
||||
return self.name == other
|
||||
return False
|
||||
return self.__cmp__(other.value if isinstance(other, EnumMember) else other) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.__cmp__(other.value if isinstance(other, EnumMember) else other) > -1
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.__cmp__(other.value if isinstance(other, EnumMember) else other) == 1
|
||||
|
||||
@@ -100,77 +106,105 @@ class EnumMember:
|
||||
def __repr__(self):
|
||||
return '<%s%s (%d)>' % (self.enum.name + '.' if self.enum.name else '', self.name, self.value)
|
||||
|
||||
|
||||
# numeric operations: delegate to int. Do we really need any of those?
|
||||
def __add__(self, other):
|
||||
return self.value.__add__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __sub__(self, other):
|
||||
return self.value.__sub__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __mul__(self, other):
|
||||
return self.value.__mul__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __truediv__(self, other):
|
||||
return self.value.__truediv__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
return self.value.__floordiv__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __mod__(self, other):
|
||||
return self.value.__mod__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __divmod__(self, other):
|
||||
return self.value.__divmod__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __pow__(self, other, *args):
|
||||
return self.value.__pow__(other, *args)
|
||||
|
||||
def __lshift__(self, other):
|
||||
return self.value.__lshift__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rshift__(self, other):
|
||||
return self.value.__rshift__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __radd__(self, other):
|
||||
return self.value.__radd__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rsub__(self, other):
|
||||
return self.value.__rsub__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rmul__(self, other):
|
||||
return self.value.__rmul__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rtruediv__(self, other):
|
||||
return self.value.__rtruediv__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rfloordiv__(self, other):
|
||||
return self.value.__rfloordiv__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rmod__(self, other):
|
||||
return self.value.__rmod__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rdivmod__(self, other):
|
||||
return self.value.__rdivmod__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rpow__(self, other, *args):
|
||||
return self.value.__rpow__(other, *args)
|
||||
|
||||
def __rlshift__(self, other):
|
||||
return self.value.__rlshift__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rrshift__(self, other):
|
||||
return self.value.__rrshift__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
# logical operations
|
||||
def __and__(self, other):
|
||||
return self.value.__and__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __xor__(self, other):
|
||||
return self.value.__xor__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __or__(self, other):
|
||||
return self.value.__or__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rand__(self, other):
|
||||
return self.value.__rand__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __rxor__(self, other):
|
||||
return self.value.__rxor__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
def __ror__(self, other):
|
||||
return self.value.__ror__(other.value if isinstance(other, EnumMember) else other)
|
||||
|
||||
# other stuff
|
||||
def __neg__(self):
|
||||
return self.value.__neg__()
|
||||
|
||||
def __pos__(self):
|
||||
return self.value.__pos__()
|
||||
|
||||
def __abs__(self):
|
||||
return self.value.__abs__()
|
||||
|
||||
def __invert__(self):
|
||||
return self.value.__invert__()
|
||||
|
||||
def __int__(self):
|
||||
return self.value.__int__()
|
||||
|
||||
def __float__(self):
|
||||
return self.value.__float__()
|
||||
#return NotImplemented # makes no sense
|
||||
|
||||
def __index__(self):
|
||||
return self.value.__index__()
|
||||
|
||||
@@ -206,6 +240,7 @@ class Enum(dict):
|
||||
You only can create an extended Enum.
|
||||
"""
|
||||
name = ''
|
||||
|
||||
def __init__(self, name='', parent=None, **kwds):
|
||||
super(Enum, self).__init__()
|
||||
if isinstance(name, (dict, Enum)) and parent is None:
|
||||
@@ -217,7 +252,7 @@ class Enum(dict):
|
||||
# if name was not given, use that of the parent
|
||||
# this means, an extended Enum behaves like the parent
|
||||
# THIS MAY BE CONFUSING SOMETIMES!
|
||||
name=parent.name
|
||||
name = parent.name
|
||||
# else:
|
||||
# raise TypeError('Enum instances need a name or an Enum parent!')
|
||||
if not isinstance(name, str):
|
||||
@@ -225,8 +260,9 @@ class Enum(dict):
|
||||
|
||||
names = set()
|
||||
values = set()
|
||||
|
||||
# pylint: disable=dangerous-default-value
|
||||
def add(self, k, v, names = names, value = values):
|
||||
def add(self, k, v, names=names, value=values):
|
||||
"""helper for creating the enum members"""
|
||||
if v is None:
|
||||
# sugar: take the next free number if value was None
|
||||
@@ -237,7 +273,7 @@ class Enum(dict):
|
||||
if v in names:
|
||||
v = self[v].value
|
||||
while v in values:
|
||||
v +=1
|
||||
v += 1
|
||||
|
||||
# check that the value is an int
|
||||
_v = int(v)
|
||||
@@ -290,7 +326,6 @@ class Enum(dict):
|
||||
|
||||
def __repr__(self):
|
||||
return 'Enum(%r, %s)' % (self.name, ', '.join('%s=%d' % (m.name, m.value) for m in self.members))
|
||||
# return '<Enum %r (%d values)>' % (self.name, len(self)//2)
|
||||
|
||||
def __call__(self, key):
|
||||
return self[key]
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
# *****************************************************************************
|
||||
"""Define parsing helpers"""
|
||||
|
||||
# TODO: remove, as currently not used
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
@@ -141,7 +141,7 @@ class SequencerMixin:
|
||||
return self.read_hw_status()
|
||||
return self.Status.IDLE, ''
|
||||
|
||||
def do_stop(self):
|
||||
def stop(self):
|
||||
if self.seq_is_alive():
|
||||
self._seq_stopflag = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user