Skip to content

Instantly share code, notes, and snippets.

@john1king
Last active December 16, 2015 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save john1king/5444881 to your computer and use it in GitHub Desktop.
Save john1king/5444881 to your computer and use it in GitHub Desktop.
import re
key_space_limit = 65536
class RangeError(Exception):
pass
class KeySpaceConstrainedParams(object):
def __init__(self, limit=key_space_limit):
self.limit = limit
self.size = 0
self.params = {}
def __getitem__(self, key):
return self.params[key]
def __setitem__(self, key, value):
if key and not key in self.params:
self.size += len(key)
if self.size > self.limit:
raise RangeError('exceeded available parameter key space')
self.params[key] = value
def setdefault(self, key, value):
self.params.setdefault(key, value)
def to_parms_dict(self):
dict_ = self.params
for key in dict_:
value = dict_[key]
if isinstance(value, self.__class__):
dict_[key] = value.to_parms_dict()
elif isinstance(value, list):
for i in range(len(value)):
x = value[i]
if isinstance(x, self.__class__):
value[i] = x.to_parms_dict()
else:
value[i] = x
return dict_
def unescape(s):
return s # todo
def is_params_dict_type(obj):
return isinstance(obj, (KeySpaceConstrainedParams, dict))
def parse_nested_query(qs, d = None):
params = KeySpaceConstrainedParams()
for p in re.split('[&;] *', qs or ''):
k, v = [unescape(s) for s in p.split('=', 2)]
normalize_params(params, k, v)
return params.to_parms_dict()
def normalize_params(params, name, v = None):
match = re.match('^[\[\]]*([^\[\]]+)\]*', name)
k = match.group(1) or ''
after = name[match.lastindex+len(k):] or ''
if not k:
return
if after == "":
params[k] = v
elif after == "[]":
params.setdefault(k, [])
if not isinstance(params[k], list):
raise TypeError("expected list (got %s) for param %s" % (params[k].__class__.__name__, k))
params[k].append(v)
else:
match = re.match('^\[\]\[([^\[\]]+)\]$', after)
if not match:
match = re.match('^\[\](.+)$', after)
if match:
child_key = math.group(1)
params.setdefault(k, [])
if not isinstance(params[k], list):
raise TypeError("expected list (got %s) for param %s" % (params[k].__class__.__name__, k))
if is_params_dict_type(params[k][-1]) and not child_key in params[k][-1]:
normalize_params(params[k][-1], child_key, v)
else:
params[k].append(normalize_params(params.__class__(), child_key, v))
else:
params.setdefault(k, params.__class__())
if not is_params_dict_type(params[k]):
raise TypeError("expected dict (got %s) for param %s" % (params[k].__class__.__name__, k))
params[k] = normalize_params(params[k], after, v)
return params
if __name__ == '__main__':
print parse_nested_query('foo[x]=1;foo[o]=2')
print parse_nested_query('foo[x][]=1;foo[x][]=2')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment