<s> """<STR_LIT>""" <EOL> from __future__ import unicode_literals <EOL> from base64 import b64decode , b64encode <EOL> from collections import OrderedDict , namedtuple <EOL> from django . core . paginator import Paginator as DjangoPaginator <EOL> from django . core . paginator import InvalidPage <EOL> from django . template import loader <EOL> from django . utils import six <EOL> from django . utils . six . moves . urllib import parse as urlparse <EOL> from django . utils . translation import ugettext_lazy as _ <EOL> from rest_framework . compat import template_render <EOL> from rest_framework . exceptions import NotFound <EOL> from rest_framework . response import Response <EOL> from rest_framework . settings import api_settings <EOL> from rest_framework . utils . urls import remove_query_param , replace_query_param <EOL> def _positive_int ( integer_string , strict = False , cutoff = None ) : <EOL> """<STR_LIT>""" <EOL> ret = int ( integer_string ) <EOL> if ret < <NUM_LIT:0> or ( ret == <NUM_LIT:0> and strict ) : <EOL> raise ValueError ( ) <EOL> if cutoff : <EOL> ret = min ( ret , cutoff ) <EOL> return ret <EOL> def _divide_with_ceil ( a , b ) : <EOL> """<STR_LIT>""" <EOL> if a % b : <EOL> return ( a // b ) + <NUM_LIT:1> <EOL> return a // b <EOL> def _get_count ( queryset ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> return queryset . count ( ) <EOL> except ( AttributeError , TypeError ) : <EOL> return len ( queryset ) <EOL> def _get_displayed_page_numbers ( current , final ) : <EOL> """<STR_LIT>""" <EOL> assert current >= <NUM_LIT:1> <EOL> assert final >= current <EOL> if final <= <NUM_LIT:5> : <EOL> return list ( range ( <NUM_LIT:1> , final + <NUM_LIT:1> ) ) <EOL> included = { <NUM_LIT:1> , current - <NUM_LIT:1> , current , current + <NUM_LIT:1> , final } <EOL> if current <= <NUM_LIT:4> : <EOL> included . add ( <NUM_LIT:2> ) <EOL> included . add ( <NUM_LIT:3> ) <EOL> if current >= final - <NUM_LIT:3> : <EOL> included . add ( final - <NUM_LIT:1> ) <EOL> included . add ( final - <NUM_LIT:2> ) <EOL> included = [ <EOL> idx for idx in sorted ( list ( included ) ) <EOL> if idx > <NUM_LIT:0> and idx <= final <EOL> ] <EOL> if current > <NUM_LIT:4> : <EOL> included . insert ( <NUM_LIT:1> , None ) <EOL> if current < final - <NUM_LIT:3> : <EOL> included . insert ( len ( included ) - <NUM_LIT:1> , None ) <EOL> return included <EOL> def _get_page_links ( page_numbers , current , url_func ) : <EOL> """<STR_LIT>""" <EOL> page_links = [ ] <EOL> for page_number in page_numbers : <EOL> if page_number is None : <EOL> page_link = PAGE_BREAK <EOL> else : <EOL> page_link = PageLink ( <EOL> url = url_func ( page_number ) , <EOL> number = page_number , <EOL> is_active = ( page_number == current ) , <EOL> is_break = False <EOL> ) <EOL> page_links . append ( page_link ) <EOL> return page_links <EOL> def _reverse_ordering ( ordering_tuple ) : <EOL> """<STR_LIT>""" <EOL> def invert ( x ) : <EOL> return x [ <NUM_LIT:1> : ] if ( x . startswith ( '<STR_LIT:->' ) ) else '<STR_LIT:->' + x <EOL> return tuple ( [ invert ( item ) for item in ordering_tuple ] ) <EOL> Cursor = namedtuple ( '<STR_LIT>' , [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] ) <EOL> PageLink = namedtuple ( '<STR_LIT>' , [ '<STR_LIT:url>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] ) <EOL> PAGE_BREAK = PageLink ( url = None , number = None , is_active = False , is_break = True ) <EOL> class BasePagination ( object ) : <EOL> display_page_controls = False <EOL> def paginate_queryset ( self , queryset , request , view = None ) : <EOL> raise NotImplementedError ( '<STR_LIT>' ) <EOL> def get_paginated_response ( self , data ) : <EOL> raise NotImplementedError ( '<STR_LIT>' ) <EOL> def to_html ( self ) : <EOL> raise NotImplementedError ( '<STR_LIT>' ) <EOL> def get_results ( self , data ) : <EOL> return data [ '<STR_LIT>' ] <EOL> class PageNumberPagination ( BasePagination ) : <EOL> """<STR_LIT>""" <EOL> page_size = api_settings . PAGE_SIZE <EOL> django_paginator_class = DjangoPaginator <EOL> page_query_param = '<STR_LIT>' <EOL> page_size_query_param = None <EOL> max_page_size = None <EOL> last_page_strings = ( '<STR_LIT>' , ) <EOL> template = '<STR_LIT>' <EOL> invalid_page_message = _ ( '<STR_LIT>' ) <EOL> def paginate_queryset ( self , queryset , request , view = None ) : <EOL> """<STR_LIT>""" <EOL> page_size = self . get_page_size ( request ) <EOL> if not page_size : <EOL> return None <EOL> paginator = self . django_paginator_class ( queryset , page_size ) <EOL> page_number = request . query_params . get ( self . page_query_param , <NUM_LIT:1> ) <EOL> if page_number in self . last_page_strings : <EOL> page_number = paginator . num_pages <EOL> try : <EOL> self . page = paginator . page ( page_number ) <EOL> except InvalidPage as exc : <EOL> msg = self . invalid_page_message . format ( <EOL> page_number = page_number , message = six . text_type ( exc ) <EOL> ) <EOL> raise NotFound ( msg ) <EOL> if paginator . num_pages > <NUM_LIT:1> and self . template is not None : <EOL> self . display_page_controls = True <EOL> self . request = request <EOL> return list ( self . page ) <EOL> def get_paginated_response ( self , data ) : <EOL> return Response ( OrderedDict ( [ <EOL> ( '<STR_LIT:count>' , self . page . paginator . count ) , <EOL> ( '<STR_LIT>' , self . get_next_link ( ) ) , <EOL> ( '<STR_LIT>' , self . get_previous_link ( ) ) , <EOL> ( '<STR_LIT>' , data ) <EOL> ] ) ) <EOL> def get_page_size ( self , request ) : <EOL> if self . page_size_query_param : <EOL> try : <EOL> return _positive_int ( <EOL> request . query_params [ self . page_size_query_param ] , <EOL> strict = True , <EOL> cutoff = self . max_page_size <EOL> ) <EOL> except ( KeyError , ValueError ) : <EOL> pass <EOL> return self . page_size <EOL> def get_next_link ( self ) : <EOL> if not self . page . has_next ( ) : <EOL> return None <EOL> url = self . request . build_absolute_uri ( ) <EOL> page_number = self . page . next_page_number ( ) <EOL> return replace_query_param ( url , self . page_query_param , page_number ) <EOL> def get_previous_link ( self ) : <EOL> if not self . page . has_previous ( ) : <EOL> return None <EOL> url = self . request . build_absolute_uri ( ) <EOL> page_number = self . page . previous_page_number ( ) <EOL> if page_number == <NUM_LIT:1> : <EOL> return remove_query_param ( url , self . page_query_param ) <EOL> return replace_query_param ( url , self . page_query_param , page_number ) <EOL> def get_html_context ( self ) : <EOL> base_url = self . request . build_absolute_uri ( ) <EOL> def page_number_to_url ( page_number ) : <EOL> if page_number == <NUM_LIT:1> : <EOL> return remove_query_param ( base_url , self . page_query_param ) <EOL> else : <EOL> return replace_query_param ( base_url , self . page_query_param , page_number ) <EOL> current = self . page . number <EOL> final = self . page . paginator . num_pages <EOL> page_numbers = _get_displayed_page_numbers ( current , final ) <EOL> page_links = _get_page_links ( page_numbers , current , page_number_to_url ) <EOL> return { <EOL> '<STR_LIT>' : self . get_previous_link ( ) , <EOL> '<STR_LIT>' : self . get_next_link ( ) , <EOL> '<STR_LIT>' : page_links <EOL> } <EOL> def to_html ( self ) : <EOL> template = loader . get_template ( self . template ) <EOL> context = self . get_html_context ( ) <EOL> return template_render ( template , context ) <EOL> class LimitOffsetPagination ( BasePagination ) : <EOL> """<STR_LIT>""" <EOL> default_limit = api_settings . PAGE_SIZE <EOL> limit_query_param = '<STR_LIT>' <EOL> offset_query_param = '<STR_LIT>' <EOL> max_limit = None <EOL> template = '<STR_LIT>' <EOL> def paginate_queryset ( self , queryset , request , view = None ) : <EOL> self . limit = self . get_limit ( request ) <EOL> if self . limit is None : <EOL> return None <EOL> self . offset = self . get_offset ( request ) <EOL> self . count = _get_count ( queryset ) <EOL> self . request = request <EOL> if self . count > self . limit and self . template is not None : <EOL> self . display_page_controls = True <EOL> return list ( queryset [ self . offset : self . offset + self . limit ] ) <EOL> def get_paginated_response ( self , data ) : <EOL> return Response ( OrderedDict ( [ <EOL> ( '<STR_LIT:count>' , self . count ) , <EOL> ( '<STR_LIT>' , self . get_next_link ( ) ) , <EOL> ( '<STR_LIT>' , self . get_previous_link ( ) ) , <EOL> ( '<STR_LIT>' , data ) <EOL> ] ) ) <EOL> def get_limit ( self , request ) : <EOL> if self . limit_query_param : <EOL> try : <EOL> return _positive_int ( <EOL> request . query_params [ self . limit_query_param ] , <EOL> cutoff = self . max_limit <EOL> ) <EOL> except ( KeyError , ValueError ) : <EOL> pass <EOL> return self . default_limit <EOL> def get_offset ( self , request ) : <EOL> try : <EOL> return _positive_int ( <EOL> request . query_params [ self . offset_query_param ] , <EOL> ) <EOL> except ( KeyError , ValueError ) : <EOL> return <NUM_LIT:0> <EOL> def get_next_link ( self ) : <EOL> if self . offset + self . limit >= self . count : <EOL> return None <EOL> url = self . request . build_absolute_uri ( ) <EOL> url = replace_query_param ( url , self . limit_query_param , self . limit ) <EOL> offset = self . offset + self . limit <EOL> return replace_query_param ( url , self . offset_query_param , offset ) <EOL> def get_previous_link ( self ) : <EOL> if self . offset <= <NUM_LIT:0> : <EOL> return None <EOL> url = self . request . build_absolute_uri ( ) <EOL> url = replace_query_param ( url , self . limit_query_param , self . limit ) <EOL> if self . offset - self . limit <= <NUM_LIT:0> : <EOL> return remove_query_param ( url , self . offset_query_param ) <EOL> offset = self . offset - self . limit <EOL> return replace_query_param ( url , self . offset_query_param , offset ) <EOL> def get_html_context ( self ) : <EOL> base_url = self . request . build_absolute_uri ( ) <EOL> current = _divide_with_ceil ( self . offset , self . limit ) + <NUM_LIT:1> <EOL> final = ( <EOL> _divide_with_ceil ( self . count - self . offset , self . limit ) + <EOL> _divide_with_ceil ( self . offset , self . limit ) <EOL> ) <EOL> if final < <NUM_LIT:1> : <EOL> final = <NUM_LIT:1> <EOL> if current > final : <EOL> current = final <EOL> def page_number_to_url ( page_number ) : <EOL> if page_number == <NUM_LIT:1> : <EOL> return remove_query_param ( base_url , self . offset_query_param ) <EOL> else : <EOL> offset = self . offset + ( ( page_number - current ) * self . limit ) <EOL> return replace_query_param ( base_url , self . offset_query_param , offset ) <EOL> page_numbers = _get_displayed_page_numbers ( current , final ) <EOL> page_links = _get_page_links ( page_numbers , current , page_number_to_url ) <EOL> return { <EOL> '<STR_LIT>' : self . get_previous_link ( ) , <EOL> '<STR_LIT>' : self . get_next_link ( ) , <EOL> '<STR_LIT>' : page_links <EOL> } <EOL> def to_html ( self ) : <EOL> template = loader . get_template ( self . template ) <EOL> context = self . get_html_context ( ) <EOL> return template_render ( template , context ) <EOL> class CursorPagination ( BasePagination ) : <EOL> """<STR_LIT>""" <EOL> cursor_query_param = '<STR_LIT>' <EOL> page_size = api_settings . PAGE_SIZE <EOL> invalid_cursor_message = _ ( '<STR_LIT>' ) <EOL> ordering = '<STR_LIT>' <EOL> template = '<STR_LIT>' <EOL> def paginate_queryset ( self , queryset , request , view = None ) : <EOL> self . page_size = self . get_page_size ( request ) <EOL> if not self . page_size : <EOL> return None <EOL> self . base_url = request . build_absolute_uri ( ) <EOL> self . ordering = self . get_ordering ( request , queryset , view ) <EOL> self . cursor = self . decode_cursor ( request ) <EOL> if self . cursor is None : <EOL> ( offset , reverse , current_position ) = ( <NUM_LIT:0> , False , None ) <EOL> else : <EOL> ( offset , reverse , current_position ) = self . cursor <EOL> if reverse : <EOL> queryset = queryset . order_by ( * _reverse_ordering ( self . ordering ) ) <EOL> else : <EOL> queryset = queryset . order_by ( * self . ordering ) <EOL> if current_position is not None : <EOL> order = self . ordering [ <NUM_LIT:0> ] <EOL> is_reversed = order . startswith ( '<STR_LIT:->' ) <EOL> order_attr = order . lstrip ( '<STR_LIT:->' ) <EOL> if self . cursor . reverse != is_reversed : <EOL> kwargs = { order_attr + '<STR_LIT>' : current_position } <EOL> else : <EOL> kwargs = { order_attr + '<STR_LIT>' : current_position } <EOL> queryset = queryset . filter ( ** kwargs ) <EOL> results = list ( queryset [ offset : offset + self . page_size + <NUM_LIT:1> ] ) <EOL> self . page = list ( results [ : self . page_size ] ) <EOL> if len ( results ) > len ( self . page ) : <EOL> has_following_postion = True <EOL> following_position = self . _get_position_from_instance ( results [ - <NUM_LIT:1> ] , self . ordering ) <EOL> else : <EOL> has_following_postion = False <EOL> following_position = None <EOL> if reverse : <EOL> self . page = list ( reversed ( self . page ) ) <EOL> if reverse : <EOL> self . has_next = ( current_position is not None ) or ( offset > <NUM_LIT:0> ) <EOL> self . has_previous = has_following_postion <EOL> if self . has_next : <EOL> self . next_position = current_position <EOL> if self . has_previous : <EOL> self . previous_position = following_position <EOL> else : <EOL> self . has_next = has_following_postion <EOL> self . has_previous = ( current_position is not None ) or ( offset > <NUM_LIT:0> ) <EOL> if self . has_next : <EOL> self . next_position = following_position <EOL> if self . has_previous : <EOL> self . previous_position = current_position <EOL> if ( self . has_previous or self . has_next ) and self . template is not None : <EOL> self . display_page_controls = True <EOL> return self . page <EOL> def get_page_size ( self , request ) : <EOL> return self . page_size <EOL> def get_next_link ( self ) : <EOL> if not self . has_next : <EOL> return None <EOL> if self . cursor and self . cursor . reverse and self . cursor . offset != <NUM_LIT:0> : <EOL> compare = self . _get_position_from_instance ( self . page [ - <NUM_LIT:1> ] , self . ordering ) <EOL> else : <EOL> compare = self . next_position <EOL> offset = <NUM_LIT:0> <EOL> for item in reversed ( self . page ) : <EOL> position = self . _get_position_from_instance ( item , self . ordering ) <EOL> if position != compare : <EOL> break <EOL> compare = position <EOL> offset += <NUM_LIT:1> <EOL> else : <EOL> if not self . has_previous : <EOL> offset = self . page_size <EOL> position = None <EOL> elif self . cursor . reverse : <EOL> offset = <NUM_LIT:0> <EOL> position = self . previous_position <EOL> else : <EOL> offset = self . cursor . offset + self . page_size <EOL> position = self . previous_position <EOL> cursor = Cursor ( offset = offset , reverse = False , position = position ) <EOL> return self . encode_cursor ( cursor ) <EOL> def get_previous_link ( self ) : <EOL> if not self . has_previous : <EOL> return None <EOL> if self . cursor and not self . cursor . reverse and self . cursor . offset != <NUM_LIT:0> : <EOL> compare = self . _get_position_from_instance ( self . page [ <NUM_LIT:0> ] , self . ordering ) <EOL> else : <EOL> compare = self . previous_position <EOL> offset = <NUM_LIT:0> <EOL> for item in self . page : <EOL> position = self . _get_position_from_instance ( item , self . ordering ) <EOL> if position != compare : <EOL> break <EOL> compare = position <EOL> offset += <NUM_LIT:1> <EOL> else : <EOL> if not self . has_next : <EOL> offset = self . page_size <EOL> position = None <EOL> elif self . cursor . reverse : <EOL> offset = self . cursor . offset + self . page_size <EOL> position = self . next_position <EOL> else : <EOL> offset = <NUM_LIT:0> <EOL> position = self . next_position <EOL> cursor = Cursor ( offset = offset , reverse = True , position = position ) <EOL> return self . encode_cursor ( cursor ) <EOL> def get_ordering ( self , request , queryset , view ) : <EOL> """<STR_LIT>""" <EOL> ordering_filters = [ <EOL> filter_cls for filter_cls in getattr ( view , '<STR_LIT>' , [ ] ) <EOL> if hasattr ( filter_cls , '<STR_LIT>' ) <EOL> ] <EOL> if ordering_filters : <EOL> filter_cls = ordering_filters [ <NUM_LIT:0> ] <EOL> filter_instance = filter_cls ( ) <EOL> ordering = filter_instance . get_ordering ( request , queryset , view ) <EOL> assert ordering is not None , ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' . format ( <EOL> filter_cls = filter_cls . __name__ <EOL> ) <EOL> ) <EOL> else : <EOL> ordering = self . ordering <EOL> assert ordering is not None , ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> ) <EOL> assert '<STR_LIT>' not in ordering , ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> ) <EOL> assert isinstance ( ordering , ( six . string_types , list , tuple ) ) , ( <EOL> '<STR_LIT>' . format ( <EOL> type = type ( ordering ) . __name__ <EOL> ) <EOL> ) <EOL> if isinstance ( ordering , six . string_types ) : <EOL> return ( ordering , ) <EOL> return tuple ( ordering ) <EOL> def decode_cursor ( self , request ) : <EOL> """<STR_LIT>""" <EOL> encoded = request . query_params . get ( self . cursor_query_param ) <EOL> if encoded is None : <EOL> return None <EOL> OFFSET_CUTOFF = <NUM_LIT:1000> <EOL> try : <EOL> querystring = b64decode ( encoded . encode ( '<STR_LIT:ascii>' ) ) . decode ( '<STR_LIT:ascii>' ) <EOL> tokens = urlparse . parse_qs ( querystring , keep_blank_values = True ) <EOL> offset = tokens . get ( '<STR_LIT:o>' , [ '<STR_LIT:0>' ] ) [ <NUM_LIT:0> ] <EOL> offset = _positive_int ( offset , cutoff = OFFSET_CUTOFF ) <EOL> reverse = tokens . get ( '<STR_LIT:r>' , [ '<STR_LIT:0>' ] ) [ <NUM_LIT:0> ] <EOL> reverse = bool ( int ( reverse ) ) <EOL> position = tokens . get ( '<STR_LIT:p>' , [ None ] ) [ <NUM_LIT:0> ] <EOL> except ( TypeError , ValueError ) : <EOL> raise NotFound ( self . invalid_cursor_message ) <EOL> return Cursor ( offset = offset , reverse = reverse , position = position ) <EOL> def encode_cursor ( self , cursor ) : <EOL> """<STR_LIT>""" <EOL> tokens = { } <EOL> if cursor . offset != <NUM_LIT:0> : <EOL> tokens [ '<STR_LIT:o>' ] = str ( cursor . offset ) <EOL> if cursor . reverse : <EOL> tokens [ '<STR_LIT:r>' ] = '<STR_LIT:1>' <EOL> if cursor . position is not None : <EOL> tokens [ '<STR_LIT:p>' ] = cursor . position <EOL> querystring = urlparse . urlencode ( tokens , doseq = True ) <EOL> encoded = b64encode ( querystring . encode ( '<STR_LIT:ascii>' ) ) . decode ( '<STR_LIT:ascii>' ) <EOL> return replace_query_param ( self . base_url , self . cursor_query_param , encoded ) <EOL> def _get_position_from_instance ( self , instance , ordering ) : <EOL> attr = getattr ( instance , ordering [ <NUM_LIT:0> ] . lstrip ( '<STR_LIT:->' ) ) <EOL> return six . text_type ( attr ) <EOL> def get_paginated_response ( self , data ) : <EOL> return Response ( OrderedDict ( [ <EOL> ( '<STR_LIT>' , self . get_next_link ( ) ) , <EOL> ( '<STR_LIT>' , self . get_previous_link ( ) ) , <EOL> ( '<STR_LIT>' , data ) <EOL> ] ) ) <EOL> def get_html_context ( self ) : <EOL> return { <EOL> '<STR_LIT>' : self . get_previous_link ( ) , <EOL> '<STR_LIT>' : self . get_next_link ( ) <EOL> } <EOL> def to_html ( self ) : <EOL> template = loader . get_template ( self . template ) <EOL> context = self . get_html_context ( ) <EOL> return template_render ( template , context ) </s>
