def taxcalc_results(start_year, reform_dict, itax_clp, ptax_clp): """ Use taxcalc package on this computer to compute aggregate income tax and payroll tax revenue difference (between reform and current-law policy) for ten years beginning with the specified start_year using the specified reform_dict dictionary and the two specified current-law-policy results dictionaries. Return two aggregate tax revenue difference dictionaries indexed by calendar year. """ pol = Policy() pol.implement_reform(reform_dict) calc = Calculator(policy=pol, records=Records(data=PUF_PATH), verbose=False) calc.advance_to_year(start_year) nyears = NUMBER_OF_YEARS adts = list() for iyr in range(-1, nyears - 1): calc.calc_all() adts.append(create_diagnostic_table(calc)) if iyr < nyears: calc.increment_year() adt = pd.concat(adts, axis=1) # note that adt is Pandas DataFrame object itax_ref = adt.xs('Ind Income Tax ($b)').to_dict() ptax_ref = adt.xs('Payroll Taxes ($b)').to_dict() itax_diff = {} ptax_diff = {} for year in itax_ref: itax_diff[year] = round(itax_ref[year] - itax_clp[year], 1) ptax_diff[year] = round(ptax_ref[year] - ptax_clp[year], 1) return (itax_diff, ptax_diff)
def test_make_Calculator_increment_years_first(): # create Policy object with custom indexing rates and policy reform irates = {2013: 0.01, 2014: 0.01, 2015: 0.02, 2016: 0.01, 2017: 0.03} policy = Policy(start_year=2013, inflation_rates=irates, num_years=len(irates)) reform = {2015: {}, 2016: {}} reform[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False policy.implement_reform(reform) # create Records object by reading 1991 data and saying it is 2009 data tax_dta = pd.read_csv(TAX_DTA_PATH, compression='gzip') puf = Records(tax_dta, weights=WEIGHTS, start_year=2009) # create Calculator object with Policy object as modified by reform calc = Calculator(policy=policy, records=puf) # compare expected policy parameter values with those embedded in calc exp_STD_Aged = np.array([[1500, 1200, 1200, 1500, 1500, 1200], [1550, 1200, 1200, 1550, 1550, 1200], [1600, 1300, 1600, 1300, 1600, 1300], [1632, 1326, 1632, 1326, 1632, 1326], [1648, 1339, 1648, 1339, 1648, 1339]]) exp_II_em = np.array([3900, 3950, 5000, 6000, 6000]) assert_array_equal(calc.policy._STD_Aged, exp_STD_Aged) assert_array_equal(calc.policy._II_em, exp_II_em)
def test_calculator_mtr_when_PT_rates_differ(): """ Test Calculator mtr method in special case. """ reform = {2013: {'_II_rt1': [0.40], '_II_rt2': [0.40], '_II_rt3': [0.40], '_II_rt4': [0.40], '_II_rt5': [0.40], '_II_rt6': [0.40], '_II_rt7': [0.40], '_PT_rt1': [0.30], '_PT_rt2': [0.30], '_PT_rt3': [0.30], '_PT_rt4': [0.30], '_PT_rt5': [0.30], '_PT_rt6': [0.30], '_PT_rt7': [0.30]}} funit = ( u'RECID,MARS,FLPDYR,e00200,e00200p,e00900,e00900p,extraneous\n' u'1, 1, 2009, 200000,200000, 100000,100000, 9999999999\n' ) rec = Records(pd.read_csv(StringIO(funit))) pol = Policy() calc1 = Calculator(policy=pol, records=rec) (_, mtr1, _) = calc1.mtr(variable_str='p23250') pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) (_, mtr2, _) = calc2.mtr(variable_str='p23250') assert np.allclose(mtr1, mtr2, rtol=0.0, atol=1e-06)
def test_expand_2D_accept_None(): _II_brk2 = [[36000, 72250, 36500, 48600, 72500, 36250], [38000, 74000, 36900, 49400, 73800, 36900], [40000, 74900, 37450, 50200, 74900, 37450], [41000, None, None, None, None, None]] exp1 = 74900 * 1.02 exp2 = 37450 * 1.02 exp3 = 50200 * 1.02 exp4 = 74900 * 1.02 exp5 = 37450 * 1.02 exp = [[36000, 72250, 36500, 48600, 72500, 36250], [38000, 74000, 36900, 49400, 73800, 36900], [40000, 74900, 37450, 50200, 74900, 37450], [41000, exp1, exp2, exp3, exp4, exp5]] exp = np.array(exp).astype('i4', casting='unsafe') res = Policy.expand_array(_II_brk2, inflate=True, inflation_rates=[0.02] * 5, num_years=4) npt.assert_array_equal(res, exp) user_mods = {2016: {u'_II_brk2': _II_brk2}} pol = Policy(start_year=2013) pol.implement_reform(user_mods) pol.set_year(2019) irates = Policy.default_inflation_rates() # The 2019 policy should be the combination of the user-defined # value and CPI-inflated values from 2018 exp_2019 = [41000.] + [(1 + irates[2018]) * i for i in _II_brk2[2][1:]] exp_2019 = np.array(exp_2019) npt.assert_array_equal(pol.II_brk2, exp_2019)
def test_read_json_reform_file_and_implement_reform_b(reform_file): """ Test reading and translation of reform file into a reform dictionary that is then used to call implement_reform method. NOTE: implement_reform called when policy.current_year > policy.start_year """ reform = Policy.read_json_reform_file(reform_file.name) policy = Policy() policy.set_year(2015) # the only difference between this and prior test policy.implement_reform(reform) syr = policy.start_year amt_tthd = policy._AMT_tthd assert amt_tthd[2015 - syr] == 200000 assert amt_tthd[2016 - syr] > 200000 assert amt_tthd[2017 - syr] == 300000 assert amt_tthd[2018 - syr] > 300000 ii_em = policy._II_em assert ii_em[2016 - syr] == 6000 assert ii_em[2017 - syr] == 6000 assert ii_em[2018 - syr] == 7500 assert ii_em[2019 - syr] > 7500 assert ii_em[2020 - syr] == 9000 assert ii_em[2021 - syr] > 9000 amt_em = policy._AMT_em assert amt_em[2016 - syr, 0] > amt_em[2015 - syr, 0] assert amt_em[2017 - syr, 0] > amt_em[2016 - syr, 0] assert amt_em[2018 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2019 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2020 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2021 - syr, 0] > amt_em[2020 - syr, 0] assert amt_em[2022 - syr, 0] > amt_em[2021 - syr, 0]
def diff_in_revenue(reform_on_II, orig_reform): policy_func = Policy() puf = pd.read_csv("./puf.csv") records_func = Records(puf) calc_func = Calculator(policy = policy_func, records = records_func) policy_bench = Policy() records_bench = Records(puf) calc_bench = Calculator(policy = policy_bench, records = records_bench) reform = { CURRENT_YEAR:{ "_II_rt1":[max(policy_bench._II_rt1[0] *(1 - reform_on_II),0.0)], "_II_rt2":[max(policy_bench._II_rt2[0] *(1 - reform_on_II),0.0)], "_II_rt3":[max(policy_bench._II_rt3[0] *(1 - reform_on_II),0.0)], "_II_rt4":[max(policy_bench._II_rt4[0] *(1 - reform_on_II),0.0)], "_II_rt5":[max(policy_bench._II_rt5[0] *(1 - reform_on_II),0.0)], "_II_rt6":[max(policy_bench._II_rt6[0] *(1 - reform_on_II),0.0)], "_II_rt7":[max(policy_bench._II_rt7[0] *(1 - reform_on_II),0.0)]} } policy_func.implement_reform(reform) policy_func.implement_reform(orig_reform) calc_func.advance_to_year(CURRENT_YEAR) calc_bench.advance_to_year(CURRENT_YEAR) calc_func.calc_all() calc_bench.calc_all() ans = ((calc_bench.records._combined*calc_bench.records.s006).sum()-(calc_func.records._combined*calc_func.records.s006).sum()) print("diff in revenue is ", ans) return ans
def test_round_trip_tcja_reform(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 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 = pol.metadata() # create rtr metadata dictionary for round-trip reform in fyear pol = Policy() reform_file = os.path.join(tests_path, '..', 'reforms', '2017_law.json') with open(reform_file, 'r') as rfile: rtext = rfile.read() pol.implement_reform(Policy.read_json_reform(rtext)) # eventually activate: assert not clp.parameter_warnings ctc_c_warning = 'CTC_c was redefined in release 1.0.0\n' assert pol.parameter_warnings == ctc_c_warning assert not pol.parameter_errors reform_file = os.path.join(tests_path, '..', 'reforms', 'TCJA.json') with open(reform_file, 'r') as rfile: rtext = rfile.read() pol.implement_reform(Policy.read_json_reform(rtext)) # eventually activate: assert not clp.parameter_warnings assert pol.parameter_warnings == ctc_c_warning assert not pol.parameter_errors pol.set_year(fyear) rtr_mdata = pol.metadata() # 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]['value'] clp_val = clp_mdata[pname]['value'] 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_variable_inflation_rate_with_reform(): """ Test indexing of policy parameters involved in a reform. """ pol = Policy() syr = Policy.JSON_START_YEAR assert pol._II_em[2013 - syr] == 3900 # implement reform in 2020 which is two years before the last year, 2022 reform = { 'II_em': {2018: 1000, # to avoid divide-by-zero under TCJA 2020: 20000} } pol.implement_reform(reform) pol.set_year(2020) assert pol.current_year == 2020 # extract price inflation rates pirates = pol.inflation_rates() irate2018 = pirates[2018 - syr] irate2020 = pirates[2020 - syr] irate2021 = pirates[2021 - syr] # check implied inflation rate between 2018 and 2019 (before the reform) grate = float(pol._II_em[2019 - syr]) / float(pol._II_em[2018 - syr]) assert round(grate - 1.0, 5) == round(irate2018, 5) # check implied inflation rate between 2020 and 2021 (after the reform) grate = float(pol._II_em[2021 - syr]) / float(pol._II_em[2020 - syr]) assert round(grate - 1.0, 5) == round(irate2020, 5) # check implied inflation rate between 2021 and 2022 (after the reform) grate = float(pol._II_em[2022 - syr]) / float(pol._II_em[2021 - syr]) assert round(grate - 1.0, 5) == round(irate2021, 5)
def test_credit_reforms(puf_subsample): """ Test personal credit reforms using puf.csv subsample """ rec = Records(data=puf_subsample) reform_year = 2017 # create current-law Calculator object, calc1 pol = Policy() calc1 = Calculator(policy=pol, records=rec) calc1.advance_to_year(reform_year) calc1.calc_all() itax1 = calc1.weighted_total('iitax') # create personal-refundable-credit-reform Calculator object, calc2 reform = {'II_credit': {reform_year: [1000, 1000, 1000, 1000, 1000]}} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc2.advance_to_year(reform_year) calc2.calc_all() itax2 = calc2.weighted_total('iitax') # create personal-nonrefundable-credit-reform Calculator object, calc3 reform = {'II_credit_nr': {reform_year: [1000, 1000, 1000, 1000, 1000]}} pol = Policy() pol.implement_reform(reform) calc3 = Calculator(policy=pol, records=rec) calc3.advance_to_year(reform_year) calc3.calc_all() itax3 = calc3.weighted_total('iitax') # check income tax revenues generated by the three Calculator objects assert itax2 < itax1 # because refundable credits lower revenues assert itax3 > itax2 # because nonrefundable credits lower revenues less assert itax3 < itax1 # because nonrefundable credits lower revenues some
def test_Policy_reform_makes_no_changes_before_year(): ppo = Policy(start_year=2013) reform = {2015: {'_II_em': [4400], '_II_em_cpi': True}} ppo.implement_reform(reform) ppo.set_year(2015) assert_array_equal(ppo._II_em[:3], np.array([3900, 3950, 4400])) assert ppo.II_em == 4400
def test_make_Calculator_with_reform_after_start_year(records_2009): # create Policy object using custom indexing rates irates = {2013: 0.01, 2014: 0.01, 2015: 0.02, 2016: 0.01, 2017: 0.03} parm = Policy(start_year=2013, num_years=len(irates), inflation_rates=irates) # specify reform in 2015, which is two years after Policy start_year reform = {2015: {}, 2016: {}} reform[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False parm.implement_reform(reform) calc = Calculator(policy=parm, records=records_2009) # compare actual and expected parameter values over all years assert np.allclose(calc.policy._STD_Aged, np.array([[1500, 1200, 1200, 1500, 1500, 1200], [1550, 1200, 1200, 1550, 1550, 1200], [1600, 1300, 1600, 1300, 1600, 1300], [1632, 1326, 1632, 1326, 1632, 1326], [1648, 1339, 1648, 1339, 1648, 1339]]), atol=0.5, rtol=0.0) # handles rounding to dollars assert np.allclose(calc.policy._II_em, np.array([3900, 3950, 5000, 6000, 6000])) # compare actual and expected values for 2015 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 assert np.allclose(calc.policy.II_em, 5000) assert np.allclose(calc.policy.STD_Aged, np.array([1600, 1300, 1600, 1300, 1600, 1300]))
def test_ID_HC_vs_BS(cps_subsample): """ Test that complete haircut of itemized deductions produces same results as a 100% benefit surtax with no benefit deduction. """ recs = Records.cps_constructor(data=cps_subsample) # specify complete-haircut reform policy and Calculator object hc_reform = {2013: {'_ID_Medical_hc': [1.0], '_ID_StateLocalTax_hc': [1.0], '_ID_RealEstate_hc': [1.0], '_ID_Casualty_hc': [1.0], '_ID_Miscellaneous_hc': [1.0], '_ID_InterestPaid_hc': [1.0], '_ID_Charity_hc': [1.0]}} hc_policy = Policy() hc_policy.implement_reform(hc_reform) hc_calc = Calculator(policy=hc_policy, records=recs) hc_calc.calc_all() hc_taxes = hc_calc.dataframe(['iitax', 'payrolltax']) del hc_calc # specify benefit-surtax reform policy and Calculator object bs_reform = {2013: {'_ID_BenefitSurtax_crt': [0.0], '_ID_BenefitSurtax_trt': [1.0]}} bs_policy = Policy() bs_policy.implement_reform(bs_reform) bs_calc = Calculator(policy=bs_policy, records=recs) bs_calc.calc_all() bs_taxes = bs_calc.dataframe(['iitax', 'payrolltax']) del bs_calc # compare calculated taxes generated by the two reforms assert np.allclose(hc_taxes['payrolltax'], bs_taxes['payrolltax']) assert np.allclose(hc_taxes['iitax'], bs_taxes['iitax'])
def test_Calculator_mtr_when_PT_rates_differ(): reform = {2013: {'_II_rt1': [0.40], '_II_rt2': [0.40], '_II_rt3': [0.40], '_II_rt4': [0.40], '_II_rt5': [0.40], '_II_rt6': [0.40], '_II_rt7': [0.40], '_PT_rt1': [0.30], '_PT_rt2': [0.30], '_PT_rt3': [0.30], '_PT_rt4': [0.30], '_PT_rt5': [0.30], '_PT_rt6': [0.30], '_PT_rt7': [0.30]}} funit = ( u'RECID,MARS,FLPDYR,e00200,e00200p,e00900,e00900p\n' u'1, 1, 2015, 200000,200000, 100000,100000\n' ) pol1 = Policy() rec1 = Records(pd.read_csv(StringIO(funit))) calc1 = Calculator(policy=pol1, records=rec1) (_, mtr1, _) = calc1.mtr(variable_str='p23250') pol2 = Policy() pol2.implement_reform(reform) rec2 = Records(pd.read_csv(StringIO(funit))) calc2 = Calculator(policy=pol2, records=rec2) (_, mtr2, _) = calc2.mtr(variable_str='p23250') assert np.allclose(mtr1, mtr2, rtol=0.0, atol=1e-06)
def test_dec_graph_plots(cps_subsample): pol = Policy() rec = Records.cps_constructor(data=cps_subsample) calc1 = Calculator(policy=pol, records=rec) year = 2020 calc1.advance_to_year(year) reform = { 'SS_Earnings_c': {year: 9e99}, # OASDI FICA tax on all earnings 'FICA_ss_trt': {year: 0.107484} # lower rate to keep revenue unchanged } pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc2.advance_to_year(year) assert calc1.current_year == calc2.current_year calc1.calc_all() calc2.calc_all() fig = calc1.decile_graph(calc2) assert fig dt1, dt2 = calc1.distribution_tables(calc2, 'weighted_deciles') dta = dec_graph_data(dt1, dt2, year, include_zero_incomes=True, include_negative_incomes=False) assert isinstance(dta, dict) dta = dec_graph_data(dt1, dt2, year, include_zero_incomes=False, include_negative_incomes=True) assert isinstance(dta, dict) dta = dec_graph_data(dt1, dt2, year, include_zero_incomes=False, include_negative_incomes=False) assert isinstance(dta, dict)
def test_ID_HC_vs_BS(puf_1991, weights_1991): """ Test that complete haircut of itemized deductions produces same results as a 100% benefit surtax with no benefit deduction. """ # specify complete-haircut reform policy and Calculator object hc_reform = {2013: {'_ID_Medical_hc': [1.0], '_ID_StateLocalTax_hc': [1.0], '_ID_RealEstate_hc': [1.0], '_ID_Casualty_hc': [1.0], '_ID_Miscellaneous_hc': [1.0], '_ID_InterestPaid_hc': [1.0], '_ID_Charity_hc': [1.0]}} hc_policy = Policy() hc_policy.implement_reform(hc_reform) hc_records = Records(data=puf_1991, weights=weights_1991, start_year=2009) hc_calc = Calculator(policy=hc_policy, records=hc_records) # specify benefit-surtax reform policy and Calculator object bs_reform = {2013: {'_ID_BenefitSurtax_crt': [0.0], '_ID_BenefitSurtax_trt': [1.0]}} bs_policy = Policy() bs_policy.implement_reform(bs_reform) bs_records = Records(data=puf_1991, weights=weights_1991, start_year=2009) bs_calc = Calculator(policy=bs_policy, records=bs_records) # compare calculated tax results generated by the two reforms hc_calc.calc_all() bs_calc.calc_all() assert np.allclose(hc_calc.records._payrolltax, bs_calc.records._payrolltax) assert np.allclose(hc_calc.records._iitax, bs_calc.records._iitax)
def test_distribution_tables(cps_subsample): """ Test distribution_tables method. """ pol = Policy() recs = Records.cps_constructor(data=cps_subsample) calc1 = Calculator(policy=pol, records=recs) assert calc1.current_year == 2014 calc1.calc_all() dt1, dt2 = calc1.distribution_tables(None, 'weighted_deciles') assert isinstance(dt1, pd.DataFrame) assert dt2 is None dt1, dt2 = calc1.distribution_tables(calc1, 'weighted_deciles') assert isinstance(dt1, pd.DataFrame) assert isinstance(dt2, pd.DataFrame) reform = {2014: {'_UBI_u18': [1000], '_UBI_1820': [1000], '_UBI_21': [1000]}} pol.implement_reform(reform) assert not pol.parameter_errors calc2 = Calculator(policy=pol, records=recs) calc2.calc_all() dt1, dt2 = calc1.distribution_tables(calc2, 'weighted_deciles') assert isinstance(dt1, pd.DataFrame) assert isinstance(dt2, pd.DataFrame)
def test_make_calculator_with_multiyear_reform(cps_subsample): """ Test Calculator class ctor with multi-year policy reform. """ rec = Records.cps_constructor(data=cps_subsample) year = rec.current_year # create a Policy object and apply a policy reform pol = Policy() reform = {2015: {}, 2016: {}} reform[2015]['_II_em'] = [5000, 6000] # reform values for 2015 and 2016 reform[2015]['_II_em_cpi'] = False reform[2016]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600]] pol.implement_reform(reform) # create a Calculator object using this policy-reform calc = Calculator(policy=pol, records=rec) # check that Policy object embedded in Calculator object is correct assert pol.num_years == Policy.DEFAULT_NUM_YEARS assert calc.current_year == year assert calc.policy_param('II_em') == 3950 exp_II_em = [3900, 3950, 5000] + [6000] * (Policy.DEFAULT_NUM_YEARS - 3) assert np.allclose(calc.policy_param('_II_em'), np.array(exp_II_em)) calc.increment_year() calc.increment_year() assert calc.current_year == 2016 assert np.allclose(calc.policy_param('STD_Aged'), np.array([1600, 1300, 1600, 1300, 1600]))
def test_make_calculator_increment_years_first(cps_subsample): """ Test Calculator inflation indexing of policy parameters. """ # pylint: disable=too-many-locals # create Policy object with policy reform pol = Policy() reform = {2015: {}, 2016: {}} std5 = 2000 reform[2015]['_STD_Aged'] = [[std5, std5, std5, std5, std5]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False pol.implement_reform(reform) # create Calculator object with Policy object as modified by reform rec = Records.cps_constructor(data=cps_subsample) calc = Calculator(policy=pol, records=rec) # compare expected policy parameter values with those embedded in calc irates = pol.inflation_rates() syr = Policy.JSON_START_YEAR irate2015 = irates[2015 - syr] irate2016 = irates[2016 - syr] std6 = std5 * (1.0 + irate2015) std7 = std6 * (1.0 + irate2016) exp_STD_Aged = np.array([[1500, 1200, 1200, 1500, 1500], [1550, 1200, 1200, 1550, 1550], [std5, std5, std5, std5, std5], [std6, std6, std6, std6, std6], [std7, std7, std7, std7, std7]]) act_STD_Aged = calc.policy_param('_STD_Aged') assert np.allclose(act_STD_Aged[:5], exp_STD_Aged) exp_II_em = np.array([3900, 3950, 5000, 6000, 6000]) act_II_em = calc.policy_param('_II_em') assert np.allclose(act_II_em[:5], exp_II_em)
def test_make_calculator_with_policy_reform(cps_subsample): """ Test Calculator class ctor with policy reform. """ rec = Records.cps_constructor(data=cps_subsample) year = rec.current_year # create a Policy object and apply a policy reform pol = Policy() reform = {2013: {'_II_em': [4000], '_II_em_cpi': False, '_STD_Aged': [[1600, 1300, 1300, 1600, 1600]], '_STD_Aged_cpi': False}} pol.implement_reform(reform) # create a Calculator object using this policy reform calc = Calculator(policy=pol, records=rec) # check that Policy object embedded in Calculator object is correct assert calc.current_year == year assert calc.policy_param('II_em') == 4000 assert np.allclose(calc.policy_param('_II_em'), np.array([4000] * Policy.DEFAULT_NUM_YEARS)) exp_STD_Aged = [[1600, 1300, 1300, 1600, 1600]] * Policy.DEFAULT_NUM_YEARS assert np.allclose(calc.policy_param('_STD_Aged'), np.array(exp_STD_Aged)) assert np.allclose(calc.policy_param('STD_Aged'), np.array([1600, 1300, 1300, 1600, 1600]))
def test_make_Calculator_with_reform_after_start_year(): # create Policy object using custom indexing rates irates = {2013: 0.01, 2014: 0.01, 2015: 0.02, 2016: 0.01, 2017: 0.03} parm = Policy(start_year=2013, num_years=len(irates), inflation_rates=irates) # specify reform in 2015, which is two years after Policy start_year reform = {2015: {}, 2016: {}} reform[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False parm.implement_reform(reform) recs = Records(data=TAX_DTA, weights=WEIGHTS, start_year=2009) calc = Calculator(policy=parm, records=recs) # compare actual and expected parameter values over all years exp_STD_Aged = np.array([[1500, 1200, 1200, 1500, 1500, 1200], [1550, 1200, 1200, 1550, 1550, 1200], [1600, 1300, 1600, 1300, 1600, 1300], [1632, 1326, 1632, 1326, 1632, 1326], [1648, 1339, 1648, 1339, 1648, 1339]]) exp_II_em = np.array([3900, 3950, 5000, 6000, 6000]) assert_array_equal(calc.policy._STD_Aged, exp_STD_Aged) assert_array_equal(calc.policy._II_em, exp_II_em) # compare actual and expected values for 2015 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 exp_2015_II_em = 5000 assert_array_equal(calc.policy.II_em, exp_2015_II_em) exp_2015_STD_Aged = np.array([1600, 1300, 1600, 1300, 1600, 1300]) assert_array_equal(calc.policy.STD_Aged, exp_2015_STD_Aged)
def test_read_json_param_with_suffixes_and_errors(): """ Test interaction of policy parameter suffixes and reform errors (fails without 0.10.2 bug fix as reported by Hank Doupe in PB PR#641) """ reform = { u'policy': { u'_II_brk4_separate': {u'2017': [5000.0]}, u'_STD_separate': {u'2017': [8000.0]}, u'_STD_single': {u'2018': [1000.0]}, u'_II_brk2_headhousehold': {u'2017': [1000.0]}, u'_II_brk4_single': {u'2017': [500.0]}, u'_STD_joint': {u'2017': [10000.0], u'2020': [150.0]}, u'_II_brk2_separate': {u'2017': [1000.0]}, u'_II_brk2_single': {u'2017': [1000.0]}, u'_II_brk2_joint': {u'2017': [1000.0]}, u'_FICA_ss_trt': {u'2017': [-1.0], u'2019': [0.1]}, u'_II_brk4_headhousehold': {u'2017': [500.0]}, u'_STD_headhousehold': {u'2017': [10000.0], u'2020': [150.0]}, u'_ID_Medical_frt': {u'2019': [0.06]}, u'_II_brk4_joint': {u'2017': [500.0]}, u'_ID_BenefitSurtax_Switch_medical': {u'2017': [True]} } } json_reform = json.dumps(reform) params = Calculator.read_json_param_objects(json_reform, None) assert isinstance(params, dict) pol = Policy() pol.ignore_reform_errors() pol.implement_reform(params['policy'], print_warnings=False, raise_errors=False) assert pol.parameter_errors assert pol.parameter_warnings
def test_Policy_reform_after_start_year(): ppo = Policy(start_year=2013) reform = {2015: {'_STD_Aged': [[1400, 1100, 1100, 1400, 1400, 1199]]}} ppo.implement_reform(reform) ppo.set_year(2015) assert_array_equal(ppo.STD_Aged, np.array([1400, 1100, 1100, 1400, 1400, 1199]))
def test_Policy_reform_in_start_year(): ppo = Policy(start_year=2013) reform = {2013: {'_STD_Aged': [[1400, 1100, 1100, 1400, 1400, 1199]]}} ppo.implement_reform(reform) assert_allclose(ppo.STD_Aged, np.array([1400, 1100, 1100, 1400, 1400, 1199]), atol=0.01, rtol=0.0)
def test_2017_law_reform(tests_path): """ 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(tests_path, '..', 'reforms', '2017_law.json') with open(reform_file, 'r') as rfile: rtext = rfile.read() reform = Calculator.read_json_param_objects(rtext, None) pol.implement_reform(reform['policy']) # eventually activate: assert not clp.parameter_warnings ctc_c_warning = 'CTC_c was redefined in release 1.0.0\n' assert pol.parameter_warnings == ctc_c_warning assert not pol.parameter_errors pol.set_year(2018) pre_mdata = pol.metadata() # 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]['value'] if isinstance(aval, list): act = aval[0] # comparing only first item in a vector parameter else: act = aval 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_reform_with_warning(): """ Try to use warned out-of-range parameter value in reform. """ pol = Policy() reform = {'ID_Medical_frt': {2020: 0.05}} pol.implement_reform(reform) assert pol.parameter_warnings
def test_reform_with_out_of_range_error(): """ Try to use out-of-range values versus other parameter values in a reform. """ pol = Policy() reform = {'SS_thd85': {2020: [20000, 20000, 20000, 20000, 20000]}} pol.implement_reform(reform, raise_errors=False) assert pol.parameter_errors
def test_implement_reform_raises_on_early_year(): """ Test that implement_reform raises error for early year. """ ppo = Policy() reform = {'STD_Aged': {2010: [1400, 1100, 1100, 1400, 1400]}} with pytest.raises(ValueError): ppo.implement_reform(reform)
def test_implement_reform_raises_on_no_year(): """ Test that implement_reform raises error for missing year. """ reform = {'STD_Aged': [1400, 1200, 1400, 1400, 1400]} ppo = Policy() with pytest.raises(ValueError): ppo.implement_reform(reform)
def test_Policy_reform_with_default_cpi_flags(): ppo = Policy(start_year=2013) reform = {2015: {'_II_em': [4300]}} ppo.implement_reform(reform) # '_II_em' has a default cpi_flag of True, so # in 2016 its value should be greater than 4300 ppo.set_year(2016) assert ppo.II_em > 4300
def test_Calculator_current_law_version(records_2009): policy = Policy() reform = {2013: {'_II_rt7': [0.45]}} policy.implement_reform(reform) calc = Calculator(policy=policy, records=records_2009) calc_clp = calc.current_law_version() assert isinstance(calc_clp, Calculator) assert calc.policy.II_rt6 == calc_clp.policy.II_rt6 assert calc.policy.II_rt7 != calc_clp.policy.II_rt7
def test_read_json_reform_file_and_implement_reform(reform_file, assump_file, set_year): """ Test reading and translation of reform file into a reform dictionary that is then used to call implement_reform method and Calculate.calc_all() NOTE: implement_reform called when policy.current_year == policy.start_year """ pol = Policy() if set_year: pol.set_year(2015) param_dict = Calculator.read_json_param_objects(reform_file.name, assump_file.name) pol.implement_reform(param_dict['policy']) syr = pol.start_year amt_brk1 = pol._AMT_brk1 assert amt_brk1[2015 - syr] == 200000 assert amt_brk1[2016 - syr] > 200000 assert amt_brk1[2017 - syr] == 300000 assert amt_brk1[2018 - syr] > 300000 ii_em = pol._II_em assert ii_em[2016 - syr] == 6000 assert ii_em[2017 - syr] == 6000 assert ii_em[2018 - syr] == 7500 assert ii_em[2019 - syr] > 7500 assert ii_em[2020 - syr] == 9000 assert ii_em[2021 - syr] > 9000 amt_em = pol._AMT_em assert amt_em[2016 - syr, 0] > amt_em[2015 - syr, 0] assert amt_em[2017 - syr, 0] > amt_em[2016 - syr, 0] assert amt_em[2018 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2019 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2020 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2021 - syr, 0] > amt_em[2020 - syr, 0] assert amt_em[2022 - syr, 0] > amt_em[2021 - syr, 0] add4aged = pol._ID_Medical_frt_add4aged assert add4aged[2015 - syr] == -0.025 assert add4aged[2016 - syr] == -0.025 assert add4aged[2017 - syr] == 0.0 assert add4aged[2022 - syr] == 0.0
def test_diff_table_sum_row(cps_subsample): rec = Records.cps_constructor(data=cps_subsample) # create a current-law Policy object and Calculator calc1 pol = Policy() calc1 = Calculator(policy=pol, records=rec) calc1.calc_all() # create a policy-reform Policy object and Calculator calc2 reform = {2013: {'_II_rt4': [0.56]}} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc2.calc_all() # create two difference tables and compare their content tdiff1 = create_difference_table(calc1.dataframe(DIFF_VARIABLES), calc2.dataframe(DIFF_VARIABLES), 'standard_income_bins', 'iitax') tdiff2 = create_difference_table(calc1.dataframe(DIFF_VARIABLES), calc2.dataframe(DIFF_VARIABLES), 'soi_agi_bins', 'iitax') non_digit_cols = ['perc_inc', 'perc_cut'] digit_cols = [c for c in list(tdiff1) if c not in non_digit_cols] assert np.allclose(tdiff1[digit_cols][-1:], tdiff2[digit_cols][-1:]) np.allclose(tdiff1[non_digit_cols][-1:], tdiff2[non_digit_cols][-1:])
def test_dec_graph_plots(cps_subsample): pol = Policy() rec = Records.cps_constructor(data=cps_subsample) calc1 = Calculator(policy=pol, records=rec) year = 2020 calc1.advance_to_year(year) reform = { year: { '_SS_Earnings_c': [9e99], # OASDI FICA tax on all earnings '_FICA_ss_trt': [0.107484] # lower rate to keep revenue unchanged } } pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc2.advance_to_year(year) assert calc1.current_year == calc2.current_year calc1.calc_all() calc2.calc_all() fig = calc1.decile_graph(calc2) assert fig dt1, dt2 = calc1.distribution_tables(calc2, 'weighted_deciles') dta = dec_graph_data(dt1, dt2, year, include_zero_incomes=True, include_negative_incomes=False) assert isinstance(dta, dict) dta = dec_graph_data(dt1, dt2, year, include_zero_incomes=False, include_negative_incomes=True) assert isinstance(dta, dict) dta = dec_graph_data(dt1, dt2, year, include_zero_incomes=False, include_negative_incomes=False) assert isinstance(dta, dict)
def test_row_classifier(puf_1991, weights_1991): # create a current-law Policy object and Calculator calc1 policy1 = Policy() records1 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() calc1_s006 = create_distribution_table(calc1.records, groupby='webapp_income_bins', result_type='weighted_sum').s006 # create a policy-reform Policy object and Calculator calc2 reform = {2013: {'_ALD_StudentLoan_hc': [1]}} policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() calc2_s006 = create_distribution_table(calc2.records, groupby='webapp_income_bins', result_type='weighted_sum', baseline_obj=calc1.records).s006 # use weighted sum of weights in each cell to check classifer assert_array_equal(calc1_s006, calc2_s006)
def test_expand_2D_accept_None_additional_row(): _II_brk2 = [[36000, 72250, 36500, 48600, 72500, 36250], [38000, 74000, 36900, 49400, 73800, 36900], [40000, 74900, 37450, 50200, 74900, 37450], [41000, None, None, None, None, None], [43000, None, None, None, None, None]] exp1 = 74900 * 1.02 exp2 = 37450 * 1.02 exp3 = 50200 * 1.02 exp4 = 74900 * 1.02 exp5 = 37450 * 1.02 exp6 = exp1 * 1.03 exp7 = exp2 * 1.03 exp8 = exp3 * 1.03 exp9 = exp4 * 1.03 exp10 = exp5 * 1.03 exp = [[36000, 72250, 36500, 48600, 72500, 36250], [38000, 74000, 36900, 49400, 73800, 36900], [40000, 74900, 37450, 50200, 74900, 37450], [41000, exp1, exp2, exp3, exp4, exp5], [43000, exp6, exp7, exp8, exp9, exp10]] inflation_rates = [0.015, 0.02, 0.02, 0.03] res = Policy.expand_array(_II_brk2, inflate=True, inflation_rates=inflation_rates, num_years=5) npt.assert_array_equal(res, exp) user_mods = {2016: {u'_II_brk2': _II_brk2}} pol = Policy(start_year=2013) pol.implement_reform(user_mods) pol.set_year(2020) irates = Policy.default_inflation_rates() # The 2020 policy should be the combination of the user-defined # value and CPI-inflated values from 2018 exp_2020 = [43000.] + [(1 + irates[2019]) * (1 + irates[2018]) * i for i in _II_brk2[2][1:]] exp_2020 = np.array(exp_2020) npt.assert_allclose(pol.II_brk2, exp_2020)
def test_ID_RealEstate_HC_vs_CRT(cps_subsample): """ Test that a cap on all state, local, and foreign real estate tax deductions at 0 percent of AGI is equivalent to a complete haircut on the same real estate tax deductions. """ rec = Records.cps_constructor(data=cps_subsample) # specify real estate complete haircut reform policy and Calculator object hc_reform = {2013: {'_ID_RealEstate_hc': [1.0]}} hc_policy = Policy() hc_policy.implement_reform(hc_reform) hc_calc = Calculator(policy=hc_policy, records=rec) hc_calc.calc_all() # specify AGI cap reform policy and Calculator object crt_reform = {2013: {'_ID_RealEstate_crt': [0.0]}} crt_policy = Policy() crt_policy.implement_reform(crt_reform) crt_calc = Calculator(policy=crt_policy, records=rec) crt_calc.calc_all() # compare calculated tax results generated by the two reforms assert np.allclose(hc_calc.records.payrolltax, crt_calc.records.payrolltax) assert np.allclose(hc_calc.records.iitax, crt_calc.records.iitax)
def test_reform_json(tests_path): """ Check that each JSON reform file can be converted into a reform dictionary that can then be passed to the Policy class implement_reform() method. """ reforms_path = os.path.join(tests_path, '..', 'reforms', '*.json') for jpf in glob.glob(reforms_path): # read contents of jpf (JSON parameter filename) jfile = open(jpf, 'r') jpf_text = jfile.read() # check that jpf_text has "policy" that can be implemented as a reform if '"policy"' in jpf_text: gdiffbase = {} gdiffresp = {} # pylint: disable=protected-access policy_dict = (Calculator._read_json_policy_reform_text( jpf_text, gdiffbase, gdiffresp)) policy = Policy() policy.implement_reform(policy_dict) else: # jpf_text is not a valid JSON policy reform file print('test-failing-filename: ' + jpf) assert False
def test_credit_reforms(puf_path): # pylint: disable=redefined-outer-name """ Test personal credit reforms using small puf.csv sub-sample """ # pylint: disable=too-many-locals reform_year = 2017 fullsample = pd.read_csv(puf_path) subsample = fullsample.sample( frac=0.05, # pylint: disable=no-member random_state=180) # create current-law Calculator object, calc1 recs1 = Records(data=subsample) calc1 = Calculator(policy=Policy(), records=recs1) calc1.advance_to_year(reform_year) calc1.calc_all() itax1 = (calc1.records.iitax * calc1.records.s006).sum() # create personal-refundable-credit-reform Calculator object, calc2 recs2 = Records(data=subsample) policy2 = Policy() reform = {reform_year: {'_II_credit': [[1000, 1000, 1000, 1000, 1000]]}} policy2.implement_reform(reform) calc2 = Calculator(policy=policy2, records=recs2) calc2.advance_to_year(reform_year) calc2.calc_all() itax2 = (calc2.records.iitax * calc2.records.s006).sum() # create personal-nonrefundable-credit-reform Calculator object, calc3 recs3 = Records(data=subsample) policy3 = Policy() reform = {reform_year: {'_II_credit_nr': [[1000, 1000, 1000, 1000, 1000]]}} policy3.implement_reform(reform) calc3 = Calculator(policy=policy3, records=recs3) calc3.advance_to_year(reform_year) calc3.calc_all() itax3 = (calc3.records.iitax * calc3.records.s006).sum() # check income tax revenues generated by the three Calculator objects assert itax2 < itax1 # because refundable credits lower revenues assert itax3 > itax2 # because nonrefundable credits lower revenues less assert itax3 < itax1 # because nonrefundable credits lower revenues some
def test_ce_aftertax_income(cps_subsample): # test certainty_equivalent() function with con>cmin con = 5000 cmin = 1000 assert con == round(certainty_equivalent(con, 0, cmin), 6) assert con > round(certainty_equivalent((math.log(con) - 0.1), 1, cmin), 6) # test certainty_equivalent() function with con<cmin con = 500 cmin = 1000 assert con == round(certainty_equivalent(con, 0, cmin), 6) # test with require_no_agg_tax_change equal to False cyr = 2020 # specify calc1 and calc_all() for cyr pol1 = Policy() rec1 = Records.cps_constructor(data=cps_subsample) calc1 = Calculator(policy=pol1, records=rec1) calc1.advance_to_year(cyr) calc1.calc_all() # specify calc2 and calc_all() for cyr pol2 = Policy() reform = {2018: {'_II_em': [0.0]}} pol2.implement_reform(reform) rec2 = Records.cps_constructor(data=cps_subsample) calc2 = Calculator(policy=pol2, records=rec2) calc2.advance_to_year(cyr) calc2.calc_all() cedict = ce_aftertax_income(calc1, calc2, require_no_agg_tax_change=False) assert cedict['year'] == cyr # test with require_no_agg_tax_change equal to True with pytest.raises(ValueError): ce_aftertax_income(calc1, calc2, require_no_agg_tax_change=True) # test with require_no_agg_tax_change equal to False and custom_params params = {'crra_list': [0, 2], 'cmin_value': 2000} with pytest.raises(ValueError): ce_aftertax_income(calc1, calc2, require_no_agg_tax_change=True, custom_params=params)
def test_ID_HC_vs_BS(puf_1991, weights_1991): """ Test that complete haircut of itemized deductions produces same results as a 100% benefit surtax with no benefit deduction. """ # specify complete-haircut reform policy and Calculator object hc_reform = { 2013: { '_ID_Medical_hc': [1.0], '_ID_StateLocalTax_hc': [1.0], '_ID_RealEstate_hc': [1.0], '_ID_Casualty_hc': [1.0], '_ID_Miscellaneous_hc': [1.0], '_ID_InterestPaid_hc': [1.0], '_ID_Charity_hc': [1.0] } } hc_policy = Policy() hc_policy.implement_reform(hc_reform) hc_records = Records(data=puf_1991, weights=weights_1991, start_year=2009) hc_calc = Calculator(policy=hc_policy, records=hc_records) # specify benefit-surtax reform policy and Calculator object bs_reform = { 2013: { '_ID_BenefitSurtax_crt': [0.0], '_ID_BenefitSurtax_trt': [1.0] } } bs_policy = Policy() bs_policy.implement_reform(bs_reform) bs_records = Records(data=puf_1991, weights=weights_1991, start_year=2009) bs_calc = Calculator(policy=bs_policy, records=bs_records) # compare calculated tax results generated by the two reforms hc_calc.calc_all() bs_calc.calc_all() assert np.allclose(hc_calc.records._payrolltax, bs_calc.records._payrolltax) assert np.allclose(hc_calc.records._iitax, bs_calc.records._iitax)
def test_reforms(reforms_path): # pylint: disable=redefined-outer-name """ Check that each JSON reform file can be converted into a reform dictionary, which can then be passed to the Policy.implement_reform() method. While doing this, construct a set of Policy parameters (other than those ending in '_cpi') included in the JSON reform files. """ params_set = set() for jrf in glob.glob(reforms_path): # read contents of jrf (JSON reform filename) with open(jrf) as jrfile: jrf_text = jrfile.read() # check that jrf_text can be implemented as a Policy reform jrf_dict = Policy.read_json_reform_text(jrf_text) policy = Policy() policy.implement_reform(jrf_dict) # identify policy parameters included in jrf after removing //-comments json_without_comments = re.sub('//.*', ' ', jrf_text) json_dict = json.loads(json_without_comments) for param in json_dict.keys(): if param.endswith('_cpi'): continue params_set.add(param)
def test_myr_diag_table_w_behv(records_2009): pol = Policy() behv = Behavior() calc = Calculator(policy=pol, records=records_2009, behavior=behv) assert calc.current_year == 2013 reform = { 2013: { '_II_rt7': [0.33], '_PT_rt7': [0.33], } } pol.implement_reform(reform) reform_be = {2013: {'_BE_sub': [0.4], '_BE_cg': [-3.67]}} behv.update_behavior(reform_be) calc_clp = calc.current_law_version() calc_behv = Behavior.response(calc_clp, calc) calc_behv.calc_all() liabilities_x = (calc_behv.records.combined * calc_behv.records.s006).sum() adt = multiyear_diagnostic_table(calc_behv, 1) # extract combined liabilities as a float and # adopt units of the raw calculator data in liabilities_x liabilities_y = adt.iloc[19].tolist()[0] * 1000000000 assert_almost_equal(liabilities_x, liabilities_y, 2)
def test_dec_graph_plot(cps_subsample): pol = Policy() rec = Records.cps_constructor(data=cps_subsample) calc1 = Calculator(policy=pol, records=rec) year = 2020 reform = { year: { '_SS_Earnings_c': [9e99], # OASDI FICA tax on all earnings '_FICA_ss_trt': [0.107484] # lower rate to keep revenue unchanged } } pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc1.advance_to_year(year) with pytest.raises(ValueError): dec_graph_data(calc1, calc2) calc2.advance_to_year(year) gdata = dec_graph_data(calc1, calc2) assert isinstance(gdata, dict) deciles = gdata['bars'].keys() assert len(deciles) == 14 gplot = dec_graph_plot(gdata, xlabel='', ylabel='') assert gplot
def test_variable_inflation_rate_with_reform(): syr = 2013 pol = Policy(start_year=syr, num_years=10) assert pol._II_em[2013 - syr] == 3900 # implement reform in 2020 which is two years before the last year, 2022 reform = {2020: {'_II_em': [20000]}} pol.implement_reform(reform) pol.set_year(2020) assert pol.current_year == 2020 # extract price inflation rates pirates = pol.inflation_rates() irate2018 = pirates[2018 - syr] irate2020 = pirates[2020 - syr] irate2021 = pirates[2021 - syr] # check implied inflation rate between 2018 and 2019 (before the reform) grate = float(pol._II_em[2019 - syr]) / float(pol._II_em[2018 - syr]) assert round(grate - 1.0, 5) == round(irate2018, 5) # check implied inflation rate between 2020 and 2021 (after the reform) grate = float(pol._II_em[2021 - syr]) / float(pol._II_em[2020 - syr]) assert round(grate - 1.0, 5) == round(irate2020, 5) # check implied inflation rate between 2021 and 2022 (after the reform) grate = float(pol._II_em[2022 - syr]) / float(pol._II_em[2021 - syr]) assert round(grate - 1.0, 5) == round(irate2021, 5)
def test_ID_StateLocal_HC_vs_CRT(cps_subsample): """ Test that a cap on state/local income and sales tax deductions at 0 percent of AGI is equivalent to a complete haircut on the same state/local tax deductions. """ rec = Records.cps_constructor(data=cps_subsample) # specify state/local complete haircut reform policy and Calculator object hc_policy = Policy() hc_reform = {'ID_StateLocalTax_hc': {2013: 1.0}} hc_policy.implement_reform(hc_reform) hc_calc = Calculator(policy=hc_policy, records=rec) hc_calc.calc_all() # specify AGI cap reform policy and Calculator object crt_policy = Policy() crt_reform = {'ID_StateLocalTax_crt': {2013: 0.0}} crt_policy.implement_reform(crt_reform) crt_calc = Calculator(policy=crt_policy, records=rec) crt_calc.calc_all() # compare calculated tax results generated by the two reforms assert np.allclose(hc_calc.array('payrolltax'), crt_calc.array('payrolltax')) assert np.allclose(hc_calc.array('iitax'), crt_calc.array('iitax'))
def test_percentage_change_gdp(): policy1 = Policy() records1 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() reform = { 2013: { "_STD": [[12600, 25200, 12600, 18600, 25300, 12600, 2100]], "_AMT_trt1": [0.0], "_AMT_trt2": [0.0] } } policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() gdp_diff = percentage_change_gdp(calc1, calc2, elasticity=0.36) assert gdp_diff > 0
def update_policy(policy_obj: tc.Policy, reform: Union[TaxcalcReform, ParamToolsAdjustment], **kwargs): """ Convenience method that updates the Policy object with the reform dict using the appropriate method, given the reform format. Parameters ---------- policy_obj: Tax-Calculator Policy class object Policy object for tax parameterization used for analysis reform: str or dict parameters for tax policy Returns ------- None modifies the Policy object """ if is_paramtools_format(reform): policy_obj.adjust(reform, **kwargs) else: policy_obj.implement_reform(reform, **kwargs)
def test_diff_table_sum_row(): # create a current-law Policy object and Calculator calc1 policy1 = Policy() records1 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() # create a policy-reform Policy object and Calculator calc2 reform = {2013: {'_II_rt4': [0.56]}} policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() # create two difference tables and compare their content tdiff1 = create_difference_table(calc1, calc2, groupby="small_income_bins") tdiff2 = create_difference_table(calc1, calc2, groupby="large_income_bins") non_digit_cols = ['mean', 'perc_inc', 'perc_cut', 'share_of_change'] digit_cols = [ x for x in tdiff1.columns.tolist() if x not in non_digit_cols ] npt.assert_allclose(tdiff1[digit_cols][-1:], tdiff2[digit_cols][-1:]) assert np.array_equal(tdiff1[non_digit_cols][-1:], tdiff2[non_digit_cols][-1:])
def test_make_calculator_with_multiyear_reform(cps_subsample): rec = Records.cps_constructor(data=cps_subsample) year = rec.current_year # create a Policy object and apply a policy reform pol = Policy() reform = {2015: {}, 2016: {}} reform[2015]['_II_em'] = [5000, 6000] # reform values for 2015 and 2016 reform[2015]['_II_em_cpi'] = False reform[2016]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600]] pol.implement_reform(reform) # create a Calculator object using this policy-reform calc = Calculator(policy=pol, records=rec) # check that Policy object embedded in Calculator object is correct assert calc.current_year == year assert calc.policy.II_em == 3950 assert calc.policy.num_years == Policy.DEFAULT_NUM_YEARS exp_II_em = [3900, 3950, 5000] + [6000] * (Policy.DEFAULT_NUM_YEARS - 3) assert np.allclose(calc.policy._II_em, np.array(exp_II_em)) calc.increment_year() calc.increment_year() assert calc.current_year == 2016 assert np.allclose(calc.policy.STD_Aged, np.array([1600, 1300, 1600, 1300, 1600]))
def test_make_Calculator_with_policy_reform(records_2009): # create a Policy object and apply a policy reform policy2 = Policy() reform2 = { 2013: { '_II_em': np.array([4000]), '_II_em_cpi': False, '_STD_Aged': [[1600, 1300, 1300, 1600, 1600]], "_STD_Aged_cpi": False } } policy2.implement_reform(reform2) # create a Calculator object using this policy-reform calc2 = Calculator(policy=policy2, records=records_2009) # check that Policy object embedded in Calculator object is correct assert calc2.current_year == 2013 assert calc2.policy.II_em == 4000 assert np.allclose(calc2.policy._II_em, np.array([4000] * Policy.DEFAULT_NUM_YEARS)) exp_STD_Aged = [[1600, 1300, 1300, 1600, 1600]] * Policy.DEFAULT_NUM_YEARS assert np.allclose(calc2.policy._STD_Aged, np.array(exp_STD_Aged)) assert np.allclose(calc2.policy.STD_Aged, np.array([1600, 1300, 1300, 1600, 1600]))
def test_ID_HC_vs_BS(cps_subsample): """ Test that complete haircut of itemized deductions produces same results as a 100% benefit surtax with no benefit deduction. """ rec = Records.cps_constructor(data=cps_subsample) # specify complete-haircut reform policy and Calculator object hc_reform = { 2013: { '_ID_Medical_hc': [1.0], '_ID_StateLocalTax_hc': [1.0], '_ID_RealEstate_hc': [1.0], '_ID_Casualty_hc': [1.0], '_ID_Miscellaneous_hc': [1.0], '_ID_InterestPaid_hc': [1.0], '_ID_Charity_hc': [1.0] } } hc_policy = Policy() hc_policy.implement_reform(hc_reform) hc_calc = Calculator(policy=hc_policy, records=rec) hc_calc.calc_all() # specify benefit-surtax reform policy and Calculator object bs_reform = { 2013: { '_ID_BenefitSurtax_crt': [0.0], '_ID_BenefitSurtax_trt': [1.0] } } bs_policy = Policy() bs_policy.implement_reform(bs_reform) bs_calc = Calculator(policy=bs_policy, records=rec) bs_calc.calc_all() # compare calculated tax results generated by the two reforms assert np.allclose(hc_calc.array('payrolltax'), bs_calc.array('payrolltax')) assert np.allclose(hc_calc.array('iitax'), bs_calc.array('iitax'))
def test_read_json_reform_file_and_implement_reform(reform_file, set_year): """ Test reading and translation of reform file into a reform dictionary that is then used to call implement_reform method. NOTE: implement_reform called when policy.current_year == policy.start_year """ reform = Policy.read_json_reform_file(reform_file.name) policy = Policy() if set_year: policy.set_year(2015) policy.implement_reform(reform) syr = policy.start_year amt_tthd = policy._AMT_tthd assert amt_tthd[2015 - syr] == 200000 assert amt_tthd[2016 - syr] > 200000 assert amt_tthd[2017 - syr] == 300000 assert amt_tthd[2018 - syr] > 300000 ii_em = policy._II_em assert ii_em[2016 - syr] == 6000 assert ii_em[2017 - syr] == 6000 assert ii_em[2018 - syr] == 7500 assert ii_em[2019 - syr] > 7500 assert ii_em[2020 - syr] == 9000 assert ii_em[2021 - syr] > 9000 amt_em = policy._AMT_em assert amt_em[2016 - syr, 0] > amt_em[2015 - syr, 0] assert amt_em[2017 - syr, 0] > amt_em[2016 - syr, 0] assert amt_em[2018 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2019 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2020 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2021 - syr, 0] > amt_em[2020 - syr, 0] assert amt_em[2022 - syr, 0] > amt_em[2021 - syr, 0] add4aged = policy._ID_Medical_frt_add4aged assert add4aged[2015 - syr] == -0.025 assert add4aged[2016 - syr] == -0.025 assert add4aged[2017 - syr] == 0.0 assert add4aged[2022 - syr] == 0.0
def test_mtr_pt_active(puf_subsample): """ Test whether including wages in active income causes MTRs on e00900p and e26270 to be less than -1 (i.e., -100%) """ # pylint: disable=too-many-locals rec = Records(data=puf_subsample) reform_year = 2018 # create current-law Calculator object, calc1 pol1 = Policy() calc1 = Calculator(policy=pol1, records=rec) calc1.advance_to_year(reform_year) calc1.calc_all() mtr1_e00900p = calc1.mtr('e00900p')[2] mtr1_e26270 = calc1.mtr('e26270')[2] assert min(mtr1_e00900p) > -1 assert min(mtr1_e26270) > -1 # change PT rates, calc2 reform2 = {'PT_rt7': {reform_year: 0.35}} pol2 = Policy() pol2.implement_reform(reform2) calc2 = Calculator(policy=pol2, records=rec) calc2.advance_to_year(reform_year) calc2.calc_all() mtr2_e00900p = calc2.mtr('e00900p')[2] mtr2_e26270 = calc2.mtr('e26270')[2] assert min(mtr2_e00900p) > -1 assert min(mtr2_e26270) > -1 # change PT_wages_active_income reform3 = {'PT_wages_active_income': {reform_year: True}} pol3 = Policy() pol3.implement_reform(reform3) calc3 = Calculator(policy=pol3, records=rec) calc3.advance_to_year(reform_year) calc3.calc_all() mtr3_e00900p = calc3.mtr('e00900p')[2] mtr3_e26270 = calc3.mtr('e26270')[2] assert min(mtr3_e00900p) > -1 assert min(mtr3_e26270) > -1 # change PT rates and PT_wages_active_income reform4 = { 'PT_wages_active_income': { reform_year: True }, 'PT_rt7': { reform_year: 0.35 } } pol4 = Policy() pol4.implement_reform(reform4) calc4 = Calculator(policy=pol4, records=rec) calc4.advance_to_year(reform_year) calc4.calc_all() mtr4_e00900p = calc4.mtr('e00900p')[2] mtr4_e26270 = calc4.mtr('e26270')[2] assert min(mtr4_e00900p) > -1 assert min(mtr4_e26270) > -1
def taxcalc_results(start_year, reform_dict, itax_clp, fica_clp): """ Use taxcalc package on this computer to compute aggregate income tax and payroll tax revenue difference (between reform and current-law policy) for ten years beginning with the specified start_year using the specified reform_dict dictionary and the two specified current-law-policy results dictionaries. Return two aggregate tax revenue difference dictionaries indexed by calendar year. """ pol = Policy() pol.implement_reform(reform_dict) calc = Calculator(policy=pol, records=Records(data=PUF_PATH)) calc.advance_to_year(start_year) adt = calc.diagnostic_table(num_years=NUMBER_OF_YEARS) # note that adt is Pandas DataFrame object itax_ref = adt.xs('Ind inc tax ($b)').to_dict() fica_ref = adt.xs('Payroll tax ($b)').to_dict() itax_diff = {} fica_diff = {} for year in itax_ref: itax_diff[year] = round(itax_ref[year] - itax_clp[year], 1) fica_diff[year] = round(fica_ref[year] - fica_clp[year], 1) return (itax_diff, fica_diff)
def reform_warnings_errors(user_mods): """ The reform_warnings_errors function assumes user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. This function returns a dictionary containing two STR:STR pairs: {'warnings': '<empty-or-message(s)>', 'errors': '<empty-or-message(s)>'} In each pair the second string is empty if there are no messages. Any returned messages are generated using current_law_policy.json information on known policy parameter names and parameter value ranges. Note that this function will return one or more error messages if the user_mods['policy'] dictionary contains any unknown policy parameter names or if any *_cpi parameters have values other than True or False. These situations prevent implementing the policy reform specified in user_mods, and therefore, no range-related warnings or errors will be returned in this case. """ rtn_dict = {'warnings': '', 'errors': ''} # create Growfactors object gdiff_baseline = Growdiff() gdiff_baseline.update_growdiff(user_mods['growdiff_baseline']) gdiff_response = Growdiff() gdiff_response.update_growdiff(user_mods['growdiff_response']) growfactors = Growfactors() gdiff_baseline.apply_to(growfactors) gdiff_response.apply_to(growfactors) # create Policy object and implement reform pol = Policy(gfactors=growfactors) try: pol.implement_reform(user_mods['policy']) rtn_dict['warnings'] = pol.reform_warnings rtn_dict['errors'] = pol.reform_errors except ValueError as valerr_msg: rtn_dict['errors'] = valerr_msg.__str__() return rtn_dict
def test_make_Calculator_increment_years_first(records_2009): # create Policy object with custom indexing rates and policy reform irates = {2013: 0.01, 2014: 0.01, 2015: 0.02, 2016: 0.01, 2017: 0.03} policy = Policy(start_year=2013, inflation_rates=irates, num_years=len(irates)) reform = {2015: {}, 2016: {}} reform[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False policy.implement_reform(reform) # create Calculator object with Policy object as modified by reform calc = Calculator(policy=policy, records=records_2009) # compare expected policy parameter values with those embedded in calc exp_STD_Aged = np.array([[1500, 1200, 1200, 1500, 1500, 1200], [1550, 1200, 1200, 1550, 1550, 1200], [1600, 1300, 1600, 1300, 1600, 1300], [1632, 1326, 1632, 1326, 1632, 1326], [1648, 1339, 1648, 1339, 1648, 1339]]) assert np.allclose(calc.policy._STD_Aged, exp_STD_Aged, atol=0.5, rtol=0.0) # handles rounding to dollars exp_II_em = np.array([3900, 3950, 5000, 6000, 6000]) assert np.allclose(calc.policy._II_em, exp_II_em)
def diff_in_revenue(reform_on_II, orig_reform): policy_func = Policy() puf = pd.read_csv("./puf.csv") records_func = Records(puf) calc_func = Calculator(policy=policy_func, records=records_func) policy_bench = Policy() records_bench = Records(puf) calc_bench = Calculator(policy=policy_bench, records=records_bench) reform = { CURRENT_YEAR: { "_II_rt1": [max(policy_bench._II_rt1[0] * (1 - reform_on_II), 0.0)], "_II_rt2": [max(policy_bench._II_rt2[0] * (1 - reform_on_II), 0.0)], "_II_rt3": [max(policy_bench._II_rt3[0] * (1 - reform_on_II), 0.0)], "_II_rt4": [max(policy_bench._II_rt4[0] * (1 - reform_on_II), 0.0)], "_II_rt5": [max(policy_bench._II_rt5[0] * (1 - reform_on_II), 0.0)], "_II_rt6": [max(policy_bench._II_rt6[0] * (1 - reform_on_II), 0.0)], "_II_rt7": [max(policy_bench._II_rt7[0] * (1 - reform_on_II), 0.0)] } } policy_func.implement_reform(reform) policy_func.implement_reform(orig_reform) calc_func.advance_to_year(CURRENT_YEAR) calc_bench.advance_to_year(CURRENT_YEAR) calc_func.calc_all() calc_bench.calc_all() ans = ((calc_bench.records._combined * calc_bench.records.s006).sum() - (calc_func.records._combined * calc_func.records.s006).sum()) print("diff in revenue is ", ans) return ans
def test_row_classifier(): # create a current-law Policy object and Calculator calc1 policy1 = Policy() records1 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() calc1_s006 = create_distribution_table(calc1, groupby="webapp_income_bins", result_type="weighted_sum").s006 # create a policy-reform Policy object and Calculator calc2 reform = {2013: {"_ALD_StudentLoan_HC": [1]}} policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() calc2_s006 = create_distribution_table(calc2, groupby="webapp_income_bins", result_type="weighted_sum", baseline_calc=calc1).s006 # use weighted sum of weights in each cell to check classifer npt.assert_array_equal(calc1_s006, calc2_s006)
def test_read_json_reform_file_and_implement_reform(set_year): """ Test reading and translation of reform JSON into a reform dictionary and then using that reform dictionary to implement reform. """ pol = Policy() if set_year: pol.set_year(2015) pol.implement_reform(Policy.read_json_reform(REFORM_JSON)) syr = pol.start_year # pylint: disable=protected-access amt_brk1 = pol._AMT_brk1 assert amt_brk1[2015 - syr] == 200000 assert amt_brk1[2016 - syr] > 200000 assert amt_brk1[2017 - syr] == 300000 assert amt_brk1[2018 - syr] > 300000 ii_em = pol._II_em assert ii_em[2016 - syr] == 6000 assert ii_em[2017 - syr] == 6000 assert ii_em[2018 - syr] == 7500 assert ii_em[2019 - syr] > 7500 assert ii_em[2020 - syr] == 9000 assert ii_em[2021 - syr] > 9000 amt_em = pol._AMT_em assert amt_em[2016 - syr, 0] > amt_em[2015 - syr, 0] assert amt_em[2017 - syr, 0] > amt_em[2016 - syr, 0] assert amt_em[2018 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2019 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2020 - syr, 0] == amt_em[2017 - syr, 0] assert amt_em[2021 - syr, 0] > amt_em[2020 - syr, 0] assert amt_em[2022 - syr, 0] > amt_em[2021 - syr, 0] add4aged = pol._ID_Medical_frt_add4aged assert add4aged[2015 - syr] == -0.025 assert add4aged[2016 - syr] == -0.025 assert add4aged[2017 - syr] == 0.0 assert add4aged[2022 - syr] == 0.0
def test_ID_HC_vs_BS(cps_subsample): """ Test that complete haircut of itemized deductions produces same results as a 100% benefit surtax with no benefit deduction. """ recs = Records.cps_constructor(data=cps_subsample) # specify complete-haircut reform policy and Calculator object hc_policy = Policy() hc_reform = { 'ID_Medical_hc': {2013: 1.0}, 'ID_StateLocalTax_hc': {2013: 1.0}, 'ID_RealEstate_hc': {2013: 1.0}, 'ID_Casualty_hc': {2013: 1.0}, 'ID_Miscellaneous_hc': {2013: 1.0}, 'ID_InterestPaid_hc': {2013: 1.0}, 'ID_Charity_hc': {2013: 1.0} } hc_policy.implement_reform(hc_reform) hc_calc = Calculator(policy=hc_policy, records=recs) hc_calc.calc_all() hc_taxes = hc_calc.dataframe(['iitax', 'payrolltax']) del hc_calc # specify benefit-surtax reform policy and Calculator object bs_policy = Policy() bs_reform = { 'ID_BenefitSurtax_crt': {2013: 0.0}, 'ID_BenefitSurtax_trt': {2013: 1.0} } bs_policy.implement_reform(bs_reform) bs_calc = Calculator(policy=bs_policy, records=recs) bs_calc.calc_all() bs_taxes = bs_calc.dataframe([], all_vars=True) del bs_calc # compare calculated taxes generated by the two reforms assert np.allclose(hc_taxes['payrolltax'], bs_taxes['payrolltax']) assert np.allclose(hc_taxes['iitax'], bs_taxes['iitax'])