1# -*- coding: utf-8 -*- 2"""Base class to query a webservice and parse the result to py objects.""" 3 4import json 5import logging 6from time import sleep 7from time import time as timestamp 8 9from . import webservice 10from ._exceptions import DataNotFoundAtServiceError, ServiceIsDownError 11 12UA = 'isbnlib (gzip)' 13OUT_OF_SERVICE = 'Temporarily out of service' 14BOOK_NOT_FOUND = 'No results match your search' 15LOGGER = logging.getLogger(__name__) 16THROTTLING = 1 17 18 19# pylint: disable=useless-object-inheritance 20class WEBQuery(object): 21 """Base class to query a webservice and parse the result to py objects.""" 22 23 T = {'id': timestamp()} # noqa 24 25 def __init__(self, service_url, ua=UA, throttling=THROTTLING): 26 """Initialize & call webservice.""" 27 srv = service_url[8:20] 28 last = WEBQuery.T[srv] if srv in WEBQuery.T else 0.0 29 wait = 0 if timestamp() - last > throttling else throttling 30 sleep(wait) 31 self.url = service_url 32 self.data = webservice.query(service_url, ua) 33 WEBQuery.T[srv] = timestamp() 34 35 def check_data(self, data_checker=None): # pragma: no cover 36 """Check the data & handle errors.""" 37 if data_checker: 38 return data_checker(self.data) 39 if self.data == '{}': # noqa 40 LOGGER.warning('DataNotFoundAtServiceError for %s', self.url) 41 raise DataNotFoundAtServiceError(self.url) 42 if BOOK_NOT_FOUND in self.data: 43 LOGGER.warning('DataNotFoundAtServiceError for %s', self.url) 44 raise DataNotFoundAtServiceError(self.url) 45 if OUT_OF_SERVICE in self.data: 46 LOGGER.critical('ServiceIsDownError for %s', self.url) 47 raise ServiceIsDownError(self.url) 48 return True 49 50 def parse_data(self, parser=json.loads): 51 """Parse the data (default JSON -> PY).""" 52 if parser is None: # pragma: no cover 53 return self.data 54 return parser(self.data) # <-- data is now unicode 55 56 57def query( 58 url, 59 user_agent=UA, 60 data_checker=None, 61 parser=json.loads, 62 throttling=THROTTLING, 63): 64 """Put call and return the data from the web service.""" 65 wq = WEBQuery(url, user_agent, throttling) 66 return wq.parse_data(parser) if wq.check_data(data_checker) else None 67