-
-
Notifications
You must be signed in to change notification settings - Fork 160
/
policy.py
179 lines (161 loc) · 6.74 KB
/
policy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
"""
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
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',
# 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."
),
# 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 | GrowFactors): # 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.
"""
if isinstance(growfactors, Path):
growfactors = GrowFactors(growfactors_filename=str(growfactors))
else:
assert isinstance(growfactors, GrowFactors)
return Policy(gfactors=growfactors)
@staticmethod
def read_json_reform(obj):
"""
Return a reform dictionary suitable for use with implement_reform
method generated from the specified JSON object, which can be None or
a string containing a local filename, a URL beginning with 'http'
pointing to a valid JSON file hosted online, or a valid JSON text.
"""
return Parameters._read_json_revision(obj, 'policy')
def implement_reform(self, reform,
print_warnings=True, raise_errors=True):
"""
Implement reform using Tax-Calculator syled reforms/adjustments. Users
may also use the adjust method with ParamTools styled reforms.
"""
# need to do conversion:
return self._update(reform, print_warnings, raise_errors)
@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"]
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
)