diff --git a/taxcalc/__init__.py b/taxcalc/__init__.py index 9aba956b3..fa0c5d7bb 100644 --- a/taxcalc/__init__.py +++ b/taxcalc/__init__.py @@ -14,6 +14,6 @@ from taxcalc.utils import * from taxcalc.cli import * -__version__ = '4.3.4' +__version__ = '4.3.4a' __min_python3_version__ = 10 __max_python3_version__ = 12 diff --git a/taxcalc/calculator.py b/taxcalc/calculator.py index d0b92a598..3c1cac849 100644 --- a/taxcalc/calculator.py +++ b/taxcalc/calculator.py @@ -1110,7 +1110,7 @@ def read_json_param_objects(reform, assump): return param_dict @staticmethod - def reform_documentation(params, policy_dicts=None): + def reform_documentation(params, growfactors, policy_dicts=None): """ Generate reform documentation versus current-law policy. @@ -1120,6 +1120,9 @@ def reform_documentation(params, policy_dicts=None): dictionary is structured like dict returned from the static Calculator.read_json_param_objects() method + growfactors: GrowFactors + GrowFactors object used to construct Calculator Policy object + policy_dicts : list of dict or None each dictionary in list is a params['policy'] dictionary representing second and subsequent elements of a compound @@ -1255,13 +1258,14 @@ def lines(text, num_indent_spaces, max_line_length=77): # create Policy object with current-law-policy values gdiff_base = GrowDiff() gdiff_base.update_growdiff(params['growdiff_baseline']) - gfactors_clp = GrowFactors() + assert isinstance(growfactors, GrowFactors) + gfactors_clp = copy.deepcopy(growfactors) gdiff_base.apply_to(gfactors_clp) clp = Policy(gfactors=gfactors_clp) # create Policy object with post-reform values gdiff_resp = GrowDiff() gdiff_resp.update_growdiff(params['growdiff_response']) - gfactors_ref = GrowFactors() + gfactors_ref = copy.deepcopy(growfactors) gdiff_base.apply_to(gfactors_ref) gdiff_resp.apply_to(gfactors_ref) ref = Policy(gfactors=gfactors_ref) diff --git a/taxcalc/parameters.py b/taxcalc/parameters.py index 8ebbf04cb..2ec9ba004 100644 --- a/taxcalc/parameters.py +++ b/taxcalc/parameters.py @@ -1,15 +1,12 @@ -import copy import os -import re +import copy from collections import defaultdict from typing import Union, Mapping, Any, List import marshmallow as ma import paramtools as pt import numpy as np -import requests -import taxcalc from taxcalc.growfactors import GrowFactors @@ -249,7 +246,6 @@ def adjust_with_indexing(self, params_or_path, **kwargs): label_to_extend = self.label_to_extend array_first = self.array_first self.array_first = False - self._gfactors = GrowFactors() params = self.read_params(params_or_path) @@ -508,12 +504,14 @@ def set_rates(self): def wage_growth_rates(self, year=None): if year is not None: - return self._wage_growth_rates[year - self.start_year] + syr = max(self.start_year, self._gfactors.first_year) + return self._wage_growth_rates[year - syr] return self._wage_growth_rates or [] def inflation_rates(self, year=None): if year is not None: - return self._inflation_rates[year - self.start_year] + syr = max(self.start_year, self._gfactors.first_year) + return self._inflation_rates[year - syr] return self._inflation_rates or [] # alias methods below diff --git a/taxcalc/policy.py b/taxcalc/policy.py index 1c5bf52f7..8f101dd6d 100644 --- a/taxcalc/policy.py +++ b/taxcalc/policy.py @@ -8,7 +8,6 @@ import os import json from pathlib import Path -import numpy as np from taxcalc.parameters import Parameters from taxcalc.growfactors import GrowFactors @@ -148,32 +147,20 @@ def parameter_list(): return [k for k in defaults if k != "schema"] def set_rates(self): - """Initialize taxcalc indexing data.""" + """ + Initialize policy parameter indexing rates. + """ cpi_vals = [ vo["value"] for vo in self._data["parameter_indexing_CPI_offset"]["value"] ] - # extend parameter_indexing_CPI_offset values through budget window - # if they have not been extended already. - cpi_vals = cpi_vals + cpi_vals[-1:] * ( - self.end_year - self.start_year + 1 - len(cpi_vals) + # policy_current_law.json should not specify any non-zero values + # for the parameter_indexing_CPI_offset parameter, so check this + assert any(cpi_vals) is False + syr = max(self.start_year, self._gfactors.first_year) + self._inflation_rates = self._gfactors.price_inflation_rates( + syr, self.end_year ) - cpi_offset = { - (self.start_year + ix): val - for ix, val in enumerate(cpi_vals) - } - - self._gfactors = GrowFactors() - - self._inflation_rates = [ - np.round(rate + cpi_offset[self.start_year + ix], 4) - for ix, rate in enumerate( - self._gfactors.price_inflation_rates( - self.start_year, self.end_year - ) - ) - ] - self._wage_growth_rates = self._gfactors.wage_growth_rates( - self.start_year, self.end_year + syr, self.end_year ) diff --git a/taxcalc/taxcalcio.py b/taxcalc/taxcalcio.py index 2ead655e2..963731c13 100644 --- a/taxcalc/taxcalcio.py +++ b/taxcalc/taxcalcio.py @@ -68,6 +68,7 @@ def __init__(self, input_data, tax_year, baseline, reform, assump, outdir=None): # pylint: disable=too-many-arguments,too-many-locals # pylint: disable=too-many-branches,too-many-statements + self.gf_reform = None self.errmsg = '' # check name and existence of INPUT file inp = 'x' @@ -288,6 +289,7 @@ def init(self, input_data, tax_year, baseline, reform, assump, gfactors_ref = GrowFactors() gdiff_baseline.apply_to(gfactors_ref) gdiff_response.apply_to(gfactors_ref) + self.gf_reform = copy.deepcopy(gfactors_ref) # create Policy objects: # ... the baseline Policy object base = Policy(gfactors=gfactors_base) @@ -571,10 +573,13 @@ def write_doc_file(self): Write reform documentation to text file. """ if len(self.policy_dicts) <= 1: - doc = Calculator.reform_documentation(self.param_dict) + doc = Calculator.reform_documentation( + self.param_dict, self.gf_reform + ) else: - doc = Calculator.reform_documentation(self.param_dict, - self.policy_dicts[1:]) + doc = Calculator.reform_documentation( + self.param_dict, self.gf_reform, self.policy_dicts[1:] + ) doc_fname = self._output_filename.replace('.csv', '-doc.text') with open(doc_fname, 'w', encoding='utf-8') as dfile: dfile.write(doc) diff --git a/taxcalc/tests/test_calculator.py b/taxcalc/tests/test_calculator.py index c9f2cb743..ac2e18004 100644 --- a/taxcalc/tests/test_calculator.py +++ b/taxcalc/tests/test_calculator.py @@ -13,7 +13,7 @@ import pytest import numpy as np import pandas as pd -from taxcalc import Policy, Records, Calculator, Consumption +from taxcalc import GrowFactors, Policy, Records, Calculator, Consumption def test_make_calculator(cps_subsample): @@ -568,7 +568,8 @@ def test_noreform_documentation(): """ params = Calculator.read_json_param_objects(reform_json, assump_json) assert isinstance(params, dict) - actual_doc = Calculator.reform_documentation(params) + gfs = GrowFactors() + actual_doc = Calculator.reform_documentation(params, gfs) expected_doc = ( 'REFORM DOCUMENTATION\n' 'Baseline Growth-Difference Assumption Values by Year:\n' @@ -623,7 +624,8 @@ def test_reform_documentation(): 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]) + gfs = GrowFactors() + doc = Calculator.reform_documentation(params, gfs, [second_reform]) assert isinstance(doc, str) dump = False # set to True to print documentation and force test failure if dump: diff --git a/taxcalc/tests/test_parameters.py b/taxcalc/tests/test_parameters.py index ef445e1cd..b72fe8256 100644 --- a/taxcalc/tests/test_parameters.py +++ b/taxcalc/tests/test_parameters.py @@ -18,10 +18,10 @@ Parameters, Policy, Consumption, + GrowDiff, GrowFactors, is_paramtools_format, ) -from taxcalc.growdiff import GrowDiff # Test specification and use of simple Parameters-derived class that has @@ -244,7 +244,7 @@ def test_json_file_contents(tests_path, fname): elif fname == "growdiff.json": o = GrowDiff() param_list = [] - for k in o: + for k in o: if k[0].isupper(): # find parameters by case of first letter param_list.append(k) for param in param_list: @@ -395,6 +395,7 @@ def __init__(self, **kwargs): ArrayParams.NUM_YEARS, **kwargs ) + self._gfactors = GrowFactors() self._inflation_rates = [0.02] * self.num_years self._wage_growth_rates = [0.03] * self.num_years