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
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)