taxcalc 4.2.1__py3-none-any.whl → 4.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- taxcalc/__init__.py +1 -1
- taxcalc/assumptions/ASSUMPTIONS.md +53 -0
- taxcalc/assumptions/README.md +17 -0
- taxcalc/assumptions/economic_assumptions_template.json +77 -0
- taxcalc/calcfunctions.py +7 -4
- taxcalc/data.py +10 -5
- taxcalc/policy.py +1 -1
- taxcalc/policy_current_law.json +4649 -288
- taxcalc/records.py +20 -15
- taxcalc/reforms/2017_law.json +125 -0
- taxcalc/reforms/2017_law.out.csv +10 -0
- taxcalc/reforms/ARPA.json +78 -0
- taxcalc/reforms/ARPA.out.csv +10 -0
- taxcalc/reforms/BrownKhanna.json +23 -0
- taxcalc/reforms/BrownKhanna.out.csv +10 -0
- taxcalc/reforms/CARES.json +40 -0
- taxcalc/reforms/CARES.out.csv +10 -0
- taxcalc/reforms/ConsolidatedAppropriationsAct2021.json +15 -0
- taxcalc/reforms/ConsolidatedAppropriationsAct2021.out.csv +10 -0
- taxcalc/reforms/Larson2019.json +36 -0
- taxcalc/reforms/Larson2019.out.csv +10 -0
- taxcalc/reforms/README.md +22 -0
- taxcalc/reforms/REFORMS.md +92 -0
- taxcalc/reforms/Renacci.json +61 -0
- taxcalc/reforms/Renacci.out.csv +10 -0
- taxcalc/reforms/SandersDeFazio.json +15 -0
- taxcalc/reforms/SandersDeFazio.out.csv +10 -0
- taxcalc/reforms/TCJA.json +160 -0
- taxcalc/reforms/TCJA.md +48 -0
- taxcalc/reforms/TCJA.out.csv +10 -0
- taxcalc/reforms/Trump2016.json +71 -0
- taxcalc/reforms/Trump2016.out.csv +10 -0
- taxcalc/reforms/Trump2017.json +51 -0
- taxcalc/reforms/Trump2017.out.csv +10 -0
- taxcalc/reforms/archive/Clinton2016.json +56 -0
- taxcalc/reforms/archive/RyanBrady.json +104 -0
- taxcalc/reforms/archive/TCJA_House.json +144 -0
- taxcalc/reforms/archive/TCJA_House_Amended.json +152 -0
- taxcalc/reforms/archive/TCJA_Reconciliation.json +187 -0
- taxcalc/reforms/archive/TCJA_Senate.json +116 -0
- taxcalc/reforms/archive/TCJA_Senate_111417.json +169 -0
- taxcalc/reforms/archive/TCJA_Senate_120117.json +174 -0
- taxcalc/reforms/cases.csv +10 -0
- taxcalc/reforms/clp.out.csv +10 -0
- taxcalc/reforms/ext.json +59 -0
- taxcalc/reforms/growfactors_ext.csv +65 -0
- taxcalc/reforms/ptaxes0.json +37 -0
- taxcalc/reforms/ptaxes0.out.csv +10 -0
- taxcalc/reforms/ptaxes1.json +21 -0
- taxcalc/reforms/ptaxes1.out.csv +10 -0
- taxcalc/reforms/ptaxes2.json +18 -0
- taxcalc/reforms/ptaxes2.out.csv +10 -0
- taxcalc/reforms/ptaxes3.json +28 -0
- taxcalc/reforms/ptaxes3.out.csv +10 -0
- taxcalc/taxcalcio.py +44 -22
- taxcalc/tests/benefits_expect.csv +169 -0
- taxcalc/tests/cmpi_cps_expect.txt +132 -0
- taxcalc/tests/cmpi_puf_expect.txt +132 -0
- taxcalc/tests/conftest.py +143 -0
- taxcalc/tests/cpscsv_agg_expect.csv +26 -0
- taxcalc/tests/puf_var_correl_coeffs_2016.csv +80 -0
- taxcalc/tests/puf_var_wght_means_by_year.csv +80 -0
- taxcalc/tests/pufcsv_agg_expect.csv +26 -0
- taxcalc/tests/pufcsv_mtr_expect.txt +63 -0
- taxcalc/tests/reforms.json +649 -0
- taxcalc/tests/reforms_expect.csv +65 -0
- taxcalc/tests/test_4package.py +67 -0
- taxcalc/tests/test_benefits.py +86 -0
- taxcalc/tests/test_calcfunctions.py +871 -0
- taxcalc/tests/test_calculator.py +1021 -0
- taxcalc/tests/test_compare.py +336 -0
- taxcalc/tests/test_compatible_data.py +338 -0
- taxcalc/tests/test_consumption.py +144 -0
- taxcalc/tests/test_cpscsv.py +163 -0
- taxcalc/tests/test_data.py +133 -0
- taxcalc/tests/test_decorators.py +332 -0
- taxcalc/tests/test_growdiff.py +102 -0
- taxcalc/tests/test_growfactors.py +94 -0
- taxcalc/tests/test_parameters.py +617 -0
- taxcalc/tests/test_policy.py +1557 -0
- taxcalc/tests/test_puf_var_stats.py +194 -0
- taxcalc/tests/test_pufcsv.py +385 -0
- taxcalc/tests/test_records.py +234 -0
- taxcalc/tests/test_reforms.py +386 -0
- taxcalc/tests/test_responses.py +41 -0
- taxcalc/tests/test_taxcalcio.py +755 -0
- taxcalc/tests/test_utils.py +792 -0
- taxcalc/validation/CSV_INPUT_VARS.md +29 -0
- taxcalc/validation/CSV_OUTPUT_VARS.md +63 -0
- taxcalc/validation/README.md +68 -0
- taxcalc/validation/taxsim35/Differences_Explained.md +54 -0
- taxcalc/validation/taxsim35/README.md +139 -0
- taxcalc/validation/taxsim35/expected_differences/a17-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/a18-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/a19-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/a20-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/a21-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b17-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b18-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b19-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b20-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b21-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/c17-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/c18-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/c19-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/input_setup.py +67 -0
- taxcalc/validation/taxsim35/main_comparison.py +183 -0
- taxcalc/validation/taxsim35/prepare_taxcalc_input.py +161 -0
- taxcalc/validation/taxsim35/process_taxcalc_output.py +140 -0
- taxcalc/validation/taxsim35/taxsim_emulation.json +49 -0
- taxcalc/validation/taxsim35/taxsim_input.py +321 -0
- taxcalc/validation/taxsim35/tc_sims.py +98 -0
- taxcalc/validation/taxsim35/tests_35.py +80 -0
- taxcalc/validation/tests_35.sh +13 -0
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/METADATA +3 -4
- taxcalc-4.3.0.dist-info/RECORD +139 -0
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/WHEEL +1 -1
- taxcalc/tmd_growfactors.csv +0 -55
- taxcalc/tmd_weights.csv.gz +0 -0
- taxcalc-4.2.1.dist-info/RECORD +0 -34
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/LICENSE +0 -0
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/entry_points.txt +0 -0
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,332 @@
|
|
1
|
+
# CODING-STYLE CHECKS:
|
2
|
+
# pycodestyle test_decorators.py
|
3
|
+
|
4
|
+
import os
|
5
|
+
import sys
|
6
|
+
import pytest
|
7
|
+
import importlib
|
8
|
+
import numpy as np
|
9
|
+
from pandas import DataFrame
|
10
|
+
from pandas.testing import assert_frame_equal
|
11
|
+
import taxcalc
|
12
|
+
from taxcalc.decorators import *
|
13
|
+
|
14
|
+
|
15
|
+
def test_create_apply_function_string():
|
16
|
+
ans = create_apply_function_string(['a', 'b', 'c'], ['d', 'e'], [])
|
17
|
+
exp = ("def ap_func(x_0,x_1,x_2,x_3,x_4):\n"
|
18
|
+
" for i in range(len(x_0)):\n"
|
19
|
+
" x_0[i],x_1[i],x_2[i] = jitted_f(x_3[i],x_4[i])\n"
|
20
|
+
" return x_0,x_1,x_2\n")
|
21
|
+
assert ans == exp
|
22
|
+
|
23
|
+
|
24
|
+
def test_create_apply_function_string_with_params():
|
25
|
+
ans = create_apply_function_string(['a', 'b', 'c'], ['d', 'e'], ['d'])
|
26
|
+
exp = ("def ap_func(x_0,x_1,x_2,x_3,x_4):\n"
|
27
|
+
" for i in range(len(x_0)):\n"
|
28
|
+
" x_0[i],x_1[i],x_2[i] = jitted_f(x_3,x_4[i])\n"
|
29
|
+
" return x_0,x_1,x_2\n")
|
30
|
+
assert ans == exp
|
31
|
+
|
32
|
+
|
33
|
+
def test_create_toplevel_function_string_mult_outputs():
|
34
|
+
ans = create_toplevel_function_string(['a', 'b'], ['d', 'e'],
|
35
|
+
['pm', 'pm', 'pf', 'pm'])
|
36
|
+
exp = ''
|
37
|
+
exp = ("def hl_func(pm, pf):\n"
|
38
|
+
" from pandas import DataFrame\n"
|
39
|
+
" import numpy as np\n"
|
40
|
+
" import pandas as pd\n"
|
41
|
+
" def get_values(x):\n"
|
42
|
+
" if isinstance(x, pd.Series):\n"
|
43
|
+
" return x.values\n"
|
44
|
+
" else:\n"
|
45
|
+
" return x\n"
|
46
|
+
" outputs = \\\n"
|
47
|
+
" (pm.a, pm.b) = \\\n"
|
48
|
+
" applied_f(get_values(pm.a[0]), get_values(pm.b[0]), "
|
49
|
+
"get_values(pf.d), get_values(pm.e[0]), )\n"
|
50
|
+
" header = ['a', 'b']\n"
|
51
|
+
" return DataFrame(data=np.column_stack(outputs),"
|
52
|
+
"columns=header)")
|
53
|
+
|
54
|
+
assert ans == exp
|
55
|
+
|
56
|
+
|
57
|
+
def test_create_toplevel_function_string():
|
58
|
+
ans = create_toplevel_function_string(['a'], ['d', 'e'],
|
59
|
+
['pm', 'pf', 'pm'])
|
60
|
+
exp = ''
|
61
|
+
exp = ("def hl_func(pm, pf):\n"
|
62
|
+
" from pandas import DataFrame\n"
|
63
|
+
" import numpy as np\n"
|
64
|
+
" import pandas as pd\n"
|
65
|
+
" def get_values(x):\n"
|
66
|
+
" if isinstance(x, pd.Series):\n"
|
67
|
+
" return x.values\n"
|
68
|
+
" else:\n"
|
69
|
+
" return x\n"
|
70
|
+
" outputs = \\\n"
|
71
|
+
" (pm.a) = \\\n"
|
72
|
+
" applied_f(get_values(pm.a[0]), get_values(pf.d), "
|
73
|
+
"get_values(pm.e[0]), )\n"
|
74
|
+
" header = ['a']\n"
|
75
|
+
" return DataFrame(data=outputs,"
|
76
|
+
"columns=header)")
|
77
|
+
assert ans == exp
|
78
|
+
|
79
|
+
|
80
|
+
def some_calc(x, y, z):
|
81
|
+
a = x + y
|
82
|
+
b = x + y + z
|
83
|
+
return (a, b)
|
84
|
+
|
85
|
+
|
86
|
+
def test_make_apply_function():
|
87
|
+
ans_do_jit = make_apply_function(some_calc, ['a', 'b'], ['x', 'y', 'z'],
|
88
|
+
[], do_jit=True, no_python=True)
|
89
|
+
assert ans_do_jit
|
90
|
+
ans_no_jit = make_apply_function(some_calc, ['a', 'b'], ['x', 'y', 'z'],
|
91
|
+
[], do_jit=False, no_python=True)
|
92
|
+
assert ans_no_jit
|
93
|
+
|
94
|
+
|
95
|
+
@apply_jit(["a", "b"], ["x", "y", "z"], nopython=True)
|
96
|
+
def Magic_calc(x, y, z):
|
97
|
+
a = x + y
|
98
|
+
b = x + y + z
|
99
|
+
return (a, b)
|
100
|
+
|
101
|
+
|
102
|
+
def Magic(pm, pf):
|
103
|
+
# Adjustments
|
104
|
+
outputs = pf.a, pf.b = Magic_calc(pm, pf)
|
105
|
+
header = ['a', 'b']
|
106
|
+
return DataFrame(data=np.column_stack(outputs), columns=header)
|
107
|
+
|
108
|
+
|
109
|
+
@iterate_jit(nopython=True)
|
110
|
+
def Magic_calc2(x, y, z):
|
111
|
+
a = x + y
|
112
|
+
b = x + y + z
|
113
|
+
return (a, b)
|
114
|
+
|
115
|
+
|
116
|
+
class Foo(object):
|
117
|
+
pass
|
118
|
+
|
119
|
+
|
120
|
+
@iterate_jit(nopython=True)
|
121
|
+
def faux_function(MARS):
|
122
|
+
if MARS == 1:
|
123
|
+
var = 2
|
124
|
+
else:
|
125
|
+
var = 1
|
126
|
+
return var
|
127
|
+
|
128
|
+
|
129
|
+
@iterate_jit(nopython=True)
|
130
|
+
def ret_everything(a, b, c, d, e, f):
|
131
|
+
|
132
|
+
c = a + b
|
133
|
+
d = a + b
|
134
|
+
e = a + b
|
135
|
+
f = a + b
|
136
|
+
|
137
|
+
return (c, d, e,
|
138
|
+
f)
|
139
|
+
|
140
|
+
|
141
|
+
def test_magic_apply_jit():
|
142
|
+
pm = Foo()
|
143
|
+
pf = Foo()
|
144
|
+
pm.a = np.ones((5,))
|
145
|
+
pm.b = np.ones((5,))
|
146
|
+
pf.x = np.ones((5,))
|
147
|
+
pf.y = np.ones((5,))
|
148
|
+
pf.z = np.ones((5,))
|
149
|
+
xx = Magic(pm, pf)
|
150
|
+
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=["a", "b"])
|
151
|
+
assert_frame_equal(xx, exp)
|
152
|
+
|
153
|
+
|
154
|
+
def test_magic_apply_jit_swap():
|
155
|
+
pm = Foo()
|
156
|
+
pf = Foo()
|
157
|
+
pm.a = np.ones((5,))
|
158
|
+
pm.b = np.ones((5,))
|
159
|
+
pf.x = np.ones((5,))
|
160
|
+
pf.y = np.ones((5,))
|
161
|
+
pf.z = np.ones((5,))
|
162
|
+
xx = Magic(pf, pm)
|
163
|
+
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=["a", "b"])
|
164
|
+
assert_frame_equal(xx, exp)
|
165
|
+
|
166
|
+
|
167
|
+
def test_magic_iterate_jit():
|
168
|
+
pm = Foo()
|
169
|
+
pf = Foo()
|
170
|
+
pm.a = np.ones((1, 5))
|
171
|
+
pm.b = np.ones((1, 5))
|
172
|
+
pf.x = np.ones((5,))
|
173
|
+
pf.y = np.ones((5,))
|
174
|
+
pf.z = np.ones((5,))
|
175
|
+
xx = Magic_calc2(pm, pf)
|
176
|
+
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=["a", "b"])
|
177
|
+
assert_frame_equal(xx, exp)
|
178
|
+
|
179
|
+
|
180
|
+
def test_faux_function_iterate_jit():
|
181
|
+
pm = Foo()
|
182
|
+
pf = Foo()
|
183
|
+
pf.MARS = np.ones((5,))
|
184
|
+
pf.var = np.ones((5,))
|
185
|
+
ans = faux_function(pm, pf)
|
186
|
+
exp = DataFrame(data=[2.0] * 5, columns=['var'])
|
187
|
+
assert_frame_equal(ans, exp)
|
188
|
+
|
189
|
+
|
190
|
+
def test_ret_everything_iterate_jit():
|
191
|
+
pm = Foo()
|
192
|
+
pf = Foo()
|
193
|
+
pf.a = np.ones((5,))
|
194
|
+
pf.b = np.ones((5,))
|
195
|
+
pf.c = np.ones((5,))
|
196
|
+
pf.d = np.ones((5,))
|
197
|
+
pf.e = np.ones((5,))
|
198
|
+
pf.f = np.ones((5,))
|
199
|
+
ans = ret_everything(pm, pf)
|
200
|
+
exp = DataFrame(data=[[2.0, 2.0, 2.0, 2.0]] * 5,
|
201
|
+
columns=["c", "d", "e", "f"])
|
202
|
+
assert_frame_equal(ans, exp)
|
203
|
+
|
204
|
+
|
205
|
+
@iterate_jit(nopython=True)
|
206
|
+
def Magic_calc3(x, y, z):
|
207
|
+
a = x + y
|
208
|
+
b = a + z
|
209
|
+
return (a, b)
|
210
|
+
|
211
|
+
|
212
|
+
def test_function_takes_kwarg():
|
213
|
+
pm = Foo()
|
214
|
+
pf = Foo()
|
215
|
+
pm.a = np.ones((1, 5))
|
216
|
+
pm.b = np.ones((1, 5))
|
217
|
+
pf.x = np.ones((5,))
|
218
|
+
pf.y = np.ones((5,))
|
219
|
+
pf.z = np.ones((5,))
|
220
|
+
ans = Magic_calc3(pm, pf)
|
221
|
+
exp = DataFrame(data=[[2.0, 3.0]] * 5,
|
222
|
+
columns=["a", "b"])
|
223
|
+
assert_frame_equal(ans, exp)
|
224
|
+
|
225
|
+
|
226
|
+
@iterate_jit(nopython=True)
|
227
|
+
def Magic_calc4(x, y, z):
|
228
|
+
a = x + y
|
229
|
+
b = a + z
|
230
|
+
return (a, b)
|
231
|
+
|
232
|
+
|
233
|
+
def test_function_no_parameters_listed():
|
234
|
+
pm = Foo()
|
235
|
+
pf = Foo()
|
236
|
+
pm.a = np.ones((1, 5))
|
237
|
+
pm.b = np.ones((1, 5))
|
238
|
+
pf.x = np.ones((5,))
|
239
|
+
pf.y = np.ones((5,))
|
240
|
+
pf.z = np.ones((5,))
|
241
|
+
ans = Magic_calc4(pm, pf)
|
242
|
+
exp = DataFrame(data=[[2.0, 3.0]] * 5,
|
243
|
+
columns=["a", "b"])
|
244
|
+
assert_frame_equal(ans, exp)
|
245
|
+
|
246
|
+
|
247
|
+
@iterate_jit(parameters=['w'], nopython=True)
|
248
|
+
def Magic_calc5(w, x, y, z):
|
249
|
+
a = x + y
|
250
|
+
b = w[0] + x + y + z
|
251
|
+
return (a, b)
|
252
|
+
|
253
|
+
|
254
|
+
def test_function_parameters_optional():
|
255
|
+
pm = Foo()
|
256
|
+
pf = Foo()
|
257
|
+
pm.a = np.ones((1, 5))
|
258
|
+
pm.b = np.ones((1, 5))
|
259
|
+
pm.w = np.ones((1, 5))
|
260
|
+
pf.x = np.ones((5,))
|
261
|
+
pf.y = np.ones((5,))
|
262
|
+
pf.z = np.ones((5,))
|
263
|
+
ans = Magic_calc5(pm, pf)
|
264
|
+
exp = DataFrame(data=[[2.0, 4.0]] * 5,
|
265
|
+
columns=["a", "b"])
|
266
|
+
assert_frame_equal(ans, exp)
|
267
|
+
|
268
|
+
|
269
|
+
def unjittable_function1(w, x, y, z):
|
270
|
+
a = x + y
|
271
|
+
b = w[0] + x + y + z
|
272
|
+
|
273
|
+
|
274
|
+
def unjittable_function2(w, x, y, z):
|
275
|
+
a = x + y
|
276
|
+
b = w[0] + x + y + z
|
277
|
+
return (a, b, c)
|
278
|
+
|
279
|
+
|
280
|
+
def test_iterate_jit_raises_on_no_return():
|
281
|
+
with pytest.raises(ValueError):
|
282
|
+
ij = iterate_jit(parameters=['w'], nopython=True)
|
283
|
+
ij(unjittable_function1)
|
284
|
+
|
285
|
+
|
286
|
+
def test_iterate_jit_raises_on_unknown_return_argument():
|
287
|
+
ij = iterate_jit(parameters=['w'], nopython=True)
|
288
|
+
uf2 = ij(unjittable_function2)
|
289
|
+
pm = Foo()
|
290
|
+
pf = Foo()
|
291
|
+
pm.a = np.ones((1, 5))
|
292
|
+
pm.b = np.ones((1, 5))
|
293
|
+
pm.w = np.ones((1, 5))
|
294
|
+
pf.x = np.ones((5,))
|
295
|
+
pf.y = np.ones((5,))
|
296
|
+
pf.z = np.ones((5,))
|
297
|
+
with pytest.raises(AttributeError):
|
298
|
+
ans = uf2(pm, pf)
|
299
|
+
|
300
|
+
|
301
|
+
def Magic_calc6(w, x, y, z):
|
302
|
+
a = x + y
|
303
|
+
b = w[0] + x + y + z
|
304
|
+
return (a, b)
|
305
|
+
|
306
|
+
|
307
|
+
def test_force_no_jit():
|
308
|
+
"""
|
309
|
+
Force execution of code for "DO_JIT = False", which tests the
|
310
|
+
id_wrapper function in the decorators.py file.
|
311
|
+
"""
|
312
|
+
# set environment variable that turns off JIT decorator logic
|
313
|
+
os.environ['NOTAXCALCJIT'] = 'NOJIT'
|
314
|
+
# reload the decorators module
|
315
|
+
importlib.reload(taxcalc.decorators)
|
316
|
+
# verify Magic_calc6 function works as expected
|
317
|
+
Magic_calc6_ = iterate_jit(parameters=['w'], nopython=True)(Magic_calc6)
|
318
|
+
pm = Foo()
|
319
|
+
pf = Foo()
|
320
|
+
pm.a = np.ones((1, 5))
|
321
|
+
pm.b = np.ones((1, 5))
|
322
|
+
pm.w = np.ones((1, 5))
|
323
|
+
pf.x = np.ones((5,))
|
324
|
+
pf.y = np.ones((5,))
|
325
|
+
pf.z = np.ones((5,))
|
326
|
+
ans = Magic_calc6_(pm, pf)
|
327
|
+
exp = DataFrame(data=[[2.0, 4.0]] * 5,
|
328
|
+
columns=["a", "b"])
|
329
|
+
assert_frame_equal(ans, exp)
|
330
|
+
# restore normal JIT operation of decorators module
|
331
|
+
del os.environ['NOTAXCALCJIT']
|
332
|
+
importlib.reload(taxcalc.decorators)
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# CODING-STYLE CHECKS:
|
2
|
+
# pycodestyle test_growdiff.py
|
3
|
+
|
4
|
+
import os
|
5
|
+
import json
|
6
|
+
import numpy as np
|
7
|
+
import pytest
|
8
|
+
from taxcalc import GrowDiff, GrowFactors, Policy
|
9
|
+
|
10
|
+
|
11
|
+
def test_year_consistency():
|
12
|
+
assert GrowDiff.JSON_START_YEAR == Policy.JSON_START_YEAR
|
13
|
+
assert GrowDiff.DEFAULT_NUM_YEARS == Policy.DEFAULT_NUM_YEARS
|
14
|
+
|
15
|
+
|
16
|
+
def test_update_and_apply_growdiff():
|
17
|
+
gdiff = GrowDiff()
|
18
|
+
# update GrowDiff instance
|
19
|
+
diffs = {
|
20
|
+
'AWAGE': {2014: 0.01,
|
21
|
+
2016: 0.02}
|
22
|
+
}
|
23
|
+
gdiff.update_growdiff(diffs)
|
24
|
+
expected_wage_diffs = [0.00, 0.01, 0.01, 0.02, 0.02]
|
25
|
+
extra_years = GrowDiff.DEFAULT_NUM_YEARS - len(expected_wage_diffs)
|
26
|
+
expected_wage_diffs.extend([0.02] * extra_years)
|
27
|
+
assert np.allclose(gdiff._AWAGE, expected_wage_diffs, atol=0.0, rtol=0.0)
|
28
|
+
# apply growdiff to GrowFactors instance
|
29
|
+
gf = GrowFactors()
|
30
|
+
syr = GrowDiff.JSON_START_YEAR
|
31
|
+
nyrs = GrowDiff.DEFAULT_NUM_YEARS
|
32
|
+
lyr = syr + nyrs - 1
|
33
|
+
pir_pre = gf.price_inflation_rates(syr, lyr)
|
34
|
+
wgr_pre = gf.wage_growth_rates(syr, lyr)
|
35
|
+
gfactors = GrowFactors()
|
36
|
+
gdiff.apply_to(gfactors)
|
37
|
+
pir_pst = gfactors.price_inflation_rates(syr, lyr)
|
38
|
+
wgr_pst = gfactors.wage_growth_rates(syr, lyr)
|
39
|
+
expected_wgr_pst = [wgr_pre[i] + expected_wage_diffs[i]
|
40
|
+
for i in range(0, nyrs)]
|
41
|
+
assert np.allclose(pir_pre, pir_pst, atol=0.0, rtol=0.0)
|
42
|
+
assert np.allclose(wgr_pst, expected_wgr_pst, atol=1.0e-9, rtol=0.0)
|
43
|
+
|
44
|
+
|
45
|
+
def test_has_any_response():
|
46
|
+
start_year = GrowDiff.JSON_START_YEAR
|
47
|
+
gdiff = GrowDiff()
|
48
|
+
assert gdiff.current_year == start_year
|
49
|
+
assert gdiff.has_any_response() is False
|
50
|
+
gdiff.update_growdiff({'AWAGE': {2020: 0.01}})
|
51
|
+
assert gdiff.current_year == start_year
|
52
|
+
assert gdiff.has_any_response() is True
|
53
|
+
|
54
|
+
|
55
|
+
def test_description_punctuation(tests_path):
|
56
|
+
"""
|
57
|
+
Check that each description ends in a period.
|
58
|
+
"""
|
59
|
+
# read JSON file into a dictionary
|
60
|
+
path = os.path.join(tests_path, '..', 'growdiff.json')
|
61
|
+
with open(path, 'r') as jsonfile:
|
62
|
+
dct = json.load(jsonfile)
|
63
|
+
all_desc_ok = True
|
64
|
+
for param in dct.keys():
|
65
|
+
if param == "schema":
|
66
|
+
continue
|
67
|
+
if not dct[param]['description'].endswith('.'):
|
68
|
+
all_desc_ok = False
|
69
|
+
print('param,description=',
|
70
|
+
str(param),
|
71
|
+
dct[param]['description'])
|
72
|
+
assert all_desc_ok
|
73
|
+
|
74
|
+
|
75
|
+
def test_boolean_value_infomation(tests_path):
|
76
|
+
"""
|
77
|
+
Check consistency of boolean_value in growdiff.json file.
|
78
|
+
"""
|
79
|
+
# read growdiff.json file into a dictionary
|
80
|
+
path = os.path.join(tests_path, '..', 'growdiff.json')
|
81
|
+
with open(path, 'r') as gddfile:
|
82
|
+
gdd = json.load(gddfile)
|
83
|
+
for param in gdd.keys():
|
84
|
+
if param == "schema":
|
85
|
+
continue
|
86
|
+
val = gdd[param]['value']
|
87
|
+
if isinstance(val, list):
|
88
|
+
val = val[0]
|
89
|
+
if isinstance(val, list):
|
90
|
+
val = val[0]
|
91
|
+
valstr = str(val)
|
92
|
+
if valstr == 'True' or valstr == 'False':
|
93
|
+
val_is_boolean = True
|
94
|
+
else:
|
95
|
+
val_is_boolean = False
|
96
|
+
type_is_boolean = gdd[param]['type'] == 'bool'
|
97
|
+
if val_is_boolean and not type_is_boolean:
|
98
|
+
print('param,value_type,val,val_is_boolean=',
|
99
|
+
str(param),
|
100
|
+
gdd[param]['value_type'],
|
101
|
+
val,
|
102
|
+
val_is_boolean)
|
@@ -0,0 +1,94 @@
|
|
1
|
+
"""
|
2
|
+
Tests of Tax-Calculator GrowFactors class.
|
3
|
+
"""
|
4
|
+
# CODING-STYLE CHECKS:
|
5
|
+
# pycodestyle test_growfactors.py
|
6
|
+
# pylint --disable=locally-disabled test_growfactors.py
|
7
|
+
|
8
|
+
import os
|
9
|
+
import tempfile
|
10
|
+
import pytest
|
11
|
+
# pylint: disable=import-error
|
12
|
+
from taxcalc import GrowFactors, Records, Policy
|
13
|
+
|
14
|
+
|
15
|
+
@pytest.fixture(scope='module', name='bad_gf_file')
|
16
|
+
def fixture_bad_gf_file():
|
17
|
+
"""
|
18
|
+
Fixture for invalid growfactors file.
|
19
|
+
"""
|
20
|
+
txt = (u'YEAR,AWAGE,ACPIU,ABADNAME,ASOCSEC\n'
|
21
|
+
u'2015,1.000,1.000,1.000000,1.00000\n')
|
22
|
+
tfile = tempfile.NamedTemporaryFile(mode='a', delete=False)
|
23
|
+
tfile.write(txt)
|
24
|
+
tfile.close()
|
25
|
+
yield tfile
|
26
|
+
os.remove(tfile.name)
|
27
|
+
|
28
|
+
|
29
|
+
def test_improper_usage(bad_gf_file):
|
30
|
+
"""
|
31
|
+
Tests of improper usage of GrowFactors object.
|
32
|
+
"""
|
33
|
+
with pytest.raises(ValueError):
|
34
|
+
gfo = GrowFactors(dict())
|
35
|
+
with pytest.raises(ValueError):
|
36
|
+
gfo = GrowFactors('non_existent_file.csv')
|
37
|
+
with pytest.raises(ValueError):
|
38
|
+
gfo = GrowFactors(bad_gf_file.name)
|
39
|
+
gfo = GrowFactors()
|
40
|
+
fyr = gfo.first_year
|
41
|
+
lyr = gfo.last_year
|
42
|
+
with pytest.raises(ValueError):
|
43
|
+
gfo.price_inflation_rates(fyr - 1, lyr)
|
44
|
+
with pytest.raises(ValueError):
|
45
|
+
gfo.price_inflation_rates(fyr, lyr + 1)
|
46
|
+
with pytest.raises(ValueError):
|
47
|
+
gfo.price_inflation_rates(lyr, fyr)
|
48
|
+
with pytest.raises(ValueError):
|
49
|
+
gfo.wage_growth_rates(fyr - 1, lyr)
|
50
|
+
with pytest.raises(ValueError):
|
51
|
+
gfo.wage_growth_rates(fyr, lyr + 1)
|
52
|
+
with pytest.raises(ValueError):
|
53
|
+
gfo.wage_growth_rates(lyr, fyr)
|
54
|
+
with pytest.raises(ValueError):
|
55
|
+
gfo.factor_value('BADNAME', fyr)
|
56
|
+
with pytest.raises(ValueError):
|
57
|
+
gfo.factor_value('AWAGE', fyr - 1)
|
58
|
+
with pytest.raises(ValueError):
|
59
|
+
gfo.factor_value('AWAGE', lyr + 1)
|
60
|
+
|
61
|
+
|
62
|
+
def test_update_after_use():
|
63
|
+
"""
|
64
|
+
Test of improper update after GrowFactors object has been used.
|
65
|
+
"""
|
66
|
+
gfo = GrowFactors()
|
67
|
+
gfo.price_inflation_rates(gfo.first_year, gfo.last_year)
|
68
|
+
with pytest.raises(ValueError):
|
69
|
+
gfo.update('AWAGE', 2013, 0.01)
|
70
|
+
|
71
|
+
|
72
|
+
def test_proper_usage():
|
73
|
+
"""
|
74
|
+
Test proper usage of GrowFactors object.
|
75
|
+
"""
|
76
|
+
gfo = GrowFactors()
|
77
|
+
pir = gfo.price_inflation_rates(2013, 2020)
|
78
|
+
assert len(pir) == 8
|
79
|
+
wgr = gfo.wage_growth_rates(2013, 2021)
|
80
|
+
assert len(wgr) == 9
|
81
|
+
val = gfo.factor_value('AWAGE', 2013)
|
82
|
+
assert val > 1.0
|
83
|
+
|
84
|
+
|
85
|
+
def test_growfactors_csv_values():
|
86
|
+
"""
|
87
|
+
Test numerical contents of growfactors.csv file.
|
88
|
+
"""
|
89
|
+
gfo = GrowFactors()
|
90
|
+
min_data_year = min(Records.PUFCSV_YEAR, Records.CPSCSV_YEAR)
|
91
|
+
if min_data_year < Policy.JSON_START_YEAR:
|
92
|
+
for gfname in GrowFactors.VALID_NAMES:
|
93
|
+
val = gfo.factor_value(gfname, min_data_year)
|
94
|
+
assert val == 1
|