pypexels/src/pexelspage.py
###############################################################################
# Copyright (c) 2017 Salvatore Ventura <salvoventura@gmail.com>
#
# File: pexelspage.py
#
# Author: Salvatore Ventura <salvoventura@gmail.com>
# Date: 27 Sep 2017
# Purpose: Base class for Pexels API pages
#
# Revision: 1
# Comment: What's new in revision 1
# Any object exposes GET
# _url is optional; if none provided, the current _url is used.
# next, previous, last, first *might* be available and usable.
# Object itself has no memory.
# GET, next, previous, last, first return a new object
#
###############################################################################
from .errors import PexelsError
from .liblogging import logger
from .rest import Rest
from .settings import API_VERSION
class PexelsPage(Rest):
def __init__(self, url, api_key, api_version=API_VERSION, valid_options=None, **kwargs):
if url is None:
raise PexelsError('PexelsPage: _url cannot be None')
super(PexelsPage, self).__init__(api_key=api_key, api_version=api_version)
self._valid_options = valid_options
self._url = self._sanitized_url(url)
self._query_parameters = self._sanitized_query_parameters(kwargs)
self._navigation = None
# Load the page at the given URL, and if status OK, parse it too
# otherwise raise an exception with the status_code. (Issue#7)
self._response = self.get(self._url, self._query_parameters)
if self._status_code == 200:
self._parse_navigation()
else:
raise PexelsError('PexelsPage: REST request failed with status code %s' % self._status_code)
@property
def body(self):
if self._response and self._status_code == 200:
return self._body
@property
def entries(self):
# must override in child class
raise NotImplementedError
@property
def headers(self):
if self._response:
return self._headers
@property
def link_self(self):
return self._ret_link('self')
@property
def link_next(self):
return self._ret_link('next')
@property
def link_previous(self):
return self._ret_link('prev')
@property
def link_first(self):
return self._ret_link('first')
@property
def link_last(self):
return self._ret_link('last')
@property
def has_next(self):
return self.link_next is not None
@property
def has_previous(self):
return self.link_previous is not None
def get_page(self, page):
url = '%s&per_page=%s&page=%s' % (self.nopaging_url, self.per_page, page)
return self.__class__(url=url, api_key=self.api_key, api_version=self.api_version)
def get_next_page(self):
if self.link_next:
return self.__class__(url=self.link_next, api_key=self.api_key, api_version=self.api_version)
def get_previous_page(self):
if self.link_previous:
return self.__class__(url=self.link_previous, api_key=self.api_key, api_version=self.api_version)
def get_first_page(self):
if self.link_first:
return self.__class__(url=self.link_first, api_key=self.api_key, api_version=self.api_version)
def get_last_page(self):
if self.link_last:
return self.__class__(url=self.link_last, api_key=self.api_key, api_version=self.api_version)
def _sanitized_query_parameters(self, kwargs):
logger.debug('Call _sanitized_query_parameters(%s)', kwargs)
query_params = {}
for key in kwargs:
if self._valid_options and key not in self._valid_options:
logger.debug('Invalid parameter %s, safely ignoring it', key)
continue
query_params[key] = kwargs[key]
# add defaults for page and per_page
if 'page' not in query_params:
query_params['page'] = 1
if 'per_page' not in query_params:
query_params['per_page'] = 15
logger.debug(' returning %s', query_params)
return query_params
def _parse_navigation(self):
nopaging_query_parameters = ['{}={}'.format(k, v) for k, v in self._query_parameters.items() if
k not in ['page', 'per_page']]
self.nopaging_url = '?'.join([self._url, '&'.join(nopaging_query_parameters)])
self.page = int(self.body.get('page', 1))
self.per_page = int(self.body.get('per_page', 15))
self.total_results = int(self.body.get('total_results', 0))
self._navigation = {
'self': self._url,
'first': '%s&per_page=%s&page=%s' % (self.nopaging_url, self.per_page, 1),
'prev': self.body.get('prev_page', None),
'next': self.body.get('next_page', None),
'last': '%s&per_page=%s&page=%s' % (
self.nopaging_url, self.per_page, self.total_results / self.per_page + 1),
}
def _ret_link(self, which):
if self._navigation:
return self._navigation.get(which, None)