Unicode Handling and Additonal complex query support.

1: Abandoned idea to add 'encoding' parameter to function
 * risk of clobbering someone using 'encoding' as a query-string key provided via **kwargs - will rethink
 * setting encoding to utf8 if no other encoding is specified.
 * utf8 seems hard-coded in ZPublisher marshalling, so...

2: Using 'config.zpublisher_default_encoding' to get configured encoding
  * not sure about this.  ZPublisher seems to use utf8 exclusively, so maybe this is not needed
  * zpublisher_default_encoding seems to control the html/xml content-type encoding - a different beast.
   
3: Rigorous testing of Lists-In-Records and other complex data structures:
  * for better testing and less changes, I left the original test cases unmodified and added my own for Unicode

4: Re-write of complex_marshal for recursive solution.
  * other option is to check value type in multiple places in the code, maintenance nightmares occur.
  * extra test cases added for now supported RecordsInLists, ListsInLists, RecordsInRecords
  * exercise Recursion Depth Exceeded - for fun.

Note:
   Lists In Lists can produce ambiguous results:  [sublist1, sublist2] produces the same output as sublist1+sublist2.  There are many easy workarounds for this case, tho.

 

This monkey patch must not happen at import time:  even though it is a "test" module, it could still end up being imported in non-test mode.

Rather, do the patching as part of the set-up for one or more testcases (either in 'setUp' or a helper method called from a testcase method);  and tear it down afterwards.  I've grown fond of a ~_Monkey` context manager for such purposes:


    class _Monkey(object):
        # context-manager for replacing module names in the scope of a test.

        def __init__(self, module, **kw):
            self.module = module
            self.to_restore = dict([(key, getattr(module, key)) for key in kw])
            for key, value in kw.items():
                setattr(module, key, value)

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            for key, value in self.to_restore.items():
                setattr(self.module, key, value)