Exemplo n.º 1
0
def test_translate_json_reform_suffixes_eic():
    """
    Test read_json_param_objects method using EIC-indexed parameter suffixes.
    """
    json1 = """{"policy": {
      "_II_em": {"2020": [20000], "2015": [15000]},
      "_EITC_c_0kids": {"2018": [510], "2019": [510]},
      "_EITC_c_1kid": {"2019": [3400], "2018": [3400]},
      "_EITC_c_2kids": {"2018": [5616], "2019": [5616]},
      "_EITC_c_3+kids": {"2019": [6318], "2018": [6318]}
    }}"""
    pdict1 = Calculator.read_json_param_objects(reform=json1, assump=None)
    rdict1 = pdict1['policy']
    json2 = """{"policy": {
      "_EITC_c": {"2019": [[510, 3400, 5616, 6318]],
                  "2018": [[510, 3400, 5616, 6318]]},
      "_II_em": {"2020": [20000], "2015": [15000]}
    }}"""
    pdict2 = Calculator.read_json_param_objects(reform=json2, assump=None)
    rdict2 = pdict2['policy']
    assert len(rdict2) == len(rdict1)
    for year in rdict2.keys():
        if '_II_em' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_II_em'],
                               rdict2[year]['_II_em'],
                               atol=0.01, rtol=0.0)
        if '_EITC_c' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_EITC_c'],
                               rdict2[year]['_EITC_c'],
                               atol=0.01, rtol=0.0)
Exemplo n.º 2
0
def test_translate_json_reform_suffixes_mars_non_indexed():
    """
    Test read_json_param_objects method using MARS-indexed parameter suffixes.
    """
    json1 = """{"policy": {
      "_II_em": {"2020": [20000], "2015": [15000]},
      "_AMEDT_ec_joint": {"2018": [400000], "2016": [300000]},
      "_AMEDT_ec_separate": {"2017": [150000], "2019": [200000]}
    }}"""
    pdict1 = Calculator.read_json_param_objects(reform=json1, assump=None)
    rdict1 = pdict1['policy']
    json2 = """{"policy": {
      "_AMEDT_ec": {"2016": [[200000, 300000, 125000, 200000, 200000]],
                    "2017": [[200000, 300000, 150000, 200000, 200000]],
                    "2018": [[200000, 400000, 150000, 200000, 200000]],
                    "2019": [[200000, 400000, 200000, 200000, 200000]]},
      "_II_em": {"2015": [15000], "2020": [20000]}
    }}"""
    pdict2 = Calculator.read_json_param_objects(reform=json2, assump=None)
    rdict2 = pdict2['policy']
    assert len(rdict2) == len(rdict1)
    for year in rdict2.keys():
        if '_II_em' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_II_em'],
                               rdict2[year]['_II_em'],
                               atol=0.01, rtol=0.0)
        if '_AMEDT_ec' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_AMEDT_ec'],
                               rdict2[year]['_AMEDT_ec'],
                               atol=0.01, rtol=0.0)
Exemplo n.º 3
0
def test_translate_json_reform_suffixes_mars_non_indexed():
    # test read_json_param_objects()
    # using MARS-indexed parameter suffixes
    json1 = """{"policy": {
      "_II_em": {"2020": [20000], "2015": [15000]},
      "_AMEDT_ec_joint": {"2018": [400000], "2016": [300000]},
      "_AMEDT_ec_separate": {"2017": [150000], "2019": [200000]}
    }}"""
    pdict1 = Calculator.read_json_param_objects(reform=json1, assump=None)
    rdict1 = pdict1['policy']
    json2 = """{"policy": {
      "_AMEDT_ec": {"2016": [[200000, 300000, 125000, 200000, 200000]],
                    "2017": [[200000, 300000, 150000, 200000, 200000]],
                    "2018": [[200000, 400000, 150000, 200000, 200000]],
                    "2019": [[200000, 400000, 200000, 200000, 200000]]},
      "_II_em": {"2015": [15000], "2020": [20000]}
    }}"""
    pdict2 = Calculator.read_json_param_objects(reform=json2, assump=None)
    rdict2 = pdict2['policy']
    assert len(rdict2) == len(rdict1)
    for year in rdict2.keys():
        if '_II_em' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_II_em'],
                               rdict2[year]['_II_em'],
                               atol=0.01,
                               rtol=0.0)
        if '_AMEDT_ec' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_AMEDT_ec'],
                               rdict2[year]['_AMEDT_ec'],
                               atol=0.01,
                               rtol=0.0)
Exemplo n.º 4
0
def test_translate_json_reform_suffixes_eic():
    # test read_json_param_objects(...)
    # using EIC-indexed parameter suffixes
    json1 = """{"policy": {
      "_II_em": {"2020": [20000], "2015": [15000]},
      "_EITC_c_0kids": {"2018": [510], "2019": [510]},
      "_EITC_c_1kid": {"2019": [3400], "2018": [3400]},
      "_EITC_c_2kids": {"2018": [5616], "2019": [5616]},
      "_EITC_c_3+kids": {"2019": [6318], "2018": [6318]}
    }}"""
    pdict1 = Calculator.read_json_param_objects(reform=json1, assump=None)
    rdict1 = pdict1['policy']
    json2 = """{"policy": {
      "_EITC_c": {"2019": [[510, 3400, 5616, 6318]],
                  "2018": [[510, 3400, 5616, 6318]]},
      "_II_em": {"2020": [20000], "2015": [15000]}
    }}"""
    pdict2 = Calculator.read_json_param_objects(reform=json2, assump=None)
    rdict2 = pdict2['policy']
    assert len(rdict2) == len(rdict1)
    for year in rdict2.keys():
        if '_II_em' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_II_em'],
                               rdict2[year]['_II_em'],
                               atol=0.01,
                               rtol=0.0)
        if '_EITC_c' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_EITC_c'],
                               rdict2[year]['_EITC_c'],
                               atol=0.01,
                               rtol=0.0)
def test_json_reform_url():
    """
    Test reading a JSON reform from a URL. Results from the URL are expected
    to match the results from the string.
    """
    reform_str = """
    {
    "policy": {
        // raise FICA payroll tax rate in 2018 and 2020
        "FICA_ss_trt": {
            "2018": 0.130,
            "2020": 0.140
        },
        // raise Medicare payroll tax rate in 2019 and 2021
        "FICA_mc_trt": {
            "2019": 0.030,
            "2021": 0.032
        }
      }
    }
    """
    reform_url = ('https://raw.githubusercontent.com/PSLmodels/'
                  'Tax-Calculator/master/taxcalc/reforms/ptaxes0.json')
    params_str = Calculator.read_json_param_objects(reform_str, None)
    params_url = Calculator.read_json_param_objects(reform_url, None)
    assert params_str == params_url
Exemplo n.º 6
0
def test_json_doesnt_exist():
    """
    Test JSON file which doesn't exist
    """
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, './reforms/doesnt_exist.json')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects('./reforms/doesnt_exist.json', None)
Exemplo n.º 7
0
def test_read_bad_json_assump_file(bad1assumpfile, bad2assumpfile,
                                   bad3assumpfile):
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, bad1assumpfile.name)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, bad2assumpfile.name)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, bad3assumpfile.name)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'unknown_file_name')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, list())
Exemplo n.º 8
0
def test_read_bad_json_assump_file(bad1assumpfile, bad2assumpfile,
                                   bad3assumpfile):
    """
    Test invalid JSON assumption files.
    """
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, bad1assumpfile.name)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, bad2assumpfile.name)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, bad3assumpfile.name)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'unknown_file_name')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, list())
Exemplo n.º 9
0
def test_reform_documentation():
    reform_json = """
    {
    "policy": {
      "_II_em_cpi": {"2016": false,
                     "2018": true},
      "_II_em": {"2016": [5000],
                 "2018": [6000],
                 "2020": [7000]},
      "_EITC_indiv": {"2017": [true]},
      "_STD_Aged_cpi": {"2016": false},
      "_STD_Aged": {"2016": [[1600, 1300, 1300, 1600, 1600]],
                    "2020": [[2000, 2000, 2000, 2000, 2000]]},
      "_ID_BenefitCap_Switch_medical": {"2020": [false]},
      "_ID_BenefitCap_Switch_casualty": {"2020": [false]},
      "_ID_BenefitCap_Switch_misc": {"2020": [false]},
      "_ID_BenefitCap_Switch_interest": {"2020": [false]},
      "_ID_BenefitCap_Switch_charity": {"2020": [false]}
      }
    }
    """
    params = Calculator.read_json_param_objects(reform_json, None)
    assert isinstance(params, dict)
    doc = Calculator.reform_documentation(params)
    assert isinstance(doc, str)
    dump = False  # set to True to print documentation and force test failure
    if dump:
        print(doc)
        assert 1 == 2
Exemplo n.º 10
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'_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.implement_reform(params['policy'])
    assert len(pol.reform_errors) > 0
    assert len(pol.reform_warnings) > 0
Exemplo n.º 11
0
def fixture_baseline_2017_law(tests_path):
    """
    Read ../reforms/2017_law.json and return its policy dictionary.
    """
    pre_tcja_jrf = os.path.join(tests_path, '..', 'reforms', '2017_law.json')
    pre_tcja = Calculator.read_json_param_objects(pre_tcja_jrf, None)
    return pre_tcja['policy']
Exemplo n.º 12
0
def test_noreform_documentation():
    """
    Test automatic documentation creation.
    """
    reform_json = """
    {
    "policy": {}
    }
    """
    assump_json = """
    {
    "consumption": {},
    "growdiff_baseline": {},
    "growdiff_response": {}
    }
    """
    params = Calculator.read_json_param_objects(reform_json, assump_json)
    assert isinstance(params, dict)
    actual_doc = Calculator.reform_documentation(params)
    expected_doc = (
        'REFORM DOCUMENTATION\n'
        'Baseline Growth-Difference Assumption Values by Year:\n'
        'none: using default baseline growth assumptions\n'
        'Policy Reform Parameter Values by Year:\n'
        'none: using current-law policy parameters\n'
    )
    assert actual_doc == expected_doc
Exemplo n.º 13
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
Exemplo n.º 14
0
def test_noreform_documentation():
    """
    Test automatic documentation creation.
    """
    reform_json = """
    {
    }
    """
    assump_json = """
    {
    "consumption": {},
    "growdiff_baseline": {},
    "growdiff_response": {}
    }
    """
    params = Calculator.read_json_param_objects(reform_json, assump_json)
    assert isinstance(params, dict)
    actual_doc = Calculator.reform_documentation(params)
    expected_doc = ('REFORM DOCUMENTATION\n'
                    'Baseline Growth-Difference Assumption Values by Year:\n'
                    'none: using default growth assumptions\n'
                    'Response Growth-Difference Assumption Values by Year:\n'
                    'none: using default growth assumptions\n'
                    'Policy Reform Parameter Values by Year:\n'
                    'none: using current-law policy parameters\n')
    assert actual_doc == expected_doc
Exemplo n.º 15
0
def fixture_baseline_2017_law(tests_path):
    """
    Read ../reforms/2017_law.json and return its policy dictionary.
    """
    pre_tcja_jrf = os.path.join(tests_path, '..', 'reforms', '2017_law.json')
    pre_tcja = Calculator.read_json_param_objects(pre_tcja_jrf, None)
    return pre_tcja['policy']
Exemplo n.º 16
0
def test_2017_law_reform(tests_path):
    """
    Check that policy parameter values in a future year under current-law
    policy and under the reform specified in the 2017_law.json file are
    sensible.
    """
    # create pre metadata dictionary for 2017_law.json reform in fyear
    pol = Policy()
    reform_file = os.path.join(tests_path, '..', 'reforms', '2017_law.json')
    with open(reform_file, 'r') as rfile:
        rtext = rfile.read()
    reform = Calculator.read_json_param_objects(rtext, None)
    pol.implement_reform(reform['policy'])
    # eventually activate: assert not clp.parameter_warnings
    ctc_c_warning = 'CTC_c was redefined in release 1.0.0\n'
    assert pol.parameter_warnings == ctc_c_warning
    assert not pol.parameter_errors
    pol.set_year(2018)
    pre_mdata = pol.metadata()
    # check some policy parameter values against expected values under 2017 law
    pre_expect = {
        # relation '<' implies asserting that actual < expect
        # relation '>' implies asserting that actual > expect
        # ... parameters not affected by TCJA and that are not indexed
        'AMEDT_ec': {'relation': '=', 'value': 200000},
        'SS_thd85': {'relation': '=', 'value': 34000},
        # ... parameters not affected by TCJA and that are indexed
        'STD_Dep': {'relation': '>', 'value': 1050},
        'CG_brk2': {'relation': '>', 'value': 425800},
        'AMT_CG_brk1': {'relation': '>', 'value': 38600},
        'AMT_brk1': {'relation': '>', 'value': 191100},
        'EITC_c': {'relation': '>', 'value': 519},
        'EITC_ps': {'relation': '>', 'value': 8490},
        'EITC_ps_MarriedJ': {'relation': '>', 'value': 5680},
        'EITC_InvestIncome_c': {'relation': '>', 'value': 3500},
        # ... parameters affected by TCJA and that are not indexed
        'ID_Charity_crt_all': {'relation': '=', 'value': 0.5},
        'II_rt3': {'relation': '=', 'value': 0.25},
        # ... parameters affected by TCJA and that are indexed
        'II_brk3': {'relation': '>', 'value': 91900},
        'STD': {'relation': '<', 'value': 7000},
        'II_em': {'relation': '>', 'value': 4050},
        'AMT_em_pe': {'relation': '<', 'value': 260000}
    }
    assert isinstance(pre_expect, dict)
    assert set(pre_expect.keys()).issubset(set(pre_mdata.keys()))
    for name in pre_expect:
        aval = pre_mdata[name]['value']
        if isinstance(aval, list):
            act = aval[0]  # comparing only first item in a vector parameter
        else:
            act = aval
        exp = pre_expect[name]['value']
        if pre_expect[name]['relation'] == '<':
            assert act < exp, '{} a={} !< e={}'.format(name, act, exp)
        elif pre_expect[name]['relation'] == '>':
            assert act > exp, '{} a={} !> e={}'.format(name, act, exp)
        elif pre_expect[name]['relation'] == '=':
            assert act == exp, '{} a={} != e={}'.format(name, act, exp)
Exemplo n.º 17
0
def test_read_bad_json_reform_file(bad1reformfile, bad2reformfile,
                                   bad3reformfile):
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(bad1reformfile.name, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(bad2reformfile.name, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(bad3reformfile.name, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(list(), None)
Exemplo n.º 18
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, 1, 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)
    pol7 = Policy()
    ref7 = {2019: {'_FICA_ss_trt_cpi': True}}
    with pytest.raises(ValueError):
        pol7.implement_reform(ref7)
    # test 8 was contributed by Hank Doupe in bug report #1956
    pol8 = Policy()
    ref8 = {2019: {'_AMEDT_rt': [True]}}
    with pytest.raises(ValueError):
        pol8.implement_reform(ref8)
    # test 9 extends test 8 to integer parameters
    pol9 = Policy()
    ref9 = {2019: {'_AMT_KT_c_Age': [True]}}
    with pytest.raises(ValueError):
        pol9.implement_reform(ref9)
    # test 10 was contributed by Hank Doupe in bug report #1980
    json_reform = """
    {"policy": {"_ID_BenefitSurtax_Switch_medical": {"2018": [true]}}}
    """
    pdict = Calculator.read_json_param_objects(json_reform, None)
    pol = Policy()
    pol.implement_reform(pdict["policy"], raise_errors=False)
    assert pol.parameter_errors == ''
Exemplo n.º 19
0
def test_bad_json_names(tests_path):
    """
    Test that ValueError raised with assump or reform do not end in '.json'
    """
    csvname = os.path.join(tests_path, '..', 'growfactors.csv')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(csvname, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects('http://name.json.html', None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, csvname)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'http://name.json.html')
Exemplo n.º 20
0
def test_read_json_param_and_implement_reform(reform0_file):
    """
    Test reading and translation of reform file into a reform dictionary
    that is then used to call implement_reform method.
    """
    policy = Policy()
    param_dict = Calculator.read_json_param_objects(reform0_file.name, None)
    policy.implement_reform(param_dict['policy'])
    syr = policy.start_year
    assert syr == 2017
    rebate_ceiling = policy._rebate_ceiling
def test_bad_json_names(tests_path):
    """
    Test that ValueError raised with assump or reform do not end in '.json'
    """
    csvname = os.path.join(tests_path, '..', 'growfactors.csv')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(csvname, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects('http://name.json.html', None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, csvname)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'http://name.json.html')
Exemplo n.º 22
0
def test_translate_json_reform_suffixes_mars_indexed():
    # test read_json_param_objects()
    # using MARS-indexed parameter suffixes
    json1 = """{"policy": {
      "_II_em": {"2020": [20000], "2015": [15000]},
      "_STD_single": {"2018": [18000], "2016": [16000]},
      "_STD_widow": {"2017": [17000], "2019": [19000]}
    }}"""
    assump_json = """{
      "consumption": {},
      "behavior": {},
      "growdiff_baseline": {
        "_ACPIU": {"2013": [0.01]},
        "_AWAGE": {"2013": [0.01]}},
      "growdiff_response": {}
    }"""
    pdict1 = Calculator.read_json_param_objects(reform=json1,
                                                assump=assump_json)
    rdict1 = pdict1['policy']
    json2 = """{"policy": {
      "_STD": {"2016": [[16000.00, 12600.00, 6300.00,  9300.00, 12600.00]],
               "2017": [[16363.20, 12886.02, 6443.01,  9511.11, 17000.00]],
               "2018": [[18000.00, 13304.82, 6652.41,  9820.22, 17552.50]],
               "2019": [[18583.20, 13735.90, 6867.95,  10138.4, 19000.00]]},
      "_II_em": {"2020": [20000], "2015": [15000]}
    }}"""
    pdict2 = Calculator.read_json_param_objects(reform=json2,
                                                assump=assump_json)
    rdict2 = pdict2['policy']
    assert len(rdict2) == len(rdict1)
    for year in rdict2.keys():
        if '_II_em' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_II_em'],
                               rdict2[year]['_II_em'],
                               atol=0.01,
                               rtol=0.0)
        if '_STD' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_STD'],
                               rdict2[year]['_STD'],
                               atol=0.01,
                               rtol=0.0)
Exemplo n.º 23
0
def test_translate_json_reform_suffixes_mars_indexed():
    # test read_json_param_objects()
    # using MARS-indexed parameter suffixes
    json1 = """{"policy": {
      "_II_em": {"2020": [20000], "2015": [15000]},
      "_STD_single": {"2018": [18000], "2016": [16000]},
      "_STD_widow": {"2017": [17000], "2019": [19000]}
    }}"""
    assump_json = """{
      "consumption": {},
      "behavior": {},
      "growdiff_baseline": {
        "_ACPIU": {"2013": [0.01]},
        "_AWAGE": {"2013": [0.01]}},
      "growdiff_response": {}
    }"""
    pdict1 = Calculator.read_json_param_objects(reform=json1,
                                                assump=assump_json)
    rdict1 = pdict1['policy']
    json2 = """{"policy": {
      "_STD": {"2016": [[16000.00, 12600.00, 6300.00,  9300.00, 12600.00]],
               "2017": [[16524.80, 13013.28, 6506.64,  9605.04, 17000.00]],
               "2018": [[18000.00, 13432.31, 6716.15,  9914.32, 17547.40]],
               "2019": [[18592.20, 13874.23, 6937.11, 10240.50, 19000.00]]},
      "_II_em": {"2020": [20000], "2015": [15000]}
    }}"""
    pdict2 = Calculator.read_json_param_objects(reform=json2,
                                                assump=assump_json)
    rdict2 = pdict2['policy']
    assert len(rdict2) == len(rdict1)
    for year in rdict2.keys():
        if '_II_em' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_II_em'],
                               rdict2[year]['_II_em'],
                               atol=0.01,
                               rtol=0.0)
        if '_STD' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_STD'],
                               rdict2[year]['_STD'],
                               atol=0.01,
                               rtol=0.0)
Exemplo n.º 24
0
 def __init__(self, input_filename, reform, exact_calculations,
              emulate_taxsim_2441_logic, output_records):
     """
     SimpleTaxIO class constructor.
     """
     # pylint: disable=too-many-arguments
     # check that input_filename is a string
     if not isinstance(input_filename, six.string_types):
         msg = 'SimpleTaxIO.ctor input_filename is not a string'
         raise ValueError(msg)
     # construct output_filename and delete old output file if it exists
     # ... construct reform extension to output_filename
     if reform is None:
         ref = ''
         self._using_reform_file = True
     else:  # if reform is not None
         if isinstance(reform, six.string_types):
             if reform.endswith('.json'):
                 ref = '-{}'.format(reform[:-5])
             else:
                 ref = '-{}'.format(reform)
             self._using_reform_file = True
         elif isinstance(reform, dict):
             ref = ''
             self._using_reform_file = False
         else:
             msg = 'SimpleTaxIO.ctor reform is neither None, str, nor dict'
             raise ValueError(msg)
     # ... construct whole output_filename
     self._using_input_file = True
     self._output_filename = '{}.out-simtax{}'.format(input_filename, ref)
     if os.path.isfile(self._output_filename):
         os.remove(self._output_filename)
     # check for existence of file named input_filename
     if not os.path.isfile(input_filename):
         msg = 'INPUT file named {} could not be found'
         raise ValueError(msg.format(input_filename))
     # read input file contents into self._input dictionary
     self._read_input(input_filename)
     self.policy = Policy()
     # implement reform if reform is specified
     if reform:
         if self._using_reform_file:
             param_dict = Calculator.read_json_param_objects(reform, None)
             r_pol = param_dict['policy']
         else:
             r_pol = reform
         self.policy.implement_reform(r_pol)
     # validate input variable values
     self._validate_input()
     self.calc = self._calc_object(exact_calculations,
                                   emulate_taxsim_2441_logic,
                                   output_records)
Exemplo n.º 25
0
def test_translate_json_reform_suffixes_idedtype():
    """
    Test read_json_param_objects method using idedtype-indexed param suffixes.
    """
    # test read_json_param_objects(...)
    # using idedtype-indexed parameter suffixes
    json1 = """{"policy": {
      "_ID_BenefitCap_rt": {"2019": [0.2]},
      "_ID_BenefitCap_Switch_medical": {"2019": [false]},
      "_ID_BenefitCap_Switch_casualty": {"2019": [false]},
      "_ID_BenefitCap_Switch_misc": {"2019": [false]},
      "_ID_BenefitCap_Switch_interest": {"2019": [false]},
      "_ID_BenefitCap_Switch_charity": {"2019": [false]},
      "_II_em": {"2020": [20000], "2015": [15000]}
    }}"""
    pdict1 = Calculator.read_json_param_objects(reform=json1, assump=None)
    rdict1 = pdict1['policy']
    json2 = """{"policy": {
      "_II_em": {"2020": [20000], "2015": [15000]},
      "_ID_BenefitCap_Switch": {
        "2019": [[false, true, true, false, false, false, false]]
      },
      "_ID_BenefitCap_rt": {"2019": [0.2]}
    }}"""
    pdict2 = Calculator.read_json_param_objects(reform=json2, assump=None)
    rdict2 = pdict2['policy']
    assert len(rdict2) == len(rdict1)
    for year in rdict2.keys():
        if '_II_em' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_II_em'],
                               rdict2[year]['_II_em'],
                               atol=0.01, rtol=0.0)
        if '_ID_BenefitCap_rt' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_ID_BenefitCap_rt'],
                               rdict2[year]['_ID_BenefitCap_rt'],
                               atol=0.01, rtol=0.0)
        if '_ID_BenefitCap_Switch' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_ID_BenefitCap_Switch'],
                               rdict2[year]['_ID_BenefitCap_Switch'],
                               atol=0.01, rtol=0.0)
Exemplo n.º 26
0
def test_translate_json_reform_suffixes_idedtype():
    # test read_json_param_objects(...)
    # using idedtype-indexed parameter suffixes
    json1 = """{"policy": {
      "_ID_BenefitCap_rt": {"2019": [0.2]},
      "_ID_BenefitCap_Switch_medical": {"2019": [false]},
      "_ID_BenefitCap_Switch_casualty": {"2019": [false]},
      "_ID_BenefitCap_Switch_misc": {"2019": [false]},
      "_ID_BenefitCap_Switch_interest": {"2019": [false]},
      "_ID_BenefitCap_Switch_charity": {"2019": [false]},
      "_II_em": {"2020": [20000], "2015": [15000]}
    }}"""
    pdict1 = Calculator.read_json_param_objects(reform=json1, assump=None)
    rdict1 = pdict1['policy']
    json2 = """{"policy": {
      "_II_em": {"2020": [20000], "2015": [15000]},
      "_ID_BenefitCap_Switch": {
        "2019": [[false, true, true, false, false, false, false]]
      },
      "_ID_BenefitCap_rt": {"2019": [0.2]}
    }}"""
    pdict2 = Calculator.read_json_param_objects(reform=json2, assump=None)
    rdict2 = pdict2['policy']
    assert len(rdict2) == len(rdict1)
    for year in rdict2.keys():
        if '_II_em' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_II_em'],
                               rdict2[year]['_II_em'],
                               atol=0.01,
                               rtol=0.0)
        if '_ID_BenefitCap_rt' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_ID_BenefitCap_rt'],
                               rdict2[year]['_ID_BenefitCap_rt'],
                               atol=0.01,
                               rtol=0.0)
        if '_ID_BenefitCap_Switch' in rdict2[year].keys():
            assert np.allclose(rdict1[year]['_ID_BenefitCap_Switch'],
                               rdict2[year]['_ID_BenefitCap_Switch'],
                               atol=0.01,
                               rtol=0.0)
Exemplo n.º 27
0
def test_noreform_documentation():
    reform_json = """
    {
    "policy": {}
    }
    """
    params = Calculator.read_json_param_objects(reform_json, None)
    assert isinstance(params, dict)
    actual_doc = Calculator.reform_documentation(params)
    expected_doc = ('REFORM DOCUMENTATION\n'
                    'Policy Reform Parameter Values by Year:\n'
                    'none: using current-law policy parameters\n')
    assert actual_doc == expected_doc
Exemplo n.º 28
0
def test_calc_all(reform_file, rawinputfile):
    cyr = 2016
    pol = Policy()
    param_dict = Calculator.read_json_param_objects(reform_file.name, None)
    pol.implement_reform(param_dict['policy'])
    pol.set_year(cyr)
    nonstd = Records(data=rawinputfile.name, gfactors=None,
                     weights=None, start_year=cyr)
    assert nonstd.array_length == RAWINPUTFILE_FUNITS
    calc = Calculator(policy=pol, records=nonstd,
                      sync_years=False)  # keeps raw data unchanged
    assert calc.current_year == cyr
    calc.calc_all()
Exemplo n.º 29
0
def test_bad_json_names(tests_path):
    """
    Test that ValueError raised with assump or reform do not end in '.json'
    """
    test_url = ('https://raw.githubusercontent.com/PSLmodels/'
                'Tax-Calculator/master/taxcalc/reforms/'
                '2017_law.out.csv')
    csvname = os.path.join(tests_path, '..', 'growfactors.csv')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(csvname, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(test_url, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, csvname)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, test_url)
Exemplo n.º 30
0
def test_puf_var_stats(tests_path, puf_fullsample):
    """
    Main logic of test.
    """
    # 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 Calculator object using baseline_policy and full puf.csv sample
    rec = Records(data=puf_fullsample)
    calc = Calculator(policy=baseline_policy, records=rec, verbose=False)
    # create base tables
    table_mean = create_base_table(tests_path)
    table_corr = copy.deepcopy(table_mean)
    del table_corr['description']
    # add statistics to tables
    year_headers = ['description']
    for year in range(Policy.JSON_START_YEAR, Policy.LAST_BUDGET_YEAR + 1):
        assert year == calc.policy_current_year()
        year_headers.append(str(year))
        calc.calc_all()
        calculate_mean_stats(calc, table_mean, year)
        if year == 2016:
            calculate_corr_stats(calc, table_corr)
        if year < Policy.LAST_BUDGET_YEAR:
            calc.increment_year()
    # write tables to new CSV files
    mean_path = os.path.join(tests_path, MEAN_FILENAME + '-new')
    table_mean.sort_index(inplace=True)
    table_mean.to_csv(mean_path, header=year_headers, float_format='%8.0f')
    corr_path = os.path.join(tests_path, CORR_FILENAME + '-new')
    table_corr.sort_index(inplace=True)
    table_corr.to_csv(corr_path, float_format='%8.2f',
                      columns=table_corr.index)
    # compare new and old CSV files for nonsmall differences
    if sys.version_info.major == 2:
        # tighter tests for Python 2.7
        mean_msg = differences(mean_path, mean_path[:-4],
                               'MEAN', small=0.0)
        corr_msg = differences(corr_path, corr_path[:-4],
                               'CORR', small=0.0)
    else:
        # looser tests for Python 3.6
        mean_msg = differences(mean_path, mean_path[:-4],
                               'MEAN', small=1.0)
        corr_msg = differences(corr_path, corr_path[:-4],
                               'CORR', small=0.01)
    if mean_msg or corr_msg:
        raise ValueError(mean_msg + corr_msg)
def test_reform_documentation():
    """
    Test automatic documentation creation.
    """
    reform_json = """
{
"policy": {
    "II_em-indexed": {
        "2016": false,
        "2018": true
    },
    "II_em": {
        "2016": 5000,
        "2018": 6000,
        "2020": 7000
    },
    "EITC_indiv": {
        "2017": true
    },
    "STD_Aged-indexed": {
        "2016": false
    },
    "STD_Aged": {
        "2016": [1600, 1300, 1300, 1600, 1600],
        "2020": [2000, 2000, 2000, 2000, 2000]
    },
    "ID_BenefitCap_Switch": {
        "2020": [false, false, false, false, false, false, false]
    }
}
}
"""
    assump_json = """
{
"consumption": {},
// increase baseline inflation rate by one percentage point in 2014+
// (has no effect on known policy parameter values)
"growdiff_baseline": {"ACPIU": {"2014": 0.010}},
"growdiff_response": {"ACPIU": {"2014": 0.015}}
}
"""
    params = Calculator.read_json_param_objects(reform_json, assump_json)
    assert isinstance(params, dict)
    second_reform = {'II_em': {2019: 6500}}
    doc = Calculator.reform_documentation(params, [second_reform])
    assert isinstance(doc, str)
    dump = False  # set to True to print documentation and force test failure
    if dump:
        print(doc)
        assert 1 == 2
Exemplo n.º 32
0
def test_json_reform_url():
    """
    Test reading a JSON reform from a URL. Results from the URL are expected
    to match the results from the string.
    """
    reform_str = """
    {
    "policy": {
        "_FICA_ss_trt": {
            "2018": [0.130],
            "2020": [0.140]
        },
        "_FICA_mc_trt": {
            "2019": [0.030],
            "2021": [0.032]
        }
      }
    }
    """
    reform_url = ('https://raw.githubusercontent.com/PSLmodels/'
                  'Tax-Calculator/master/taxcalc/reforms/ptaxes0.json')
    params_str = Calculator.read_json_param_objects(reform_str, None)
    params_url = Calculator.read_json_param_objects(reform_url, None)
    assert params_str == params_url
Exemplo n.º 33
0
def test_reform_documentation():
    """
    Test automatic documentation creation.
    """
    reform_json = """
{
    "II_em-indexed": {
        "2016": false,
        "2018": true
    },
    "II_em": {
        "2016": 5000,
        "2018": 6000,
        "2020": 7000
    },
    "EITC_indiv": {
        "2017": true
    },
    "STD_Aged-indexed": {
        "2016": false
    },
    "STD_Aged": {
        "2016": [1600, 1300, 1300, 1600, 1600],
        "2020": [2000, 2000, 2000, 2000, 2000]
    },
    "ID_BenefitCap_Switch": {
        "2020": [false, false, false, false, false, false, false]
    }
}
"""
    assump_json = """
{
"consumption": {},
// increase baseline inflation rate by one percentage point in 2014+
// (has no effect on known policy parameter values)
"growdiff_baseline": {"ACPIU": {"2014": 0.010}},
"growdiff_response": {"ACPIU": {"2014": 0.015}}
}
"""
    params = Calculator.read_json_param_objects(reform_json, assump_json)
    assert isinstance(params, dict)
    second_reform = {'II_em': {2019: 6500}}
    doc = Calculator.reform_documentation(params, [second_reform])
    assert isinstance(doc, str)
    dump = False  # set to True to print documentation and force test failure
    if dump:
        print(doc)
        assert 1 == 2
def test_calc_all():
    """
    Test calc_all method.
    """
    cyr = 2016
    pol = Policy()
    param_dict = Calculator.read_json_param_objects(REFORM_JSON, None)
    pol.implement_reform(param_dict['policy'])
    pol.set_year(cyr)
    nonstd = Records(data=pd.read_csv(StringIO(RAWINPUT_CONTENTS)),
                     start_year=cyr, gfactors=None, weights=None)
    assert nonstd.array_length == RAWINPUT_FUNITS
    calc = Calculator(policy=pol, records=nonstd,
                      sync_years=False)  # keeps raw data unchanged
    assert calc.current_year == cyr
    assert calc.reform_warnings == ''
Exemplo n.º 35
0
def test_calc_all(reform_file, rawinputfile):
    """
    Test calc_all method.
    """
    cyr = 2016
    pol = Policy()
    param_dict = Calculator.read_json_param_objects(reform_file.name, None)
    pol.implement_reform(param_dict['policy'])
    pol.set_year(cyr)
    nonstd = Records(data=rawinputfile.name, gfactors=None,
                     weights=None, start_year=cyr)
    assert nonstd.array_length == RAWINPUTFILE_FUNITS
    calc = Calculator(policy=pol, records=nonstd,
                      sync_years=False)  # keeps raw data unchanged
    assert calc.current_year == cyr
    assert calc.reform_warnings == ''
Exemplo n.º 36
0
def test_reform_documentation():
    """
    Test automatic documentation creation.
    """
    reform_json = """
    {
    "policy": {
      "_II_em_cpi": {"2016": false,
                     "2018": true},
      "_II_em": {"2016": [5000],
                 "2018": [6000],
                 "2020": [7000]},
      "_EITC_indiv": {"2017": [true]},
      "_STD_Aged_cpi": {"2016": false},
      "_STD_Aged": {"2016": [[1600, 1300, 1300, 1600, 1600]],
                    "2020": [[2000, 2000, 2000, 2000, 2000]]},
      "_ID_BenefitCap_Switch_medical": {"2020": [false]},
      "_ID_BenefitCap_Switch_casualty": {"2020": [false]},
      "_ID_BenefitCap_Switch_misc": {"2020": [false]},
      "_ID_BenefitCap_Switch_interest": {"2020": [false]},
      "_ID_BenefitCap_Switch_charity": {"2020": [false]}
      }
    }
    """
    assump_json = """
    {
    "consumption": {},
    // increase baseline inflation rate by one percentage point in 2014+
    // (has no effect on known policy parameter values)
    "growdiff_baseline": {"_ACPIU": {"2014": [0.01]}},
    "growdiff_response": {}
    }
    """
    params = Calculator.read_json_param_objects(reform_json, assump_json)
    assert isinstance(params, dict)
    doc = Calculator.reform_documentation(params)
    assert isinstance(doc, str)
    dump = False  # set to True to print documentation and force test failure
    if dump:
        print(doc)
        assert 1 == 2
Exemplo n.º 37
0
def test_read_json_reform_file_and_implement_reform(reform_file,
                                                    assump_file,
                                                    set_year):
    """
    Test reading and translation of reform file into a reform dictionary
    that is then used to call implement_reform method and Calculate.calc_all()
    NOTE: implement_reform called when policy.current_year == policy.start_year
    """
    pol = Policy()
    if set_year:
        pol.set_year(2015)
    param_dict = Calculator.read_json_param_objects(reform_file.name,
                                                    assump_file.name)
    pol.implement_reform(param_dict['policy'])
    syr = pol.start_year
    # pylint: disable=protected-access,no-member
    amt_brk1 = pol._AMT_brk1
    assert amt_brk1[2015 - syr] == 200000
    assert amt_brk1[2016 - syr] > 200000
    assert amt_brk1[2017 - syr] == 300000
    assert amt_brk1[2018 - syr] > 300000
    ii_em = pol._II_em
    assert ii_em[2016 - syr] == 6000
    assert ii_em[2017 - syr] == 6000
    assert ii_em[2018 - syr] == 7500
    assert ii_em[2019 - syr] > 7500
    assert ii_em[2020 - syr] == 9000
    assert ii_em[2021 - syr] > 9000
    amt_em = pol._AMT_em
    assert amt_em[2016 - syr, 0] > amt_em[2015 - syr, 0]
    assert amt_em[2017 - syr, 0] > amt_em[2016 - syr, 0]
    assert amt_em[2018 - syr, 0] == amt_em[2017 - syr, 0]
    assert amt_em[2019 - syr, 0] == amt_em[2017 - syr, 0]
    assert amt_em[2020 - syr, 0] == amt_em[2017 - syr, 0]
    assert amt_em[2021 - syr, 0] > amt_em[2020 - syr, 0]
    assert amt_em[2022 - syr, 0] > amt_em[2021 - syr, 0]
    add4aged = pol._ID_Medical_frt_add4aged
    assert add4aged[2015 - syr] == -0.025
    assert add4aged[2016 - syr] == -0.025
    assert add4aged[2017 - syr] == 0.0
    assert add4aged[2022 - syr] == 0.0
Exemplo n.º 38
0
def test_read_json_reform_file_and_implement_reform(reform_file,
                                                    assump_file,
                                                    set_year):
    """
    Test reading and translation of reform file into a reform dictionary
    that is then used to call implement_reform method and Calculate.calc_all()
    NOTE: implement_reform called when policy.current_year == policy.start_year
    """
    pol = Policy()
    if set_year:
        pol.set_year(2015)
    param_dict = Calculator.read_json_param_objects(reform_file.name,
                                                    assump_file.name)
    pol.implement_reform(param_dict['policy'])
    syr = pol.start_year
    amt_brk1 = pol._AMT_brk1
    assert amt_brk1[2015 - syr] == 200000
    assert amt_brk1[2016 - syr] > 200000
    assert amt_brk1[2017 - syr] == 300000
    assert amt_brk1[2018 - syr] > 300000
    ii_em = pol._II_em
    assert ii_em[2016 - syr] == 6000
    assert ii_em[2017 - syr] == 6000
    assert ii_em[2018 - syr] == 7500
    assert ii_em[2019 - syr] > 7500
    assert ii_em[2020 - syr] == 9000
    assert ii_em[2021 - syr] > 9000
    amt_em = pol._AMT_em
    assert amt_em[2016 - syr, 0] > amt_em[2015 - syr, 0]
    assert amt_em[2017 - syr, 0] > amt_em[2016 - syr, 0]
    assert amt_em[2018 - syr, 0] == amt_em[2017 - syr, 0]
    assert amt_em[2019 - syr, 0] == amt_em[2017 - syr, 0]
    assert amt_em[2020 - syr, 0] == amt_em[2017 - syr, 0]
    assert amt_em[2021 - syr, 0] > amt_em[2020 - syr, 0]
    assert amt_em[2022 - syr, 0] > amt_em[2021 - syr, 0]
    add4aged = pol._ID_Medical_frt_add4aged
    assert add4aged[2015 - syr] == -0.025
    assert add4aged[2016 - syr] == -0.025
    assert add4aged[2017 - syr] == 0.0
    assert add4aged[2022 - syr] == 0.0
Exemplo n.º 39
0
def test_reform_documentation():
    reform_json = """
    {
    "policy": {
      "_II_em_cpi": {"2016": false,
                     "2018": true},
      "_II_em": {"2016": [5000],
                 "2018": [6000],
                 "2020": [7000]},
      "_EITC_indiv": {"2017": [true]},
      "_STD_Aged_cpi": {"2016": false},
      "_STD_Aged": {"2016": [[1600, 1300, 1300, 1600, 1600]],
                    "2020": [[2000, 2000, 2000, 2000, 2000]]},
      "_ID_BenefitCap_Switch_medical": {"2020": [false]},
      "_ID_BenefitCap_Switch_casualty": {"2020": [false]},
      "_ID_BenefitCap_Switch_misc": {"2020": [false]},
      "_ID_BenefitCap_Switch_interest": {"2020": [false]},
      "_ID_BenefitCap_Switch_charity": {"2020": [false]}
      }
    }
    """
    assump_json = """
    {
    "consumption": {},
    "behavior": {},
    // increase baseline inflation rate by one percentage point in 2014+
    // (has no effect on known policy parameter values)
    "growdiff_baseline": {"_ACPIU": {"2014": [0.01]}},
    "growdiff_response": {},
    "growmodel": {}
    }
    """
    params = Calculator.read_json_param_objects(reform_json, assump_json)
    assert isinstance(params, dict)
    doc = Calculator.reform_documentation(params)
    assert isinstance(doc, str)
    dump = False  # set to True to print documentation and force test failure
    if dump:
        print(doc)
        assert 1 == 2
Exemplo n.º 40
0
def test_puf_var_stats(tests_path, puf_fullsample):
    """
    Main logic of test.
    """
    # 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 Calculator object using baseline_policy and full puf.csv sample
    rec = Records(data=puf_fullsample)
    calc = Calculator(policy=baseline_policy, records=rec, verbose=False)
    # create base tables
    table_mean = create_base_table(tests_path)
    table_corr = copy.deepcopy(table_mean)
    del table_corr['description']
    # add statistics to tables
    year_headers = ['description']
    for year in range(Policy.JSON_START_YEAR, Policy.LAST_BUDGET_YEAR + 1):
        assert year == calc.current_year
        year_headers.append(str(year))
        calc.calc_all()
        calculate_mean_stats(calc, table_mean, year)
        if year == 2016:
            calculate_corr_stats(calc, table_corr)
        if year < Policy.LAST_BUDGET_YEAR:
            calc.increment_year()
    # write tables to new CSV files
    mean_path = os.path.join(tests_path, MEAN_FILENAME + '-new')
    table_mean.sort_index(inplace=True)
    table_mean.to_csv(mean_path, header=year_headers, float_format='%8.0f')
    corr_path = os.path.join(tests_path, CORR_FILENAME + '-new')
    table_corr.sort_index(inplace=True)
    table_corr.to_csv(corr_path, float_format='%8.2f',
                      columns=table_corr.index)
    # compare new and old CSV files for nonsmall differences
    mean_msg = differences(mean_path, mean_path[:-4], 'MEAN')
    corr_msg = differences(corr_path, corr_path[:-4], 'CORR')
    if mean_msg or corr_msg:
        raise ValueError(mean_msg + corr_msg)
Exemplo n.º 41
0
def test_read_bad_json_assump_file():
    """
    Test invalid JSON assumption files.
    """
    badassump1 = """
    {
      "consumption": { // example of incorrect JSON because 'x' must be "x"
        'x': {"2014": 0.25}
      },
      "growdiff_baseline": {},
      "growdiff_response": {}
    }
    """
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, badassump1)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'unknown_file_name')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, list())
def test_read_bad_json_assump_file():
    """
    Test invalid JSON assumption files.
    """
    badassump1 = """
    {
      "consumption": { // example of incorrect JSON because 'x' must be "x"
        'x': {"2014": 0.25}
      },
      "growdiff_baseline": {},
      "growdiff_response": {}
    }
    """
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, badassump1)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'unknown_file_name')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, list())
Exemplo n.º 43
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
Exemplo n.º 44
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)
Exemplo n.º 45
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
Exemplo n.º 46
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 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(tests_path, '..', 'reforms', '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(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'])
            assert not pol.parameter_errors
        pol.implement_reform(reform['policy'])
        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)
Exemplo n.º 47
0
def run_micro_macro(user_params):
    # Grab a reform JSON file already in Tax-Calculator
    # In this example the 'reform' is a change to 2017 law (the
    # baseline policy is tax law in 2018)
    reform_url = ('https://raw.githubusercontent.com/'
                  'PSLmodels/Tax-Calculator/master/taxcalc/'
                  'reforms/2017_law.json')
    ref = Calculator.read_json_param_objects(reform_url, None)
    reform = ref['policy']

    # Define parameters to use for multiprocessing
    client = Client(processes=False)
    num_workers = 1  # multiprocessing.cpu_count()
    print('Number of workers = ', num_workers)
    start_time = time.time()

    # Set some model parameters
    # See parameters.py for description of these parameters
    alpha_T = np.zeros(50)
    alpha_T[0:2] = 0.09
    alpha_T[2:10] = 0.09 + 0.01
    alpha_T[10:40] = 0.09 - 0.01
    alpha_T[40:] = 0.09
    alpha_G = np.zeros(7)
    alpha_G[0:3] = 0.05 - 0.01
    alpha_G[3:6] = 0.05 - 0.005
    alpha_G[6:] = 0.05
    small_open = False
    user_params = {'frisch': 0.41, 'start_year': 2018,
                   'tau_b': [(0.21 * 0.55) * (0.017 / 0.055), (0.21 * 0.55) * (0.017 / 0.055)],
                   'debt_ratio_ss': 1.0, 'alpha_T': alpha_T.tolist(),
                   'alpha_G': alpha_G.tolist(), 'small_open': small_open}

    '''
    ------------------------------------------------------------------------
    Run baseline policy first
    ------------------------------------------------------------------------
    '''
    output_base = BASELINE_DIR
    kwargs = {'output_base': output_base, 'baseline_dir': BASELINE_DIR,
              'test': False, 'time_path': True, 'baseline': True,
              'user_params': user_params, 'guid': '_example',
              'run_micro': True, 'data': 'cps', 'client': client,
              'num_workers': num_workers}

    start_time = time.time()
    runner(**kwargs)
    print('run time = ', time.time()-start_time)

    '''
    ------------------------------------------------------------------------
    Run reform policy
    ------------------------------------------------------------------------
    '''
    user_params = {'frisch': 0.41, 'start_year': 2018,
                   'tau_b': [(0.35 * 0.55) * (0.017 / 0.055)],
                   'debt_ratio_ss': 1.0, 'alpha_T': alpha_T.tolist(),
                   'alpha_G': alpha_G.tolist(), 'small_open': small_open}
    output_base = REFORM_DIR
    kwargs = {'output_base': output_base, 'baseline_dir': BASELINE_DIR,
              'test': False, 'time_path': True, 'baseline': False,
              'user_params': user_params, 'guid': '_example',
              'reform': reform, 'run_micro': True, 'data': 'cps',
              'client': client, 'num_workers': num_workers}

    start_time = time.time()
    runner(**kwargs)
    print('run time = ', time.time()-start_time)

    # return ans - the percentage changes in macro aggregates and prices
    # due to policy changes from the baseline to the reform
    ans = postprocess.create_diff(
        baseline_dir=BASELINE_DIR, policy_dir=REFORM_DIR)

    print("total time was ", (time.time() - start_time))
    print('Percentage changes in aggregates:', ans)
Exemplo n.º 48
0
def test_round_trip_tcja_reform(tests_path):
    """
    Check that current-law policy has the same policy parameter values in
    a future year as does a compound reform that first implements the
    reform specified in the 2017_law.json file and then implements the
    reform specified in the TCJA.json file.  This test checks that the
    future-year parameter values for current-law policy (which incorporates
    TCJA) are the same as future-year parameter values for the compound
    round-trip reform.  Doing this check ensures that the 2017_law.json
    and TCJA.json reform files are specified in a consistent manner.
    """
    # pylint: disable=too-many-locals
    fyear = 2020
    # create clp metadata dictionary for current-law policy in fyear
    pol = Policy()
    pol.set_year(fyear)
    clp_mdata = pol.metadata()
    # create rtr metadata dictionary for round-trip reform in fyear
    pol = Policy()
    reform_file = os.path.join(tests_path, '..', 'reforms', '2017_law.json')
    with open(reform_file, 'r') as rfile:
        rtext = rfile.read()
    reform = Calculator.read_json_param_objects(rtext, None)
    pol.implement_reform(reform['policy'])
    # eventually activate: assert not clp.parameter_warnings
    ctc_c_warning = 'CTC_c was redefined in release 1.0.0\n'
    assert pol.parameter_warnings == ctc_c_warning
    assert not pol.parameter_errors
    reform_file = os.path.join(tests_path, '..', 'reforms', 'TCJA.json')
    with open(reform_file, 'r') as rfile:
        rtext = rfile.read()
    reform = Calculator.read_json_param_objects(rtext, None)
    pol.implement_reform(reform['policy'])
    # eventually activate: assert not clp.parameter_warnings
    assert pol.parameter_warnings == ctc_c_warning
    assert not pol.parameter_errors
    pol.set_year(fyear)
    rtr_mdata = pol.metadata()
    # compare fyear policy parameter values
    assert clp_mdata.keys() == rtr_mdata.keys()
    fail_dump = False
    if fail_dump:
        rtr_fails = open('fails_rtr', 'w')
        clp_fails = open('fails_clp', 'w')
    fail_params = list()
    msg = '\nRound-trip-reform and current-law-policy param values differ for:'
    for pname in clp_mdata.keys():
        rtr_val = rtr_mdata[pname]['value']
        clp_val = clp_mdata[pname]['value']
        if not np.allclose(rtr_val, clp_val):
            fail_params.append(pname)
            msg += '\n  {} in {} : rtr={} clp={}'.format(
                pname, fyear, rtr_val, clp_val
            )
            if fail_dump:
                rtr_fails.write('{} {} {}\n'.format(pname, fyear, rtr_val))
                clp_fails.write('{} {} {}\n'.format(pname, fyear, clp_val))
    if fail_dump:
        rtr_fails.close()
        clp_fails.close()
    if fail_params:
        raise ValueError(msg)
Exemplo n.º 49
0
def test_json_assump_url():
    """
    Test reading JSON assumption file using URL.
    """
    assump_str = """
    {
        "consumption": {
            // all BEN_*_value parameters have a default value of one
            "BEN_housing_value": {"2017": 1.0},
            "BEN_snap_value": {"2017": 1.0},
            "BEN_tanf_value": {"2017": 1.0},
            "BEN_vet_value": {"2017": 1.0},
            "BEN_wic_value": {"2017": 1.0},
            "BEN_mcare_value": {"2017": 1.0},
            "BEN_mcaid_value": {"2017": 1.0},
            "BEN_other_value": {"2017": 1.0},
            // all MPC_* parameters have a default value of zero
            "MPC_e17500": {"2017": 0.0},
            "MPC_e18400": {"2017": 0.0},
            "MPC_e19800": {"2017": 0.0},
            "MPC_e20400": {"2017": 0.0}
        },
        "growdiff_baseline": {
            // all growdiff_baseline parameters have a default value of zero
            "ABOOK": {"2017": 0.0},
            "ACGNS": {"2017": 0.0},
            "ACPIM": {"2017": 0.0},
            "ACPIU": {"2017": 0.0},
            "ADIVS": {"2017": 0.0},
            "AINTS": {"2017": 0.0},
            "AIPD": {"2017": 0.0},
            "ASCHCI": {"2017": 0.0},
            "ASCHCL": {"2017": 0.0},
            "ASCHEI": {"2017": 0.0},
            "ASCHEL": {"2017": 0.0},
            "ASCHF": {"2017": 0.0},
            "ASOCSEC": {"2017": 0.0},
            "ATXPY": {"2017": 0.0},
            "AUCOMP": {"2017": 0.0},
            "AWAGE": {"2017": 0.0},
            "ABENOTHER": {"2017": 0.0},
            "ABENMCARE": {"2017": 0.0},
            "ABENMCAID": {"2017": 0.0},
            "ABENSSI": {"2017": 0.0},
            "ABENSNAP": {"2017": 0.0},
            "ABENWIC": {"2017": 0.0},
            "ABENHOUSING": {"2017": 0.0},
            "ABENTANF": {"2017": 0.0},
            "ABENVET": {"2017": 0.0}
        },
        "growdiff_response": {
            // all growdiff_response parameters have a default value of zero
            "ABOOK": {"2017": 0.0},
            "ACGNS": {"2017": 0.0},
            "ACPIM": {"2017": 0.0},
            "ACPIU": {"2017": 0.0},
            "ADIVS": {"2017": 0.0},
            "AINTS": {"2017": 0.0},
            "AIPD": {"2017": 0.0},
            "ASCHCI": {"2017": 0.0},
            "ASCHCL": {"2017": 0.0},
            "ASCHEI": {"2017": 0.0},
            "ASCHEL": {"2017": 0.0},
            "ASCHF": {"2017": 0.0},
            "ASOCSEC": {"2017": 0.0},
            "ATXPY": {"2017": 0.0},
            "AUCOMP": {"2017": 0.0},
            "AWAGE": {"2017": 0.0},
            "ABENOTHER": {"2017": 0.0},
            "ABENMCARE": {"2017": 0.0},
            "ABENMCAID": {"2017": 0.0},
            "ABENSSI": {"2017": 0.0},
            "ABENSNAP": {"2017": 0.0},
            "ABENWIC": {"2017": 0.0},
            "ABENHOUSING": {"2017": 0.0},
            "ABENTANF": {"2017": 0.0},
            "ABENVET": {"2017": 0.0}
        }
    }
    """
    assump_url = ('https://raw.githubusercontent.com/PSLmodels/'
                  'Tax-Calculator/master/taxcalc/assumptions/'
                  'economic_assumptions_template.json')
    params_str = Calculator.read_json_param_objects(None, assump_str)
    assert params_str
    params_url = Calculator.read_json_param_objects(None, assump_url)
    assert params_url
    assert params_url == params_str
Exemplo n.º 50
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 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 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(float_format='%8.1f') + '\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)
Exemplo n.º 51
0
def test_read_bad_json_reform_file(bad1reformfile, bad2reformfile,
                                   bad3reformfile):
    """
    Test invalid JSON reform files.
    """
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(bad1reformfile.name, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(bad2reformfile.name, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(bad3reformfile.name, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(list(), None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'unknown_file_name')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, list())
def test_read_bad_json_assump_file():
    """
    Test invalid JSON assumption files.
    """
    badassump1 = """
    {
      "consumption": { // example of incorrect JSON because 'x' must be "x"
        'x': {"2014": 0.25}
      },
      "growdiff_baseline": {},
      "growdiff_response": {}
    }
    """
    badassump2 = """
    {
      "consumptionx": {}, // example of file not containing "consumption" key
      "growdiff_baseline": {},
      "growdiff_response": {}
    }
    """
    badassump3 = """
    {
      "consumption": {},
      "growdiff_baseline": {},
      "growdiff_response": {},
      "policy": { // example of misplaced policy key
        "SS_Earnings_c": {"2018": 9e99}
      }
    }
    """
    badassump4 = """
    {
      "consumption": {},
      "growdiff_baseline": {},
      "growdiff_response": {},
      "illegal_key": {}
    }
    """
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, badassump1)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, badassump2)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, badassump3)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, badassump4)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'unknown_file_name')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, list())
def test_read_bad_json_reform_file():
    """
    Test invalid JSON reform files.
    """
    badreform1 = """
    {
      "policy": { // example of incorrect JSON because 'x' must be "x"
        'x': {"2014": 4000}
      }
    }
    """
    badreform2 = """
    {
      "title": "",
      "policyx": { // example of reform file not containing "policy" key
        "SS_Earnings_c": {"2018": 9e99}
      }
    }
    """
    badreform3 = """
    {
      "title": "",
      "policy": {
        "SS_Earnings_c": {"2018": 9e99}
      },
      "consumption": { // example of misplaced "consumption" key
      }
    }
    """
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(badreform1, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(badreform2, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(badreform3, None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(list(), None)
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, 'unknown_file_name')
    with pytest.raises(ValueError):
        Calculator.read_json_param_objects(None, list())
Exemplo n.º 54
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 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 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, 'standard_income_bins',
                                           scaling=False)
        for stat in unused_dist_stats:
            del dist[stat]
        dist = dist[used_dist_stats]
        dist.rename(mapper=renamed_columns, axis='columns', inplace=True)
        with open(resfilename, 'w') as resfile:
            dist.to_string(resfile, float_format='%7.0f')

    # 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.parameter_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)
Exemplo n.º 55
0
def test_json_assump_url():
    """
    Test reading JSON assumption file using URL.
    """
    assump_str = """
    {
        "consumption": {
            "_BEN_housing_value": {"2017": [1.0]},
            "_BEN_snap_value": {"2017": [1.0]},
            "_BEN_tanf_value": {"2017": [1.0]},
            "_BEN_vet_value": {"2017": [1.0]},
            "_BEN_wic_value": {"2017": [1.0]},
            "_BEN_mcare_value": {"2017": [1.0]},
            "_BEN_mcaid_value": {"2017": [1.0]},
            "_BEN_other_value": {"2017": [1.0]},
            "_MPC_e17500": {"2017": [0.0]},
            "_MPC_e18400": {"2017": [0.0]},
            "_MPC_e19800": {"2017": [0.0]},
            "_MPC_e20400": {"2017": [0.0]}
        },
        "growdiff_baseline": {
            "_ABOOK": {"2017": [0.0]},
            "_ACGNS": {"2017": [0.0]},
            "_ACPIM": {"2017": [0.0]},
            "_ACPIU": {"2017": [0.0]},
            "_ADIVS": {"2017": [0.0]},
            "_AINTS": {"2017": [0.0]},
            "_AIPD": {"2017": [0.0]},
            "_ASCHCI": {"2017": [0.0]},
            "_ASCHCL": {"2017": [0.0]},
            "_ASCHEI": {"2017": [0.0]},
            "_ASCHEL": {"2017": [0.0]},
            "_ASCHF": {"2017": [0.0]},
            "_ASOCSEC": {"2017": [0.0]},
            "_ATXPY": {"2017": [0.0]},
            "_AUCOMP": {"2017": [0.0]},
            "_AWAGE": {"2017": [0.0]},
            "_ABENOTHER": {"2017": [0.0]},
            "_ABENMCARE": {"2017": [0.0]},
            "_ABENMCAID": {"2017": [0.0]},
            "_ABENSSI": {"2017": [0.0]},
            "_ABENSNAP": {"2017": [0.0]},
            "_ABENWIC": {"2017": [0.0]},
            "_ABENHOUSING": {"2017": [0.0]},
            "_ABENTANF": {"2017": [0.0]},
            "_ABENVET": {"2017": [0.0]}
        },
        "growdiff_response": {
            "_ABOOK": {"2017": [0.0]},
            "_ACGNS": {"2017": [0.0]},
            "_ACPIM": {"2017": [0.0]},
            "_ACPIU": {"2017": [0.0]},
            "_ADIVS": {"2017": [0.0]},
            "_AINTS": {"2017": [0.0]},
            "_AIPD": {"2017": [0.0]},
            "_ASCHCI": {"2017": [0.0]},
            "_ASCHCL": {"2017": [0.0]},
            "_ASCHEI": {"2017": [0.0]},
            "_ASCHEL": {"2017": [0.0]},
            "_ASCHF": {"2017": [0.0]},
            "_ASOCSEC": {"2017": [0.0]},
            "_ATXPY": {"2017": [0.0]},
            "_AUCOMP": {"2017": [0.0]},
            "_AWAGE": {"2017": [0.0]},
            "_ABENOTHER": {"2017": [0.0]},
            "_ABENMCARE": {"2017": [0.0]},
            "_ABENMCAID": {"2017": [0.0]},
            "_ABENSSI": {"2017": [0.0]},
            "_ABENSNAP": {"2017": [0.0]},
            "_ABENWIC": {"2017": [0.0]},
            "_ABENHOUSING": {"2017": [0.0]},
            "_ABENTANF": {"2017": [0.0]},
            "_ABENVET": {"2017": [0.0]}
        }
    }
    """
    assump_url = ('https://raw.githubusercontent.com/PSLmodels/'
                  'Tax-Calculator/master/taxcalc/assumptions/'
                  'economic_assumptions_template.json')
    params_str = Calculator.read_json_param_objects(None, assump_str)
    assert params_str
    params_url = Calculator.read_json_param_objects(None, assump_url)
    assert params_str == params_url
Exemplo n.º 56
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)
Exemplo n.º 57
0
def test_read_json_param_and_implement_reform(set_year):
    """
    Test reading and translation of reform file into a reform dictionary
    that is then used to call implement_reform method.
    NOTE: implement_reform called when policy.current_year == policy.start_year
    """
    reform_json = """
    // Example of JSON reform text suitable for the
    // Calculator.read_json_param_objects() method.
    // This JSON text can contain any number of trailing //-style comments,
    // which will be removed before the contents are converted from JSON to
    // a dictionary.
    // The primary keys are policy parameters and secondary keys are years.
    // Both the primary & secondary key values must be enclosed in quotes (").
    // Boolean variables are specified as true or false with no quotes and all
    // lowercase characters.
    {
    "policy": {
        "AMT_brk1": // top of first AMT tax bracket
        {"2015": 200000,
         "2017": 300000
        },
        "EITC_c": // max EITC amount by number of qualifying kids (0,1,2,3+)
        {"2016": [ 900, 5000,  8000,  9000],
         "2019": [1200, 7000, 10000, 12000]
        },
        "II_em": // personal exemption amount (see indexing changes below)
        {"2016": 6000,
         "2018": 7500,
         "2020": 9000
        },
        "II_em-indexed": // personal exemption amount indexing status
        {"2016": false, // values in future years are same as this year value
         "2018": true   // vals in future years indexed with this year as base
        },
        "SS_Earnings_c": // Social Security (OASDI) maximum taxable earnings
        {"2016": 300000,
         "2018": 500000,
         "2020": 700000
        },
        "AMT_em-indexed": // AMT exemption amount indexing status
        {"2017": false, // values in future years are same as this year value
         "2020": true   // vals in future years indexed with this year as base
        }
    }
    }
    """
    policy = Policy()
    if set_year:
        policy.set_year(2015)
    param_dict = Calculator.read_json_param_objects(reform_json, 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
Exemplo n.º 58
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
    recs = Records(data=puf_fullsample)
    # create a Calculator object using baseline policy and puf 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 results to a string with a trailing EOL character
    adtstr = adt.to_string(float_format='%8.1f') + '\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
    diffs = nonsmall_diffs(actual, expect)
    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 = 2222  # to ensure sub-sample is always the same
    subfrac = 0.05  # sub-sample fraction
    subsample = fullsample.sample(frac=subfrac, random_state=rn_seed)
    recs_subsample = Records(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):
        reltol = 0.01  # maximum allowed relative difference in tax liability
        if not np.allclose(taxes_subsample[cyr], taxes_fullsample[cyr],
                           atol=0.0, rtol=reltol):
            reldiff = (taxes_subsample[cyr] / taxes_fullsample[cyr]) - 1.
            line1 = '\nPUFCSV 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)