Пример #1
0
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]))
Пример #2
0
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)
Пример #3
0
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)
Пример #4
0
def test_read_json_reform_file_and_implement_reform_a(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.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]
Пример #5
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
Пример #6
0
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)
Пример #7
0
def test_strip_Nones():
    x = [None, None]
    assert Policy.strip_Nones(x) == []
    x = [1, 2, None]
    assert Policy.strip_Nones(x) == [1, 2]
    x = [[1, 2, 3], [4, None, None]]
    assert Policy.strip_Nones(x) == [[1, 2, 3], [4, -1, -1]]
Пример #8
0
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]))
Пример #9
0
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)
Пример #10
0
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)
Пример #11
0
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
Пример #12
0
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]))
Пример #13
0
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)
Пример #14
0
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)
Пример #15
0
def test_reform_pkey_year():
    with pytest.raises(ValueError):
        rdict = Policy._reform_pkey_year({4567: {2013: [40000]}})
    with pytest.raises(ValueError):
        rdict = Policy._reform_pkey_year({'_II_em': 40000})
    with pytest.raises(ValueError):
        rdict = Policy._reform_pkey_year({'_II_em': {'2013': [40000]}})
Пример #16
0
def test_calculator_using_nonstd_input(rawinputfile):
    """
    Test Calculator using non-standard input records.
    """
    # check Calculator handling of raw, non-standard input data with no aging
    pol = Policy()
    pol.set_year(RAWINPUTFILE_YEAR)  # set policy params to input data year
    nonstd = Records(data=rawinputfile.name,
                     gfactors=None,  # keeps raw data unchanged
                     weights=None,
                     start_year=RAWINPUTFILE_YEAR)  # set raw input data year
    assert nonstd.array_length == RAWINPUTFILE_FUNITS
    calc = Calculator(policy=pol, records=nonstd,
                      sync_years=False)  # keeps raw data unchanged
    assert calc.current_year == RAWINPUTFILE_YEAR
    calc.calc_all()
    assert calc.weighted_total('e00200') == 0
    assert calc.total_weight() == 0
    varlist = ['RECID', 'MARS']
    dframe = calc.dataframe(varlist)
    assert isinstance(dframe, pd.DataFrame)
    assert dframe.shape == (RAWINPUTFILE_FUNITS, len(varlist))
    mars = calc.array('MARS')
    assert isinstance(mars, np.ndarray)
    assert mars.shape == (RAWINPUTFILE_FUNITS,)
    exp_iitax = np.zeros((nonstd.array_length,))
    assert np.allclose(calc.array('iitax'), exp_iitax)
    mtr_ptax, _, _ = calc.mtr(wrt_full_compensation=False)
    exp_mtr_ptax = np.zeros((nonstd.array_length,))
    exp_mtr_ptax.fill(0.153)
    assert np.allclose(mtr_ptax, exp_mtr_ptax)
Пример #17
0
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]))
Пример #18
0
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
Пример #19
0
    def test_convert(self):

        values = {"II_brk2_0": [36000., 38000., 40000.],
                    "II_brk2_1": [72250., 74000.],
                    "II_brk2_2": [36500.]
                    }

        ans = package_up_vars(values, first_budget_year=FBY)
        pp = Policy(start_year=2013)
        pp.set_year(FBY)
        # irates are rates for 2015, 2016, and 2017
        irates = pp.indexing_rates_for_update(param_name='II_brk2', calyear=FBY,
                                            num_years_to_expand=3)

        # User choices propagate through to all future years
        # The user has specified part of the parameter up to 2017.
        # So, we choose to fill in the propagated value, which is
        # either inflated or not.

        f2_2016 = int(36500 * (1.0 + irates[0]))
        f3_2016 = int(50200 * (1.0 + irates[0]))
        f4_2016 = int(74900 * (1.0 + irates[0]))
        f5_2016 = int(37450 * (1.0 + irates[0]))

        f1_2017 = int(74000 * (1.0 + irates[1]))
        f2_2017 = int(f2_2016 * (1.0 + irates[1]))
    
        exp =  [[36000, 72250, 36500, 50200, 74900, 37450],
                [38000, 74000, f2_2016, 50400, 75300, 37650],
                [40000, f1_2017, f2_2017, None, None, None]]

        assert ans['_II_brk2'] == exp
        assert len(ans) == 1
Пример #20
0
def test_create_parameters_from_file(policyfile):
    with open(policyfile.name) as pfile:
        policy = json.load(pfile)
    ppo = Policy(parameter_dict=policy)
    irates = Policy.default_inflation_rates()
    inf_rates = [irates[ppo.start_year + i] for i in range(0, ppo.num_years)]
    assert_allclose(ppo._almdep,
                    Policy.expand_array(np.array([7150, 7250, 7400]),
                                        inflate=True,
                                        inflation_rates=inf_rates,
                                        num_years=ppo.num_years),
                    atol=0.01, rtol=0.0)
    assert_allclose(ppo._almsep,
                    Policy.expand_array(np.array([40400, 41050]),
                                        inflate=True,
                                        inflation_rates=inf_rates,
                                        num_years=ppo.num_years),
                    atol=0.01, rtol=0.0)
    assert_allclose(ppo._rt5,
                    Policy.expand_array(np.array([0.33]),
                                        inflate=False,
                                        inflation_rates=inf_rates,
                                        num_years=ppo.num_years),
                    atol=0.01, rtol=0.0)
    assert_allclose(ppo._rt7,
                    Policy.expand_array(np.array([0.396]),
                                        inflate=False,
                                        inflation_rates=inf_rates,
                                        num_years=ppo.num_years),
                    atol=0.01, rtol=0.0)
Пример #21
0
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)
Пример #22
0
def test_parameters_get_default_start_year():
    paramdata = Policy.default_data(metadata=True, start_year=2015)
    # 1D data, has 2015 values
    meta_II_em = paramdata['_II_em']
    assert meta_II_em['start_year'] == 2015
    assert meta_II_em['row_label'] == ['2015', '2016']
    assert meta_II_em['value'] == [4000, 4050]
    # 2D data, has 2015 values
    meta_std_aged = paramdata['_STD_Aged']
    assert meta_std_aged['start_year'] == 2015
    assert meta_std_aged['row_label'] == ['2015', '2016']
    assert meta_std_aged['value'] == [[1550, 1250, 1250, 1550, 1550, 1250],
                                      [1550, 1250, 1250, 1550, 1550, 1250]]
    # 1D data, doesn't have 2015 values, is CPI inflated
    meta_amt_thd_marrieds = paramdata['_AMT_thd_MarriedS']
    assert meta_amt_thd_marrieds['start_year'] == 2015
    assert meta_amt_thd_marrieds['row_label'] == ['2015']
    # Take the 2014 parameter value and multiply by inflation for that year
    should_be = 41050 * (1.0 + Policy.default_inflation_rates()[2014])
    meta_amt_thd_marrieds['value'] == should_be
    # 1D data, doesn't have 2015 values, is not CPI inflated
    meta_kt_c_age = paramdata['_KT_c_Age']
    assert meta_kt_c_age['start_year'] == 2015
    assert meta_kt_c_age['row_label'] == ['2015']
    assert meta_kt_c_age['value'] == [24]
Пример #23
0
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)
Пример #24
0
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
Пример #25
0
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
Пример #26
0
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)
Пример #27
0
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
Пример #28
0
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)
Пример #29
0
def test_indexing_rates_for_update():
    """
    Check private _indexing_rates_for_update method.
    """
    pol = Policy()
    wgrates = pol._indexing_rates_for_update('_SS_Earnings_c', 2017, 10)
    pirates = pol._indexing_rates_for_update('_II_em', 2017, 10)
    assert len(wgrates) == len(pirates)
Пример #30
0
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
Пример #31
0
def test_read_json_param_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
    """
    policy = Policy()
    if set_year:
        policy.set_year(2015)
    param_dict = Calculator.read_json_param_objects(reform_file.name, None)
    policy.implement_reform(param_dict['policy'])
    syr = policy.start_year
    amt_brk1 = policy._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 = 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
Пример #32
0
def test_parameters_get_default():
    paramdata = Policy.default_data()
    assert paramdata['_CDCC_ps'] == [15000]
Пример #33
0
def test_reform_json_and_output(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 that
    generates no reform_errors.
    Then use each reform to generate static tax results for small set of
    filing units in a single tax_year and compare those results with
    expected results from a text file.
    """
    # pylint: disable=too-many-statements,too-many-locals
    used_dist_stats = [
        'c00100',  # AGI
        'c04600',  # personal exemptions
        'standard',  # standard deduction
        'c04800',  # regular taxable income
        'c05800',  # income tax before credits
        'iitax',  # income tax after credits
        'payrolltax',  # payroll taxes
        'aftertax_income'
    ]  # aftertax expanded income
    unused_dist_stats = set(DIST_TABLE_COLUMNS) - set(used_dist_stats)
    renamed_columns = {
        'c00100': 'AGI',
        'c04600': 'pexempt',
        'standard': 'stdded',
        'c04800': 'taxinc',
        'c05800': 'tax-wo-credits',
        'iitax': 'inctax',
        'payrolltax': 'paytax',
        'aftertax_income': 'ataxinc'
    }

    # embedded function used only in test_reform_json_and_output
    def write_distribution_table(calc, resfilename):
        """
        Write abbreviated distribution table calc to file with resfilename.
        """
        dist, _ = calc.distribution_tables(None, groupby='large_income_bins')
        for stat in unused_dist_stats:
            del dist[stat]
        dist = dist[used_dist_stats]
        dist.rename(mapper=renamed_columns, axis='columns', inplace=True)
        pd.options.display.float_format = '{:7.0f}'.format
        with open(resfilename, 'w') as resfile:
            dist.to_string(resfile)

    # embedded function used only in test_reform_json_and_output
    def res_and_out_are_same(base):
        """
        Return True if base.res and base.out file contents are the same;
        return False if base.res and base.out file contents differ.
        """
        with open(base + '.res') as resfile:
            act_res = resfile.read()
        with open(base + '.out') as outfile:
            exp_res = outfile.read()
        # check to see if act_res & exp_res have differences
        return not nonsmall_diffs(act_res.splitlines(True),
                                  exp_res.splitlines(True))

    # specify Records object containing cases data
    tax_year = 2020
    cases_path = os.path.join(tests_path, '..', 'reforms', 'cases.csv')
    cases = Records(
        data=cases_path,
        gfactors=None,  # keeps raw data unchanged
        weights=None,
        adjust_ratios=None,
        start_year=tax_year)  # set raw input data year
    # specify list of reform failures
    failures = list()
    # specify current-law-policy Calculator object
    calc1 = Calculator(policy=Policy(), records=cases, verbose=False)
    calc1.advance_to_year(tax_year)
    calc1.calc_all()
    res_path = cases_path.replace('cases.csv', 'clp.res')
    write_distribution_table(calc1, res_path)
    if res_and_out_are_same(res_path.replace('.res', '')):
        os.remove(res_path)
    else:
        failures.append(res_path)
    # read 2017_law.json reform file and specify its parameters dictionary
    pre_tcja_jrf = os.path.join(tests_path, '..', 'reforms', '2017_law.json')
    pre_tcja = Calculator.read_json_param_objects(pre_tcja_jrf, None)
    # check reform file contents and reform results for each reform
    reforms_path = os.path.join(tests_path, '..', 'reforms', '*.json')
    json_reform_files = glob.glob(reforms_path)
    for jrf in json_reform_files:
        # determine reform's baseline by reading contents of jrf
        with open(jrf, 'r') as rfile:
            jrf_text = rfile.read()
            pre_tcja_baseline = 'Reform_Baseline: 2017_law.json' in jrf_text
        # implement the reform relative to its baseline
        reform = Calculator.read_json_param_objects(jrf_text, None)
        pol = Policy()  # current-law policy
        if pre_tcja_baseline:
            pol.implement_reform(pre_tcja['policy'])
        pol.implement_reform(reform['policy'])
        assert not pol.reform_errors
        calc2 = Calculator(policy=pol, records=cases, verbose=False)
        calc2.advance_to_year(tax_year)
        calc2.calc_all()
        res_path = jrf.replace('.json', '.res')
        write_distribution_table(calc2, res_path)
        if res_and_out_are_same(res_path.replace('.res', '')):
            os.remove(res_path)
        else:
            failures.append(res_path)
    if failures:
        msg = 'Following reforms have res-vs-out differences:\n'
        for ref in failures:
            msg += '{}\n'.format(os.path.basename(ref))
        raise ValueError(msg)
Пример #34
0
def test_behavioral_response(use_puf_not_cps, puf_subsample, cps_fullsample):
    """
    Test that behavioral-response results are the same
    when generated from standard Tax-Calculator calls and
    when generated from tbi.run_nth_year_taxcalc_model() calls
    """
    # specify reform and assumptions
    reform_json = """
    {"policy": {
        "_II_rt5": {"2020": [0.25]},
        "_II_rt6": {"2020": [0.25]},
        "_II_rt7": {"2020": [0.25]},
        "_PT_rt5": {"2020": [0.25]},
        "_PT_rt6": {"2020": [0.25]},
        "_PT_rt7": {"2020": [0.25]},
        "_II_em": {"2020": [1000]}
    }}
    """
    assump_json = """
    {"behavior": {"_BE_sub": {"2013": [0.25]}},
     "growdiff_baseline": {},
     "growdiff_response": {},
     "consumption": {},
     "growmodel": {}
    }
    """
    params = Calculator.read_json_param_objects(reform_json, assump_json)
    # specify keyword arguments used in tbi function call
    kwargs = {
        'start_year': 2019,
        'year_n': 0,
        'use_puf_not_cps': use_puf_not_cps,
        'use_full_sample': False,
        'user_mods': {
            'policy': params['policy'],
            'behavior': params['behavior'],
            'growdiff_baseline': params['growdiff_baseline'],
            'growdiff_response': params['growdiff_response'],
            'consumption': params['consumption'],
            'growmodel': params['growmodel']
        },
        'return_dict': False
    }
    # generate aggregate results two ways: using tbi and standard calls
    num_years = 9
    std_res = dict()
    tbi_res = dict()
    if use_puf_not_cps:
        rec = Records(data=puf_subsample)
    else:
        # IMPORTANT: must use same subsample as used in test_cpscsv.py because
        #            that is the subsample used by run_nth_year_taxcalc_model
        std_cps_subsample = cps_fullsample.sample(frac=0.03, random_state=180)
        rec = Records.cps_constructor(data=std_cps_subsample)
    for using_tbi in [True, False]:
        for year in range(0, num_years):
            cyr = year + kwargs['start_year']
            if using_tbi:
                kwargs['year_n'] = year
                tables = run_nth_year_taxcalc_model(**kwargs)
                tbi_res[cyr] = dict()
                for tbl in ['aggr_1', 'aggr_2', 'aggr_d']:
                    tbi_res[cyr][tbl] = tables[tbl]
            else:
                pol = Policy()
                calc1 = Calculator(policy=pol, records=rec)
                pol.implement_reform(params['policy'])
                assert not pol.parameter_errors
                beh = Behavior()
                beh.update_behavior(params['behavior'])
                calc2 = Calculator(policy=pol, records=rec, behavior=beh)
                assert calc2.behavior_has_response()
                calc1.advance_to_year(cyr)
                calc2.advance_to_year(cyr)
                calc2 = Behavior.response(calc1, calc2)
                std_res[cyr] = dict()
                for tbl in ['aggr_1', 'aggr_2', 'aggr_d']:
                    if tbl.endswith('_1'):
                        itax = calc1.weighted_total('iitax')
                        ptax = calc1.weighted_total('payrolltax')
                        ctax = calc1.weighted_total('combined')
                    elif tbl.endswith('_2'):
                        itax = calc2.weighted_total('iitax')
                        ptax = calc2.weighted_total('payrolltax')
                        ctax = calc2.weighted_total('combined')
                    elif tbl.endswith('_d'):
                        itax = (calc2.weighted_total('iitax') -
                                calc1.weighted_total('iitax'))
                        ptax = (calc2.weighted_total('payrolltax') -
                                calc1.weighted_total('payrolltax'))
                        ctax = (calc2.weighted_total('combined') -
                                calc1.weighted_total('combined'))
                    cols = ['0_{}'.format(year)]
                    rows = ['ind_tax', 'payroll_tax', 'combined_tax']
                    datalist = [itax, ptax, ctax]
                    std_res[cyr][tbl] = pd.DataFrame(data=datalist,
                                                     index=rows,
                                                     columns=cols)
                    for col in std_res[cyr][tbl].columns:
                        val = std_res[cyr][tbl][col] * 1e-9
                        std_res[cyr][tbl][col] = round(val, 3)

    # compare the two sets of results
    # NOTE that the PUF tbi results have been "fuzzed" for privacy reasons,
    #      so there is no expectation that those results should be identical.
    no_diffs = True
    cps_dump = False  # setting to True produces dump output and test failure
    if use_puf_not_cps:
        reltol = 0.004  # std and tbi differ if more than 0.4 percent different
        dataset = 'PUF'
        dumping = False
    else:  # CPS results are not "fuzzed", so
        reltol = 1e-9  # std and tbi should be virtually identical
        dataset = 'CPS'
        dumping = cps_dump
    for year in range(0, num_years):
        cyr = year + kwargs['start_year']
        do_dump = bool(dumping and cyr >= 2019 and cyr <= 2020)
        col = '0_{}'.format(year)
        for tbl in ['aggr_1', 'aggr_2', 'aggr_d']:
            tbi = tbi_res[cyr][tbl][col]
            if do_dump:
                txt = 'DUMP of {} {} table for year {}:'
                print(txt.format(dataset, tbl, cyr))
                print(tbi)
            std = std_res[cyr][tbl][col]
            if not np.allclose(tbi, std, atol=0.0, rtol=reltol):
                no_diffs = False
                txt = '***** {} diff in {} table for year {} (year_n={}):'
                print(txt.format(dataset, tbl, cyr, year))
                print('TBI RESULTS:')
                print(tbi)
                print('STD RESULTS:')
                print(std)
    assert no_diffs
    assert not dumping
Пример #35
0
def test_agg(tests_path, puf_fullsample):
    """
    Test Tax-Calculator aggregate taxes with no policy reform using
    the full-sample puf.csv and a small sub-sample of puf.csv
    """
    # pylint: disable=too-many-locals,too-many-statements
    nyrs = 10
    # create a baseline Policy object containing 2017_law.json parameters
    pre_tcja_jrf = os.path.join(tests_path, '..', 'reforms', '2017_law.json')
    pre_tcja = Calculator.read_json_param_objects(pre_tcja_jrf, None)
    baseline_policy = Policy()
    baseline_policy.implement_reform(pre_tcja['policy'])
    # create a Records object (rec) containing all puf.csv input records
    rec = Records(data=puf_fullsample)
    # create a Calculator object using baseline policy and puf records
    calc = Calculator(policy=baseline_policy, records=rec)
    calc_start_year = calc.current_year
    # create aggregate diagnostic table (adt) as a Pandas DataFrame object
    adt = calc.diagnostic_table(nyrs)
    taxes_fullsample = adt.loc["Combined Liability ($b)"]
    # convert adt results to a string with a trailing EOL character
    adtstr = adt.to_string() + '\n'
    # create actual and expected lists of diagnostic table lines
    actual = adtstr.splitlines(True)
    aggres_path = os.path.join(tests_path, 'pufcsv_agg_expect.txt')
    with open(aggres_path, 'r') as expected_file:
        txt = expected_file.read()
    expected_results = txt.rstrip('\n\t ') + '\n'  # cleanup end of file txt
    expect = expected_results.splitlines(True)
    # ensure actual and expect lines have differences no more than small value
    if sys.version_info.major == 2:
        small = 0.0  # tighter test for Python 2.7
    else:
        small = 0.1  # looser test for Python 3.6
    diffs = nonsmall_diffs(actual, expect, small)
    if diffs:
        new_filename = '{}{}'.format(aggres_path[:-10], 'actual.txt')
        with open(new_filename, 'w') as new_file:
            new_file.write(adtstr)
        msg = 'PUFCSV AGG RESULTS DIFFER FOR FULL-SAMPLE\n'
        msg += '-------------------------------------------------\n'
        msg += '--- NEW RESULTS IN pufcsv_agg_actual.txt FILE ---\n'
        msg += '--- if new OK, copy pufcsv_agg_actual.txt to  ---\n'
        msg += '---                 pufcsv_agg_expect.txt     ---\n'
        msg += '---            and rerun test.                ---\n'
        msg += '-------------------------------------------------\n'
        raise ValueError(msg)
    # create aggregate diagnostic table using unweighted sub-sample of records
    fullsample = puf_fullsample
    rn_seed = 180  # to ensure sub-sample is always the same
    subfrac = 0.05  # sub-sample fraction
    subsample = fullsample.sample(frac=subfrac, random_state=rn_seed)
    rec_subsample = Records(data=subsample)
    calc_subsample = Calculator(policy=baseline_policy, records=rec_subsample)
    adt_subsample = calc_subsample.diagnostic_table(nyrs)
    # compare combined tax liability from full and sub samples for each year
    taxes_subsample = adt_subsample.loc["Combined Liability ($b)"]
    reltol = 0.01  # maximum allowed relative difference in tax liability
    if not np.allclose(taxes_subsample, taxes_fullsample,
                       atol=0.0, rtol=reltol):
        msg = 'PUFCSV AGG RESULTS DIFFER IN SUB-SAMPLE AND FULL-SAMPLE\n'
        msg += 'WHEN subfrac={:.3f}, rtol={:.4f}, seed={}\n'.format(subfrac,
                                                                    reltol,
                                                                    rn_seed)
        it_sub = np.nditer(taxes_subsample, flags=['f_index'])
        it_all = np.nditer(taxes_fullsample, flags=['f_index'])
        while not it_sub.finished:
            cyr = it_sub.index + calc_start_year
            tax_sub = float(it_sub[0])
            tax_all = float(it_all[0])
            reldiff = abs(tax_sub - tax_all) / abs(tax_all)
            if reldiff > reltol:
                msgstr = ' year,sub,full,reldiff= {}\t{:.2f}\t{:.2f}\t{:.4f}\n'
                msg += msgstr.format(cyr, tax_sub, tax_all, reldiff)
            it_sub.iternext()
            it_all.iternext()
        raise ValueError(msg)
Пример #36
0
def test_mtr(tests_path, puf_path):
    """
    Test Tax-Calculator marginal tax rates with no policy reform using puf.csv

    Compute histograms for each marginal tax rate income type using
    sample input from the puf.csv file and writing output to a string,
    which is then compared for differences with EXPECTED_MTR_RESULTS.
    """
    # pylint: disable=too-many-locals,too-many-statements
    assert len(PTAX_MTR_BIN_EDGES) == len(ITAX_MTR_BIN_EDGES)
    # construct actual results string, res
    res = ''
    if MTR_NEG_DIFF:
        res += 'MTR computed using NEGATIVE finite_diff '
    else:
        res += 'MTR computed using POSITIVE finite_diff '
    res += 'for tax year {}\n'.format(MTR_TAX_YEAR)
    # create a Policy object (clp) containing current-law policy parameters
    clp = Policy()
    clp.set_year(MTR_TAX_YEAR)
    # create a Records object (puf) containing puf.csv input records
    puf = Records(data=puf_path)
    recid = puf.RECID  # pylint: disable=no-member
    # create a Calculator object using clp policy and puf records
    calc = Calculator(policy=clp, records=puf)
    res += '{} = {}\n'.format('Total number of data records', puf.array_length)
    res += 'PTAX mtr histogram bin edges:\n'
    res += '     {}\n'.format(PTAX_MTR_BIN_EDGES)
    res += 'ITAX mtr histogram bin edges:\n'
    res += '     {}\n'.format(ITAX_MTR_BIN_EDGES)
    variable_header = 'PTAX and ITAX mtr histogram bin counts for'
    # compute marginal tax rate (mtr) histograms for each mtr variable
    for var_str in Calculator.MTR_VALID_VARIABLES:
        zero_out = (var_str == 'e01400')
        (mtr_ptax, mtr_itax, _) = calc.mtr(variable_str=var_str,
                                           negative_finite_diff=MTR_NEG_DIFF,
                                           zero_out_calculated_vars=zero_out,
                                           wrt_full_compensation=False)
        if zero_out:
            # check that calculated variables are consistent
            assert np.allclose((calc.array('iitax') +
                                calc.array('payrolltax')),
                               calc.array('combined'))
            assert np.allclose((calc.array('ptax_was') +
                                calc.array('setax') +
                                calc.array('ptax_amc')),
                               calc.array('payrolltax'))
            assert np.allclose(calc.array('c21060') - calc.array('c21040'),
                               calc.array('c04470'))
            assert np.allclose(calc.array('taxbc') + calc.array('c09600'),
                               calc.array('c05800'))
            assert np.allclose((calc.array('c05800') +
                                calc.array('othertaxes') -
                                calc.array('c07100')),
                               calc.array('c09200'))
            assert np.allclose(calc.array('c09200') - calc.array('refund'),
                               calc.array('iitax'))
        if var_str == 'e00200s':
            # only MARS==2 filing units have valid MTR values
            mtr_ptax = mtr_ptax[calc.array('MARS') == 2]
            mtr_itax = mtr_itax[calc.array('MARS') == 2]
        res += '{} {}:\n'.format(variable_header, var_str)
        res += mtr_bin_counts(mtr_ptax, PTAX_MTR_BIN_EDGES, recid)
        res += mtr_bin_counts(mtr_itax, ITAX_MTR_BIN_EDGES, recid)
    # check for differences between actual and expected results
    mtrres_path = os.path.join(tests_path, 'pufcsv_mtr_expect.txt')
    with open(mtrres_path, 'r') as expected_file:
        txt = expected_file.read()
    expected_results = txt.rstrip('\n\t ') + '\n'  # cleanup end of file txt
    if nonsmall_diffs(res.splitlines(True), expected_results.splitlines(True)):
        new_filename = '{}{}'.format(mtrres_path[:-10], 'actual.txt')
        with open(new_filename, 'w') as new_file:
            new_file.write(res)
        msg = 'PUFCSV MTR RESULTS DIFFER\n'
        msg += '-------------------------------------------------\n'
        msg += '--- NEW RESULTS IN pufcsv_mtr_actual.txt FILE ---\n'
        msg += '--- if new OK, copy pufcsv_mtr_actual.txt to  ---\n'
        msg += '---                 pufcsv_mtr_expect.txt     ---\n'
        msg += '---            and rerun test.                ---\n'
        msg += '-------------------------------------------------\n'
        raise ValueError(msg)
Пример #37
0
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)
Пример #38
0
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_make_Calculator_deepcopy(records_2009):
    parm = Policy()
    calc1 = Calculator(policy=parm, records=records_2009)
    calc2 = copy.deepcopy(calc1)
    assert isinstance(calc2, Calculator)
Пример #40
0
def test_benefits(tests_path, cps_fullsample):
    """
    Test CPS benefits.
    """
    # pylint: disable=too-many-locals
    benefit_names = [
        'ssi', 'mcare', 'mcaid', 'snap', 'wic', 'tanf', 'vet', 'housing'
    ]
    # write benefits_actual.csv file
    recs = Records.cps_constructor(data=cps_fullsample)
    start_year = recs.current_year
    calc = Calculator(policy=Policy(), records=recs, verbose=False)
    assert calc.current_year == start_year
    year_list = list()
    bname_list = list()
    benamt_list = list()
    bencnt_list = list()
    benavg_list = list()
    for year in range(start_year, Policy.LAST_BUDGET_YEAR + 1):
        calc.advance_to_year(year)
        size = calc.array('XTOT')
        wght = calc.array('s006')
        # compute benefit aggregate amounts and head counts and average benefit
        # (head counts include all members of filing unit receiving a benefit,
        #  which means benavg is f.unit benefit amount divided by f.unit size)
        for bname in benefit_names:
            ben = calc.array('{}_ben'.format(bname))
            benamt = round((ben * wght).sum() * 1e-9, 3)
            bencnt = round((size[ben > 0] * wght[ben > 0]).sum() * 1e-6, 3)
            benavg = round(benamt / bencnt, 1)
            year_list.append(year)
            bname_list.append(bname)
            benamt_list.append(benamt)
            bencnt_list.append(bencnt)
            benavg_list.append(benavg)
    adict = {
        'year': year_list,
        'bname': bname_list,
        'benamt': benamt_list,
        'bencnt': bencnt_list,
        'benavg': benavg_list
    }
    adf = pd.DataFrame(data=adict,
                       columns=['year', 'bname', 'benamt', 'bencnt', 'benavg'])
    ben_act_path = os.path.join(tests_path, 'benefits_actual.csv')
    adf.to_csv(ben_act_path, index=False)
    # read benefits_expect.csv file
    ben_exp_path = os.path.join(tests_path, 'benefits_expect.csv')
    edf = pd.read_csv(ben_exp_path)
    # compare benefit information
    atol = 0.0001
    rtol = 0.0
    diffs = False
    for col in ['benamt', 'bencnt', 'benavg']:
        if not np.allclose(adf[col], edf[col], atol=atol, rtol=rtol):
            diffs = True
    if diffs:
        msg = 'CPS BENEFITS RESULTS DIFFER\n'
        msg += '-------------------------------------------------\n'
        msg += '--- NEW RESULTS IN benefits_actual.txt FILE   ---\n'
        msg += '--- if new OK, copy benefits_actual.txt to    ---\n'
        msg += '---                 benefits_expect.txt       ---\n'
        msg += '---            and rerun test.                ---\n'
        msg += '-------------------------------------------------\n'
        raise ValueError(msg)
    else:
        os.remove(ben_act_path)
Пример #41
0
def test_validate_param_values_warnings_errors():
    """
    Check detection of out_of_range policy parameters in reforms.
    """
    pol1 = Policy()
    ref1 = {2020: {'_ID_Medical_frt': [0.05]}}
    pol1.implement_reform(ref1)
    assert len(pol1.reform_warnings) > 0
    pol2 = Policy()
    ref2 = {2021: {'_ID_Charity_crt_all': [0.61]}}
    pol2.implement_reform(ref2)
    assert len(pol2.reform_warnings) > 0
    pol3 = Policy()
    ref3 = {2024: {'_II_brk4': [[0, 0, 0, 0, 0]]}}
    pol3.implement_reform(ref3)
    assert len(pol3.reform_errors) > 0
    pol4 = Policy()
    ref4 = {2024: {'_II_brk4': [[0, 9e9, 0, 0, 0]]}}
    pol4.implement_reform(ref4)
    assert len(pol4.reform_errors) > 0
    pol5 = Policy()
    ref5 = {2025: {'_ID_BenefitSurtax_Switch': [[False, True, 0, 1, 0, 1, 0]]}}
    pol5.implement_reform(ref5)
    assert len(pol5.reform_errors) == 0
    pol6 = Policy()
    ref6 = {2013: {'_STD': [[20000, 25000, 20000, 20000, 25000]]}}
    pol6.implement_reform(ref6)
    assert pol6.reform_errors == ''
    assert pol6.reform_warnings == ''
Пример #42
0
def test_validate_param_names_types_errors():
    """
    Check detection of invalid policy parameter names and types in reforms.
    """
    pol0 = Policy()
    ref0 = {2020: {'_STD_cpi': 2}}
    with pytest.raises(ValueError):
        pol0.implement_reform(ref0)
    pol1 = Policy()
    ref1 = {2020: {'_badname_cpi': True}}
    with pytest.raises(ValueError):
        pol1.implement_reform(ref1)
    pol2 = Policy()
    ref2 = {2020: {'_II_em_cpi': 5}}
    with pytest.raises(ValueError):
        pol2.implement_reform(ref2)
    pol3 = Policy()
    ref3 = {2020: {'_badname': [0.4]}}
    with pytest.raises(ValueError):
        pol3.implement_reform(ref3)
    pol4 = Policy()
    ref4 = {2020: {'_EITC_MinEligAge': [21.4]}}
    with pytest.raises(ValueError):
        pol4.implement_reform(ref4)
    pol5 = Policy()
    ref5 = {2025: {'_ID_BenefitSurtax_Switch': [[False, True, 0, 2, 0, 1, 0]]}}
    with pytest.raises(ValueError):
        pol5.implement_reform(ref5)
    pol6 = Policy()
    ref6 = {2021: {'_II_em': ['not-a-number']}}
    with pytest.raises(ValueError):
        pol6.implement_reform(ref6)
Пример #43
0
def test_correct_Policy_instantiation():
    pol = Policy()
    assert pol
    pol.implement_reform({})
    with pytest.raises(ValueError):
        pol.implement_reform(list())
    with pytest.raises(ValueError):
        pol.implement_reform({2099: {'_II_em': [99000]}})
    pol.set_year(2019)
    with pytest.raises(ValueError):
        pol.implement_reform({2018: {'_II_em': [99000]}})
Пример #44
0
def test_multi_year_reform():
    """
    Test multi-year reform involving 1D and 2D parameters.
    """
    # specify dimensions of policy Policy object
    syr = 2013
    nyrs = Policy.DEFAULT_NUM_YEARS
    pol = Policy(start_year=syr)
    iratelist = pol.inflation_rates()
    ifactor = {}
    for i in range(0, nyrs):
        ifactor[syr + i] = 1.0 + iratelist[i]
    wratelist = pol.wage_growth_rates()
    wfactor = {}
    for i in range(0, nyrs):
        wfactor[syr + i] = 1.0 + wratelist[i]
    # confirm that parameters have current-law values
    assert_allclose(getattr(pol, '_EITC_c'),
                    Policy._expand_array(np.array(
                        [[487, 3250, 5372, 6044], [496, 3305, 5460, 6143],
                         [503, 3359, 5548, 6242], [506, 3373, 5572, 6269],
                         [510, 3400, 5616, 6318]],
                        dtype=np.float64),
                                         False,
                                         inflate=True,
                                         inflation_rates=iratelist,
                                         num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    assert_allclose(getattr(pol, '_STD_Dep'),
                    Policy._expand_array(np.array(
                        [1000, 1000, 1050, 1050, 1050], dtype=np.float64),
                                         False,
                                         inflate=True,
                                         inflation_rates=iratelist,
                                         num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    assert_allclose(getattr(pol, '_CTC_c'),
                    Policy._expand_array(np.array([1000] * 5 + [1400] * 4 +
                                                  [1500] * 3 + [1600] + [1000],
                                                  dtype=np.float64),
                                         False,
                                         inflate=False,
                                         inflation_rates=iratelist,
                                         num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    # this parameter uses a different indexing rate
    assert_allclose(getattr(pol, '_SS_Earnings_c'),
                    Policy._expand_array(np.array(
                        [113700, 117000, 118500, 118500, 127200],
                        dtype=np.float64),
                                         False,
                                         inflate=True,
                                         inflation_rates=wratelist,
                                         num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    # specify multi-year reform using a dictionary of year_provisions dicts
    reform = {
        2015: {
            '_CTC_c': [2000]
        },
        2016: {
            '_EITC_c': [[900, 5000, 8000, 9000]],
            '_II_em': [7000],
            '_SS_Earnings_c': [300000]
        },
        2017: {
            '_SS_Earnings_c': [500000],
            '_SS_Earnings_c_cpi': False
        },
        2019: {
            '_EITC_c': [[1200, 7000, 10000, 12000]],
            '_II_em': [9000],
            '_SS_Earnings_c': [700000],
            '_SS_Earnings_c_cpi': True
        }
    }
    # implement multi-year reform
    pol.implement_reform(reform)
    assert pol.current_year == syr
    # move policy Policy object forward in time so current_year is syr+2
    #   Note: this would be typical usage because the first budget year
    #         is greater than Policy start_year.
    pol.set_year(pol.start_year + 2)
    assert pol.current_year == syr + 2
    # confirm that actual parameters have expected post-reform values
    check_eitc_c(pol, reform, ifactor)
    check_ii_em(pol, reform, ifactor)
    check_ss_earnings_c(pol, reform, wfactor)
    check_ctc_c(pol, reform)
Пример #45
0
def run():
    """
    Execute Calculator.calc_all() method using 'puf.csv' input and
    writing truncated ouput to a CSV file named 'results_puf.csv'.
    """
    # create a Policy object containing current-law policy (clp) parameters
    clp = Policy()

    # create a Records object (puf) containing puf.csv input records
    puf = Records()

    # create a Calculator object using clp policy and puf records
    calc = Calculator(policy=clp, records=puf)

    calc.calc_all()
    rshape = calc.records.e00100.shape
    dataf = pd.DataFrame()
    for attr in dir(calc.records):
        value = getattr(calc.records, attr)
        if hasattr(value, "shape"):
            if value.shape == rshape:
                dataf[attr] = value

    # truncate the outputs
    col_names = ['EICYB1', 'EICYB2', 'EICYB3', 'NIIT', '_addamt', '_addtax',
                 '_agep', '_ages', '_agierr', '_alminc', '_amed', '_amt15pc',
                 '_amt20pc', '_amt25pc', '_amt5pc', '_amtfei', '_amtsepadd',
                 '_amtstd', '_avail', '_cglong', '_cmbtp', '_comb',
                 '_combined', '_ctc1', '_ctc2', '_ctcagi', '_ctctax', '_dclim',
                 '_dwks12', '_dwks16', '_dwks17', '_dwks21', '_dwks25',
                 '_dwks26', '_dwks28', '_dwks31', '_dwks5', '_dwks9', '_dy',
                 '_earned', '_eitc', '_exocrd', '_expanded_income', '_feided',
                 '_feitax', '_fica', '_hasgain', '_ieic', 'c03260',
                 '_limitratio', '_line17', '_line19', '_line22', '_line30',
                 '_line31', '_line32', '_line33', '_line34', '_line35',
                 '_line36', '_modagi', '_nctcr', '_ncu13', '_ngamty', '_noncg',
                 '_nonlimited', '_num', '_numextra', '_oldfei', '_othadd',
                 '_othded', '_othertax', '_othtax', '_parents', '_phase2_i',
                 '_posagi', '_precrd', '_preeitc', '_prexmp', '_refund',
                 '_regcrd', '_s1291', '_sep', '_sey', 'c09400', 'c03260',
                 '_seywage', '_standard', '_statax', '_tamt2', '_taxbc',
                 '_taxinc', '_taxspecial', '_tratio', '_txpyers',
                 '_val_rtbase', '_val_rtless', '_val_ymax', '_xyztax', '_ymod',
                 '_ymod1', '_ymod2', '_ymod3', '_ywossbc', '_ywossbe',
                 'c00100', 'c01000', 'c02500', 'c02650', 'c02700', 'c02900',
                 'c04100', 'c04200', 'c04470', 'c04500', 'c04600', 'c04800',
                 'c05100', 'c05200', 'c05700', 'c05750', 'c05800', 'c07100',
                 'c07150', 'c07180', 'c07220', 'c07230', 'c07240', 'c07300',
                 'c07600', 'c07970', 'c08795', 'c08800', 'c09200', 'c09600',
                 'c10300', 'c10950', 'c10960', 'c11055', 'c11070', 'c15100',
                 'c15200', 'c17000', 'c17750', 'c18300', 'c19200', 'c19700',
                 'c20400', 'c20500', 'c20750', 'c20800', 'c21040', 'c21060',
                 'c23650', 'c24505', 'c24510', 'c24516', 'c24517', 'c24520',
                 'c24530', 'c24534', 'c24540', 'c24550', 'c24560', 'c24570',
                 'c24580', 'c24597', 'c24598', 'c24610', 'c24615', 'c32800',
                 'c32840', 'c32880', 'c32890', 'c33000', 'c33200', 'c33400',
                 'c33465', 'c33470', 'c33475', 'c33480', 'c37703', 'c59430',
                 'c59450', 'c59460', 'c59485', 'c59490', 'c59560', 'c59660',
                 'c59680', 'c59700', 'c59720', 'c60000', 'c60130', 'c60200',
                 'c60220', 'c60240', 'c60260', 'c62100', 'c62100_everyone',
                 'c62600', 'c62700', 'c62720', 'c62730', 'c62740', 'c62745',
                 'c62747', 'c62755', 'c62760', 'c62770', 'c62780', 'c62800',
                 'c62900', 'c63000', 'c63100', 'c82880', 'c82885', 'c82890',
                 'c82900', 'c82905', 'c82910', 'c82915', 'c82920', 'c82925',
                 'c82930', 'c82935', 'c82937', 'c82940', 'c87482', 'c87483',
                 'c87487', 'c87488', 'c87492', 'c87493', 'c87497', 'c87498',
                 'c87521', 'c87530', 'c87540', 'c87550', 'c87560', 'c87570',
                 'c87580', 'c87590', 'c87600', 'c87610', 'c87620', 'c87654',
                 'c87656', 'c87658', 'c87660', 'c87662', 'c87664', 'c87666',
                 'c87668', 'c87681', 'e00650', 'e02500', 'e08795', 'h82880',
                 'x04500', 'x07100', 'y07100', 'y62745']
    dataf_truncated = dataf[col_names]

    # write test output to csv file named 'results_puf.csv'
    dataf_truncated.to_csv('results_puf.csv', float_format='%1.3f', sep=',',
                           header=True, index=False)
Пример #46
0
def test_implement_reform_Policy_raises_on_no_year():
    reform = {'_STD_Aged': [[1400, 1200]]}
    ppo = Policy()
    with pytest.raises(ValueError):
        ppo.implement_reform(reform)
Пример #47
0
def test_implement_reform_Policy_raises_on_future_year():
    ppo = Policy(start_year=2013)
    with pytest.raises(ValueError):
        reform = {2010: {'_STD_Aged': [[1400, 1100, 1100, 1400, 1400, 1199]]}}
        ppo.implement_reform(reform)
def test_Calculator_attr_access_to_policy(records_2009):
    policy = Policy()
    calc = Calculator(policy=policy, records=records_2009)
    assert hasattr(calc.records, 'c01000')
    assert hasattr(calc.policy, '_AMT_Child_em')
    assert hasattr(calc, 'policy')
Пример #49
0
def test_reform_json_and_output():
    """
    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 that
    generates no parameter_errors.
    Then use each reform to generate static tax results for small set of
    filing units in a single tax_year and compare those results with
    expected results from a CSV-formatted file.
    """

    # pylint: disable=too-many-statements,too-many-locals

    # embedded function used only in test_reform_json_and_output
    def write_res_file(calc, resfilename):
        """
        Write calc output to CSV-formatted file with resfilename.
        """
        varlist = [
            'RECID', 'c00100', 'standard', 'c04800', 'iitax', 'payrolltax'
        ]
        # varnames  AGI    STD         TaxInc    ITAX     PTAX
        stats = calc.dataframe(varlist)
        stats['RECID'] = stats['RECID'].astype(int)
        with open(resfilename, 'w') as resfile:
            stats.to_csv(resfile, index=False, float_format='%.2f')

    # embedded function used only in test_reform_json_and_output
    def res_and_out_are_same(base):
        """
        Return True if base.res.csv and base.out.csv file contents are same;
        return False if base.res.csv and base.out.csv file contents differ.
        """
        resdf = pd.read_csv(base + '.res.csv')
        outdf = pd.read_csv(base + '.out.csv')
        diffs = False
        for col in resdf:
            if col in outdf:
                if not np.allclose(resdf[col], outdf[col]):
                    diffs = True
            else:
                diffs = True
        return not diffs

    # specify Records object containing cases data
    tax_year = 2020
    cases_path = os.path.join(CUR_PATH, '..', 'taxcalc', 'cases.csv')
    cases = Records(
        data=cases_path,
        start_year=tax_year,  # set raw input data year
        gfactors=None,  # keeps raw data unchanged
        weights=None,
        adjust_ratios=None)
    # specify list of reform failures
    failures = list()
    # specify current-law-policy Calculator object
    calc = Calculator(policy=Policy(), records=cases, verbose=False)
    calc.advance_to_year(tax_year)
    calc.calc_all()
    res_path = cases_path.replace('cases.csv', 'clp.res.csv')
    write_res_file(calc, res_path)
    if res_and_out_are_same(res_path.replace('.res.csv', '')):
        os.remove(res_path)
    else:
        failures.append(res_path)
    del calc
    # read 2017_law.json reform file and specify its parameters dictionary
    pre_tcja_jrf = os.path.join(CUR_PATH, '..', 'taxcalc', '2017_law.json')
    pre_tcja = Policy.read_json_reform(pre_tcja_jrf)
    # check reform file contents and reform results for each reform
    reforms_path = os.path.join(CUR_PATH, '..', 'taxcalc', '*.json')
    json_reform_files = glob.glob(reforms_path)
    for jrf in json_reform_files:
        # determine reform's baseline by reading contents of jrf
        with open(jrf, 'r') as rfile:
            jrf_text = rfile.read()
        pre_tcja_baseline = 'Reform_Baseline: 2017_law.json' in jrf_text
        # implement the reform relative to its baseline
        reform = Policy.read_json_reform(jrf_text)
        pol = Policy()  # current-law policy
        if pre_tcja_baseline:
            pol.implement_reform(pre_tcja)
            assert not pol.parameter_errors
        pol.implement_reform(reform)
        assert not pol.parameter_errors
        calc = Calculator(policy=pol, records=cases, verbose=False)
        calc.advance_to_year(tax_year)
        calc.calc_all()
        res_path = jrf.replace('.json', '.res.csv')
        write_res_file(calc, res_path)
        if res_and_out_are_same(res_path.replace('.res.csv', '')):
            os.remove(res_path)
        else:
            failures.append(res_path)
        del calc
    if failures:
        msg = 'Following reforms have res-vs-out differences:\n'
        for ref in failures:
            msg += '{}\n'.format(os.path.basename(ref))
        raise ValueError(msg)
def test_Calculator_create_diagnostic_table(records_2009):
    calc = Calculator(policy=Policy(), records=records_2009)
    calc.calc_all()
    adt = create_diagnostic_table(calc)
    assert isinstance(adt, pd.DataFrame)
Пример #51
0
def fixture_baseline_2017_law():
    """
    Read ../taxcalc/2017_law.json and return its policy dictionary.
    """
    pre_tcja_jrf = os.path.join(CUR_PATH, '..', 'taxcalc', '2017_law.json')
    return Policy.read_json_reform(pre_tcja_jrf)
Пример #52
0
def calculator_objects(year_n, start_year,
                       use_puf_not_cps,
                       use_full_sample,
                       user_mods,
                       behavior_allowed):
    """
    This function assumes that the specified user_mods is a dictionary
      returned by the Calculator.read_json_param_objects() function.
    This function returns (calc1, calc2) where
      calc1 is pre-reform Calculator object calculated for year_n, and
      calc2 is post-reform Calculator object calculated for year_n.
    Set behavior_allowed to False when generating static results or
      set behavior_allowed to True when generating dynamic results.
    """
    # pylint: disable=too-many-arguments,too-many-locals
    # pylint: disable=too-many-branches,too-many-statements

    check_user_mods(user_mods)

    # specify Consumption instance
    consump = Consumption()
    consump_assumptions = user_mods['consumption']
    consump.update_consumption(consump_assumptions)

    # specify growdiff_baseline and growdiff_response
    growdiff_baseline = GrowDiff()
    growdiff_response = GrowDiff()
    growdiff_base_assumps = user_mods['growdiff_baseline']
    growdiff_resp_assumps = user_mods['growdiff_response']
    growdiff_baseline.update_growdiff(growdiff_base_assumps)
    growdiff_response.update_growdiff(growdiff_resp_assumps)

    # create pre-reform and post-reform GrowFactors instances
    growfactors_pre = GrowFactors()
    growdiff_baseline.apply_to(growfactors_pre)
    growfactors_post = GrowFactors()
    growdiff_baseline.apply_to(growfactors_post)
    growdiff_response.apply_to(growfactors_post)

    # create sample pd.DataFrame from specified input file and sampling scheme
    tbi_path = os.path.abspath(os.path.dirname(__file__))
    if use_puf_not_cps:
        # first try TaxBrain deployment path
        input_path = 'puf.csv.gz'
        if not os.path.isfile(input_path):
            # otherwise try local Tax-Calculator deployment path
            input_path = os.path.join(tbi_path, '..', '..', 'puf.csv')
        sampling_frac = 0.05
        sampling_seed = 2222
    else:  # if using cps input not puf input
        # first try Tax-Calculator code path
        input_path = os.path.join(tbi_path, '..', 'cps.csv.gz')
        if not os.path.isfile(input_path):
            # otherwise read from taxcalc package "egg"
            input_path = None  # pragma: no cover
            full_sample = read_egg_csv('cps.csv.gz')  # pragma: no cover
        sampling_frac = 0.03
        sampling_seed = 180
    if input_path:
        full_sample = pd.read_csv(input_path)
    if use_full_sample:
        sample = full_sample
    else:
        sample = full_sample.sample(frac=sampling_frac,
                                    random_state=sampling_seed)

    # create pre-reform Calculator instance
    if use_puf_not_cps:
        recs1 = Records(data=sample,
                        gfactors=growfactors_pre)
    else:
        recs1 = Records.cps_constructor(data=sample,
                                        gfactors=growfactors_pre)
    policy1 = Policy(gfactors=growfactors_pre)
    calc1 = Calculator(policy=policy1, records=recs1, consumption=consump)
    while calc1.current_year < start_year:
        calc1.increment_year()
    calc1.calc_all()
    assert calc1.current_year == start_year

    # specify Behavior instance
    behv = Behavior()
    behavior_assumps = user_mods['behavior']
    behv.update_behavior(behavior_assumps)

    # always prevent both behavioral response and growdiff response
    if behv.has_any_response() and growdiff_response.has_any_response():
        msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE'
        raise ValueError(msg)

    # optionally prevent behavioral response
    if behv.has_any_response() and not behavior_allowed:
        msg = 'A behavior RESPONSE IS NOT ALLOWED'
        raise ValueError(msg)

    # create post-reform Calculator instance
    if use_puf_not_cps:
        recs2 = Records(data=sample,
                        gfactors=growfactors_post)
    else:
        recs2 = Records.cps_constructor(data=sample,
                                        gfactors=growfactors_post)
    policy2 = Policy(gfactors=growfactors_post)
    policy_reform = user_mods['policy']
    policy2.implement_reform(policy_reform)
    calc2 = Calculator(policy=policy2, records=recs2,
                       consumption=consump, behavior=behv)
    while calc2.current_year < start_year:
        calc2.increment_year()
    assert calc2.current_year == start_year

    # delete objects now embedded in calc1 and calc2
    del sample
    del full_sample
    del consump
    del growdiff_baseline
    del growdiff_response
    del growfactors_pre
    del growfactors_post
    del behv
    del recs1
    del recs2
    del policy1
    del policy2

    # increment Calculator objects for year_n years and calculate
    for _ in range(0, year_n):
        calc1.increment_year()
        calc2.increment_year()
    calc1.calc_all()
    if calc2.behavior_has_response():
        calc2 = Behavior.response(calc1, calc2)
    else:
        calc2.calc_all()

    # return calculated Calculator objects
    return (calc1, calc2)
Пример #53
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 = {reform_year: {'_PT_rt7': [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 = {reform_year: {'_PT_wages_active_income': [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 = {reform_year: {'_PT_wages_active_income': [True],
                             '_PT_rt7': [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
Пример #54
0
def convert_defaults(pcl):
    '''
    Function to convert default Tax-Calculator policy parameters to
    ParamTools compliant parameters.
    '''
    type_map = {
        "real": "float",
        "boolean": "bool",
        "integer": "int",
        "string": "str",
    }

    new_pcl = defaultdict(dict)
    new_pcl["schema"] = POLICY_SCHEMA
    LAST_YEAR = TC_LAST_YEAR
    pol = Policy()
    pol.set_year(TC_LAST_YEAR)
    for param, item in pcl.items():
        values = []
        pol_val = getattr(pol, f"_{param}").tolist()
        min_year = min(item["value_yrs"])
        if isinstance(pol_val[0], list):
            for year in range(len(pol_val)):
                if min_year + year > LAST_YEAR:
                    break
                for dim1 in range(len(pol_val[0])):
                    values.append({
                        "year": min_year + year,
                        item["vi_name"]: item["vi_vals"][dim1],
                        "value": pol_val[year][dim1]
                    })
        else:
            for year in range(len(pol_val)):
                if min_year + year > LAST_YEAR:
                    break
                values.append({
                    "year": min_year + year,
                    "value": pol_val[year]
                })

        new_pcl[param]['value'] = values
        new_pcl[param]['title'] = pcl[param]["long_name"]
        new_pcl[param]['type'] = type_map[pcl[param]["value_type"]]

        new_pcl[param]["validators"] = {"range": pcl[param]["valid_values"]}

        # checkbox if indexable
        if item["indexable"]:
            if item["indexed"]:
                new_pcl[param]["checkbox"] = True
            else:
                new_pcl[param]["checkbox"] = False

        to_keep = list(POLICY_SCHEMA["additional_members"].keys()) + [
            "description", "notes",
        ]
        for k in to_keep:
            if k in pcl[param]:
                new_pcl[param][k] = pcl[param][k]

    return new_pcl
Пример #55
0
def test_agg(tests_path, cps_fullsample):
    """
    Test current-law aggregate taxes using cps.csv file.
    """
    # pylint: disable=too-many-statements,too-many-locals
    nyrs = 10
    # create a baseline Policy object containing current law policy parameters
    baseline_policy = Policy()
    # create a Records object (rec) containing all cps.csv input records
    recs = Records.cps_constructor(data=cps_fullsample)
    # create a Calculator object using baseline policy and cps records
    calc = Calculator(policy=baseline_policy, records=recs)
    calc_start_year = calc.current_year
    # create aggregate diagnostic table (adt) as a Pandas DataFrame object
    adt = calc.diagnostic_table(nyrs)
    taxes_fullsample = adt.loc["Combined Liability ($b)"]
    # convert adt to a string with a trailing EOL character
    actual_results = adt.to_string() + '\n'
    # read expected results from file
    aggres_path = os.path.join(tests_path, 'cpscsv_agg_expect.txt')
    with open(aggres_path, 'r') as expected_file:
        txt = expected_file.read()
    expected_results = txt.rstrip('\n\t ') + '\n'  # cleanup end of file txt
    # ensure actual and expected results have no nonsmall differences
    diffs = nonsmall_diffs(actual_results.splitlines(True),
                           expected_results.splitlines(True))
    if diffs:
        new_filename = '{}{}'.format(aggres_path[:-10], 'actual.txt')
        with open(new_filename, 'w') as new_file:
            new_file.write(actual_results)
        msg = 'CPSCSV AGG RESULTS DIFFER\n'
        msg += '-------------------------------------------------\n'
        msg += '--- NEW RESULTS IN cpscsv_agg_actual.txt FILE ---\n'
        msg += '--- if new OK, copy cpscsv_agg_actual.txt to  ---\n'
        msg += '---                 cpscsv_agg_expect.txt     ---\n'
        msg += '---            and rerun test.                ---\n'
        msg += '-------------------------------------------------\n'
        raise ValueError(msg)
    # create aggregate diagnostic table using unweighted sub-sample of records
    rn_seed = 180  # to ensure sub-sample is always the same
    subfrac = 0.03  # sub-sample fraction
    subsample = cps_fullsample.sample(frac=subfrac, random_state=rn_seed)
    recs_subsample = Records.cps_constructor(data=subsample)
    calc_subsample = Calculator(policy=baseline_policy, records=recs_subsample)
    adt_subsample = calc_subsample.diagnostic_table(nyrs)
    # compare combined tax liability from full and sub samples for each year
    taxes_subsample = adt_subsample.loc["Combined Liability ($b)"]
    msg = ''
    for cyr in range(calc_start_year, calc_start_year + nyrs):
        if cyr == calc_start_year:
            reltol = 0.014
        else:
            reltol = 0.006
        if not np.allclose(
                taxes_subsample[cyr], taxes_fullsample[cyr], atol=0.0,
                rtol=reltol):
            reldiff = (taxes_subsample[cyr] / taxes_fullsample[cyr]) - 1.
            line1 = '\nCPSCSV AGG SUB-vs-FULL RESULTS DIFFER IN {}'
            line2 = '\n  when subfrac={:.3f}, rtol={:.4f}, seed={}'
            line3 = '\n  with sub={:.3f}, full={:.3f}, rdiff={:.4f}'
            msg += line1.format(cyr)
            msg += line2.format(subfrac, reltol, rn_seed)
            msg += line3.format(taxes_subsample[cyr], taxes_fullsample[cyr],
                                reldiff)
    if msg:
        raise ValueError(msg)
Пример #56
0
def test_multi_year_reform():
    """
    Test multi-year reform involving 1D and 2D parameters.
    """
    # specify dimensions of policy Policy object
    syr = 2013
    nyrs = 10
    # specify assumed inflation rates
    irates = {
        2013: 0.02,
        2014: 0.02,
        2015: 0.02,
        2016: 0.03,
        2017: 0.03,
        2018: 0.04,
        2019: 0.04,
        2020: 0.04,
        2021: 0.04,
        2022: 0.04
    }
    ifactor = {}
    for i in range(0, nyrs):
        ifactor[syr + i] = 1.0 + irates[syr + i]
    iratelist = [irates[syr + i] for i in range(0, nyrs)]
    # specify assumed inflation rates
    wrates = {
        2013: 0.0276,
        2014: 0.0419,
        2015: 0.0465,
        2016: 0.0498,
        2017: 0.0507,
        2018: 0.0481,
        2019: 0.0451,
        2020: 0.0441,
        2021: 0.0437,
        2022: 0.0435
    }
    wfactor = {}
    for i in range(0, nyrs):
        wfactor[syr + i] = 1.0 + wrates[syr + i]
    wratelist = [wrates[syr + i] for i in range(0, nyrs)]
    # instantiate policy Policy object
    ppo = Policy(start_year=syr,
                 num_years=nyrs,
                 inflation_rates=irates,
                 wage_growth_rates=wrates)
    # confirm that parameters have current-law values
    assert_allclose(getattr(ppo, '_AMT_thd_MarriedS'),
                    Policy.expand_array(np.array([40400, 41050]),
                                        inflate=True,
                                        inflation_rates=iratelist,
                                        num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    assert_allclose(getattr(ppo, '_EITC_c'),
                    Policy.expand_array(np.array([[487, 3250, 5372, 6044],
                                                  [496, 3305, 5460, 6143],
                                                  [503, 3359, 5548, 6242],
                                                  [506, 3373, 5572, 6269]]),
                                        inflate=True,
                                        inflation_rates=iratelist,
                                        num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    assert_allclose(getattr(ppo, '_II_em'),
                    Policy.expand_array(np.array([3900, 3950, 4000, 4050]),
                                        inflate=True,
                                        inflation_rates=iratelist,
                                        num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    assert_allclose(getattr(ppo, '_CTC_c'),
                    Policy.expand_array(np.array([1000]),
                                        inflate=False,
                                        inflation_rates=iratelist,
                                        num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    # this parameter uses a different inflating rate
    assert_allclose(getattr(ppo, '_SS_Earnings_c'),
                    Policy.expand_array(np.array(
                        [113700, 117000, 118500, 118500]),
                                        inflate=True,
                                        inflation_rates=wratelist,
                                        num_years=nyrs),
                    atol=0.01,
                    rtol=0.0)
    # specify multi-year reform using a dictionary of year_provisions dicts
    reform = {
        2015: {
            '_AMT_thd_MarriedS': [60000],
            '_CTC_c': [2000]
        },
        2016: {
            '_EITC_c': [[900, 5000, 8000, 9000]],
            '_II_em': [7000],
            '_SS_Earnings_c': [300000]
        },
        2017: {
            '_AMT_thd_MarriedS': [80000],
            '_SS_Earnings_c': [500000],
            '_SS_Earnings_c_cpi': False
        },
        2019: {
            '_EITC_c': [[1200, 7000, 10000, 12000]],
            '_II_em': [9000],
            '_SS_Earnings_c': [700000],
            '_SS_Earnings_c_cpi': True
        }
    }
    # implement multi-year reform
    ppo.implement_reform(reform)
    assert ppo.current_year == syr
    # move policy Policy object forward in time so current_year is syr+2
    #   Note: this would be typical usage because the first budget year
    #         is greater than Policy start_year.
    ppo.set_year(ppo.start_year + 2)
    assert ppo.current_year == syr + 2
    # confirm that actual parameters have expected post-reform values
    check_amt_thd_marrieds(ppo, reform, ifactor)
    check_eitc_c(ppo, reform, ifactor)
    check_ii_em(ppo, reform, ifactor)
    check_ss_earnings_c(ppo, reform, wfactor)
    check_ctc_c(ppo, reform)
Пример #57
0
def test_behavioral_response(puf_subsample):
    """
    Test that behavioral-response results are the same
    when generated from standard Tax-Calculator calls and
    when generated from tbi.run_nth_year_taxcalc_model() calls
    """
    # specify reform and assumptions
    reform_json = """
    {"policy": {
        "_II_rt5": {"2020": [0.25]},
        "_II_rt6": {"2020": [0.25]},
        "_II_rt7": {"2020": [0.25]},
        "_PT_rt5": {"2020": [0.25]},
        "_PT_rt6": {"2020": [0.25]},
        "_PT_rt7": {"2020": [0.25]},
        "_II_em": {"2020": [1000]}
    }}
    """
    assump_json = """
    {"behavior": {"_BE_sub": {"2013": [0.25]}},
     "growdiff_baseline": {},
     "growdiff_response": {},
     "consumption": {},
     "growmodel": {}
    }
    """
    params = Calculator.read_json_param_objects(reform_json, assump_json)
    # specify keyword arguments used in tbi function call
    kwargs = {
        'start_year': 2019,
        'year_n': 0,
        'use_puf_not_cps': True,
        'use_full_sample': False,
        'user_mods': {
            'policy': params['policy'],
            'behavior': params['behavior'],
            'growdiff_baseline': params['growdiff_baseline'],
            'growdiff_response': params['growdiff_response'],
            'consumption': params['consumption'],
            'growmodel': params['growmodel']
        },
        'return_dict': False
    }
    # generate aggregate results two ways: using tbi and standard calls
    num_years = 9
    std_res = dict()
    tbi_res = dict()
    for using_tbi in [True, False]:
        for year in range(0, num_years):
            cyr = year + kwargs['start_year']
            if using_tbi:
                kwargs['year_n'] = year
                tables = run_nth_year_taxcalc_model(**kwargs)
                tbi_res[cyr] = dict()
                for tbl in ['aggr_1', 'aggr_2', 'aggr_d']:
                    tbi_res[cyr][tbl] = tables[tbl]
            else:
                rec = Records(data=puf_subsample)
                pol = Policy()
                calc1 = Calculator(policy=pol, records=rec)
                pol.implement_reform(params['policy'])
                assert not pol.parameter_errors
                beh = Behavior()
                beh.update_behavior(params['behavior'])
                calc2 = Calculator(policy=pol, records=rec, behavior=beh)
                assert calc2.behavior_has_response()
                calc1.advance_to_year(cyr)
                calc2.advance_to_year(cyr)
                calc2 = Behavior.response(calc1, calc2)
                std_res[cyr] = dict()
                for tbl in ['aggr_1', 'aggr_2', 'aggr_d']:
                    if tbl.endswith('_1'):
                        itax = calc1.weighted_total('iitax')
                        ptax = calc1.weighted_total('payrolltax')
                        ctax = calc1.weighted_total('combined')
                    elif tbl.endswith('_2'):
                        itax = calc2.weighted_total('iitax')
                        ptax = calc2.weighted_total('payrolltax')
                        ctax = calc2.weighted_total('combined')
                    elif tbl.endswith('_d'):
                        itax = (calc2.weighted_total('iitax') -
                                calc1.weighted_total('iitax'))
                        ptax = (calc2.weighted_total('payrolltax') -
                                calc1.weighted_total('payrolltax'))
                        ctax = (calc2.weighted_total('combined') -
                                calc1.weighted_total('combined'))
                    cols = ['0_{}'.format(year)]
                    rows = ['ind_tax', 'payroll_tax', 'combined_tax']
                    datalist = [itax, ptax, ctax]
                    std_res[cyr][tbl] = pd.DataFrame(data=datalist,
                                                     index=rows,
                                                     columns=cols)
    # compare the two sets of results
    # NOTE that the tbi results have been "fuzzed" for PUF privacy reasons,
    #      so there is no expectation that the results should be identical.
    no_diffs = True
    reltol = 0.004  # std and tbi differ if more than 0.4 percent different
    for year in range(0, num_years):
        cyr = year + kwargs['start_year']
        col = '0_{}'.format(year)
        for tbl in ['aggr_1', 'aggr_2', 'aggr_d']:
            tbi = tbi_res[cyr][tbl][col]
            std = std_res[cyr][tbl][col]
            if not np.allclose(tbi, std, atol=0.0, rtol=reltol):
                no_diffs = False
                print('**** DIFF for year {} (year_n={}):'.format(cyr, year))
                print('TBI RESULTS:')
                print(tbi)
                print('STD RESULTS:')
                print(std)
    assert no_diffs
Пример #58
0
def test_create_parameters():
    p = Policy()
    assert p
Пример #59
0
def calculators(year_n, start_year,
                use_puf_not_cps,
                use_full_sample,
                user_mods):
    """
    This function assumes that the specified user_mods is a dictionary
      returned by the Calculator.read_json_param_objects() function.
    This function returns (calc1, calc2) where
      calc1 is pre-reform Calculator object for year_n, and
      calc2 is post-reform Calculator object for year_n.
    Neither Calculator object has had the calc_all() method executed.
    """
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements

    check_user_mods(user_mods)

    # specify Consumption instance
    consump = Consumption()
    consump_assumptions = user_mods['consumption']
    consump.update_consumption(consump_assumptions)

    # specify growdiff_baseline and growdiff_response
    growdiff_baseline = GrowDiff()
    growdiff_response = GrowDiff()
    growdiff_base_assumps = user_mods['growdiff_baseline']
    growdiff_resp_assumps = user_mods['growdiff_response']
    growdiff_baseline.update_growdiff(growdiff_base_assumps)
    growdiff_response.update_growdiff(growdiff_resp_assumps)

    # create pre-reform and post-reform GrowFactors instances
    growfactors_pre = GrowFactors()
    growdiff_baseline.apply_to(growfactors_pre)
    growfactors_post = GrowFactors()
    growdiff_baseline.apply_to(growfactors_post)
    growdiff_response.apply_to(growfactors_post)

    # create sample pd.DataFrame from specified input file and sampling scheme
    tbi_path = os.path.abspath(os.path.dirname(__file__))
    if use_puf_not_cps:
        # first try TaxBrain deployment path
        input_path = 'puf.csv.gz'
        if not os.path.isfile(input_path):
            # otherwise try local Tax-Calculator deployment path
            input_path = os.path.join(tbi_path, '..', '..', 'puf.csv')
        sampling_frac = 0.05
        sampling_seed = 2222
    else:  # if using cps input not puf input
        # first try Tax-Calculator code path
        input_path = os.path.join(tbi_path, '..', 'cps.csv.gz')
        if not os.path.isfile(input_path):
            # otherwise read from taxcalc package "egg"
            input_path = None  # pragma: no cover
            full_sample = read_egg_csv('cps.csv.gz')  # pragma: no cover
        sampling_frac = 0.03
        sampling_seed = 180
    if input_path:
        full_sample = pd.read_csv(input_path)
    if use_full_sample:
        sample = full_sample
    else:
        sample = full_sample.sample(frac=sampling_frac,
                                    random_state=sampling_seed)

    # create pre-reform Calculator instance
    if use_puf_not_cps:
        recs1 = Records(data=sample,
                        gfactors=growfactors_pre)
    else:
        recs1 = Records.cps_constructor(data=sample,
                                        gfactors=growfactors_pre)
    policy1 = Policy(gfactors=growfactors_pre)
    calc1 = Calculator(policy=policy1, records=recs1, consumption=consump)
    while calc1.current_year < start_year:
        calc1.increment_year()
    assert calc1.current_year == start_year

    # create post-reform Calculator instance
    if use_puf_not_cps:
        recs2 = Records(data=sample,
                        gfactors=growfactors_post)
    else:
        recs2 = Records.cps_constructor(data=sample,
                                        gfactors=growfactors_post)
    policy2 = Policy(gfactors=growfactors_post)
    policy_reform = user_mods['policy']
    policy2.implement_reform(policy_reform)
    calc2 = Calculator(policy=policy2, records=recs2, consumption=consump)
    while calc2.current_year < start_year:
        calc2.increment_year()
    assert calc2.current_year == start_year

    # delete objects now embedded in calc1 and calc2
    del sample
    del full_sample
    del consump
    del growdiff_baseline
    del growdiff_response
    del growfactors_pre
    del growfactors_post
    del recs1
    del recs2
    del policy1
    del policy2

    # increment Calculator objects for year_n years
    for _ in range(0, year_n):
        calc1.increment_year()
        calc2.increment_year()

    # return Calculator objects
    return (calc1, calc2)
Пример #60
0
def propagate_user_list(x,
                        name,
                        defaults,
                        cpi,
                        first_budget_year,
                        multi_param_idx=-1):
    """
    Dispatch to either expand_1D or expand2D depending on the dimension of x

    Parameters:
    -----------
    x : list from user to propagate forward in time. The first value is for
        year 'first_budget_year'. The value at index i is the value for
        budget year first_budget_year + i.

    defaults: list of default values; our result must be at least this long

    name: the parameter name for looking up the indexing rate

    cpi: Bool

    first_budget_year: int

    multi_param_idx: int, optional. If this parameter is multi-valued, this
        is the index for which the values for 'x' apply. So, for exampe, if
        multi_param_idx=0, the values for x are typically for the 'single'
        filer status. -1 indidcates that this is not a multi-valued
        parameter

    Returns:
    --------
    list of length 'num_years'. if 'cpi'==True, the values will be inflated
    based on the last value the user specified

    """
    # x must have a real first value
    assert len(x) > 0
    assert x[0] not in ("", None)

    num_years = max(len(defaults), len(x))

    is_rate = any([i < 1.0 for i in x])

    current_policy = Policy(start_year=2013)
    current_policy.set_year(first_budget_year)
    # irates are rates for 2015, 2016, and 2017
    if cpi:
        irates = current_policy._indexing_rates_for_update(
            param_name=name,
            calyear=first_budget_year,
            num_years_to_expand=num_years)
    else:
        irates = [0.0] * num_years

    ans = [None] * num_years
    for i in range(num_years):
        if i < len(x):
            if is_wildcard(x[i]):
                if multi_param_idx > -1:
                    ans[i] = defaults[i][multi_param_idx]
                else:
                    ans[i] = defaults[i]

            else:
                ans[i] = x[i]

        if ans[i] is not None:
            continue
        else:
            newval = ans[i - 1] * (1.0 + irates[i - 1])
            ans[i] = newval if is_rate else int(newval)

    return ans