__author__ = 'Jack Kaliko'
-import logging
-
from datetime import datetime, timedelta
-from time import sleep
from requests import get, Request, Timeout, ConnectionError
from sima import ECH
from sima.lib.meta import Artist
-from sima.utils.utils import getws
-if len(ECH.get('apikey')) == 23:
+from sima.utils.utils import WSError, WSNotFound, WSTimeout, WSHTTPError
+from sima.utils.utils import getws, Throttle, Cache, purge_cache
+if len(ECH.get('apikey')) == 23: # simple hack allowing imp.reload
getws(ECH)
# Some definitions
SOCKET_TIMEOUT = 4
-class EchoError(Exception):
- pass
-
-class EchoNotFound(EchoError):
- pass
-
-class EchoTimeout(EchoError):
- pass
-
-class EchoHTTPError(EchoError):
- pass
-
-class Throttle():
- def __init__(self, wait):
- self.wait = wait
- self.last_called = datetime.now()
-
- def __call__(self, func):
- def wrapper(*args, **kwargs):
- while self.last_called + self.wait > datetime.now():
- sleep(0.1)
- result = func(*args, **kwargs)
- self.last_called = datetime.now()
- return result
- return wrapper
-
-
-class Cache():
- def __init__(self, elem, last=None):
- self.elem = elem
- self.requestdate = last
- if not last:
- self.requestdate = datetime.utcnow()
-
- def created(self):
- return self.requestdate
-
- def get(self):
- return self.elem
-
-
-def purge_cache(age=4):
- now = datetime.utcnow()
- if now.hour == SimaEch.timestamp.hour:
- return
- SimaEch.timestamp = datetime.utcnow()
- cache = SimaEch.cache
- delta = timedelta(hours=age)
- for url in list(cache.keys()):
- timestamp = cache.get(url).created()
- if now - timestamp > delta:
- cache.pop(url)
-
-
-class SimaEch():
- """
+class SimaEch:
+ """EchoNest http client
"""
root_url = 'http://{host}/api/{version}'.format(**ECH)
cache = {}
timestamp = datetime.utcnow()
ratelimit = None
+ name = 'EchoNest'
def __init__(self, cache=True):
self.artist = None
self._ressource = None
self.current_element = None
self.caching = cache
- purge_cache()
+ purge_cache(self.__class__)
def _fetch(self, payload):
"""Use cached elements or proceed http request"""
self.current_element = SimaEch.cache.get(url).elem
return
try:
- self._fetch_ech(payload)
+ self._fetch_ws(payload)
except Timeout:
- raise EchoTimeout('Failed to reach server within {0}s'.format(
+ raise WSTimeout('Failed to reach server within {0}s'.format(
SOCKET_TIMEOUT))
except ConnectionError as err:
- raise EchoError(err)
+ raise WSError(err)
@Throttle(WAIT_BETWEEN_REQUESTS)
- def _fetch_ech(self, payload):
+ def _fetch_ws(self, payload):
"""fetch from web service"""
req = get(self._ressource, params=payload,
timeout=SOCKET_TIMEOUT)
self.__class__.ratelimit = req.headers.get('x-ratelimit-remaining', None)
if req.status_code is not 200:
- raise EchoHTTPError(req.status_code)
+ raise WSHTTPError(req.status_code)
self.current_element = req.json()
self._controls_answer()
if self.caching:
if code is 0:
return True
if code is 5:
- raise EchoNotFound('Artist not found: "{0}"'.format(self.artist))
- raise EchoError(status.get('message'))
+ raise WSNotFound('Artist not found: "{0}"'.format(self.artist))
+ raise WSError(status.get('message'))
def _forge_payload(self, artist):
- """
+ """Build payload
"""
payload = {'api_key': ECH.get('apikey')}
if not isinstance(artist, Artist):
payload.update(
id='musicbrainz:artist:{0}'.format(artist.mbid))
else:
- payload.update(name=artist.name)
+ payload.update(name=artist.name)
payload.update(bucket='id:musicbrainz')
payload.update(results=100)
return payload
def get_similar(self, artist=None):
- """
+ """Fetch similar artists
"""
payload = self._forge_payload(artist)
# Construct URL