Cómo convertir un MultiDict a un diccionario nested

Me gustaría convertir un POST de Webob MultiDict a un diccionario nested. P.ej

Así que a partir de un POST de:

'name=Kyle&phone.number=1234&phone.type=home&phone.number=5678&phone.type=work' 

a un multidict

 [('name', 'Kyle'), ('phone.number', '1234'), ('phone.type', 'home'), ('phone.number', '5678'), ('phone.type', 'work')] 

a un diccionario nested

 {'name': 'Kyle', 'phone': [ { 'number': '12345', 'type': 'home', },{ 'number': '5678', 'type': 'work', }, 

¿Algunas ideas?

    EDITAR

    Terminé extrayendo el método variable_decode del paquete formencode como lo publicó Will. El único cambio que se requirió es hacer las listas explícitas, por ejemplo,

     'name=Kyle&phone-1.number=1234&phone-1.type=home&phone-2.number=5678&phone-2.type=work' 

    Lo cual es mejor por muchas razones.

    Si tiene instalado formencode o puede instalarlo, revise su módulo de código variable

    No he tenido tiempo de probarlo y es bastante restrictivo, pero espero que esto funcione (solo lo estoy publicando porque ha pasado un tiempo desde que publicaste la pregunta):

     >>> def toList(s): ... answer = [] ... L = s.split("&") ... for i in L: ... answer.append(tuple(i.split('='))) ... return answer >>> def toDict(L): ... answer = {} ... answer[L[0][0]] = L[0][1] ... for i in L[1:]: ... pk,sk = L[i][0].split('.') ... if pk not in answer: ... answer[pk] = [] ... if sk not in answer[pk][-1]: ... answer[pk][sk] = L[i][1] ... else: ... answer[pk].append({sk:L[i][1]}) 

    Si esto no es el 100%, al menos debería tener un buen comienzo.

    Espero que esto ayude

    Prefiero una forma explícita de resolver su problema:

    1. Divida los miembros que pertenecen a la misma estructura (o dict) en un mismo grupo con el mismo nombre de campo, como

       'name=Kyle&phone1=1234&phone1=home&phone2=5678&phone2=work' 
    2. El orden de los campos en el formulario está garantizado, por lo que el elemento múltiple será: ((‘name’, ‘Kyle’), (‘phone1’, ‘1234’, ‘home’), (‘phone2’, ‘5678’ , ‘trabajo’))

    3. Entonces el código será como:

       def extract(key, values): extractor = { "name":str, "phone":lambda *args:dict(zip(('number', 'type'), args) } trimed_key = re.match(r"^(\w+)", key).group(1) return trimed_key, extractor(trimed_key, *values) nested_dict = {} for i in multidict(): key, values = i[0], i[1:] nested_dict.setdefault(key, []) trimed_key, data_wanted = extract(key, values) nested_dict[trimed_key].append(data_wanted) for key in nested_dict: if len(nested_dict[key]) == 1: nested_dict[key] = nested_dict[key][0]