def get_delete_data(contract_type, now, sess, last_run, start_date=None, end_date=None, metrics=None):
    ' Get data from the delete feed '
    if (not metrics):
        metrics = {}
    data = []
    yesterday = (now - datetime.timedelta(days=1))
    last_run_date = (last_run - relativedelta(days=1))
    params = (((('LAST_MOD_DATE:[' + last_run_date.strftime('%Y/%m/%d')) + ',') + yesterday.strftime('%Y/%m/%d')) + '] ')
    if (start_date and end_date):
        params = (((('LAST_MOD_DATE:[' + start_date) + ',') + end_date) + '] ')
        if (not metrics['start_date']):
            metrics['start_date'] = start_date
        if (not metrics['end_date']):
            metrics['end_date'] = end_date
    base_url = ((((delete_url + params) + 'CONTRACT_TYPE:"') + contract_type.upper()) + '"')
    logger.info('Starting delete feed: %s', base_url)
    total_expected_records = get_total_expected_records(base_url)
    logger.info('{} record(s) expected from this feed'.format(total_expected_records))
    processed_deletions = 0
    while True:
        exception_retries = (- 1)
        retry_sleep_times = [5, 30, 60, 180, 300, 360, 420, 480, 540, 600]
        request_timeout = 60
        try:
            resp = requests.get(((base_url + '&start=') + str(processed_deletions)), timeout=request_timeout)
            resp_data = xmltodict.parse(resp.text, process_namespaces=True, namespaces=FPDS_NAMESPACES)
        except (ConnectionResetError, ReadTimeoutError, ConnectionError, ReadTimeout) as e:
            exception_retries += 1
            request_timeout += 60
            if (exception_retries < len(retry_sleep_times)):
                logger.info('Connection exception caught. Sleeping {}s and then retrying with a max wait of {}s...'.format(retry_sleep_times[exception_retries], request_timeout))
                time.sleep(retry_sleep_times[exception_retries])
            else:
                logger.info('Connection to FPDS feed lost, maximum retry attempts exceeded.')
                raise e
        try:
            listed_data = list_data(resp_data['feed']['entry'])
        except KeyError:
            listed_data = []
        if (processed_deletions > total_expected_records):
            raise Exception('Total number of expected records has changed\nExpected: {}\nRetrieved so far: {}'.format(total_expected_records, len(processed_deletions)))
        for ld in listed_data:
            data.append(ld)
            processed_deletions += 1
        if ((processed_deletions % 100) == 0):
            logger.info('On line %s of %s delete feed', str(processed_deletions), contract_type)
        if (len(listed_data) < 10):
            if (processed_deletions != total_expected_records):
                raise Exception('Records retrieved != Total expected records\nExpected: {}\nRetrieved: {}'.format(total_expected_records, len(listed_data)))
            else:
                if ('deletes_received' not in metrics):
                    metrics['deletes_received'] = total_expected_records
                else:
                    metrics['deletes_received'] += total_expected_records
                break
        else:
            listed_data = []
    logger.info('Total entries in %s delete feed: %s', contract_type, str(processed_deletions))
    delete_list = []
    delete_dict = {}
    for value in data:
        last_modified = value['content'][contract_type]['transactionInformation']['lastModifiedDate']
        unique_string = process_delete_data(value['content'][contract_type], atom_type=contract_type)
        existing_item = sess.query(DetachedAwardProcurement).filter_by(detached_award_proc_unique=unique_string).one_or_none()
        if existing_item:
            if (last_modified > existing_item.last_modified):
                delete_list.append(existing_item.detached_award_procurement_id)
                delete_dict[existing_item.detached_award_procurement_id] = existing_item.detached_award_proc_unique
    if delete_list:
        if ('records_deleted' not in metrics):
            metrics['records_deleted'] = len(delete_list)
        else:
            metrics['records_deleted'] += len(delete_list)
        sess.query(DetachedAwardProcurement).filter(DetachedAwardProcurement.detached_award_procurement_id.in_(delete_list)).delete(synchronize_session=False)
    seconds = int((datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)).total_seconds())
    file_name = (((((now.strftime('%m-%d-%Y') + '_delete_records_') + contract_type) + '_') + str(seconds)) + '.csv')
    metrics['deleted_{}_records_file'.format(contract_type).lower()] = file_name
    headers = ['detached_award_procurement_id', 'detached_award_proc_unique']
    if CONFIG_BROKER['use_aws']:
        s3client = boto3.client('s3', region_name=CONFIG_BROKER['aws_region'])
        contents = bytes((','.join(headers) + '\n').encode())
        for (key, value) in delete_dict.items():
            contents += bytes('{},{}\n'.format(key, value).encode())
        s3client.put_object(Bucket=CONFIG_BROKER['fpds_delete_bucket'], Key=file_name, Body=contents)
    else:
        with CsvLocalWriter(file_name, headers) as writer:
            for (key, value) in delete_dict.items():
                writer.write([key, value])
            writer.finish_batch()
Get data from the delete feed
def get_delete_data(contract_type, now, sess, last_run, start_date=None, end_date=None, metrics=None):
    '  '
    if (not metrics):
        metrics = {}
    data = []
    yesterday = (now - datetime.timedelta(days=1))
    last_run_date = (last_run - relativedelta(days=1))
    params = (((('LAST_MOD_DATE:[' + last_run_date.strftime('%Y/%m/%d')) + ',') + yesterday.strftime('%Y/%m/%d')) + '] ')
    if (start_date and end_date):
        params = (((('LAST_MOD_DATE:[' + start_date) + ',') + end_date) + '] ')
        if (not metrics['start_date']):
            metrics['start_date'] = start_date
        if (not metrics['end_date']):
            metrics['end_date'] = end_date
    base_url = ((((delete_url + params) + 'CONTRACT_TYPE:"') + contract_type.upper()) + '"')
    logger.info('Starting delete feed: %s', base_url)
    total_expected_records = get_total_expected_records(base_url)
    logger.info('{} record(s) expected from this feed'.format(total_expected_records))
    processed_deletions = 0
    while True:
        exception_retries = (- 1)
        retry_sleep_times = [5, 30, 60, 180, 300, 360, 420, 480, 540, 600]
        request_timeout = 60
        try:
            resp = requests.get(((base_url + '&start=') + str(processed_deletions)), timeout=request_timeout)
            resp_data = xmltodict.parse(resp.text, process_namespaces=True, namespaces=FPDS_NAMESPACES)
        except (ConnectionResetError, ReadTimeoutError, ConnectionError, ReadTimeout) as e:
            exception_retries += 1
            request_timeout += 60
            if (exception_retries < len(retry_sleep_times)):
                logger.info('Connection exception caught. Sleeping {}s and then retrying with a max wait of {}s...'.format(retry_sleep_times[exception_retries], request_timeout))
                time.sleep(retry_sleep_times[exception_retries])
            else:
                logger.info('Connection to FPDS feed lost, maximum retry attempts exceeded.')
                raise e
        try:
            listed_data = list_data(resp_data['feed']['entry'])
        except KeyError:
            listed_data = []
        if (processed_deletions > total_expected_records):
            raise Exception('Total number of expected records has changed\nExpected: {}\nRetrieved so far: {}'.format(total_expected_records, len(processed_deletions)))
        for ld in listed_data:
            data.append(ld)
            processed_deletions += 1
        if ((processed_deletions % 100) == 0):
            logger.info('On line %s of %s delete feed', str(processed_deletions), contract_type)
        if (len(listed_data) < 10):
            if (processed_deletions != total_expected_records):
                raise Exception('Records retrieved != Total expected records\nExpected: {}\nRetrieved: {}'.format(total_expected_records, len(listed_data)))
            else:
                if ('deletes_received' not in metrics):
                    metrics['deletes_received'] = total_expected_records
                else:
                    metrics['deletes_received'] += total_expected_records
                break
        else:
            listed_data = []
    logger.info('Total entries in %s delete feed: %s', contract_type, str(processed_deletions))
    delete_list = []
    delete_dict = {}
    for value in data:
        last_modified = value['content'][contract_type]['transactionInformation']['lastModifiedDate']
        unique_string = process_delete_data(value['content'][contract_type], atom_type=contract_type)
        existing_item = sess.query(DetachedAwardProcurement).filter_by(detached_award_proc_unique=unique_string).one_or_none()
        if existing_item:
            if (last_modified > existing_item.last_modified):
                delete_list.append(existing_item.detached_award_procurement_id)
                delete_dict[existing_item.detached_award_procurement_id] = existing_item.detached_award_proc_unique
    if delete_list:
        if ('records_deleted' not in metrics):
            metrics['records_deleted'] = len(delete_list)
        else:
            metrics['records_deleted'] += len(delete_list)
        sess.query(DetachedAwardProcurement).filter(DetachedAwardProcurement.detached_award_procurement_id.in_(delete_list)).delete(synchronize_session=False)
    seconds = int((datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)).total_seconds())
    file_name = (((((now.strftime('%m-%d-%Y') + '_delete_records_') + contract_type) + '_') + str(seconds)) + '.csv')
    metrics['deleted_{}_records_file'.format(contract_type).lower()] = file_name
    headers = ['detached_award_procurement_id', 'detached_award_proc_unique']
    if CONFIG_BROKER['use_aws']:
        s3client = boto3.client('s3', region_name=CONFIG_BROKER['aws_region'])
        contents = bytes((','.join(headers) + '\n').encode())
        for (key, value) in delete_dict.items():
            contents += bytes('{},{}\n'.format(key, value).encode())
        s3client.put_object(Bucket=CONFIG_BROKER['fpds_delete_bucket'], Key=file_name, Body=contents)
    else:
        with CsvLocalWriter(file_name, headers) as writer:
            for (key, value) in delete_dict.items():
                writer.write([key, value])
            writer.finish_batch()