예제 #1
0
def test_init_errors(reformfile0, assumpfile0, year, asm, gdr):
    """
    Ensure error messages generated by TaxCalcIO.init method.
    """
    recdict = {'RECID': 1, 'MARS': 1, 'e00300': 100000, 's006': 1e8}
    recdf = pd.DataFrame(data=recdict, index=[0])
    if asm == 'assumpfile0':
        assump = assumpfile0.name
    else:
        assump = asm
    if gdr == 'has_gdiff_response':
        gdiff_response = Growdiff()
        gdiff_response.update_growdiff({2015: {"_ABOOK": [-0.01]}})
    else:
        gdiff_response = gdr
    tcio = TaxCalcIO(input_data=recdf,
                     tax_year=year,
                     reform=reformfile0.name,
                     assump=assump)
    assert len(tcio.errmsg) == 0
    tcio.init(input_data=recdf,
              tax_year=year,
              reform=reformfile0.name,
              assump=assump,
              growdiff_response=gdiff_response,
              aging_input_data=False,
              exact_calculations=False)
    assert len(tcio.errmsg) > 0
예제 #2
0
def test_response_json(tests_path):
    """
    Check that each JSON file can be converted into dictionaries that
    can be used to construct objects needed for a Calculator object.
    """
    responses_path = os.path.join(tests_path, '..', 'responses', '*.json')
    for jpf in glob.glob(responses_path):
        # read contents of jpf (JSON parameter filename)
        jfile = open(jpf, 'r')
        jpf_text = jfile.read()
        # check that jpf_text can be used to construct objects
        response_file = ('"consumption"' in jpf_text and
                         '"behavior"' in jpf_text and
                         '"growdiff_baseline"' in jpf_text and
                         '"growdiff_response"' in jpf_text)
        if response_file:
            # pylint: disable=protected-access
            (con, beh, gdiff_base,
             gdiff_resp) = Calculator._read_json_econ_assump_text(jpf_text)
            cons = Consumption()
            cons.update_consumption(con)
            behv = Behavior()
            behv.update_behavior(beh)
            growdiff_baseline = Growdiff()
            growdiff_baseline.update_growdiff(gdiff_base)
            growdiff_response = Growdiff()
            growdiff_response.update_growdiff(gdiff_resp)
        else:  # jpf_text is not a valid JSON response assumption file
            print('test-failing-filename: ' +
                  jpf)
            assert False
예제 #3
0
def test_taxbrain_json(taxbrain_path):  # pylint: disable=redefined-outer-name
    """
    Check that each JSON parameter file can be converted into dictionaries
    that can be used to construct objects needed for a Calculator object.
    """
    for jpf in glob.glob(taxbrain_path):
        # read contents of jpf (JSON parameter filename)
        jfile = open(jpf, 'r')
        jpf_text = jfile.read()
        # check that jpf_text can be used to construct objects
        if '"policy"' in jpf_text:
            pol = Calculator.read_json_policy_reform_text(jpf_text)
            policy = Policy()
            policy.implement_reform(pol)
        elif ('"consumption"' in jpf_text and
              '"behavior"' in jpf_text and
              '"growdiff_baseline"' in jpf_text and
              '"growdiff_response"' in jpf_text):
            (con, beh, gdiff_base,
             gdiff_resp) = Calculator.read_json_econ_assump_text(jpf_text)
            cons = Consumption()
            cons.update_consumption(con)
            behv = Behavior()
            behv.update_behavior(beh)
            growdiff_baseline = Growdiff()
            growdiff_baseline.update_growdiff(gdiff_base)
            growdiff_response = Growdiff()
            growdiff_response.update_growdiff(gdiff_resp)
        else:  # jpf_text is not a valid JSON parameter file
            print('test-failing-filename: ' +
                  jpf)
            assert False
예제 #4
0
def test_creation_with_aging(rawinputfile, reformfile0):
    """
    Test TaxCalcIO instantiation with/without no policy reform and with aging.
    """
    taxyear = 2021
    tcio = TaxCalcIO(input_data=rawinputfile.name,
                     tax_year=taxyear,
                     reform=reformfile0.name,
                     assump=None)
    assert len(tcio.errmsg) == 0
    tcio.init(input_data=rawinputfile.name,
              tax_year=taxyear,
              reform=reformfile0.name,
              assump=None,
              growdiff_response=Growdiff(),
              aging_input_data=True,
              exact_calculations=False)
    assert len(tcio.errmsg) == 0
    assert tcio.tax_year() == taxyear
    taxyear = 2016
    tcio = TaxCalcIO(input_data=rawinputfile.name,
                     tax_year=taxyear,
                     reform=None,
                     assump=None)
    assert len(tcio.errmsg) == 0
    tcio.init(input_data=rawinputfile.name,
              tax_year=taxyear,
              reform=None,
              assump=None,
              growdiff_response=None,
              aging_input_data=True,
              exact_calculations=False)
    assert len(tcio.errmsg) == 0
    assert tcio.tax_year() == taxyear
예제 #5
0
def test_init_errors(reformfile0, reformfilex1, reformfilex2, baselinebad,
                     assumpfile0, year, base, ref, asm, gdr):
    """
    Ensure error messages generated by TaxCalcIO.init method.
    """
    # pylint: disable=too-many-arguments,too-many-locals
    recdict = {'RECID': 1, 'MARS': 1, 'e00300': 100000, 's006': 1e8}
    recdf = pd.DataFrame(data=recdict, index=[0])
    if base == 'reformfile0':
        baseline = reformfile0.name
    elif base == 'baselinebad':
        baseline = baselinebad.name
    else:
        baseline = base
    if ref == 'reformfile0':
        reform = reformfile0.name
    elif ref == 'reformfilex1':
        reform = reformfilex1.name
    elif ref == 'reformfilex2':  # specify compound reform
        reform = '{}+{}'.format(reformfilex1.name, reformfilex2.name)
    else:
        reform = ref
    if asm == 'assumpfile0':
        assump = assumpfile0.name
    else:
        assump = asm
    if gdr == 'has_gdiff_response':
        gdiff_response = Growdiff()
        gdiff_response.update_growdiff({2015: {"_ABOOK": [-0.01]}})
    else:
        gdiff_response = gdr
    tcio = TaxCalcIO(input_data=recdf,
                     tax_year=year,
                     baseline=baseline,
                     reform=reform,
                     assump=assump)
    assert not tcio.errmsg
    tcio.init(input_data=recdf,
              tax_year=year,
              baseline=baseline,
              reform=reform,
              assump=assump,
              growdiff_response=gdiff_response,
              aging_input_data=False,
              exact_calculations=False)
    assert tcio.errmsg
예제 #6
0
def test_has_any_response():
    syr = 2014
    gdiff = Growdiff(start_year=syr)
    assert gdiff.has_any_response() is False
    gdiff.update_growdiff({2020: {'_AWAGE': [0.01]}})
    assert gdiff.current_year == syr
    assert gdiff.has_any_response() is True
예제 #7
0
def test_chained_cpi_reform(offset):
    """
    Test that _cpi_offset policy parameter works as expected.
    """
    # specify reform without using cpi_offset parameter
    pem = 10000
    bare_reform = {2022: {'_II_em': [pem]}}
    with_reform = {2022: {'_II_em': [pem]}, 2020: {'_cpi_offset': [offset]}}
    syr = Policy.JSON_START_YEAR
    pol_bare = Policy(start_year=syr)
    pol_bare.implement_reform(bare_reform)
    pol_with = Policy(start_year=syr)
    pol_with.implement_reform(with_reform)
    # check relative _II_em values in the two reforms for several years
    pem_bare = pol_bare._II_em
    pem_with = pol_with._II_em
    if offset == 0:
        assert pem_with[2019 - syr] == pem_bare[2019 - syr]
        assert pem_with[2020 - syr] == pem_bare[2020 - syr]
        assert pem_with[2021 - syr] == pem_bare[2021 - syr]
        assert pem_with[2022 - syr] == pem
        assert pem_bare[2022 - syr] == pem
        assert pem_with[2023 - syr] == pem_bare[2023 - syr]
    elif offset < 0:
        assert pem_with[2019 - syr] == pem_bare[2019 - syr]
        assert pem_with[2020 - syr] == pem_bare[2020 - syr]
        assert pem_with[2021 - syr] < pem_bare[2021 - syr]
        assert pem_with[2022 - syr] == pem
        assert pem_bare[2022 - syr] == pem
        assert pem_with[2023 - syr] < pem_bare[2023 - syr]
    # check exact _II_em values for 2023, which are
    # equal to 2022 values indexed by 2022 inflation rates
    unchained_cpi = pol_bare.inflation_rates()[2022 - syr]
    assert pem_bare[2023 - syr] == round(pem * (1 + unchained_cpi), 2)
    chained_cpi = unchained_cpi + offset
    assert pem_with[2023 - syr] == round(pem * (1 + chained_cpi), 2)
    # check that _STD value for 2023 with chained CPI indexing is
    # equal to _STD value for 2023 when specifying chained CPI indexing
    # as a difference in assumed inflation rates
    if offset != 0:
        # ... compute _STD value using difference-in-growth-factors approach
        growfactors = Growfactors()
        growdiff = Growdiff()
        growdiff.update_growdiff({2020: {'_ACPIU': [offset]}})
        growdiff.apply_to(growfactors)
        pol = Policy(gfactors=growfactors, start_year=syr)
        pol.implement_reform(bare_reform)
        # ... compare the _STD values derived from the two approaches
        assert_allclose(pol_with._STD[2023 - syr],
                        pol._STD[2023 - syr],
                        atol=0.01,
                        rtol=0.0)
예제 #8
0
def test_update_and_apply_growdiff():
    syr = 2013
    nyrs = 5
    lyr = syr + nyrs - 1
    gdiff = Growdiff(start_year=syr, num_years=nyrs)
    # update Growdiff instance
    diffs = {2014: {'_AWAGE': [0.01]}, 2016: {'_AWAGE': [0.02]}}
    gdiff.update_growdiff(diffs)
    expected_wage_diffs = [0.00, 0.01, 0.01, 0.02, 0.02]
    assert_allclose(gdiff._AWAGE, expected_wage_diffs, atol=0.0, rtol=0.0)
    # apply growdiff to Growfactors instance
    gf = Growfactors()
    pir_pre = gf.price_inflation_rates(syr, lyr)
    wgr_pre = gf.wage_growth_rates(syr, lyr)
    gfactors = Growfactors()
    gdiff.apply_to(gfactors)
    pir_pst = gfactors.price_inflation_rates(syr, lyr)
    wgr_pst = gfactors.wage_growth_rates(syr, lyr)
    expected_wgr_pst = [
        wgr_pre[i] + expected_wage_diffs[i] for i in range(0, nyrs)
    ]
    assert_allclose(pir_pre, pir_pst, atol=0.0, rtol=0.0)
    assert_allclose(wgr_pst, expected_wgr_pst, atol=1.0e-9, rtol=0.0)
예제 #9
0
def reform_warnings_errors(user_mods):
    """
    The reform_warnings_errors function assumes user_mods is a dictionary
    returned by the Calculator.read_json_param_objects() function.

    This function returns a dictionary containing two STR:STR pairs:
    {'warnings': '<empty-or-message(s)>', 'errors': '<empty-or-message(s)>'}
    In each pair the second string is empty if there are no messages.
    Any returned messages are generated using current_law_policy.json
    information on known policy parameter names and parameter value ranges.

    Note that this function will return one or more error messages if
    the user_mods['policy'] dictionary contains any unknown policy
    parameter names or if any *_cpi parameters have values other than
    True or False.  These situations prevent implementing the policy
    reform specified in user_mods, and therefore, no range-related
    warnings or errors will be returned in this case.
    """
    rtn_dict = {'warnings': '', 'errors': ''}
    # create Growfactors object
    gdiff_baseline = Growdiff()
    gdiff_baseline.update_growdiff(user_mods['growdiff_baseline'])
    gdiff_response = Growdiff()
    gdiff_response.update_growdiff(user_mods['growdiff_response'])
    growfactors = Growfactors()
    gdiff_baseline.apply_to(growfactors)
    gdiff_response.apply_to(growfactors)
    # create Policy object and implement reform
    pol = Policy(gfactors=growfactors)
    try:
        pol.implement_reform(user_mods['policy'])
        rtn_dict['warnings'] = pol.reform_warnings
        rtn_dict['errors'] = pol.reform_errors
    except ValueError as valerr_msg:
        rtn_dict['errors'] = valerr_msg.__str__()
    return rtn_dict
예제 #10
0
def test_correct_but_not_useful_growdiff_ctor():
    gdiff = Growdiff(growdiff_dict={})
    assert gdiff
예제 #11
0
def test_incorrect_growdiff_ctor():
    with pytest.raises(ValueError):
        gdiff = Growdiff(growdiff_dict=list())
    with pytest.raises(ValueError):
        gdiff = Growdiff(num_years=0)
예제 #12
0
def calculate_baseline_and_reform(year_n, start_year, taxrec_df, user_mods):
    """
    calculate_baseline_and_reform function assumes specified user_mods is
    a dictionary returned by the Calculator.read_json_parameter_files()
    function with an extra key:value pair that is specified as
    'gdp_elasticity': {'value': <float_value>}.
    """
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements

    check_user_mods(user_mods)

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

    # Specify growdiff_baseline and growdiff_response
    growdiff_baseline = Growdiff()
    growdiff_response = Growdiff()
    growdiff_base_assumps = user_mods['growdiff_baseline']
    growdiff_resp_assumps = user_mods['growdiff_response']
    growdiff_baseline.update_growdiff(growdiff_base_assumps)
    growdiff_response.update_growdiff(growdiff_resp_assumps)

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

    # Create pre-reform Calculator instance
    recs1 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre)
    policy1 = Policy(gfactors=growfactors_pre)
    calc1 = Calculator(policy=policy1, records=recs1, consumption=consump)
    while calc1.current_year < start_year:
        calc1.increment_year()
    calc1.calc_all()
    assert calc1.current_year == start_year

    # Create pre-reform Calculator instance with extra income
    recs1p = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre)
    # add one dollar to total wages and salaries of each filing unit
    recs1p.e00200 += 1.0  # pylint: disable=no-member
    policy1p = Policy(gfactors=growfactors_pre)
    calc1p = Calculator(policy=policy1p, records=recs1p, consumption=consump)
    while calc1p.current_year < start_year:
        calc1p.increment_year()
    calc1p.calc_all()
    assert calc1p.current_year == start_year

    # Construct mask to show which of the calc1 and calc1p results differ
    soit1 = results(calc1)
    soit1p = results(calc1p)
    mask = (soit1._iitax != soit1p._iitax)  # pylint: disable=protected-access

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

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

    # Create post-reform Calculator instance with behavior
    recs2 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_post)
    policy2 = Policy(gfactors=growfactors_post)
    policy_reform = user_mods['policy']
    policy2.implement_reform(policy_reform)
    calc2 = Calculator(policy=policy2,
                       records=recs2,
                       consumption=consump,
                       behavior=behv)
    while calc2.current_year < start_year:
        calc2.increment_year()
    calc2.calc_all()
    assert calc2.current_year == start_year

    # Seed random number generator with a seed value based on user_mods
    seed = random_seed(user_mods)
    print('seed={}'.format(seed))
    np.random.seed(seed)  # pylint: disable=no-member

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

    # Return calculated results and mask
    soit1 = results(calc1)
    soit2 = results(calc2)
    return soit1, soit2, mask
예제 #13
0
def calculate(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods,
              behavior_allowed):
    """
    The calculate function assumes the specified user_mods is a dictionary
      returned by the Calculator.read_json_param_objects() function.
    The function returns (calc1, calc2, mask) where
      calc1 is pre-reform Calculator object calculated for year_n,
      calc2 is post-reform Calculator object calculated for year_n, and
      mask is boolean array marking records with reform-induced iitax diffs
    Set behavior_allowed to False when generating static results or
      set behavior_allowed to True when generating dynamic results.
    """
    # pylint: disable=too-many-arguments,too-many-locals
    # pylint: disable=too-many-branches,too-many-statements

    check_user_mods(user_mods)

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

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

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

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

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

    # compute mask array
    res1 = calc1.dataframe(DIST_VARIABLES)
    if use_puf_not_cps:
        # create pre-reform Calculator instance with extra income
        recs1p = Records(data=copy.deepcopy(sample), gfactors=growfactors_pre)
        # add one dollar to the income of each filing unit to determine
        # which filing units undergo a resulting change in tax liability
        recs1p.e00200 += 1.0  # pylint: disable=no-member
        recs1p.e00200p += 1.0  # pylint: disable=no-member
        policy1p = Policy(gfactors=growfactors_pre)
        # create Calculator with recs1p and calculate for start_year
        calc1p = Calculator(policy=policy1p,
                            records=recs1p,
                            consumption=consump)
        while calc1p.current_year < start_year:
            calc1p.increment_year()
        calc1p.calc_all()
        assert calc1p.current_year == start_year
        # compute mask showing which of the calc1 and calc1p results differ;
        # mask is true if a filing unit's income tax liability changed after
        # a dollar was added to the filing unit's wage and salary income
        res1p = calc1p.dataframe(DIST_VARIABLES)
        mask = np.logical_not(  # pylint: disable=no-member
            np.isclose(res1.iitax, res1p.iitax, atol=0.001, rtol=0.0))
        assert np.any(mask)
    else:  # if use_cps_not_cps is False
        # indicate that no fuzzing of reform results is required
        mask = np.zeros(res1.shape[0], dtype=np.int8)

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

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

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

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

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

    # return calculated Calculator objects and mask
    return (calc1, calc2, mask)
예제 #14
0
def calculate(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods,
              behavior_allowed):
    """
    The calculate function assumes the specified user_mods is a dictionary
      returned by the Calculator.read_json_param_objects() function.
    The function returns (calc1, calc2) where
      calc1 is pre-reform Calculator object calculated for year_n, and
      calc2 is post-reform Calculator object calculated for year_n.
    Set behavior_allowed to False when generating static results or
      set behavior_allowed to True when generating dynamic results.
    """
    # pylint: disable=too-many-arguments,too-many-locals
    # pylint: disable=too-many-branches,too-many-statements

    check_user_mods(user_mods)

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

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

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

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

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

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

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

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

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

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

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

    # return calculated Calculator objects
    return (calc1, calc2)
예제 #15
0
    afile.write(contents)
    afile.close()
    # must close and then yield for Windows platform
    yield afile
    if os.path.isfile(afile.name):
        try:
            os.remove(afile.name)
        except OSError:
            pass  # sometimes we can't remove a generated temporary file


# for fixture args, pylint: disable=redefined-outer-name


@pytest.mark.parametrize("year, asm, gdr", [
    (2000, 'assumpfile0', Growdiff()),
    (2099, None, None),
    (2020, None, dict()),
    (2020, 'assumpfile0', 'has_gdiff_response'),
])
def test_init_errors(reformfile0, assumpfile0, year, asm, gdr):
    """
    Ensure error messages generated by TaxCalcIO.init method.
    """
    recdict = {'RECID': 1, 'MARS': 1, 'e00300': 100000, 's006': 1e8}
    recdf = pd.DataFrame(data=recdict, index=[0])
    if asm == 'assumpfile0':
        assump = assumpfile0.name
    else:
        assump = asm
    if gdr == 'has_gdiff_response':
예제 #16
0
])
def test_ctor_errors(input_data, baseline, reform, assump, outdir):
    """
    Ensure error messages are generated by TaxCalcIO.__init__.
    """
    tcio = TaxCalcIO(input_data=input_data,
                     tax_year=2013,
                     baseline=baseline,
                     reform=reform,
                     assump=assump,
                     outdir=outdir)
    assert tcio.errmsg


@pytest.mark.parametrize('year, base, ref, asm, gdr', [
    (2000, 'reformfile0', 'reformfile0', 'assumpfile0', Growdiff()),
    (2099, 'reformfile0', 'reformfile0', None, None),
    (2020, 'reformfile0', 'reformfile0', None, dict()),
    (2020, 'reformfile0', 'reformfile0', 'assumpfile0', 'has_gdiff_response'),
    (2020, 'reformfile0', 'reformfilex1', 'assumpfile0', 'has_gdiff_response'),
    (2020, 'reformfile0', 'reformfilex2', 'assumpfile0', 'has_gdiff_response'),
    (2020, 'baselinebad', 'reformfile0', 'assumpfile0', 'has_gdiff_response')
])
def test_init_errors(reformfile0, reformfilex1, reformfilex2, baselinebad,
                     assumpfile0, year, base, ref, asm, gdr):
    """
    Ensure error messages generated by TaxCalcIO.init method.
    """
    # pylint: disable=too-many-arguments,too-many-locals
    recdict = {'RECID': 1, 'MARS': 1, 'e00300': 100000, 's006': 1e8}
    recdf = pd.DataFrame(data=recdict, index=[0])
예제 #17
0
def dropq_calculate(year_n, start_year, taxrec_df, user_mods, behavior_allowed,
                    mask_computed):
    """
    The dropq_calculate function assumes specified user_mods is
      a dictionary returned by the Calculator.read_json_parameter_files()
      function with an extra key:value pair that is specified as
      'gdp_elasticity': {'value': <float_value>}.
    The function returns (calc1, calc2, mask) where
      calc1 is pre-reform Calculator object calculated for year_n,
      calc2 is post-reform Calculator object calculated for year_n, and
      mask is boolean array if compute_mask=True or None otherwise
    """
    # pylint: disable=too-many-arguments,too-many-locals,too-many-statements

    check_user_mods(user_mods)

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

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

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

    # create pre-reform Calculator instance
    recs1 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre)
    policy1 = Policy(gfactors=growfactors_pre)
    calc1 = Calculator(policy=policy1, records=recs1, consumption=consump)
    while calc1.current_year < start_year:
        calc1.increment_year()
    calc1.calc_all()
    assert calc1.current_year == start_year

    # optionally compute mask
    if mask_computed:
        # create pre-reform Calculator instance with extra income
        recs1p = Records(data=taxrec_df.copy(deep=True),
                         gfactors=growfactors_pre)
        # add one dollar to total wages and salaries of each filing unit
        recs1p.e00200 += 1.0  # pylint: disable=no-member
        recs1p.e00200p += 1.0  # pylint: disable=no-member
        policy1p = Policy(gfactors=growfactors_pre)
        # create Calculator with recs1p and calculate for start_year
        calc1p = Calculator(policy=policy1p,
                            records=recs1p,
                            consumption=consump)
        while calc1p.current_year < start_year:
            calc1p.increment_year()
        calc1p.calc_all()
        assert calc1p.current_year == start_year
        # compute mask that shows which of the calc1 and calc1p results differ
        res1 = results(calc1.records)
        res1p = results(calc1p.records)
        mask = (res1.iitax != res1p.iitax)
    else:
        mask = None

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

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

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

    # create post-reform Calculator instance
    recs2 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_post)
    policy2 = Policy(gfactors=growfactors_post)
    policy_reform = user_mods['policy']
    policy2.implement_reform(policy_reform)
    calc2 = Calculator(policy=policy2,
                       records=recs2,
                       consumption=consump,
                       behavior=behv)
    while calc2.current_year < start_year:
        calc2.increment_year()
    calc2.calc_all()
    assert calc2.current_year == start_year

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

    # return calculated Calculator objects and mask
    return (calc1, calc2, mask)
예제 #18
0
def run_nth_year_gdp_elast_model(year_n,
                                 start_year,
                                 taxrec_df,
                                 user_mods,
                                 return_json=True):
    """
    The run_nth_year_gdp_elast_model function assumes user_mods is a
    dictionary returned by the Calculator.read_json_parameter_files()
    function with an extra key:value pair that is specified as
    'gdp_elasticity': {'value': <float_value>}.
    """
    # pylint: disable=too-many-arguments,too-many-locals,too-many-statements

    check_user_mods(user_mods)

    # Only makes sense to run for budget years 1 through n-1 (not for year 0)
    assert year_n > 0

    # Specify value of gdp_elasticity
    gdp_elasticity = user_mods['gdp_elasticity']['value']

    # Specify Consumption instance
    consump = Consumption()
    consump_assumps = user_mods['consumption']
    consump.update_consumption(consump_assumps)

    # Specify growdiff_baseline and growdiff_response
    growdiff_baseline = Growdiff()
    growdiff_response = Growdiff()
    growdiff_base_assumps = user_mods['growdiff_baseline']
    growdiff_resp_assumps = user_mods['growdiff_response']
    growdiff_baseline.update_growdiff(growdiff_base_assumps)
    growdiff_response.update_growdiff(growdiff_resp_assumps)

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

    # Create pre-reform Calculator instance
    records1 = Records(data=taxrec_df.copy(deep=True),
                       gfactors=growfactors_pre)
    policy1 = Policy(gfactors=growfactors_pre)
    calc1 = Calculator(policy=policy1, records=records1, consumption=consump)
    while calc1.current_year < start_year:
        calc1.increment_year()
    assert calc1.current_year == start_year

    # Create post-reform Calculator instance
    records2 = Records(data=taxrec_df.copy(deep=True),
                       gfactors=growfactors_post)
    policy2 = Policy(gfactors=growfactors_post)
    policy_reform = user_mods['policy']
    policy2.implement_reform(policy_reform)
    calc2 = Calculator(policy=policy2, records=records2, consumption=consump)
    while calc2.current_year < start_year:
        calc2.increment_year()
    assert calc2.current_year == start_year

    # Seed random number generator with a seed value based on user_mods
    seed = random_seed(user_mods)
    np.random.seed(seed)  # pylint: disable=no-member
    for _ in range(0, year_n - 1):
        calc1.increment_year()
        calc2.increment_year()
    calc1.calc_all()
    calc2.calc_all()

    # Assert that the current year is one behind the year we are calculating
    assert (calc1.current_year + 1) == (start_year + year_n)
    assert (calc2.current_year + 1) == (start_year + year_n)

    # Compute gdp effect
    gdp_effect = proportional_change_gdp(calc1, calc2, gdp_elasticity)

    # Return gdp_effect results
    if return_json:
        gdp_df = pd.DataFrame(data=[gdp_effect], columns=['col0'])
        gdp_elast_names_i = [
            x + '_' + str(year_n) for x in GDP_ELAST_ROW_NAMES
        ]
        gdp_elast_total = create_json_table(gdp_df,
                                            row_names=gdp_elast_names_i,
                                            num_decimals=5)
        gdp_elast_total = dict((k, v[0]) for k, v in gdp_elast_total.items())
        return gdp_elast_total
    else:
        return gdp_effect