Okay, so you folks may remember variablesdecode() from formencode. I
said it wasn't good for any client-side javascript there too. I wasn't
just saying that because I was whining -- I wrote a filter that will
convert form variables with names like "foo.bar.baz" into full fledged
dictionaries and lists.

I even tested it on a TG server, so it should work :).

Example #1:
>>> print _nestedList({'company': 'Unexistential Inc',
                     'names.firstName': ['Joe', 'Boe', 'Moe'],
                     'names.lastName': ['Smith', 'Myth', 'Keith'],
                     'phone': '555-8980'})
>>> { 'company' : 'Unexistential Inc',
      'names' : [{'firstName' : 'Joe', 'lastName' : 'Smith'},
                 {'firstName' : 'Boe', 'lastName' : 'Myth'},
                 {'firstName' : 'Moe', 'lastName' : 'Keith'}],
      'phone' : '555-8980' }

####
####

class NestedListFilter(BaseFilter):
    """
    Will build a nested list for request params with periods in the
name,
    for an example look at _nestedList().
    """
    def beforeMain(self):
        cherrypy.request.paramMap =
self._nestedList(cherrypy.request.paramMap)

    def _nestedList(self, oldDict):
        """
        Given a dictionary with keys like 'foo.bar.joo' : [oldValue1,
oldValue2],
        this will return a new tree with a key of
        foo : [{ 'bar': {'joo' : oldValue1}}, { 'bar': {'joo' :
oldValue2}}],
        for every key.

        Example #1:
        >>> print self._nestedList({'company': 'Unexistential Inc',
                             'names.firstName': ['Joe', 'Boe', 'Moe'],
                             'names.lastName': ['Smith', 'Myth',
'Keith'],
                             'phone': '555-8980'})
        >>> { 'company' : 'Unexistential Inc',
              'names' : [{'firstName' : 'Joe', 'lastName' : 'Smith'},
                         {'firstName' : 'Boe', 'lastName' : 'Myth'},
                         {'firstName' : 'Moe', 'lastName' : 'Keith'}],
              'phone' : '555-8980' }

        Example #2
        >>> print self._nestedList(
                                {'misc': 'Trespassing Prohibited!',
                                 'top.locations.state': ['IL', 'NY'],
                                 'top.locations.zip': [48890, 21142],
                                 'top.markets': ['Belmont', 'Reasan']}
)
        >>> {'misc': 'Trespassing Prohibited!',
             'top': [{'markets': 'Belmont', 'locations':
                         {'state': 'IL', 'zip': 48890}},
                     {'markets': 'Reasan', 'locations':
                         {'state': 'NY', 'zip': 21142}}
                    ]}
        """
        y = {}
        for oldKey, oldValue in oldDict.iteritems():
            splitList = oldKey.split(".")
            if len(splitList) > 1: #there was a period in the key
                if type(oldValue) != list:
                    forceValue = [oldValue] #force to be a list
                else:
                    forceValue = oldValue
                key = splitList[0]

                #print "Fixing %s with %s" %(str(oldKey),
str(forceValue))

                #create list indices if necessary, since we'll be using
them
                if y.get(key, None) == None:
                    #y[key] = [None]*len(forceValue)
                    y[key] = [dict() for i in range(len(forceValue))]

                    #print "%s wasn't found, so we padded it %d times"
%(str(key), len(forceValue))
                    #print y[key]
                elif len(y[key]) < len(forceValue):
                    #y[key][len(y[key]):] = [None]*len(forceValue) #pad
list if necessary
                    y[key][len(y[key]):] = \
                        [dict() for i in range(len(forceValue) -
len(y[key]))]

                    #print "%s was too short, so we padded it %d times"
%(str(key), len(forceValue) - len(y[key]))
                    #print y[key]

                for index, realValue in enumerate(forceValue):
                    #start = y[key][index]

                    if type(y[key][index]) != dict: #will be dict from
earlier
                        y[key][index] = {}
                        start = y[key][index]

                        if type(start) != dict:
                            print "%s not a dict, making {}"
%str(start)
                        else: #none
                            print "%s isn't there, making {}"
%str(start)

                    else:
                        start = y[key][index]

                    #print "Starting %s on %d with %s" %(str(start),
index, str(realValue))

                    #drop down and create dictionaries

                    for nestKey in splitList[1:-1]:
                        if type(start) != dict or \
                                              start.get(nestKey, None)
== None:

                            #if type(start) != dict:
                                #print "%s not a dict, making {}"
%str(start)
                            #else: #none
                                #print "%s isn't there, making {}"
%str(start)

                            start[nestKey] = {}
                            #overwrite old non-dict values if necessary

                        #else:
                            #print "%s is there, dropping down"
%str(start)

                        start = start[nestKey]
                        #drop down to a deeper level

                    if type(start) == dict:
                        old_old = start.get(splitList[-1], None)
                    else:
                        old_old = None
                    #print "Dropping %s down to %s with %s and setting
to %s" %(
                    #    str(start), str(old_old), str(splitList[-1]),
str(realValue) )

                    if type(start) != dict:
                        start = { splitList[-1] : realValue}
                    else:
                        start[splitList[-1]] = realValue

                    #print "Finished y[%s][%s] and now its %s"
%(str(key), str(index), str(y[key][index]))
                    #print "Entire y[%s] is %s" %(str(key),
str(y[key]))
                    #print

                #print
                #print

            else: #regular dict member, just go ahead and add it
                y[oldKey] = oldValue 
                
        return y

Reply via email to