Commits

Jesper Nøhr  committed 23ebc37

refactoring emitter registry, adding pickle emitter, accepting 'emitter_format' special kwarg in url mappings to use that instead of ?format

  • Participants
  • Parent commits 3ebe711

Comments (0)

Files changed (3)

File examples/blogserver/api/urls.py

 
 urlpatterns = patterns('',
     url(r'^posts/$', blogposts),
+    url(r'^posts/(?P<emitter_format>.+)/$', blogposts),
+    url(r'^posts\.(?P<emitter_format>.+)', blogposts),
 )

File piston/emitters.py

 except ImportError:
     import StringIO
 
+try:
+    import cPickle as pickle
+except ImportError:
+    import pickle
+
 class Emitter(object):
     """
     Super emitter. All other emitters should subclass
     usually the only method you want to use in your
     emitter. See below for examples.
     """
+    EMITTERS = { }
+
     def __init__(self, payload, typemapper, handler, fields=(), anonymous=True):
         self.typemapper = typemapper
         self.data = payload
         """
         Gets an emitter, returns the class and a content-type.
         """
-        if format == 'xml':
-            return XMLEmitter, 'text/xml; charset=utf-8'
-        elif format == 'json':
-            return JSONEmitter, 'application/json; charset=utf-8'
-        elif format == 'yaml':
-            return YAMLEmitter, 'application/x-yaml; charset=utf-8'
+        if cls.EMITTERS.has_key(format):
+            return cls.EMITTERS.get(format)
+
+        raise ValueError("No emitters found for type %s" % format)
+    
+    @classmethod
+    def register(cls, name, klass, content_type='text/plain'):
+        """
+        Register an emitter.
+        
+        Parameters::
+         - `name`: The name of the emitter ('json', 'xml', 'yaml', ...)
+         - `klass`: The emitter class.
+         - `content_type`: The content type to serve response as.
+        """
+        cls.EMITTERS[name] = (klass, content_type)
+        
+    @classmethod
+    def unregister(cls, name):
+        """
+        Remove an emitter from the registry. Useful if you don't
+        want to provide output in one of the built-in emitters.
+        """
+        return cls.EMITTERS.pop(name, None)
     
 class XMLEmitter(Emitter):
     def _to_xml(self, xml, data):
         
         return stream.getvalue()
 
+Emitter.register('xml', XMLEmitter, 'text/xml; charset=utf-8')
+
 class JSONEmitter(Emitter):
     """
     JSON emitter, understands timestamps.
 
         return seria
     
+Emitter.register('json', JSONEmitter, 'application/json; charset=utf-8')
+    
 class YAMLEmitter(Emitter):
     """
     YAML emitter, uses `safe_dump` to omit the
     """
     def render(self, request):
         return yaml.safe_dump(self.construct())
+
+Emitter.register('yaml', YAMLEmitter, 'application/x-yaml; charset=utf-8')
+
+class PickleEmitter(Emitter):
+    """
+    Emitter that returns Python pickled.
+    """
+    def render(self, request):
+        return pickle.dumps(self.construct())
+        
+Emitter.register('pickle', PickleEmitter, 'application/octet-stream')

File piston/resource.py

         
         if not meth:
             raise Http404
+
+        # Support emitter both through (?P<emitter_format>) and ?format=emitter.
+        em_format = kwargs.pop('emitter_format', request.GET.get('format', 'json'))
         
         # Clean up the request object a bit, since we might
         # very well have `oauth_`-headers in there, and we
             else:
                 raise
 
-        emitter, ct = Emitter.get(request.GET.get('format', 'json'))
+        emitter, ct = Emitter.get(em_format)
         srl = emitter(result, typemapper, handler, handler.fields, anonymous)
         
         try: