Calculates the VAT rate for a customer based on their declared country
    and any declared exception information.

    :param country_code:
        The two-character country code where the user resides

    :param exception_name:
        The name of an exception for the country, as returned from
        vat_moss.declared_residence.options()

    :raises:
        ValueError - if country_code is not two characers, or exception_name is not None or a valid exception from options()

    :return:
        A tuple of (Decimal VAT rate, country_code, exception name [or None])

def calculate_rate(country_code, exception_name):
    """
    Calculates the VAT rate for a customer based on their declared country
    and any declared exception information.

    :param country_code:
        The two-character country code where the user resides

    :param exception_name:
        The name of an exception for the country, as returned from
        vat_moss.declared_residence.options()

    :raises:
        ValueError - if country_code is not two characers, or exception_name is not None or a valid exception from options()

    :return:
        A tuple of (Decimal VAT rate, country_code, exception name [or None])
    """

    if not country_code or not isinstance(country_code, str_cls) or len(country_code) != 2:
        raise ValueError('Invalidly formatted country code')

    if exception_name and not isinstance(exception_name, str_cls):
        raise ValueError('Exception name is not None or a string')

    country_code = country_code.upper()

    if country_code not in rates.BY_COUNTRY:
        return (Decimal('0.0'), country_code, None)

    country_info = rates.BY_COUNTRY[country_code]

    if not exception_name:
        return (country_info['rate'], country_code, None)

    if exception_name not in country_info['exceptions']:
        raise ValueError('"%s" is not a valid exception for %s' % (exception_name, country_code))

    rate_info = country_info['exceptions'][exception_name]
    if isinstance(rate_info, Decimal):
        rate = rate_info
    else:
        # This allows handling the complex case of the UK RAF bases in Cyprus
        # that map to the standard country rate. The country code and exception
        # name need to be changed in addition to gettting a special rate.
        rate, country_code, exception_name = rate_info
    return (rate, country_code, exception_name)