def test_round_trip_tcja_reform():
    """
    Check that current-law policy has the same policy parameter values in
    a future year as does a compound reform that first implements the
    reform specified in the 2017_law.json file and then implements the
    reform specified in the TCJA.json file.  This test checks that the
    future-year parameter values for current-law policy (which incorporates
    TCJA) are the same as future-year parameter values for the compound
    round-trip reform.  Doing this check ensures that the 2017_law.json
    and TCJA.json reform files are specified in a consistent manner.
    """
    # pylint: disable=too-many-locals
    fyear = 2020
    # create clp metadata dictionary for current-law policy in fyear
    pol = Policy()
    pol.set_year(fyear)
    clp_mdata = dict(pol.items())
    # create rtr metadata dictionary for round-trip reform in fyear
    pol = Policy()
    reform_file = os.path.join(CUR_PATH, '..', 'taxcalc', '2017_law.json')
    with open(reform_file, 'r') as rfile:
        rtext = rfile.read()
    pol.implement_reform(Policy.read_json_reform(rtext))

    assert not pol.parameter_warnings
    assert not pol.errors
    reform_file = os.path.join(CUR_PATH, '..', 'taxcalc', 'TCJA.json')
    with open(reform_file, 'r') as rfile:
        rtext = rfile.read()
    pol.implement_reform(Policy.read_json_reform(rtext))
    assert not pol.parameter_warnings
    assert not pol.errors
    pol.set_year(fyear)
    rtr_mdata = dict(pol.items())
    # compare fyear policy parameter values
    assert clp_mdata.keys() == rtr_mdata.keys()
    fail_dump = False
    if fail_dump:
        rtr_fails = open('fails_rtr', 'w')
        clp_fails = open('fails_clp', 'w')
    fail_params = list()
    msg = '\nRound-trip-reform and current-law-policy param values differ for:'
    for pname in clp_mdata.keys():
        rtr_val = rtr_mdata[pname]
        clp_val = clp_mdata[pname]
        if not np.allclose(rtr_val, clp_val):
            fail_params.append(pname)
            msg += '\n  {} in {} : rtr={} clp={}'.format(
                pname, fyear, rtr_val, clp_val)
            if fail_dump:
                rtr_fails.write('{} {} {}\n'.format(pname, fyear, rtr_val))
                clp_fails.write('{} {} {}\n'.format(pname, fyear, clp_val))
    if fail_dump:
        rtr_fails.close()
        clp_fails.close()
    if fail_params:
        raise ValueError(msg)
def test_2017_law_reform():
    """
    Check that policy parameter values in a future year under current-law
    policy and under the reform specified in the 2017_law.json file are
    sensible.
    """
    # create pre metadata dictionary for 2017_law.json reform in fyear
    pol = Policy()
    reform_file = os.path.join(CUR_PATH, '..', 'taxcalc', '2017_law.json')
    with open(reform_file, 'r') as rfile:
        rtext = rfile.read()
    pol.implement_reform(Policy.read_json_reform(rtext))
    assert not pol.parameter_warnings
    pol.set_year(2018)
    pre_mdata = dict(pol.items())
    # check some policy parameter values against expected values under 2017 law
    pre_expect = {
        # relation '<' implies asserting that actual < expect
        # relation '>' implies asserting that actual > expect
        # ... parameters not affected by TCJA and that are not indexed
        'AMEDT_ec': {
            'relation': '=',
            'value': 200000
        },
        'SS_thd85': {
            'relation': '=',
            'value': 34000
        },
        # ... parameters not affected by TCJA and that are indexed
        'STD_Dep': {
            'relation': '>',
            'value': 1050
        },
        'CG_brk2': {
            'relation': '>',
            'value': 425800
        },
        'AMT_CG_brk1': {
            'relation': '>',
            'value': 38600
        },
        'AMT_brk1': {
            'relation': '>',
            'value': 191100
        },
        'EITC_c': {
            'relation': '>',
            'value': 519
        },
        'EITC_ps': {
            'relation': '>',
            'value': 8490
        },
        'EITC_ps_MarriedJ': {
            'relation': '>',
            'value': 5680
        },
        'EITC_InvestIncome_c': {
            'relation': '>',
            'value': 3500
        },
        # ... parameters affected by TCJA and that are not indexed
        'ID_Charity_crt_all': {
            'relation': '=',
            'value': 0.5
        },
        'II_rt3': {
            'relation': '=',
            'value': 0.25
        },
        # ... parameters affected by TCJA and that are indexed
        'II_brk3': {
            'relation': '>',
            'value': 91900
        },
        'STD': {
            'relation': '<',
            'value': 7000
        },
        'II_em': {
            'relation': '>',
            'value': 4050
        },
        'AMT_em_pe': {
            'relation': '<',
            'value': 260000
        }
    }
    assert isinstance(pre_expect, dict)
    assert set(pre_expect.keys()).issubset(set(pre_mdata.keys()))
    for name in pre_expect:
        aval = pre_mdata[name]
        if aval.ndim == 2:
            act = aval[0][0]  # comparing only first item in a vector parameter
        else:
            act = aval[0]
        exp = pre_expect[name]['value']
        if pre_expect[name]['relation'] == '<':
            assert act < exp, '{} a={} !< e={}'.format(name, act, exp)
        elif pre_expect[name]['relation'] == '>':
            assert act > exp, '{} a={} !> e={}'.format(name, act, exp)
        elif pre_expect[name]['relation'] == '=':
            assert act == exp, '{} a={} != e={}'.format(name, act, exp)
Exemple #3
0
def test_round_trip_reforms(fyear, tests_path):
    """
    Check that current-law policy has the same policy parameter values in
    a future year as does a compound reform that first implements the
    2017 tax law as specified in the 2017_law.json file and then implements
    reforms that represents new tax legislation since 2017.
    This test checks that the future-year parameter values for
    current-law policy (which incorporates recent legislation such as
    the TCJA, CARES Act, and ARPA) are the same as future-year
    parameter values for the compound round-trip reform.
    Doing this check ensures that the 2017_law.json
    and subsequent reform files that represent recent legislation are
    specified in a consistent manner.
    """
    # pylint: disable=too-many-locals
    # create clp metadata dictionary for current-law policy in fyear
    clp_pol = Policy()
    clp_pol.set_year(fyear)
    clp_mdata = dict(clp_pol.items())
    # create rtr metadata dictionary for round-trip reform in fyear
    rtr_pol = Policy()
    # Revert to 2017 law
    reform_file = os.path.join(tests_path, '..', 'reforms', '2017_law.json')
    with open(reform_file, 'r') as rfile:
        rtext = rfile.read()
    rtr_pol.implement_reform(Policy.read_json_reform(rtext))
    assert not rtr_pol.parameter_warnings
    assert not rtr_pol.errors
    # Layer on TCJA
    reform_file = os.path.join(tests_path, '..', 'reforms', 'TCJA.json')
    with open(reform_file, 'r') as rfile:
        rtext = rfile.read()
    rtr_pol.implement_reform(Policy.read_json_reform(rtext))
    assert not rtr_pol.parameter_warnings
    assert not rtr_pol.errors
    # Layer on the CARES Act
    rtr_pol.implement_reform({
        'ID_Charity_crt_all': {
            2020: 1.0,
            2021: 0.6
        },
        'STD_allow_charity_ded_nonitemizers': {
            2020: True,
            2021: False
        },
        'STD_charity_ded_nonitemizers_max': {
            2020: 300.0,
            2021: 0.0
        }
    })
    assert not rtr_pol.parameter_warnings
    assert not rtr_pol.errors
    # Layer on ARPA
    rtr_pol.implement_reform({
        'RRC_c': {
            2021: 1400,
            2022: 0
        },
        'RRC_ps': {
            2021: [75000, 150000, 75000, 112500, 150000],
            2022: [0, 0, 0, 0, 0]
        },
        'RRC_pe': {
            2021: [80000, 160000, 80000, 120000, 160000],
            2022: [0, 0, 0, 0, 0]
        },
        'UI_em': {
            2020: 10200,
            2021: 0
        },
        'UI_thd': {
            2020: [150000, 150000, 150000, 150000, 150000],
            2021: [0, 0, 0, 0, 0]
        },
        'CTC_refundable': {
            2021: True,
            2022: False
        },
        'CTC_include17': {
            2021: True,
            2022: False
        },
        'CTC_new_c': {
            2021: 1000,
            2022: 0
        },
        'CTC_new_c_under6_bonus': {
            2021: 600,
            2022: 0
        },
        'CTC_new_for_all': {
            2021: True,
            2022: False
        },
        'CTC_new_ps': {
            2021: [75000, 150000, 75000, 112500, 150000],
            2022: [0, 0, 0, 0, 0]
        },
        'CTC_new_prt': {
            2021: 0.05,
            2022: 0
        },
        'EITC_c': {
            2021: [1502.46, 3606.44, 5960.95, 6706.58],
            2022: [546.21, 3640.7, 6017.58, 6770.29]
        },
        'EITC_rt': {
            2021: [0.153, 0.34, 0.4, 0.45],
            2022: [0.0765, 0.34, 0.4, 0.45]
        },
        'EITC_ps': {
            2021: [11610, 19464.12, 19464.12, 19464.12],
            2022: [8931.38, 19649.03, 19649.03, 19649.03]
        },
        'EITC_MinEligAge': {
            2021: 19,
            2022: 25
        },
        'EITC_MaxEligAge': {
            2021: 125,
            2022: 64
        },
        'EITC_InvestIncome_c': {
            2021: 10000
        },
        'EITC_sep_filers_elig': {
            2021: True
        },
        'CDCC_c': {
            2021: 8000,
            2022: 3000
        },
        'CDCC_ps': {
            2021: 125000,
            2022: 15000
        },
        'CDCC_ps2': {
            2021: 400000,
            2022: 9e+99
        },
        'CDCC_crt': {
            2021: 50.0,
            2022: 35.0
        },
        'CDCC_refundable': {
            2021: True,
            2022: False
        },
        'ALD_BusinessLosses_c': {
            2026: [283535.22, 567070.42, 283535.22, 283535.22, 567070.42],
            2027: [9e+99, 9e+99, 9e+99, 9e+99, 9e+99]
        }
    })
    assert not rtr_pol.parameter_warnings
    assert not rtr_pol.errors
    rtr_pol.set_year(fyear)
    rtr_mdata = dict(rtr_pol.items())
    # compare fyear policy parameter values
    assert clp_mdata.keys() == rtr_mdata.keys()
    fail_dump = False
    if fail_dump:
        rtr_fails = open('fails_rtr', 'w')
        clp_fails = open('fails_clp', 'w')
    fail_params = list()
    msg = '\nRound-trip-reform and current-law-policy param values differ for:'
    for pname in clp_mdata.keys():
        rtr_val = rtr_mdata[pname]
        clp_val = clp_mdata[pname]
        if not np.allclose(rtr_val, clp_val):
            fail_params.append(pname)
            msg += '\n  {} in {} : rtr={} clp={}'.format(
                pname, fyear, rtr_val, clp_val)
            if fail_dump:
                rtr_fails.write('{} {} {}\n'.format(pname, fyear, rtr_val))
                clp_fails.write('{} {} {}\n'.format(pname, fyear, clp_val))
    if fail_dump:
        rtr_fails.close()
        clp_fails.close()
    if fail_params:
        raise ValueError(msg)