"""Spotify release status polling.""" import sys from availability import datastructures from availability import exceptions from availability.connectors import loggly from availability.connectors.stores import spotify from availability.constants import models logger = loggly.get_current_logger() def get_status_from_store(*, upc, countries, **kwargs): """Get release status from Spotify. - query store - call store response parsing function - set ReleaseStatus.db_release_status Args: upc (str): The Universal Product Code. countries (list): ISO 3166-1 alpha-2 country codes. Returns: A ReleaseStatus instance with the followimg attributes set on success: ReleaseStatus( store_release_id='1000000001', live_countries=['US', 'CA'], db_release_status='live', ) and only 'db_release_status' set on empty response from parser. """ release_status = None # Get JSON response as dict from the API. logger.info('Received upc = {0}, countries = {1}'.format(upc, countries)) for country_code in countries: store_response_dict = spotify.query_store(upc, country_code) logger.info( 'Spotify response for product {0}, country_code {1} is {2}'.format( upc, country_code, store_response_dict)) if store_response_dict is None: continue # Parse store response into a ReleaseStatus object. release_status = release_status_from_dict(store_response_dict) if release_status: logger.info( 'Found release for upc {0}, country_code = {1}'.format( upc, country_code)) break # Set internal status in DB based on store response. if not release_status: logger.info('Release with upc {} not found in Spotify'.format(upc)) release_status = datastructures.ReleaseStatus( db_release_status=models.RELEASE_STATUS_DELIVERED) else: logger.info('Release status parsed from store response') release_status.db_release_status = models.RELEASE_STATUS_LIVE return release_status def release_status_from_dict(store_response_dict): """Get release status from the Spotify API dict response. Try to get data out of the dict of a known structure re-raising a custom exception on any error that could happen during parsing invalid response. Args: store_response_dict (dict): response from the Spotify API as dict. Returns: A ReleaseStatus instance with store_release_id, and live_countries set on non empty response from store, for example: ReleaseStatus( store_release_id='1000000001', live_countries=['US', 'CA']) and None on empty response from store. Raises: StoreResponseParseError: Error parsing response from the store. """ key_albums = 'albums' key_total = 'total' key_id = 'id' key_items = 'items' key_available_markets = 'available_markets' try: # Make sure we did not receive something (that was a valid JSON) # we are unable to work with. if not isinstance(store_response_dict, dict): raise exceptions.StoreResponseParseError( 'Expecting Spotify response to be dict. It is {}: {}'.format( type(store_response_dict), store_response_dict)) albums = store_response_dict[key_albums] albums_items = albums[key_items] if not albums_items: return None # Make sure we have an exact match. if not (albums[key_total] == len(albums_items) == 1): raise exceptions.StoreResponseParseError( 'Expecting to get 1 album from Spotify.' ' Got {} (claimed:{})'.format( len(albums_items), albums[key_total])) album = albums_items[0] album_id = album[key_id] # We catch any fatal response parsing error and re-raise it as a custom # exception. except KeyError: exc_info = sys.exc_info() raise exceptions.StoreResponseParseError( exc_info[1]).with_traceback(exc_info[2]) return datastructures.ReleaseStatus( live_countries=album.get(key_available_markets), store_release_id=album_id)