From f911f1be9b07d0489f4e51c8d39e277c552ed9ae Mon Sep 17 00:00:00 2001 From: cliechti Date: Wed, 16 Oct 2013 02:57:27 +0000 Subject: Ensure working with bytes in write() calls. to_bytes() extended to handle bytes and memoryview instaces git-svn-id: http://svn.code.sf.net/p/pyserial/code/trunk/pyserial@479 f19166aa-fa4f-0410-85c2-fa1106f25c8a --- CHANGES.txt | 1 + serial/rfc2217.py | 2 +- serial/serialposix.py | 4 ++-- serial/serialutil.py | 33 +++++++++++++++++++++++++++------ serial/serialwin32.py | 2 +- serial/urlhandler/protocol_loop.py | 2 +- serial/urlhandler/protocol_socket.py | 2 +- test/test_iolib.py | 3 ++- 8 files changed, 36 insertions(+), 13 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 16def23..c749814 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -446,6 +446,7 @@ Version 2.7 2012-nn-nn - Posix: [Patch pyserial:28] Accept any speed on Linux - Posix: [Patch pyserial:29] PosixSerial.read() should "ignore" errno.EINTR - OSX: [Patch pyserial:27] Scan by VendorID/Product ID for USB Serial devices +- Ensure working with bytes in write() calls Bugfixes: diff --git a/serial/rfc2217.py b/serial/rfc2217.py index fa9e07a..2012ea7 100644 --- a/serial/rfc2217.py +++ b/serial/rfc2217.py @@ -592,7 +592,7 @@ class RFC2217Serial(SerialBase): self._write_lock.acquire() try: try: - self._socket.sendall(data.replace(IAC, IAC_DOUBLED)) + self._socket.sendall(to_bytes(data).replace(IAC, IAC_DOUBLED)) except socket.error, e: raise SerialException("connection failed (socket error): %s" % e) # XXX what exception if socket connection fails finally: diff --git a/serial/serialposix.py b/serial/serialposix.py index fa5c999..ce1ff21 100644 --- a/serial/serialposix.py +++ b/serial/serialposix.py @@ -488,8 +488,8 @@ class PosixSerial(SerialBase): def write(self, data): """Output the given string over the serial port.""" if not self._isOpen: raise portNotOpenError - tx_len = len(data) - d = data + d = to_bytes(data) + tx_len = len(d) if self._writeTimeout is not None and self._writeTimeout > 0: timeout = time.time() + self._writeTimeout else: diff --git a/serial/serialutil.py b/serial/serialutil.py index a8f0716..f575963 100644 --- a/serial/serialutil.py +++ b/serial/serialutil.py @@ -46,14 +46,35 @@ except (NameError, AttributeError): other = bytearray(other) return list.__eq__(self, other) -# all Python versions prior 3.x convert str([17]) to '[17]' instead of '\x11' -# so a simple bytes(sequence) doesn't work for all versions +# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)`` +# isn't returning the contents (very unfortunate). Therefore we need special +# cases and test for it. Ensure that there is a ``memoryview`` object for older +# Python versions. This is easier than making every test dependent on its +# existence. +try: + memoryview +except (NameError, AttributeError): + # implementation does not matter as we do not realy use it. + # it just must not inherit from something else we might care for. + class memoryview: + pass + + +# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11' +# so a simple ``bytes(sequence)`` doesn't work for all versions def to_bytes(seq): """convert a sequence to a bytes type""" - b = bytearray() - for item in seq: - b.append(item) # this one handles int and str - return bytes(b) + if isinstance(seq, bytes): + return seq + elif isinstance(seq, bytearray): + return bytes(seq) + elif isinstance(seq, memoryview): + return seq.tobytes() + else: + b = bytearray() + for item in seq: + b.append(item) # this one handles int and str + return bytes(b) # create control bytes XON = to_bytes([17]) diff --git a/serial/serialwin32.py b/serial/serialwin32.py index 6264bab..dfdd953 100644 --- a/serial/serialwin32.py +++ b/serial/serialwin32.py @@ -280,7 +280,7 @@ class Win32Serial(SerialBase): #~ if not isinstance(data, (bytes, bytearray)): #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) # convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview - data = bytes(data) + data = to_bytes(data) if data: #~ win32event.ResetEvent(self._overlappedWrite.hEvent) n = win32.DWORD() diff --git a/serial/urlhandler/protocol_loop.py b/serial/urlhandler/protocol_loop.py index e6b3ebd..7da94ad 100644 --- a/serial/urlhandler/protocol_loop.py +++ b/serial/urlhandler/protocol_loop.py @@ -145,7 +145,7 @@ class LoopbackSerial(SerialBase): closed.""" if not self._isOpen: raise portNotOpenError # ensure we're working with bytes - data = bytes(data) + data = to_bytes(data) # calculate aprox time that would be used to send the data time_used_to_send = 10.0*len(data) / self._baudrate # when a write timeout is configured check if we would be successful diff --git a/serial/urlhandler/protocol_socket.py b/serial/urlhandler/protocol_socket.py index 58eddd1..c90a8e4 100644 --- a/serial/urlhandler/protocol_socket.py +++ b/serial/urlhandler/protocol_socket.py @@ -168,7 +168,7 @@ class SocketSerial(SerialBase): closed.""" if not self._isOpen: raise portNotOpenError try: - self._socket.sendall(data) + self._socket.sendall(to_bytes(data)) except socket.error, e: # XXX what exception if socket connection fails raise SerialException("socket connection failed: %s" % e) diff --git a/test/test_iolib.py b/test/test_iolib.py index 8342b40..8d76e45 100644 --- a/test/test_iolib.py +++ b/test/test_iolib.py @@ -56,6 +56,7 @@ class Test_SerialAndIO(unittest.TestCase): def setUp(self): self.s = serial.serial_for_url(PORT, timeout=1) + #~ self.io = io.TextIOWrapper(self.s) self.io = io.TextIOWrapper(io.BufferedRWPair(self.s, self.s)) def tearDown(self): @@ -67,7 +68,7 @@ class Test_SerialAndIO(unittest.TestCase): hello = self.io.readline() self.failUnlessEqual(hello, unicode("hello\n")) - +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if __name__ == '__main__': import sys sys.stdout.write(__doc__) -- cgit v1.2.1