def _extract_input(req: RunCheckRequest) -> Tuple[List[Error], Optional[IndividualData]]:
    errors = []

    # Extract address
    # TODO: Validate required address fields
    current_address = req.check_input.get_current_address()
    if current_address is None and req.provider_config.require_address:
        errors.append(Error.missing_required_field(Field.ADDRESS_HISTORY))

    # Extract DOB
    dob = req.check_input.get_dob()
    if dob is None and req.provider_config.require_dob:
        errors.append(Error.missing_required_field(Field.DOB))

    # Extract given names
    given_names = req.check_input.get_given_names()
    if given_names is None:
        errors.append(Error.missing_required_field(Field.GIVEN_NAMES))

    # Extract family name
    family_name = req.check_input.get_family_name()
    if family_name is None:
        errors.append(Error.missing_required_field(Field.FAMILY_NAME))

    # Extract documents
    documents = req.check_input.get_documents()
    if not documents:
        errors.append(Error.missing_documents())

    if errors:
        return errors, None
    else:
        return [], req.check_input
def _run_demo_check(check_id: UUID, check_input: IndividualData, demo_result: str) -> RunCheckResponse:
    documents = check_input.get_documents()
    verified_documents = [
        _synthesize_demo_result(doc, check_input, demo_result)
        for doc in documents
    ]
    check_input.documents = verified_documents

    custom_data = {'errors': []}
    if demo_result == DemoResultType.ERROR_INVALID_CREDENTIALS:
        custom_data['errors'].append(Error.invalid_credentials('Invalid credentials demo').serialize())

    if demo_result == DemoResultType.ERROR_ANY_PROVIDER_MESSAGE:
        custom_data['errors'].append(Error.provider_message('Demo provider message').serialize())

    if demo_result == DemoResultType.ERROR_CONNECTION_TO_PROVIDER:
        custom_data['errors'].append(Error.provider_connection('Demo provider connection issue').serialize())

    if demo_result not in DemoResultType.variants:
        custom_data['errors'].append(Error.unsupported_demo_result(demo_result).serialize())

    if len(custom_data['errors']) == 0:
        custom_data['check_output'] = check_input.serialize()

    response = RunCheckResponse({
        'provider_id': DEMO_PROVIDER_ID,
        'reference': f'DEMODATA-{check_id}',
        'custom_data': custom_data,
    })

    # Prepare a callback to be fired in another thread
    _cb = Thread(target=task_thread, args=(response['provider_id'], response['reference']))
    _cb.start()

    return response
def search(req: SearchRequest) -> SearchResponse:
    errors, search_input = _extract_search_input(req)
    if errors:
        return SearchResponse.error(errors)

    country = search_input.country_of_incorporation
    if country not in SUPPORTED_COUNTRIES:
        return SearchResponse.error([Error.unsupported_country()])

    if req.demo_result is not None:
        return _run_demo_search(search_input, req.demo_result, req.commercial_relationship)

    return SearchResponse.error([Error({
        'type': ErrorType.PROVIDER_MESSAGE,
        'message': 'Live searches are not supported',
    })])
def run_check(req: RunCheckRequest) -> RunCheckResponse:
    errors, check_input = _extract_check_input(req)
    if errors:
        return RunCheckResponse.error(errors)

    country = check_input.country_of_incorporation
    if country not in SUPPORTED_COUNTRIES:
        return RunCheckResponse.error([Error.unsupported_country()])

    if req.demo_result is not None:
        return _run_demo_check(check_input, req.demo_result, req.commercial_relationship)

    return RunCheckResponse.error([Error({
        'type': ErrorType.PROVIDER_MESSAGE,
        'message': 'Live checks are not supported',
    })])
def finish_check(req: FinishRequest, _id: UUID) -> FinishResponse:
    # We probably shouldn't have made it this far if they were trying a live check
    if not req.reference.startswith('DEMODATA-'):
        return FinishResponse.error([Error({
            'type': ErrorType.PROVIDER_MESSAGE,
            'message': 'Live checks are not supported',
        })])

    if not req.custom_data:
        return FinishResponse.error([Error({
            'type': ErrorType.PROVIDER_MESSAGE,
            'message': 'Demo finish request did not contain demo result',
        })])

    resp = FinishResponse()
    resp.import_data(req.custom_data)
    return resp
def run_check(req: RunCheckRequest) -> RunCheckResponse:
    errors, _external_ref = _extract_input(req)
    if errors:
        return RunCheckResponse.error(errors)

    country = req.check_input.get_current_address().country
    if country not in SUPPORTED_COUNTRIES:
        return RunCheckResponse.error([Error.unsupported_country()])

    if req.demo_result is not None:
        return _run_demo_check(req.id, req.check_input, req.demo_result)

    return RunCheckResponse.error([
        Error({
            'type': ErrorType.PROVIDER_MESSAGE,
            'message': 'Live checks are not supported',
        })
    ])
def _extract_input(req: RunCheckRequest) -> Tuple[List[Error], str]:
    errors = []

    external_ref = req.check_input.get_external_ref()
    if external_ref is None:
        errors.append(Error.missing_required_field(Field.EXTERNAL_REFERENCE))

    if errors:
        return errors, None
    else:
        return [], external_ref
def _extract_search_input(req: RunCheckRequest) -> Tuple[List[Error], Optional[SearchInput]]:
    errors = []

    # Extract country of incorporation
    country_of_incorporation = req.search_input.country_of_incorporation
    if country_of_incorporation is None:
        errors.append(Error.missing_required_field(Field.COUNTRY_OF_INCORPORATION))

    if errors:
        return errors, None
    else:
        return [], SearchInput(
            country_of_incorporation=country_of_incorporation
        )
def run_check(req: RunCheckRequest) -> RunCheckResponse:
    errors, check_input = _extract_input(req)
    if errors:
        return RunCheckResponse.error(DEMO_PROVIDER_ID, errors)

    country = check_input.get_current_address().country
    if country not in SUPPORTED_COUNTRIES:
        return RunCheckResponse.error(DEMO_PROVIDER_ID, [Error.unsupported_country()])

    # Download the images even though we won't do anything with them
    doc_images = {}
    for doc_image_id in check_input.get_document_image_ids():
        content = _download_image(doc_image_id)
        assert len(content) > 0
        doc_images[doc_image_id] = content

    if req.demo_result is not None:
        return _run_demo_check(req.id, check_input, req.demo_result)

    return RunCheckResponse.error(DEMO_PROVIDER_ID, [Error({
        'type': ErrorType.PROVIDER_MESSAGE,
        'message': 'Live checks are not supported',
    })])
def _extract_check_input(req: RunCheckRequest) -> Tuple[List[Error], Optional[CheckInput]]:
    errors = []

    # Extract country of incorporation
    country_of_incorporation = req.check_input.get_country_of_incorporation()
    if country_of_incorporation is None:
        errors.append(Error.missing_required_field(Field.COUNTRY_OF_INCORPORATION))

    name = req.check_input.get_company_name()
    number = req.check_input.get_company_number()

    if errors:
        return errors, None
    else:
        return [], CheckInput(
            name=name,
            number=number,
            country_of_incorporation=country_of_incorporation,
        )