Completed
Push — master ( 87b508...86a146 )
by
unknown
01:28
created

Range   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 69
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 69
rs 10
wmc 15

5 Methods

Rating   Name   Duplication   Size   Complexity  
A content_range() 0 8 2
A __init__() 0 4 1
A get_page_size() 0 6 1
A set_response_headers() 0 13 3
D parse() 0 33 8
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