Issue #131 new

Plist Emitter

davidtreynolds
created an issue

Since python has an in-built plist decoder/encoder library, I've coded up a quick PlistEmitter, which I think could be pretty useful for many iPhone apps.

I had a small problem with the example app and I had to update request.POST in Blogposthandler.create to request.data to make this work. I'm not sure if there's a bug in that handler or if I'm doing something wrong?

Comments (3)

  1. Álex González

    Hi! I've use your .diff to create my own emitter.

    To use it you must put in a file under your API path, and import it. I'm importing it from urls.py.

    plistlib give me errors when it found a NoneType, so I must to create a function that erase all NoneType in my dict. As my API objects have serveral levels, I must do a nested function to erase in all of them.

    This is the code:

    from piston.emitters import Emitter
    from piston.utils import Mimer
    
    try:
        import cStringIO as StringIO
    except ImportError:
        import StringIO
    
    try:
        import plistlib
    except:
        plistlib = None
    
    class PlistEmitter(Emitter):
        """
        Plist emitter, uses the inbuilt Python plistlib
        """
        def render(self, request):
            data = StringIO.StringIO()
    
            try:
                construct = self.construct()
                plistlib.writePlist(construct, data)
            except:
                construct = erase_none(self.construct())
                plistlib.writePlist(construct, data)
    
            data.seek(0)
            return ''.join(data.readlines())
    
        @classmethod
        def decode_plist(cls, data):
            return plistlib.readPlist(StringIO.StringIO(data.strip()))
    
    
    if plistlib:
        Emitter.register('plist', PlistEmitter, 'application/plist')
        Mimer.register(PlistEmitter.decode_plist, ('application/plist',))
    
    
    def erase_none(the_dict):
        """
            Nested function that removes all NoneType values in a dict(). If you have several levels in the dict, this function will search in all of them.
        """
        to_delete = list()
    
        # Nested search
        for key in the_dict:
            # If I found a type dict, I must search inside with this same function
            if type(the_dict[key]) == type(dict()):
                the_dict[key] = erase_none(the_dict[key])
    
            # If I find a list I must range it and send the dicts inside to this function
            elif type(the_dict[key]) == type(list()):
                for index in range(len(the_dict[key])):
                    the_dict[key][index] = erase_none(the_dict[key][index])
    
            # If the key haves a NoneType value I prepare to delete it
            elif not the_dict[key]:
                to_delete.append(key)
    
        # Delete all NoneType values found
        for key in to_delete:
            del the_dict[key]
    
        return the_dict
    
  2. davidtreynolds reporter

    I'm not entirely sure that just removing the None values is the right move in all situations - what about if your code checks for the existence of a blank or empty value against a key, your solution would cause an error in that case. Perhaps this emitter should just come with a warning that you should consider designing your API to not rely on None as the plist format / objective c doesn't support the type.

    Obviously this emitter works for your use case, so I would suggest a little tweak to the code. In the render method, I would catch the TypeError exception as the docs for plistlib state that:

    A TypeError will be raised if the object is of an unsupported type or a container that contains 
    objects of unsupported types.
    

    Your current implementation will hide any other exceptions that might be raised and could make debugging of other problems difficult.

  3. Log in to comment