allow multiple tags (#303)
[wolnelektury.git] / apps / piston / emitters.py
index 1ff0a52..c2116d2 100644 (file)
@@ -58,7 +58,7 @@ class Emitter(object):
     as the methods on the handler. Issue58 says that's no good.
     """
     EMITTERS = { }
     as the methods on the handler. Issue58 says that's no good.
     """
     EMITTERS = { }
-    RESERVED_FIELDS = set([ 'read', 'update', 'create', 
+    RESERVED_FIELDS = set([ 'read', 'update', 'create',
                             'delete', 'model', 'anonymous',
                             'allowed_methods', 'fields', 'exclude' ])
 
                             'delete', 'model', 'anonymous',
                             'allowed_methods', 'fields', 'exclude' ])
 
@@ -68,16 +68,16 @@ class Emitter(object):
         self.handler = handler
         self.fields = fields
         self.anonymous = anonymous
         self.handler = handler
         self.fields = fields
         self.anonymous = anonymous
-        
+
         if isinstance(self.data, Exception):
             raise
         if isinstance(self.data, Exception):
             raise
-    
+
     def method_fields(self, handler, fields):
         if not handler:
             return { }
 
         ret = dict()
     def method_fields(self, handler, fields):
         if not handler:
             return { }
 
         ret = dict()
-            
+
         for field in fields - Emitter.RESERVED_FIELDS:
             t = getattr(handler, str(field), None)
 
         for field in fields - Emitter.RESERVED_FIELDS:
             t = getattr(handler, str(field), None)
 
@@ -85,13 +85,13 @@ class Emitter(object):
                 ret[field] = t
 
         return ret
                 ret[field] = t
 
         return ret
-    
+
     def construct(self):
         """
         Recursively serialize a lot of types, and
         in cases where it doesn't recognize the type,
         it will fall back to Django's `smart_unicode`.
     def construct(self):
         """
         Recursively serialize a lot of types, and
         in cases where it doesn't recognize the type,
         it will fall back to Django's `smart_unicode`.
-        
+
         Returns `dict`.
         """
         def _any(thing, fields=()):
         Returns `dict`.
         """
         def _any(thing, fields=()):
@@ -99,7 +99,7 @@ class Emitter(object):
             Dispatch, all types are routed through here.
             """
             ret = None
             Dispatch, all types are routed through here.
             """
             ret = None
-            
+
             if isinstance(thing, QuerySet):
                 ret = _qs(thing, fields=fields)
             elif isinstance(thing, (tuple, list)):
             if isinstance(thing, QuerySet):
                 ret = _qs(thing, fields=fields)
             elif isinstance(thing, (tuple, list)):
@@ -131,19 +131,19 @@ class Emitter(object):
             Foreign keys.
             """
             return _any(getattr(data, field.name))
             Foreign keys.
             """
             return _any(getattr(data, field.name))
-        
+
         def _related(data, fields=()):
             """
             Foreign keys.
             """
             return [ _model(m, fields) for m in data.iterator() ]
         def _related(data, fields=()):
             """
             Foreign keys.
             """
             return [ _model(m, fields) for m in data.iterator() ]
-        
+
         def _m2m(data, field, fields=()):
             """
             Many to many (re-route to `_model`.)
             """
             return [ _model(m, fields) for m in getattr(data, field.name).iterator() ]
         def _m2m(data, field, fields=()):
             """
             Many to many (re-route to `_model`.)
             """
             return [ _model(m, fields) for m in getattr(data, field.name).iterator() ]
-        
+
         def _model(data, fields=()):
             """
             Models. Will respect the `fields` and/or
         def _model(data, fields=()):
             """
             Models. Will respect the `fields` and/or
@@ -152,7 +152,7 @@ class Emitter(object):
             ret = { }
             handler = self.in_typemapper(type(data), self.anonymous)
             get_absolute_uri = False
             ret = { }
             handler = self.in_typemapper(type(data), self.anonymous)
             get_absolute_uri = False
-            
+
             if handler or fields:
                 v = lambda f: getattr(data, f.attname)
 
             if handler or fields:
                 v = lambda f: getattr(data, f.attname)
 
@@ -167,26 +167,26 @@ class Emitter(object):
 
                     if 'absolute_uri' in get_fields:
                         get_absolute_uri = True
 
                     if 'absolute_uri' in get_fields:
                         get_absolute_uri = True
-                
+
                     if not get_fields:
                         get_fields = set([ f.attname.replace("_id", "", 1)
                             for f in data._meta.fields ])
                     if not get_fields:
                         get_fields = set([ f.attname.replace("_id", "", 1)
                             for f in data._meta.fields ])
-                
+
                     # sets can be negated.
                     for exclude in exclude_fields:
                         if isinstance(exclude, basestring):
                             get_fields.discard(exclude)
                     # sets can be negated.
                     for exclude in exclude_fields:
                         if isinstance(exclude, basestring):
                             get_fields.discard(exclude)
-                            
+
                         elif isinstance(exclude, re._pattern_type):
                             for field in get_fields.copy():
                                 if exclude.match(field):
                                     get_fields.discard(field)
                         elif isinstance(exclude, re._pattern_type):
                             for field in get_fields.copy():
                                 if exclude.match(field):
                                     get_fields.discard(field)
-                                    
+
                 else:
                     get_fields = set(fields)
 
                 met_fields = self.method_fields(handler, get_fields)
                 else:
                     get_fields = set(fields)
 
                 met_fields = self.method_fields(handler, get_fields)
-                           
+
                 for f in data._meta.local_fields:
                     if f.serialize and not any([ p in met_fields for p in [ f.attname, f.name ]]):
                         if not f.rel:
                 for f in data._meta.local_fields:
                     if f.serialize and not any([ p in met_fields for p in [ f.attname, f.name ]]):
                         if not f.rel:
@@ -197,13 +197,13 @@ class Emitter(object):
                             if f.attname[:-3] in get_fields:
                                 ret[f.name] = _fk(data, f)
                                 get_fields.remove(f.name)
                             if f.attname[:-3] in get_fields:
                                 ret[f.name] = _fk(data, f)
                                 get_fields.remove(f.name)
-                
+
                 for mf in data._meta.many_to_many:
                     if mf.serialize and mf.attname not in met_fields:
                         if mf.attname in get_fields:
                             ret[mf.name] = _m2m(data, mf)
                             get_fields.remove(mf.name)
                 for mf in data._meta.many_to_many:
                     if mf.serialize and mf.attname not in met_fields:
                         if mf.attname in get_fields:
                             ret[mf.name] = _m2m(data, mf)
                             get_fields.remove(mf.name)
-                
+
                 # try to get the remainder of fields
                 for maybe_field in get_fields:
                     if isinstance(maybe_field, (list, tuple)):
                 # try to get the remainder of fields
                 for maybe_field in get_fields:
                     if isinstance(maybe_field, (list, tuple)):
@@ -225,7 +225,7 @@ class Emitter(object):
                         # using different names.
                         ret[maybe_field] = _any(met_fields[maybe_field](data))
 
                         # using different names.
                         ret[maybe_field] = _any(met_fields[maybe_field](data))
 
-                    else:                    
+                    else:
                         maybe = getattr(data, maybe_field, None)
                         if maybe:
                             if callable(maybe):
                         maybe = getattr(data, maybe_field, None)
                         if maybe:
                             if callable(maybe):
@@ -242,13 +242,13 @@ class Emitter(object):
             else:
                 for f in data._meta.fields:
                     ret[f.attname] = _any(getattr(data, f.attname))
             else:
                 for f in data._meta.fields:
                     ret[f.attname] = _any(getattr(data, f.attname))
-                
+
                 fields = dir(data.__class__) + ret.keys()
                 add_ons = [k for k in dir(data) if k not in fields]
                 fields = dir(data.__class__) + ret.keys()
                 add_ons = [k for k in dir(data) if k not in fields]
-                
+
                 for k in add_ons:
                     ret[k] = _any(getattr(data, k))
                 for k in add_ons:
                     ret[k] = _any(getattr(data, k))
-            
+
             # resouce uri
             if self.in_typemapper(type(data), self.anonymous):
                 handler = self.in_typemapper(type(data), self.anonymous)
             # resouce uri
             if self.in_typemapper(type(data), self.anonymous):
                 handler = self.in_typemapper(type(data), self.anonymous)
@@ -259,51 +259,51 @@ class Emitter(object):
                         ret['resource_uri'] = reverser( lambda: (url_id, fields) )()
                     except NoReverseMatch, e:
                         pass
                         ret['resource_uri'] = reverser( lambda: (url_id, fields) )()
                     except NoReverseMatch, e:
                         pass
-            
+
             if hasattr(data, 'get_api_url') and 'resource_uri' not in ret:
                 try: ret['resource_uri'] = data.get_api_url()
                 except: pass
             if hasattr(data, 'get_api_url') and 'resource_uri' not in ret:
                 try: ret['resource_uri'] = data.get_api_url()
                 except: pass
-            
+
             # absolute uri
             if hasattr(data, 'get_absolute_url') and get_absolute_uri:
                 try: ret['absolute_uri'] = data.get_absolute_url()
                 except: pass
             # absolute uri
             if hasattr(data, 'get_absolute_url') and get_absolute_uri:
                 try: ret['absolute_uri'] = data.get_absolute_url()
                 except: pass
-            
+
             return ret
             return ret
-        
+
         def _qs(data, fields=()):
             """
             Querysets.
             """
             return [ _any(v, fields) for v in data ]
         def _qs(data, fields=()):
             """
             Querysets.
             """
             return [ _any(v, fields) for v in data ]
-                
+
         def _list(data):
             """
             Lists.
             """
             return [ _any(v) for v in data ]
         def _list(data):
             """
             Lists.
             """
             return [ _any(v) for v in data ]
-            
+
         def _dict(data):
             """
             Dictionaries.
             """
             return dict([ (k, _any(v)) for k, v in data.iteritems() ])
         def _dict(data):
             """
             Dictionaries.
             """
             return dict([ (k, _any(v)) for k, v in data.iteritems() ])
-            
+
         # Kickstart the seralizin'.
         return _any(self.data, self.fields)
         # Kickstart the seralizin'.
         return _any(self.data, self.fields)
-    
+
     def in_typemapper(self, model, anonymous):
         for klass, (km, is_anon) in self.typemapper.iteritems():
             if model is km and is_anon is anonymous:
                 return klass
     def in_typemapper(self, model, anonymous):
         for klass, (km, is_anon) in self.typemapper.iteritems():
             if model is km and is_anon is anonymous:
                 return klass
-        
+
     def render(self):
         """
         This super emitter does not implement `render`,
         this is a job for the specific emitter below.
         """
         raise NotImplementedError("Please implement render.")
     def render(self):
         """
         This super emitter does not implement `render`,
         this is a job for the specific emitter below.
         """
         raise NotImplementedError("Please implement render.")
-        
+
     def stream_render(self, request, stream=True):
         """
         Tells our patched middleware not to look
     def stream_render(self, request, stream=True):
         """
         Tells our patched middleware not to look
@@ -312,7 +312,7 @@ class Emitter(object):
         more memory friendly for large datasets.
         """
         yield self.render(request)
         more memory friendly for large datasets.
         """
         yield self.render(request)
-        
+
     @classmethod
     def get(cls, format):
         """
     @classmethod
     def get(cls, format):
         """
@@ -322,19 +322,19 @@ class Emitter(object):
             return cls.EMITTERS.get(format)
 
         raise ValueError("No emitters found for type %s" % 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.
     @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)
         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):
         """
     @classmethod
     def unregister(cls, name):
         """
@@ -342,7 +342,7 @@ class Emitter(object):
         want to provide output in one of the built-in emitters.
         """
         return cls.EMITTERS.pop(name, None)
         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):
         if isinstance(data, (list, tuple)):
 class XMLEmitter(Emitter):
     def _to_xml(self, xml, data):
         if isinstance(data, (list, tuple)):
@@ -360,16 +360,16 @@ class XMLEmitter(Emitter):
 
     def render(self, request):
         stream = StringIO.StringIO()
 
     def render(self, request):
         stream = StringIO.StringIO()
-        
+
         xml = SimplerXMLGenerator(stream, "utf-8")
         xml.startDocument()
         xml.startElement("response", {})
         xml = SimplerXMLGenerator(stream, "utf-8")
         xml.startDocument()
         xml.startElement("response", {})
-        
+
         self._to_xml(xml, self.construct())
         self._to_xml(xml, self.construct())
-        
+
         xml.endElement("response")
         xml.endDocument()
         xml.endElement("response")
         xml.endDocument()
-        
+
         return stream.getvalue()
 
 Emitter.register('xml', XMLEmitter, 'text/xml; charset=utf-8')
         return stream.getvalue()
 
 Emitter.register('xml', XMLEmitter, 'text/xml; charset=utf-8')
@@ -388,10 +388,10 @@ class JSONEmitter(Emitter):
             return '%s(%s)' % (cb, seria)
 
         return seria
             return '%s(%s)' % (cb, seria)
 
         return seria
-    
+
 Emitter.register('json', JSONEmitter, 'application/json; charset=utf-8')
 Mimer.register(simplejson.loads, ('application/json',))
 Emitter.register('json', JSONEmitter, 'application/json; charset=utf-8')
 Mimer.register(simplejson.loads, ('application/json',))
-    
+
 class YAMLEmitter(Emitter):
     """
     YAML emitter, uses `safe_dump` to omit the
 class YAMLEmitter(Emitter):
     """
     YAML emitter, uses `safe_dump` to omit the
@@ -410,7 +410,7 @@ class PickleEmitter(Emitter):
     """
     def render(self, request):
         return pickle.dumps(self.construct())
     """
     def render(self, request):
         return pickle.dumps(self.construct())
-        
+
 Emitter.register('pickle', PickleEmitter, 'application/python-pickle')
 
 """
 Emitter.register('pickle', PickleEmitter, 'application/python-pickle')
 
 """
@@ -437,5 +437,5 @@ class DjangoEmitter(Emitter):
             response = serializers.serialize(format, self.data, indent=True)
 
         return response
             response = serializers.serialize(format, self.data, indent=True)
 
         return response
-        
+
 Emitter.register('django', DjangoEmitter, 'text/xml; charset=utf-8')
 Emitter.register('django', DjangoEmitter, 'text/xml; charset=utf-8')