Esempio n. 1
0
def test_reform_json(tests_path):
    """
    Check that each JSON reform file can be converted into a reform dictionary
    that can then be passed to the Policy class implement_reform() method.
    """
    reforms_path = os.path.join(tests_path, '..', 'reforms', '*.json')
    for jpf in glob.glob(reforms_path):
        # read contents of jpf (JSON parameter filename)
        jfile = open(jpf, 'r')
        jpf_text = jfile.read()
        # check that jpf_text has "policy" that can be implemented as a reform
        if '"policy"' in jpf_text:
            arrays_not_lists = True
            gdiffbase = {}
            gdiffresp = {}
            # pylint: disable=protected-access
            policy_dict = (
                Calculator._read_json_policy_reform_text(jpf_text,
                                                         arrays_not_lists,
                                                         gdiffbase, gdiffresp)
            )
            policy = Policy()
            policy.implement_reform(policy_dict)
        else:  # jpf_text is not a valid JSON policy reform file
            print('test-failing-filename: ' +
                  jpf)
            assert False
Esempio n. 2
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 + '.out') as outfile:
            exp_res = outfile.read()
        exp = exp_res.splitlines(True)
        with open(base + '.res') as resfile:
            act_res = resfile.read()
        act = act_res.splitlines(True)
        # assure act & exp line lists have differences less than "small" value
        epsilon = 1e-6
        if sys.version_info.major == 2:
            small = epsilon  # tighter test for Python 2.7
        else:
            small = epsilon  # looser test for Python 3.6 if necessary
        diff_lines = list()
        assert len(act) == len(exp)
        for actline, expline in zip(act, exp):
            if actline == expline:
                continue
            diffs = nonsmall_diff_line_list(actline, expline, small)
            if diffs:
                diff_lines.extend(diffs)
        if diff_lines:
            return False
        return 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)
    # 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:
        # read contents of jrf (JSON reform file)
        with open(jrf, 'r') as jfile:
            jrf_text = jfile.read()
        # check that jrf_text has "policy" that can be implemented as a reform
        if '"policy"' in jrf_text:
            gdiffbase = {}
            gdiffresp = {}
            # pylint: disable=protected-access
            policy_dict = (
                Calculator._read_json_policy_reform_text(jrf_text,
                                                         gdiffbase, gdiffresp)
            )
            pol = Policy()
            pol.implement_reform(policy_dict)
            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)
        else:  # jrf_text has no "policy" key
            msg = 'ERROR: missing policy key in file: {}'
            raise ValueError(msg.format(os.path.basename(jrf)))
    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)