def test_arg_validation(): with pytest.raises(ValueError): TaxBrain(2018, 2020) with pytest.raises(AssertionError): TaxBrain("2018", "2020", use_cps=True) with pytest.raises(AssertionError): TaxBrain(TaxBrain.LAST_BUDGET_YEAR, TaxBrain.FIRST_BUDGET_YEAR, use_cps=True) with pytest.raises(AssertionError): TaxBrain(TaxBrain.FIRST_BUDGET_YEAR - 1, 2018, use_cps=True) with pytest.raises(AssertionError): TaxBrain(2018, TaxBrain.LAST_BUDGET_YEAR + 1, use_cps=True)
def cli_core(startyear, endyear, data, usecps, reform, behavior, assump, baseline, outdir, name, make_report, author): """ Core logic for the CLI """ tb = TaxBrain(start_year=startyear, end_year=endyear, microdata=data, use_cps=usecps, reform=reform, behavior=behavior, assump=assump, base_policy=baseline, verbose=True) tb.run() # create outputs dirname = name if not dirname: dirname = f"TaxBrain Analysis {datetime.today().date()}" outputpath = Path(outdir, dirname) outputpath.mkdir() # create output tables aggregate = tb.weighted_totals("combined") aggregate.to_csv(Path(outputpath, "aggregate_tax_liability.csv")) for year in range(startyear, endyear + 1): yeardir = Path(outputpath, str(year)) yeardir.mkdir() make_tables(tb, year, yeardir) if make_report: report(tb, name=name, outdir=outputpath, author=author)
def cli_core(startyear, endyear, data, usecps, reform, behavior, assump, baseline, outdir, name, make_report, author): """ Core logic for the CLI Parameters ---------- startyear: int year to start analysis endyear: int last year for analysis data: str or Pandas DataFrame path to or DataFrame with data for Tax-Calculator usecps: bool whether to use the CPS or (if False) the PUF-based file reform: dict parameter changes for reform run in Tax-Calculator behavior: dict behavioral assumptions for Behavioral-Responses assump: dict consumption assumptions base_policy: dict parameter changes (relative to current law baseline) for baseline policy verbose: bool indicator for printing of output Returns ------- None reports saved to disk at path specified by outdir """ tb = TaxBrain(start_year=startyear, end_year=endyear, microdata=data, use_cps=usecps, reform=reform, behavior=behavior, assump=assump, base_policy=baseline, verbose=True) tb.run() # create outputs dirname = name if not dirname: dirname = f"TaxBrain Analysis {datetime.today().date()}" outputpath = Path(outdir, dirname) outputpath.mkdir(exist_ok=True) # create output tables aggregate = tb.weighted_totals("combined") aggregate.to_csv(Path(outputpath, "aggregate_tax_liability.csv")) for year in range(startyear, endyear + 1): yeardir = Path(outputpath, str(year)) yeardir.mkdir(exist_ok=True) make_tables(tb, year, yeardir) if make_report: report(tb, name=name, outdir=outputpath, author=author)
def test_user_input(reform_json_str, assump_json_str): valid_reform = {"II_rt7": {2019: 0.40}} # Test valid reform dictionary with No assumption TaxBrain(2018, 2020, use_cps=True, reform=valid_reform) TaxBrain(2018, 2020, use_cps=True, reform=reform_json_str) invalid_assump = {"consumption": {}} # Test valid reform and assumptions dictionary valid_assump = { "consumption": {}, "growdiff_baseline": {}, "growdiff_response": {} } TaxBrain(2018, 2019, use_cps=True, assump=valid_assump) TaxBrain(2018, 2019, use_cps=True, reform=reform_json_str, assump=assump_json_str) tb = TaxBrain(2018, 2019, use_cps=True, reform=valid_reform, assump=valid_assump) required_param_keys = { "policy", "consumption", "growdiff_baseline", "growdiff_response", "behavior", "base_policy" } assert set(tb.params.keys()) == required_param_keys with pytest.raises(ValueError): TaxBrain(2018, 2020, use_cps=True, assump=invalid_assump) invalid_assump = { "consumption": {}, "growdiff_baseline": {}, "growdiff_response": {}, "invalid": {} } with pytest.raises(ValueError): TaxBrain(2018, 2020, use_cps=True, assump=invalid_assump) with pytest.raises(TypeError): TaxBrain(2018, 2020, use_cps=True, reform=True) with pytest.raises(TypeError): TaxBrain(2018, 2020, use_cps=True, assump=True)
def test_stacked_run(): # reforms to use payroll_json = """{"SS_Earnings_thd": {"2021": 400000}}""" CG_rate_json = """{ "CG_brk3": {"2021": [1000000, 1000000, 1000000, 1000000, 1000000]}, "CG_rt4": {"2021": 0.396} }""" reform_dict = { "Payroll Threshold Increase": payroll_json, "Capital Gains Tax Changes": CG_rate_json } tb = TaxBrain(2021, 2022, reform=reform_dict, stacked=True, use_cps=True) tb.run() # check that there is a stacked table now assert isinstance(tb.stacked_table, pd.DataFrame)
def tb_dynamic(reform_json_str): return TaxBrain(2018, 2019, use_cps=True, reform=reform_json_str, behavior={"sub": 0.25})
def tb_static(reform_json_str): return TaxBrain(2018, 2019, use_cps=True, reform=reform_json_str)
def test_baseline_policy(): base = {"II_em": {2019: 0}} reform = {"II_em": {2025: 2000}} tb = TaxBrain(2018, 2019, use_cps=True, reform=reform, base_policy=base) tb.run()
def run_model(meta_params_dict, adjustment): """ Runs TaxBrain """ # update meta parameters meta_params = MetaParameters() meta_params.adjust(meta_params_dict) # convert COMP user inputs to format accepted by tax-calculator policy_mods = convert_adj(adjustment["policy"], meta_params.year.tolist()) behavior_mods = convert_behavior_adj(adjustment["behavior"]) user_mods = {"policy": policy_mods, "behavior": behavior_mods} start_year = int(meta_params.year) use_cps = meta_params.data_source == "CPS" if meta_params.data_source == "PUF": puf_df = retrieve_puf(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) if puf_df is not None: if not isinstance(puf_df, pd.DataFrame): raise TypeError("'puf_df' must be a Pandas DataFrame.") fuzz = True use_cps = False sampling_frac = 0.05 sampling_seed = 2222 full_sample = puf_df else: # Access keys are not available. Default to the CPS. print("Defaulting to the CPS") meta_params.adjust({"data_source": "CPS"}) if meta_params.data_source == "CPS": fuzz = False use_cps = True input_path = os.path.join(TCDIR, "cps.csv.gz") # full_sample = read_egg_csv(cpspath) # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 full_sample = pd.read_csv(input_path) if meta_params.use_full_sample: sample = full_sample end_year = min(start_year + 10, TaxBrain.LAST_BUDGET_YEAR) else: sample = full_sample.sample(frac=sampling_frac, random_state=sampling_seed) end_year = start_year tb = TaxBrain(start_year, end_year, microdata=sample, use_cps=use_cps, reform=policy_mods, behavior=behavior_mods) tb.run() # Collect results for each year delayed_list = [] for year in range(start_year, end_year + 1): print('delaying for', year) delay = delayed(nth_year_results)(tb, year, user_mods, fuzz) delayed_list.append(delay) results = compute(*delayed_list) # process results to get them ready for display # create aggregate plot agg_plot = aggregate_plot(tb) all_to_process = defaultdict(list) for result in results: for key, value in result.items(): all_to_process[key] += value results, downloadable = postprocess(all_to_process) agg_output, table_output = create_layout(results, start_year, end_year) model_versions_str = "" for model, version in TaxBrain.VERSIONS.items(): model_versions_str += f"{model}: {version}\n" comp_outputs = { "renderable": [agg_plot, agg_output, table_output], "model_version": model_versions_str, "downloadable": downloadable } return comp_outputs
from taxbrain import TaxBrain reform_url = "https://raw.githubusercontent.com/PSLmodels/Tax-Calculator/master/taxcalc/reforms/Larson2019.json" # run static analysis tb_static = TaxBrain(2019, 2028, use_cps=True, reform=reform_url) tb_static.run() static_table = tb_static.weighted_totals("c00100") print("Tax Liability by Year\n") print("Static Results") print(static_table) # run dynamic analysis tb_dynamic = TaxBrain(2019, 2028, use_cps=True, reform=reform_url, behavior={"sub": 0.25}) tb_dynamic.run() dynamic_table = tb_dynamic.weighted_totals("c00100") print("Dynamic Results") print(dynamic_table) # produce a differences table diff = tb_static.differences_table(2019, "weighted_deciles", "combined") print("\nDifferences Table for 2019") print(diff)
def run_tbi_model(start_year, data_source, use_full_sample, user_mods, puf_df=None): """ Run TBI using the taxbrain API """ tbi_path = os.path.abspath(os.path.dirname(__file__)) tcpath = inspect.getfile(Records) tcdir = os.path.dirname(tcpath) # use taxbrain if data_source == "PUF": if not isinstance(puf_df, pd.DataFrame): raise TypeError("'puf_df' must be a Pandas DataFrame.") fuzz = True use_cps = False sampling_frac = 0.05 sampling_seed = 2222 full_sample = puf_df else: fuzz = False use_cps = True 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 = os.path.join(tcdir, "cps.csv.gz") # full_sample = read_egg_csv(cpspath) # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 full_sample = pd.read_csv(input_path) if use_full_sample: sample = full_sample end_year = min(start_year + 10, TaxBrain.LAST_BUDGET_YEAR) else: sample = full_sample.sample(frac=sampling_frac, random_state=sampling_seed) end_year = start_year tb = TaxBrain(start_year, end_year, microdata=sample, use_cps=use_cps, reform=user_mods["policy"], behavior=user_mods["behavior"]) tb.run() # Collect results for each year delayed_list = [] for year in range(start_year, end_year + 1): print('delaying for', year) delay = delayed(nth_year_results)(tb, year, user_mods, fuzz) delayed_list.append(delay) results = compute(*delayed_list) all_to_process = defaultdict(list) for result in results: for key, value in result.items(): all_to_process[key] += value results = postprocess(all_to_process) return results