Source code for taxcalc.policy
"""
Tax-Calculator federal tax policy Policy class.
"""
# CODING-STYLE CHECKS:
# pycodestyle policy.py
# pylint --disable=locally-disabled policy.py
import os
import json
from pathlib import Path
import numpy as np
from taxcalc.parameters import Parameters
from taxcalc.growfactors import GrowFactors
[docs]
class Policy(Parameters):
"""
Policy is a subclass of the abstract Parameters class, and
therefore, inherits its methods (none of which are shown here).
Constructor for the federal tax policy class.
Parameters
----------
gfactors: GrowFactors class instance
containing price inflation rates and wage growth rates
Raises
------
ValueError:
if gfactors is not a GrowFactors class instance or None.
Returns
-------
class instance: Policy
"""
DEFAULTS_FILE_NAME = 'policy_current_law.json'
DEFAULTS_FILE_PATH = os.path.abspath(os.path.dirname(__file__))
JSON_START_YEAR = 2013 # remains the same unless earlier data added
LAST_KNOWN_YEAR = 2025 # last year for which indexed param vals are known
# should increase LAST_KNOWN_YEAR by one every calendar year
LAST_BUDGET_YEAR = 2034 # last extrapolation year
# should increase LAST_BUDGET_YEAR by one every calendar year
DEFAULT_NUM_YEARS = LAST_BUDGET_YEAR - JSON_START_YEAR + 1
# NOTE: the following three data structures use internal parameter names:
# (1) specify which Policy parameters have been removed or renamed
REMOVED_PARAMS = {
# following five parameters removed in PR 2223 merged on 2019-02-06
'DependentCredit_Child_c': 'is a removed parameter name',
'DependentCredit_Nonchild_c': 'is a removed parameter name',
'DependentCredit_before_CTC': 'is a removed parameter name',
'FilerCredit_c': 'is a removed parameter name',
'ALD_InvInc_ec_base_RyanBrady': 'is a removed parameter name',
# TODO: following parameter renamed in PR 2292 merged on 2019-04-15
"cpi_offset": (
"was renamed parameter_indexing_CPI_offset. "
"See documentation for change in usage."
),
"CPI_offset": (
"was renamed parameter_indexing_CPI_offset. "
"See documentation for change in usage."
),
# TODO: following parameters renamed in PR 2345 merged on 2019-06-24
'PT_excl_rt':
'was renamed PT_qbid_rt in release 2.4.0',
'PT_excl_wagelim_thd':
'was renamed PT_qbid_taxinc_thd in release 2.4.0',
'PT_excl_wagelim_prt':
'was renamed PT_qbid_taxinc_gap in release 2.4.0',
'PT_excl_wagelim_rt':
'was renamed PT_qbid_w2_wages_rt in release 2.4.0',
'CTC_c_under5_bonus': 'was renamed CTC_c_under6_bonus.',
'ACTC_rt_bonus_under5family':
'was renamed ACTC_rt_bonus_under6family.',
'CTC_new_c_under5_bonus': 'was renamed CTC_new_c_under6_bonus.'
}
# (2) specify which Policy parameters have been redefined recently
REDEFINED_PARAMS = {}
# (3) specify which Policy parameters are wage (rather than price) indexed
WAGE_INDEXED_PARAMS = ['SS_Earnings_c', 'SS_Earnings_thd']
def __init__(self, gfactors=None, **kwargs):
# put JSON contents of DEFAULTS_FILE_NAME into self._vals dictionary
super().__init__()
# handle gfactors argument
if gfactors is None:
self._gfactors = GrowFactors()
elif isinstance(gfactors, GrowFactors):
self._gfactors = gfactors
else:
raise ValueError('gfactors is not None or a GrowFactors instance')
# read default parameters and initialize
syr = Policy.JSON_START_YEAR
nyrs = Policy.DEFAULT_NUM_YEARS
self._inflation_rates = None
self._wage_growth_rates = None
self.initialize(syr, nyrs, Policy.LAST_KNOWN_YEAR,
Policy.REMOVED_PARAMS,
Policy.REDEFINED_PARAMS,
Policy.WAGE_INDEXED_PARAMS, **kwargs)
@staticmethod
def tmd_constructor(growfactors_path): # pragma: no cover
"""
Static method returns a Policy object instantiated with TMD
input data. This convenience method works in a analogous way
to Policy(), which returns a Policy object instantiated with
non-TMD input data.
"""
assert isinstance(growfactors_path, Path)
gf_filename = str(growfactors_path)
tmd_growfactors = GrowFactors(growfactors_filename=gf_filename)
return Policy(gfactors=tmd_growfactors)
[docs]
@staticmethod
def parameter_list():
"""
Returns list of parameter names in the policy_current_law.json file.
"""
path = os.path.join(
Policy.DEFAULTS_FILE_PATH,
Policy.DEFAULTS_FILE_NAME
)
with open(path, 'r', encoding='utf-8') as f:
defaults = json.loads(f.read()) # pylint: disable=protected-access
return [k for k in defaults if k != "schema"]
[docs]
def set_rates(self):
"""Initialize taxcalc indexing data."""
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)
)
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
)