"""Process additional data fields. Get extra data by executing some function, fill it in records by updating dicts in a list, log key fields if these records are not in the extra data. """ from src.utils import error_log def _get_dict_values_by_keys(record, key_fields): """Get dictionary value by single or multiple keys. Args: record (dict): key data source key_fields (list): one or set of key fields Returns: object or tuple: key Raises: ValueError: key_fields can not be empty. """ if not key_fields: raise ValueError('key_fields can not be empty') if len(key_fields) == 1: return record[key_fields[0]] return tuple(record[fn] for fn in key_fields) def _update_dicts(records, new_data, key_fields, remove_not_found=False): """Update dicts in a list with extra data. Extra data comes in dict with keys as single values or tuples. Modifies records list in place. Args: records (list): multiple dicts to fill new data in new_data (dict): new data to fill in, key (object or tuple) - single or set of fields from key_fields, value (dict) - new data key_fields (list): list of fields that exist in and are key of dict remove_not_found (bool): remove records which external data was not found Returns: list: records keys that were not found in """ not_found_keys = set() for record in records[:]: key = _get_dict_values_by_keys(record, key_fields) if key in new_data: record.update(new_data[key]) else: if remove_not_found: records.remove(record) not_found_keys.add(key) return sorted(not_found_keys) def get_and_update(records, key_fields, func, remove_not_found=False): """Get data by executing and update records with it. Generate list of key fields to run function with, make unique set of them. If some necessary records do not exist then send "record not found" notification. Modifies records in place. Args: records (list): multiple dicts to fill new data in key_fields (list): one or set of key fields func (function): get data function remove_not_found (bool): remove records which external data was not found Returns: list: Modified list of records. """ if not records: return [] keys = set() for record in records: keys.add(_get_dict_values_by_keys(record, key_fields)) new_data = func(list(keys)) not_found_records = _update_dicts( records, new_data, key_fields, remove_not_found) if not_found_records: error_log.log_missing_records(func, not_found_records) return records