From bb64b41fa8a02afe2cf20e8b005d232c0eb3be78 Mon Sep 17 00:00:00 2001 From: Emlyn Corrin Date: Sun, 12 Mar 2017 23:20:59 +0000 Subject: [PATCH] Address review comments and add tests --- pythonosc/osc_message.py | 11 +++---- pythonosc/osc_message_builder.py | 17 +++++----- pythonosc/test/test_osc_message.py | 37 +++++++++++++++++++--- pythonosc/test/test_osc_message_builder.py | 6 ++-- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/pythonosc/osc_message.py b/pythonosc/osc_message.py index 3ddc339..eb8b45e 100644 --- a/pythonosc/osc_message.py +++ b/pythonosc/osc_message.py @@ -37,7 +37,6 @@ class OscMessage(object): param_stack = [params] # Parse each parameter given its type. for param in type_tag: - have_val = True if param == "i": # Integer. val, index = osc_types.get_int(self._dgram, index) elif param == "f": # Float. @@ -53,20 +52,18 @@ class OscMessage(object): elif param == "F": # False. val = False elif param == "[": # Array start. - a = [] - param_stack[-1].append(a) - param_stack.append(a) - have_val = False + array = [] + param_stack[-1].append(array) + param_stack.append(array) elif param == "]": # Array stop. if len(param_stack) < 2: raise ParseError('Unexpected closing bracket in type tag: {0}'.format(type_tag)) param_stack.pop() - have_val = False # TODO: Support more exotic types as described in the specification. else: logging.warning('Unhandled parameter type: {0}'.format(param)) continue - if have_val: + if param not in "[]": param_stack[-1].append(val) if len(param_stack) != 1: raise ParseError('Missing closing bracket in type tag: {0}'.format(type_tag)) diff --git a/pythonosc/osc_message_builder.py b/pythonosc/osc_message_builder.py index 22b5ac7..51a2085 100644 --- a/pythonosc/osc_message_builder.py +++ b/pythonosc/osc_message_builder.py @@ -49,12 +49,12 @@ class OscMessageBuilder(object): """Returns the (type, value) arguments list of this message.""" return self._args - def valid_type(self, arg_type): + def _valid_type(self, arg_type): if arg_type in self._SUPPORTED_ARG_TYPES: return True elif isinstance(arg_type, list): - for a in arg_type: - if not self.valid_type(a): + for sub_type in arg_type: + if not self._valid_type(sub_type): return False return True return False @@ -69,11 +69,12 @@ class OscMessageBuilder(object): Raises: - ValueError: if the type is not supported. """ - if arg_type and not self.valid_type(arg_type): + if arg_type and not self._valid_type(arg_type): raise ValueError( - 'arg_type must be one of {}'.format(self._SUPPORTED_ARG_TYPES)) + 'arg_type must be one of {}, or an array of valid types' + .format(self._SUPPORTED_ARG_TYPES)) if not arg_type: - arg_type = self.get_arg_type(arg_value) + arg_type = self._get_arg_type(arg_value) if isinstance(arg_type, list): self._args.append((self.ARG_TYPE_ARRAY_START, None)) for v, t in zip(arg_value, arg_type): @@ -82,7 +83,7 @@ class OscMessageBuilder(object): else: self._args.append((arg_type, arg_value)) - def get_arg_type(self, arg_value): + def _get_arg_type(self, arg_value): """Guess the type of a value. Args: @@ -103,7 +104,7 @@ class OscMessageBuilder(object): elif arg_value == False: arg_type = self.ARG_TYPE_FALSE elif isinstance(arg_value, list): - arg_type = [self.get_arg_type(v) for v in arg_value] + arg_type = [self._get_arg_type(v) for v in arg_value] else: raise ValueError('Infered arg_value type is not supported') return arg_type diff --git a/pythonosc/test/test_osc_message.py b/pythonosc/test/test_osc_message.py index 883e4a1..2c2fa61 100644 --- a/pythonosc/test/test_osc_message.py +++ b/pythonosc/test/test_osc_message.py @@ -31,8 +31,19 @@ _DGRAM_ALL_STANDARD_TYPES_OF_PARAMS = ( _DGRAM_ALL_NON_STANDARD_TYPES_OF_PARAMS = ( b"/SYNC\x00\x00\x00" - b",T" # True - b"F\x00") # False + b",T" # True + b"F" # False + b"[]\x00\x00\x00") # Empty array + +_DGRAM_COMPLEX_ARRAY_PARAMS = ( + b"/SYNC\x00\x00\x00" + b",[i][[ss]][[i][i[s]]]\x00\x00\x00" + b"\x00\x00\x00\x01" # 1 + b"ABC\x00" # "ABC" + b"DEF\x00" # "DEF" + b"\x00\x00\x00\x02" # 2 + b"\x00\x00\x00\x03" # 3 + b"GHI\x00") # "GHI" _DGRAM_UNKNOWN_PARAM_TYPE = ( b"/SYNC\x00\x00\x00" @@ -80,10 +91,20 @@ class TestOscMessage(unittest.TestCase): def test_all_non_standard_params(self): msg = osc_message.OscMessage(_DGRAM_ALL_NON_STANDARD_TYPES_OF_PARAMS) self.assertEqual("/SYNC", msg.address) - self.assertEqual(2, len(msg.params)) + self.assertEqual(3, len(msg.params)) self.assertEqual(True, msg.params[0]) self.assertEqual(False, msg.params[1]) - self.assertEqual(2, len(list(msg))) + self.assertEqual([], msg.params[2]) + self.assertEqual(3, len(list(msg))) + + def test_complex_array_params(self): + msg = osc_message.OscMessage(_DGRAM_COMPLEX_ARRAY_PARAMS) + self.assertEqual("/SYNC", msg.address) + self.assertEqual(3, len(msg.params)) + self.assertEqual([1], msg.params[0]) + self.assertEqual([["ABC", "DEF"]], msg.params[1]) + self.assertEqual([[2],[3, ["GHI"]]], msg.params[2]) + self.assertEqual(3, len(list(msg))) def test_raises_on_empty_datargram(self): self.assertRaises(osc_message.ParseError, osc_message.OscMessage, b'') @@ -95,6 +116,14 @@ class TestOscMessage(unittest.TestCase): self.assertTrue(type(msg.params[0]) == float) self.assertAlmostEqual(0.5, msg.params[0]) + def test_raises_on_invalid_array(self): + self.assertRaises(osc_message.ParseError, + osc_message.OscMessage, + b"/SYNC\x00\x00\x00[]]\x00") + self.assertRaises(osc_message.ParseError, + osc_message.OscMessage, + b"/SYNC\x00\x00\x00[[]\x00") + def test_raises_on_incorrect_datargram(self): self.assertRaises( osc_message.ParseError, osc_message.OscMessage, b'foobar') diff --git a/pythonosc/test/test_osc_message_builder.py b/pythonosc/test/test_osc_message_builder.py index 6c9a52a..2be7b7e 100644 --- a/pythonosc/test/test_osc_message_builder.py +++ b/pythonosc/test/test_osc_message_builder.py @@ -32,6 +32,7 @@ class TestOscMessageBuilder(unittest.TestCase): builder.add_arg(True) builder.add_arg(False) builder.add_arg(b"\x01\x02\x03") + builder.add_arg([1, ["abc"]]) # The same args but with explicit types. builder.add_arg(4.0, builder.ARG_TYPE_FLOAT) builder.add_arg(2, builder.ARG_TYPE_INT) @@ -39,14 +40,15 @@ class TestOscMessageBuilder(unittest.TestCase): builder.add_arg(True) builder.add_arg(False) builder.add_arg(b"\x01\x02\x03", builder.ARG_TYPE_BLOB) + builder.add_arg([1, ["abc"]], [builder.ARG_TYPE_INT, [builder.ARG_TYPE_STRING]]) builder.add_arg(4278255360, builder.ARG_TYPE_RGBA) - self.assertEqual(13, len(builder.args)) + self.assertEqual(len("fisTFb[i[s]]")*2+1, len(builder.args)) self.assertEqual("/SYNC", builder.address) builder.address = '/SEEK' msg = builder.build() self.assertEqual("/SEEK", msg.address) self.assertSequenceEqual( - [4.0, 2, "value", True, False, b"\x01\x02\x03"] * 2 + [4278255360], msg.params) + [4.0, 2, "value", True, False, b"\x01\x02\x03", [1, ["abc"]]] * 2 + [4278255360], msg.params) def test_build_wrong_type_raises(self): builder = osc_message_builder.OscMessageBuilder(address="/SYNC") -- GitLab