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)
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)