From 7e521bcdf97acf39ab8b6eb75b9f90936fe8868c Mon Sep 17 00:00:00 2001 From: Emlyn Corrin Date: Thu, 9 Mar 2017 19:02:49 +0000 Subject: [PATCH] Support Arrays --- pythonosc/osc_message.py | 19 ++++++++- pythonosc/osc_message_builder.py | 69 ++++++++++++++++++++++++-------- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/pythonosc/osc_message.py b/pythonosc/osc_message.py index 297d9cd..3ddc339 100644 --- a/pythonosc/osc_message.py +++ b/pythonosc/osc_message.py @@ -33,8 +33,11 @@ class OscMessage(object): if type_tag.startswith(','): type_tag = type_tag[1:] + params = [] + 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. @@ -49,11 +52,25 @@ class OscMessage(object): val = True elif param == "F": # False. val = False + elif param == "[": # Array start. + a = [] + param_stack[-1].append(a) + param_stack.append(a) + have_val = False + 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 - self._parameters.append(val) + if have_val: + param_stack[-1].append(val) + if len(param_stack) != 1: + raise ParseError('Missing closing bracket in type tag: {0}'.format(type_tag)) + self._parameters = params except osc_types.ParseError as pe: raise ParseError('Found incorrect datagram, ignoring it', pe) diff --git a/pythonosc/osc_message_builder.py b/pythonosc/osc_message_builder.py index b798fd8..22b5ac7 100644 --- a/pythonosc/osc_message_builder.py +++ b/pythonosc/osc_message_builder.py @@ -19,6 +19,9 @@ class OscMessageBuilder(object): ARG_TYPE_TRUE = "T" ARG_TYPE_FALSE = "F" + ARG_TYPE_ARRAY_START = "[" + ARG_TYPE_ARRAY_STOP = "]" + _SUPPORTED_ARG_TYPES = ( ARG_TYPE_FLOAT, ARG_TYPE_INT, ARG_TYPE_BLOB, ARG_TYPE_STRING, ARG_TYPE_RGBA, ARG_TYPE_TRUE, ARG_TYPE_FALSE) @@ -46,6 +49,16 @@ class OscMessageBuilder(object): """Returns the (type, value) arguments list of this message.""" return self._args + 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): + return False + return True + return False + def add_arg(self, arg_value, arg_type=None): """Add a typed argument to this message. @@ -56,25 +69,44 @@ class OscMessageBuilder(object): Raises: - ValueError: if the type is not supported. """ - if arg_type and arg_type not in self._SUPPORTED_ARG_TYPES: + if arg_type and not self.valid_type(arg_type): raise ValueError( 'arg_type must be one of {}'.format(self._SUPPORTED_ARG_TYPES)) if not arg_type: - if isinstance(arg_value, str): - arg_type = self.ARG_TYPE_STRING - elif isinstance(arg_value, bytes): - arg_type = self.ARG_TYPE_BLOB - elif isinstance(arg_value, int): - arg_type = self.ARG_TYPE_INT - elif isinstance(arg_value, float): - arg_type = self.ARG_TYPE_FLOAT - elif arg_value == True: - arg_type = self.ARG_TYPE_TRUE - elif arg_value == False: - arg_type = self.ARG_TYPE_FALSE - else: - raise ValueError('Infered arg_value type is not supported') - self._args.append((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): + self.add_arg(v, t) + self._args.append((self.ARG_TYPE_ARRAY_STOP, None)) + else: + self._args.append((arg_type, arg_value)) + + def get_arg_type(self, arg_value): + """Guess the type of a value. + + Args: + - arg_value: The value to guess the type of. + Raises: + - ValueError: if the type is not supported. + """ + if isinstance(arg_value, str): + arg_type = self.ARG_TYPE_STRING + elif isinstance(arg_value, bytes): + arg_type = self.ARG_TYPE_BLOB + elif isinstance(arg_value, int): + arg_type = self.ARG_TYPE_INT + elif isinstance(arg_value, float): + arg_type = self.ARG_TYPE_FLOAT + elif arg_value == True: + arg_type = self.ARG_TYPE_TRUE + 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] + else: + raise ValueError('Infered arg_value type is not supported') + return arg_type def build(self): """Builds an OscMessage from the current state of this builder. @@ -110,7 +142,10 @@ class OscMessageBuilder(object): dgram += osc_types.write_blob(value) elif arg_type == self.ARG_TYPE_RGBA: dgram += osc_types.write_rgba(value) - elif arg_type == self.ARG_TYPE_TRUE or arg_type == self.ARG_TYPE_FALSE: + elif arg_type in (self.ARG_TYPE_TRUE, + self.ARG_TYPE_FALSE, + self.ARG_TYPE_ARRAY_START, + self.ARG_TYPE_ARRAY_STOP): continue else: raise BuildError('Incorrect parameter type found {}'.format( -- GitLab