more flexible end_of_line in stringio

in the previous version, it was not possible to give a ASCII nul
character as end_of_line, because StringType refuses this

- end_of_line might be given as bytes, str or int
- end_of_line might be given as tuple (eol_read, eol_write)

Change-Id: I8b7942320ad3ffe162cdf3a673e113a66a84fb93
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/23496
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
zolliker 2020-07-23 16:12:14 +02:00
parent 1655e252fc
commit a520e6e1e4

View File

@ -28,7 +28,7 @@ import threading
import re import re
from secop.lib.asynconn import AsynConn, ConnectionClosed from secop.lib.asynconn import AsynConn, ConnectionClosed
from secop.modules import Module, Communicator, Parameter, Command, Property, Attached from secop.modules import Module, Communicator, Parameter, Command, Property, Attached
from secop.datatypes import StringType, FloatRange, ArrayOf, BoolType, TupleOf from secop.datatypes import StringType, FloatRange, ArrayOf, BoolType, TupleOf, ValueType
from secop.errors import CommunicationFailedError, CommunicationSilentError from secop.errors import CommunicationFailedError, CommunicationSilentError
from secop.poller import REGULAR from secop.poller import REGULAR
from secop.metaclass import Done from secop.metaclass import Done
@ -43,7 +43,7 @@ class StringIO(Communicator):
'uri': 'uri':
Property('hostname:portnumber', datatype=StringType()), Property('hostname:portnumber', datatype=StringType()),
'end_of_line': 'end_of_line':
Property('end_of_line character', datatype=StringType(), Property('end_of_line character', datatype=ValueType(),
default='\n', settable=True), default='\n', settable=True),
'encoding': 'encoding':
Property('used encoding', datatype=StringType(), Property('used encoding', datatype=StringType(),
@ -73,13 +73,32 @@ class StringIO(Communicator):
def earlyInit(self): def earlyInit(self):
self._conn = None self._conn = None
self._lock = threading.RLock() self._lock = threading.RLock()
self._end_of_line = self.end_of_line.encode(self.encoding) eol = self.end_of_line
if isinstance(eol, (tuple, list)):
if len(eol) not in (1, 2):
raise ValueError('invalid end_of_line: %s' % eol)
else:
eol = [eol]
# eol for read and write might be distinct
self._eol_read = self._convert_eol(eol[0])
if not self._eol_read:
raise ValueError('end_of_line for read must not be empty')
self._eol_write = self._convert_eol(eol[-1])
self._last_error = None self._last_error = None
def _convert_eol(self, value):
if isinstance(value, str):
return value.encode(self.encoding)
if isinstance(value, int):
return bytes([value])
if isinstance(value, bytes):
return value
raise ValueError('invalid end_of_line: %s' % repr(value))
def connectStart(self): def connectStart(self):
if not self.is_connected: if not self.is_connected:
uri = self.uri uri = self.uri
self._conn = AsynConn(uri, self._end_of_line) self._conn = AsynConn(uri, self._eol_read)
self.is_connected = True self.is_connected = True
for command, regexp in self.identification: for command, regexp in self.identification:
reply = self.do_communicate(command) reply = self.do_communicate(command)
@ -159,10 +178,10 @@ class StringIO(Communicator):
try: try:
with self._lock: with self._lock:
# read garbage and wait before send # read garbage and wait before send
if self.wait_before: if self.wait_before and self._eol_write:
cmds = command.split(self.end_of_line) cmds = command.encode(self.encoding).split(self._eol_write)
else: else:
cmds = [command] cmds = [command.encode(self.encoding)]
garbage = None garbage = None
try: try:
for cmd in cmds: for cmd in cmds:
@ -171,8 +190,8 @@ class StringIO(Communicator):
if garbage is None: # read garbage only once if garbage is None: # read garbage only once
garbage = self._conn.flush_recv() garbage = self._conn.flush_recv()
if garbage: if garbage:
self.log.debug('garbage: %s', garbage.decode(self.encoding)) self.log.debug('garbage: %r', garbage)
self._conn.send((cmd + self.end_of_line).encode(self.encoding)) self._conn.send(cmd + self._eol_write)
reply = self._conn.readline(self.timeout) reply = self._conn.readline(self.timeout)
except ConnectionClosed: except ConnectionClosed:
self.closeConnection() self.closeConnection()