1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-02-22 04:49:00 +00:00

Types: Adds ParameterDict Type

Acts like a regular dictionary however will automatically url
encode/decode the data along with relevant type information.
This commit is contained in:
Marc Bonnici 2017-06-27 10:39:49 +01:00
parent e884c3bcca
commit 85218a10d2

View File

@ -32,6 +32,7 @@ import numbers
import shlex import shlex
import string import string
from bisect import insort from bisect import insort
from urllib import quote, unquote
from collections import defaultdict, MutableMapping from collections import defaultdict, MutableMapping
from copy import copy from copy import copy
@ -586,3 +587,118 @@ def enum(args, start=0, step=1):
return Enum return Enum
class ParameterDict(dict):
"""
A dict-like object that automatically encodes various types into a url safe string,
and enforces a single type for the contents in a list.
Each value is first prefixed with 2 letters to preserve type when encoding to a string.
The format used is "value_type, value_dimension" e.g a 'list of floats' would become 'fl'.
"""
# Function to determine the appropriate prefix based on the parameters type
@staticmethod
def _get_prefix(obj):
if isinstance(obj, basestring):
prefix = 's'
elif isinstance(obj, float):
prefix = 'f'
elif isinstance(obj, long):
prefix = 'd'
elif isinstance(obj, bool):
prefix = 'b'
elif isinstance(obj, int):
prefix = 'i'
elif obj is None:
prefix = 'n'
else:
raise ValueError('Unable to encode {} {}'.format(obj, type(obj)))
return prefix
# Function to add prefix and urlencode a provided parameter.
@staticmethod
def _encode(obj):
if isinstance(obj, list):
t = type(obj[0])
prefix = ParameterDict._get_prefix(obj[0]) + 'l'
for item in obj:
if not isinstance(item, t):
msg = 'Lists must only contain a single type, contains {} and {}'
raise ValueError(msg.format(t, type(item)))
obj = '0newelement0'.join(str(x) for x in obj)
else:
prefix = ParameterDict._get_prefix(obj) + 's'
return quote(prefix + str(obj))
# Function to decode a string and return a value of the original parameter type.
# pylint: disable=too-many-return-statements
@staticmethod
def _decode(string):
value_type = string[:1]
value_dimension = string[1:2]
value = unquote(string[2:])
if value_dimension == 's':
if value_type == 's':
return str(value)
elif value_type == 'b':
return boolean(value)
elif value_type == 'd':
return long(value)
elif value_type == 'f':
return float(value)
elif value_type == 'i':
return int(value)
elif value_type == 'n':
return None
elif value_dimension == 'l':
return [ParameterDict._decode(value_type + 's' + x)
for x in value.split('0newelement0')]
else:
raise ValueError('Unknown {} {}'.format(type(string), string))
def __init__(self, *args, **kwargs):
for k, v in kwargs.iteritems():
self.__setitem__(k, v)
dict.__init__(self, *args)
def __setitem__(self, name, value):
dict.__setitem__(self, name, self._encode(value))
def __getitem__(self, name):
return self._decode(dict.__getitem__(self, name))
def __contains__(self, item):
return dict.__contains__(self, self._encode(item))
def __iter__(self):
return iter((k, self._decode(v)) for (k, v) in self.items())
def iteritems(self):
return self.__iter__()
def get(self, name):
return self._decode(dict.get(self, name))
def pop(self, key):
return self._decode(dict.pop(self, key))
def popitem(self):
key, value = dict.popitem(self)
return (key, self._decode(value))
def iter_encoded_items(self):
return dict.iteritems(self)
def get_encoded_value(self, name):
return dict.__getitem__(self, name)
def values(self):
return [self[k] for k in dict.keys(self)]
def update(self, *args, **kwargs):
for d in list(args) + [kwargs]:
if isinstance(d, ParameterDict):
dict.update(self, d)
else:
for k, v in d.iteritems():
self[k] = v