diff --git a/mopidy/utils/network.py b/mopidy/utils/network.py index b7cc144d..9a02035b 100644 --- a/mopidy/utils/network.py +++ b/mopidy/utils/network.py @@ -278,9 +278,13 @@ class LineProtocol(ThreadingActor): then splitting data along line boundaries. """ - #: What terminator to use to split lines. + #: Line terinator to use for outputed lines. terminator = '\n' + #: Regex to use for splitings lines, will be set compiled version of its + #: own value, or to `terminator`s value if it is not set itself. + delimeter = None + #: What encoding to expect incomming data to be in, can be :class:`None`. encoding = 'utf-8' @@ -288,6 +292,11 @@ class LineProtocol(ThreadingActor): self.connection = connection self.recv_buffer = '' + if self.delimeter: + self.delimeter = re.compile(self.delimeter) + else: + self.delimeter = re.compile(self.terminator) + @property def host(self): return self.connection.host @@ -325,7 +334,7 @@ class LineProtocol(ThreadingActor): def parse_lines(self): """Consume new data and yield any lines found.""" while re.search(self.terminator, self.recv_buffer): - line, self.recv_buffer = re.split(self.terminator, + line, self.recv_buffer = self.delimeter.split( self.recv_buffer, 1) yield line diff --git a/tests/utils/network/lineprotocol_test.py b/tests/utils/network/lineprotocol_test.py index a87f461c..57b78417 100644 --- a/tests/utils/network/lineprotocol_test.py +++ b/tests/utils/network/lineprotocol_test.py @@ -1,5 +1,6 @@ #encoding: utf-8 +import re import unittest from mopidy.utils import network @@ -11,11 +12,21 @@ class LineProtocolTest(unittest.TestCase): self.mock = Mock(spec=network.LineProtocol) self.mock.terminator = network.LineProtocol.terminator self.mock.encoding = network.LineProtocol.encoding + self.mock.delimeter = network.LineProtocol.delimeter def test_init_stores_values_in_attributes(self): + delimeter = re.compile(network.LineProtocol.terminator) network.LineProtocol.__init__(self.mock, sentinel.connection) self.assertEqual(sentinel.connection, self.mock.connection) self.assertEqual('', self.mock.recv_buffer) + self.assertEqual(delimeter, self.mock.delimeter) + + def test_init_compiles_delimeter(self): + self.mock.delimeter = '\r?\n' + delimeter = re.compile('\r?\n') + + network.LineProtocol.__init__(self.mock, sentinel.connection) + self.assertEqual(delimeter, self.mock.delimeter) def test_on_receive_no_new_lines_adds_to_recv_buffer(self): self.mock.connection = Mock(spec=network.Connection) @@ -74,18 +85,21 @@ class LineProtocolTest(unittest.TestCase): self.assertEqual(2, self.mock.on_line_received.call_count) def test_parse_lines_emtpy_buffer(self): + self.mock.delimeter = re.compile(r'\n') self.mock.recv_buffer = '' lines = network.LineProtocol.parse_lines(self.mock) self.assertRaises(StopIteration, lines.next) def test_parse_lines_no_terminator(self): + self.mock.delimeter = re.compile(r'\n') self.mock.recv_buffer = 'data' lines = network.LineProtocol.parse_lines(self.mock) self.assertRaises(StopIteration, lines.next) def test_parse_lines_termintor(self): + self.mock.delimeter = re.compile(r'\n') self.mock.recv_buffer = 'data\n' lines = network.LineProtocol.parse_lines(self.mock) @@ -93,7 +107,17 @@ class LineProtocolTest(unittest.TestCase): self.assertRaises(StopIteration, lines.next) self.assertEqual('', self.mock.recv_buffer) + def test_parse_lines_termintor_with_carriage_return(self): + self.mock.delimeter = re.compile(r'\r?\n') + self.mock.recv_buffer = 'data\r\n' + + lines = network.LineProtocol.parse_lines(self.mock) + self.assertEqual('data', lines.next()) + self.assertRaises(StopIteration, lines.next) + self.assertEqual('', self.mock.recv_buffer) + def test_parse_lines_no_data_before_terminator(self): + self.mock.delimeter = re.compile(r'\n') self.mock.recv_buffer = '\n' lines = network.LineProtocol.parse_lines(self.mock) @@ -102,6 +126,7 @@ class LineProtocolTest(unittest.TestCase): self.assertEqual('', self.mock.recv_buffer) def test_parse_lines_extra_data_after_terminator(self): + self.mock.delimeter = re.compile(r'\n') self.mock.recv_buffer = 'data1\ndata2' lines = network.LineProtocol.parse_lines(self.mock) @@ -110,6 +135,7 @@ class LineProtocolTest(unittest.TestCase): self.assertEqual('data2', self.mock.recv_buffer) def test_parse_lines_unicode(self): + self.mock.delimeter = re.compile(r'\n') self.mock.recv_buffer = u'æøå\n'.encode('utf-8') lines = network.LineProtocol.parse_lines(self.mock) @@ -118,6 +144,7 @@ class LineProtocolTest(unittest.TestCase): self.assertEqual('', self.mock.recv_buffer) def test_parse_lines_multiple_lines(self): + self.mock.delimeter = re.compile(r'\n') self.mock.recv_buffer = 'abc\ndef\nghi\njkl' lines = network.LineProtocol.parse_lines(self.mock) @@ -128,6 +155,7 @@ class LineProtocolTest(unittest.TestCase): self.assertEqual('jkl', self.mock.recv_buffer) def test_parse_lines_multiple_calls(self): + self.mock.delimeter = re.compile(r'\n') self.mock.recv_buffer = 'data1' lines = network.LineProtocol.parse_lines(self.mock)