@@ -29,6 +29,7 @@ ovs_pyfiles = \
python/ovs/flow/__init__.py \
python/ovs/flow/decoders.py \
python/ovs/flow/kv.py \
+ python/ovs/flow/list.py \
python/ovs/json.py \
python/ovs/jsonrpc.py \
python/ovs/ovsuuid.py \
new file mode 100644
@@ -0,0 +1,121 @@
+import re
+
+from ovs.flow.kv import KeyValue, KeyMetadata, ParseError
+from ovs.flow.decoders import decode_default
+
+
+class ListDecoders(object):
+ """ListDecoders is used by ListParser to decode the elements in the list.
+
+ A decoder is a function that accepts a value and returns its decoded
+ object.
+
+ ListDecoders is initialized with a list of tuples that contains the
+ keyword and the decoding function associated with each position in the
+ list. The order is, therefore, important.
+
+ Args:
+ decoders (list of tuples): Optional; a list of tuples.
+ The first element in the tuple is the keyword associated with the
+ value. The second element in the tuple is the decoder function.
+ """
+
+ def __init__(self, decoders=None):
+ self._decoders = decoders or list()
+
+ def decode(self, index, value_str):
+ """Decode the index'th element of the list.
+
+ Args:
+ index (int): The position in the list of the element to decode.
+ value_str (str): The value string to decode.
+ """
+ if index < 0 or index >= len(self._decoders):
+ return self._default_decoder(index, value_str)
+
+ try:
+ key = self._decoders[index][0]
+ value = self._decoders[index][1](value_str)
+ return key, value
+ except Exception as e:
+ raise ParseError(
+ "Failed to decode value_str {}: {}".format(value_str, str(e))
+ )
+
+ @staticmethod
+ def _default_decoder(index, value):
+ key = "elem_{}".format(index)
+ return key, decode_default(value)
+
+
+class ListParser(object):
+ """ListParser parses a list of values and stores them as key-value pairs.
+
+ It uses a ListDecoders instance to decode each element in the list.
+
+ Args:
+ string (str): The string to parse.
+ decoders (ListDecoders): Optional, the decoders to use.
+ delims (list): Optional, list of delimiters of the list. Defaults to
+ [','].
+ """
+ def __init__(self, string, decoders=None, delims=[","]):
+ self._string = string
+ self._decoders = decoders or ListDecoders()
+ self._keyval = list()
+ self._regexp = r"({})".format("|".join(delims))
+
+ def kv(self):
+ return self._keyval
+
+ def __iter__(self):
+ return iter(self._keyval)
+
+ def parse(self):
+ """Parse the list in string.
+
+ Raises:
+ ParseError if any parsing error occurs.
+ """
+ kpos = 0
+ index = 0
+ while kpos < len(self._string) and self._string[kpos] != "\n":
+ split_parts = re.split(self._regexp, self._string[kpos:], 1)
+ value_str = split_parts[0]
+
+ key, value = self._decoders.decode(index, value_str)
+
+ meta = KeyMetadata(
+ kpos=kpos,
+ vpos=kpos,
+ kstring=value_str,
+ vstring=value_str,
+ )
+ self._keyval.append(KeyValue(key, value, meta))
+
+ kpos += len(value_str) + 1
+ index += 1
+
+
+def decode_nested_list(decoders, value, delims=[","]):
+ """Decodes a string value that contains a list of elements and returns
+ them in a dictionary.
+
+ Args:
+ decoders (ListDecoders): The ListDecoders to use.
+ value (str): The value string to decode.
+ delims (list(str)): Optional, the list of delimiters to use.
+ """
+ parser = ListParser(value, decoders, delims)
+ parser.parse()
+ return {kv.key: kv.value for kv in parser.kv()}
+
+
+def nested_list_decoder(decoders=None, delims=[","]):
+ """Helper function that creates a nested list decoder with given
+ ListDecoders and delimiters.
+ """
+ def decoder(value):
+ return decode_nested_list(decoders, value, delims)
+
+ return decoder