""" Spotify store connector. Provides query_store() function that performs the actual I/O. """ import sys import spotipy from spotipy import oauth2 as spotipy_oauth2 from availability import config from availability import exceptions from availability.connectors import loggly logger = loggly.get_current_logger() def query_store(upc, country_code): """Query Spotify HTTP API for release status. Args: upc (str): The Universal Product Code. country_code (str): ISO 3166-1 alpha-2 country code. Returns: dict: Spotify search API response JSON decoded as dict. Raises: StoreRequestError: Error sending request to remote store. """ if not all((config.SPOTIFY_CLIENT_ID, config.SPOTIFY_CLIENT_SECRET)): # We check for Spotify credentials presence only once: in the config, # but they are not strictly required for search requests. client = spotipy.Spotify() else: credentials_manager = spotipy_oauth2.SpotifyClientCredentials( client_id=config.SPOTIFY_CLIENT_ID, client_secret=config.SPOTIFY_CLIENT_SECRET) client = spotipy.Spotify( client_credentials_manager=credentials_manager) try: # The Spotipy library uses a fixed number of retries (10 by default) # on internal server errors or hitting rate limits. return client.search( q='upc:{:s}'.format(upc), type='album', market=country_code) except Exception as e: error_message = str(e) # Don't raise an exception for rate limiting - just log and return None if '429' in error_message: logger.warning( 'Spotify rate limit hit for upc={}, country={}: {}'.format( upc, country_code, error_message)) return None # For other errors, log and raise logger.error( 'Spotify API error for upc={}, country={}: {}'.format( upc, country_code, error_message)) exc_info = sys.exc_info() raise exceptions.StoreRequestError( exc_info[1]).with_traceback(exc_info[2])