Range.parse()   B
last analyzed

Complexity

Conditions 8

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
c 0
b 0
f 0
dl 0
loc 33
rs 7.2213
1
# -*- coding: utf-8 -*-
2
3
import re
4
5
6
class RangeParseException(Exception):
7
    '''
8
    Used for handling errors during range parsing
9
    '''
10
    pass
11
12
13
class Range(object):
14
    def __init__(self, start, end, page=1):
15
        self.start = start
16
        self.end = end
17
        self.page = page
18
19
    def get_page_size(self):
20
        '''
21
22
        :return: the size of a page
23
        '''
24
        return self.end - self.start + 1
25
26
    def content_range(self, length):
27
        '''
28
29
        :param length: the total number of results
30
        :return: range header string
31
        '''
32
        end = self.end if self.end <= length else length - 1
33
        return 'items %d-%d/%d' % (self.start, end, length)
34
35
    @classmethod
36
    def parse(cls, request, default_start=0, default_end=11, max_end=50):
37
        '''
38
        Parse the range headers into a range object. When there are no range headers,
39
        check for a page 'pagina' parameter, otherwise use the defaults defaults
40
41
        :param request: a request object
42
        :param default_start: default start for  paging (optional, default is 0)
43
        :param default_end: default end for paging (optional, default is 11)
44
        :param default_end: maximum end for paging (optional, default is 50, no limits in case of None)
45
        :return: :class: 'oe_utils.range_parser.Range'
46
        '''
47
        if 'Range' in request.headers and request.headers['Range'] is not '':
48
            match = re.match('^items=([0-9]+)-([0-9]+)$', request.headers['Range'])
49
50
            if match:
51
                start = int(match.group(1))
52
                end = int(match.group(2))
53
54
                if end < start:
55
                    end = start
56
                if max_end and end > start + max_end:
57
                    end = start + max_end
58
                return cls(start, end)
59
            else:
60
                raise RangeParseException('range header does not match expected format')
61
        elif 'pagina' in request.params:
62
            page = int(request.params.get('pagina'))
63
            start = default_start + (default_end + 1) * (page - 1)
64
            end = default_end * page + page - 1
65
            return cls(start, end, page)
66
        else:
67
            return cls(default_start, default_end)
68
69
    def set_response_headers(self, response, total_count):
70
        '''
71
        Set the correct range headers on the response
72
73
        :param response: a response object
74
        :param total_count: the total number of results
75
        '''
76
        response.headerlist.append(('Access-Control-Expose-Headers', 'Content-Range, X-Content-Range'))
77
        response.accept_ranges = 'items'
78
        if total_count is None:
79
            raise RangeParseException('Provided length value is null')
80
        if total_count > 0:
81
            response.content_range = self.content_range(total_count)
82