diff --git a/aprslib/IS.py b/aprslib/IS.py index 354f1cf..b2f016b 100644 --- a/aprslib/IS.py +++ b/aprslib/IS.py @@ -24,7 +24,7 @@ import time import logging import sys -from . import __version__, string_type +from . import __version__, string_type, is_py3 from .parsing import parse from .exceptions import ( GenericError, @@ -67,7 +67,15 @@ class IS(object): self.filter = "" # default filter, everything self._connected = False - self.buf = '' + if is_py3: + self.buf = b'' + else: + self.buf = '' + + def _sendall(self, text): + if is_py3: + text = text.encode('utf-8') + self.sock.sendall(text) def set_filter(self, filter_text): """ @@ -78,7 +86,7 @@ class IS(object): self.logger.info("Setting filter to: %s", self.filter) if self._connected: - self.sock.sendall("#filter %s\r\n" % self.filter) + self._sendall("#filter %s\r\n" % self.filter) def set_login(self, callsign, passwd): """ @@ -122,7 +130,10 @@ class IS(object): """ self._connected = False - self.buf = '' + if is_py3: + self.buf = b'' + else: + self.buf = '' if self.sock is not None: self.sock.close() @@ -144,7 +155,7 @@ class IS(object): try: self.sock.setblocking(1) self.sock.settimeout(5) - self.sock.sendall(line) + self._sendall(line) except socket.error as exp: self.close() raise ConnectionError(str(exp)) @@ -239,6 +250,8 @@ class IS(object): # pylint: enable=E1103 banner = self.sock.recv(512) + if is_py3: + banner = banner.decode('latin-1') if banner[0] == "#": self.logger.debug("Banner: %s", banner.rstrip()) @@ -273,9 +286,12 @@ class IS(object): self.logger.info("Sending login information") try: - self.sock.sendall(login_str) + self._sendall(login_str) self.sock.settimeout(5) - test = self.sock.recv(len(login_str) + 100).rstrip() + test = self.sock.recv(len(login_str) + 100) + if is_py3: + test = test.decode('latin-1') + test = test.rstrip() self.logger.debug("Server: %s", test) @@ -310,7 +326,12 @@ class IS(object): raise ConnectionDrop("connection dropped") while True: - short_buf = '' + if is_py3: + short_buf = b'' + newline = b'\r\n' + else: + short_buf = '' + newline = '\r\n' select.select([self.sock], [], [], None if blocking else 0) @@ -328,7 +349,7 @@ class IS(object): self.buf += short_buf - while "\r\n" in self.buf: - line, self.buf = self.buf.split("\r\n", 1) + while newline in self.buf: + line, self.buf = self.buf.split(newline, 1) yield line diff --git a/tests/test_IS.py b/tests/test_IS.py index 5309d12..ee258ce 100644 --- a/tests/test_IS.py +++ b/tests/test_IS.py @@ -7,6 +7,14 @@ import aprslib from mox3 import mox +# byte shim for testing in both py2 and py3 +def _b(text): + if sys.version_info[0] >= 3: + return text.encode('latin-1') + else: + return text + + class TC_IS(unittest.TestCase): def setUp(self): self.ais = aprslib.IS("LZ1DEV-99", "testpwd", "127.0.0.1", "11111") @@ -17,7 +25,7 @@ class TC_IS(unittest.TestCase): def test_initilization(self): self.assertFalse(self.ais._connected) - self.assertEqual(self.ais.buf, '') + self.assertEqual(self.ais.buf, _b('')) self.assertIsNone(self.ais.sock) self.assertEqual(self.ais.callsign, "LZ1DEV-99") self.assertEqual(self.ais.passwd, "testpwd") @@ -25,16 +33,15 @@ class TC_IS(unittest.TestCase): def test_close(self): self.ais._connected = True - s = mox.MockAnything() - s.close() - self.ais.sock = s - mox.Replay(s) + self.ais.sock = mox.MockAnything() + self.ais.sock.close() + mox.Replay(self.ais.sock) self.ais.close() - mox.Verify(s) + mox.Verify(self.ais.sock) self.assertFalse(self.ais._connected) - self.assertEqual(self.ais.buf, '') + self.assertEqual(self.ais.buf, _b('')) def test_open_socket(self): with self.assertRaises(socket.error): @@ -53,7 +60,7 @@ class TC_IS(unittest.TestCase): # part 2 - conn drop trying to recv self.ais.sock.setblocking(0) self.ais.sock.fileno().AndReturn(fdr) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn('') + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b('')) # part 3 - nothing to read self.ais.sock.setblocking(0) self.ais.sock.fileno().AndReturn(fdr) @@ -62,16 +69,16 @@ class TC_IS(unittest.TestCase): # part 4 - yield 3 lines (blocking False) self.ais.sock.setblocking(0) self.ais.sock.fileno().AndReturn(fdr) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("a\r\n"*3) + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("a\r\n"*3)) self.ais.sock.fileno().AndReturn(fdr) self.ais.sock.recv(mox.IgnoreArg()).AndRaise( socket.error("Resource temporarily unavailable")) # part 5 - yield 3 lines 2 times (blocking True) self.ais.sock.setblocking(0) self.ais.sock.fileno().AndReturn(fdr) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("b\r\n"*3) + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("b\r\n"*3)) self.ais.sock.fileno().AndReturn(fdr) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("b\r\n"*3) + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("b\r\n"*3)) self.ais.sock.fileno().AndReturn(fdr) self.ais.sock.recv(mox.IgnoreArg()).AndRaise(StopIteration) mox.Replay(self.ais.sock) @@ -89,44 +96,45 @@ class TC_IS(unittest.TestCase): getattr(self.ais._socket_readlines(), next_method)() # part 4 for line in self.ais._socket_readlines(): - self.assertEqual(line, 'a') + self.assertEqual(line, _b('a')) # part 5 for line in self.ais._socket_readlines(blocking=True): - self.assertEqual(line, 'b') + self.assertEqual(line, _b('b')) mox.Verify(self.ais.sock) def test_send_login(self): self.ais.sock = mox.MockAnything() self.m.StubOutWithMock(self.ais, "close") + self.m.StubOutWithMock(self.ais, "_sendall") # part 1 - raises - self.ais.sock.sendall(mox.IgnoreArg()) + self.ais._sendall(mox.IgnoreArg()) self.ais.sock.settimeout(mox.IgnoreArg()) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("invalidreply") + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("invalidreply")) self.ais.close() # part 2 - raises (empty callsign) - self.ais.sock.sendall(mox.IgnoreArg()) + self.ais._sendall(mox.IgnoreArg()) self.ais.sock.settimeout(mox.IgnoreArg()) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("# logresp verified, xx") + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("# logresp verified, xx")) self.ais.close() # part 3 - raises (callsign doesn't match - self.ais.sock.sendall(mox.IgnoreArg()) + self.ais._sendall(mox.IgnoreArg()) self.ais.sock.settimeout(mox.IgnoreArg()) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("# logresp NOMATCH verified, xx") + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("# logresp NOMATCH verified, xx")) self.ais.close() # part 4 - raises (unverified, but pass is not -1) - self.ais.sock.sendall(mox.IgnoreArg()) + self.ais._sendall(mox.IgnoreArg()) self.ais.sock.settimeout(mox.IgnoreArg()) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("# logresp CALL unverified, xx") + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("# logresp CALL unverified, xx")) self.ais.close() # part 5 - normal, receive only - self.ais.sock.sendall(mox.IgnoreArg()) + self.ais._sendall(mox.IgnoreArg()) self.ais.sock.settimeout(mox.IgnoreArg()) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("# logresp CALL unverified, xx") + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("# logresp CALL unverified, xx")) # part 6 - normal, correct pass - self.ais.sock.sendall(mox.IgnoreArg()) + self.ais._sendall(mox.IgnoreArg()) self.ais.sock.settimeout(mox.IgnoreArg()) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("# logresp CALL verified, xx") + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("# logresp CALL verified, xx")) mox.Replay(self.ais.sock) self.m.ReplayAll() @@ -171,7 +179,7 @@ class TC_IS(unittest.TestCase): self.ais.sock.setsockopt(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) self.ais.sock.setsockopt(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) self.ais.sock.setsockopt(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("junk") + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("junk")) self.ais.close() # part 3 - everything going well self.ais._open_socket() @@ -183,7 +191,7 @@ class TC_IS(unittest.TestCase): self.ais.sock.setsockopt(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) self.ais.sock.setsockopt(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) self.ais.sock.setsockopt(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) - self.ais.sock.recv(mox.IgnoreArg()).AndReturn("# server banner") + self.ais.sock.recv(mox.IgnoreArg()).AndReturn(_b("# server banner")) mox.Replay(self.ais.sock) self.m.ReplayAll() @@ -206,15 +214,14 @@ class TC_IS(unittest.TestCase): testFilter = "x/CALLSIGN" self.ais._connected = True - s = mox.MockAnything() - s.sendall("#filter %s\r\n" % testFilter) - self.ais.sock = s - mox.Replay(s) + self.ais.sock = mox.MockAnything() + self.ais.sock.sendall(_b("#filter %s\r\n" % testFilter)) + mox.Replay(self.ais.sock) self.ais.set_filter(testFilter) self.assertEqual(self.ais.filter, testFilter) - mox.Verify(s) + mox.Verify(self.ais.sock) def test_connect_from_notconnected(self): self.m.StubOutWithMock(self.ais, "_connect") @@ -301,6 +308,7 @@ class TC_IS(unittest.TestCase): def test_sendall_passing_to_socket(self): self.ais.sock = mox.MockAnything() self.m.StubOutWithMock(self.ais, "close") + self.m.StubOutWithMock(self.ais, "_sendall") # rest _unicode = str if sys.version_info[0] >= 3 else unicode @@ -316,7 +324,7 @@ class TC_IS(unittest.TestCase): self.ais.sock = mox.MockAnything() self.ais.sock.setblocking(mox.IgnoreArg()) self.ais.sock.settimeout(mox.IgnoreArg()) - self.ais.sock.sendall("%s\r\n" % str(line).rstrip('\r\n')).AndReturn(None) + self.ais._sendall(_b("%s\r\n" % str(line).rstrip('\r\n'))).AndReturn(None) mox.Replay(self.ais.sock) self.ais.sendall(line)