Revision 5c812d1b api/emitter.py

b/api/emitter.py
3 3
# Copyright © 2010 Greek Research and Technology Network
4 4
#
5 5

  
6
import re
7 6
from xml.dom import minidom
8
from django.conf.urls.defaults import url
9 7
from piston.emitters import Emitter, Mimer
10
from piston.resource import Resource as BaseResource
11

  
12
_accept_re = re.compile(r'([^\s;,]+)(?:[^,]*?;\s*q=(\d*(?:\.\d+)?))?')
13

  
14
def parse_accept_header(value):
15
    """Parse an HTTP Accept header
16

  
17
    Returns an ordered by quality list of tuples (value, quality)
18
    """
19
    if not value:
20
        return []
21

  
22
    result = []
23
    for match in _accept_re.finditer(value):
24
        quality = match.group(2)
25
        if not quality:
26
            quality = 1
27
        else:
28
            quality = max(min(float(quality), 1), 0)
29
        result.append((match.group(1), quality))
30

  
31
    # sort by quality
32
    result.sort(key=lambda x: x[1])
33

  
34
    return result
35

  
36
class Resource(BaseResource):
37
    def determine_emitter(self, request, *args, **kwargs):
38
        """
39
        Override default emitter policy to account for Accept header
40

  
41
        emitter_format (.json or .xml suffix in URL) always takes precedence.
42

  
43
        After that, the Accept header is checked; if both JSON and XML are
44
        equally preferred, use JSON.
45

  
46
        If none of the two were provided, then use JSON as per the
47
        specification.
48
        """
49

  
50
        em = request.GET.get('format', 'json')
51
        if 'emitter_format' in kwargs and \
52
           kwargs["emitter_format"] is not None:
53
            em = kwargs.pop('emitter_format')
54
        elif 'HTTP_ACCEPT' in request.META:
55
            accepts = parse_accept_header(request.META['HTTP_ACCEPT'])
56
            for content_type, quality in accepts:
57
                if content_type == 'application/json':
58
                    break
59
                elif content_type == 'application/xml':
60
                    em = request.GET.get('format', 'xml')
61
                    break
62

  
63
        return em
64 8

  
65 9
class OSXMLEmitter(Emitter):
66 10
    """
......
118 62

  
119 63
Emitter.register('xml', OSXMLEmitter, 'application/xml')
120 64
Mimer.register(lambda *a: None, ('application/xml',))
121

  
122
def url_with_format(regex, *args, **kwargs):
123
    """
124
    An extended url() that adds an .json/.xml suffix to the end to avoid DRY
125
    """
126
    if regex[-1] == '$' and regex[-2] != '\\':
127
        regex = regex[:-1]
128
    regex = regex + r'(\.(?P<emitter_format>json|xml))?$'
129
    return url(regex, *args, **kwargs)

Also available in: Unified diff