"""Helper functions.""" import datetime import re from typing import Dict, List def filter_release_deals(deals: List[Dict]) -> Dict: """Try to filter only for R0 then R1 if available. Otherwise fail.""" filtered_deals = [deal for deal in deals if 'R0' in deal['release_references']] if not filtered_deals: filtered_deals = [deal for deal in deals if 'R1' in deal['release_references']] if not filtered_deals: raise ValueError('No valid release deals found.') return filtered_deals[0] def retrieve_deal_dates(deal: Dict) -> (str, str): """Retrieve earliest sales_start_date and set timed_release_date.""" sales_start_date = None timed_release_date = None for deal_term in deal['deal_terms']: start_date = deal_term['start_date'] start_date_time = deal_term['start_date_time'] if not start_date and not start_date_time: continue if not start_date: # Strip time from datetime start_date = start_date_time[0:10] if not timed_release_date \ or timed_release_date < start_date_time: timed_release_date = start_date_time if not sales_start_date or sales_start_date > start_date: sales_start_date = start_date return sales_start_date, timed_release_date def retrieve_territory_with_differing_dates( filtered_deal: Dict, sales_start_date: str) -> Dict: """Retrieve territories when start date != sales start date.""" territory_dates = {} for deal_term in filtered_deal['deal_terms']: start_date = deal_term['start_date'] start_date_time = deal_term['start_date_time'] if not start_date and not start_date_time: continue if not start_date: # Strip time from datetime start_date = start_date_time[0:10] if start_date == sales_start_date: continue if deal_term['territories']: for territory in deal_term['territories']: territory_date = territory_dates.get(territory) if not territory_date or territory_date < start_date: territory_dates[territory] = start_date return territory_dates def filter_preorder_deals(deal: Dict) -> Dict: """Filter out preorder deal terms from release deal.""" # We have a filtered deal, weed out pre_orders deal['deal_terms'] = [ deal_term for deal_term in deal['deal_terms'] if not deal_term['pre_order'] ] if not deal['deal_terms']: raise ValueError('Only pre-order deals exist in R0 or R1.') return deal def retrieve_release_dates(deals: List[Dict]) -> Dict: """Retrieve the latest start date from deal terms.""" # Only keep R0 or R1 release deal, in that order. filtered_deal = filter_release_deals(deals) # We have a filtered deal, weed out pre_orders filtered_deal = filter_preorder_deals(filtered_deal) # Find earliest sales start date and set timed release date sales_start_date, timed_release_date = retrieve_deal_dates( filtered_deal) # Gather territory dates that are not the same as sales start date territory_dates = retrieve_territory_with_differing_dates( filtered_deal, sales_start_date) return { 'sales_start_date': sales_start_date, 'timed_release_date': timed_release_date, 'territory_dates': territory_dates, } def parse_date(date_text): """Turn date String into a datetime object.""" if not date_text: return None if isinstance(date_text, datetime.date): # don't try to parse datetime objects. return date_text try: if len(date_text) <= 10: pattern = '%Y-%m-%d' else: pattern = '%Y-%m-%dT%H:%M:%S' date_time = datetime.datetime.strptime(date_text, pattern) except ValueError: return None return date_time.date() def is_date_in_range(date, min_date, max_date): """Check if datetime object is inside the provided range.""" if not date: return False return min_date <= date <= max_date def is_isrc(isrc): """Verify the string is an ISRC.""" return re.match( r'^[A-Za-z]{2}[-]?[0-9A-Za-z]{3}[-]?[0-9]{2}[-]?[0-9]{5}$', isrc) def is_pinfo(pline): """Verify string is 4 numbers, followed by characters. Also allow optional additional PYears, separated by ', ' """ regex = r'^(19|20)\d{2}(,\s(19|20)\d{2})*\s\S.*$' return bool(pline and re.match(regex, pline)) NON_REQUIRED_CLASSICAL_ARTIST_ROLES = ( 'orchestra', 'ensemble', 'conductor' ) NON_REQUIRED_ARTIST_ROLES = ( 'remixer' ) def is_artist_required(artist_type): """Return True if artist_type is required. Args: artist_type (str): The artist type to test Returns: bool: Is required artist_type """ return (artist_type not in NON_REQUIRED_CLASSICAL_ARTIST_ROLES and artist_type not in NON_REQUIRED_ARTIST_ROLES) def is_artist_name_empty(name): """Check if the artist name is empty.""" return not name or name.strip() == '' def has_performer_role(track): """Check if track has specified role. Args: track (dict): Track dictionary role_type (str): Role type to check for Returns: bool """ role_type = 'MainArtist' return any([ artist for artist in track.get('display_artists') or [] if role_type in artist['roles']])