Last active
December 16, 2015 13:49
-
-
Save john1king/5444881 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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