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.
Files changed (123) hide show
  1. taxcalc/__init__.py +1 -1
  2. taxcalc/assumptions/ASSUMPTIONS.md +53 -0
  3. taxcalc/assumptions/README.md +17 -0
  4. taxcalc/assumptions/economic_assumptions_template.json +77 -0
  5. taxcalc/calcfunctions.py +7 -4
  6. taxcalc/data.py +10 -5
  7. taxcalc/policy.py +1 -1
  8. taxcalc/policy_current_law.json +4649 -288
  9. taxcalc/records.py +20 -15
  10. taxcalc/reforms/2017_law.json +125 -0
  11. taxcalc/reforms/2017_law.out.csv +10 -0
  12. taxcalc/reforms/ARPA.json +78 -0
  13. taxcalc/reforms/ARPA.out.csv +10 -0
  14. taxcalc/reforms/BrownKhanna.json +23 -0
  15. taxcalc/reforms/BrownKhanna.out.csv +10 -0
  16. taxcalc/reforms/CARES.json +40 -0
  17. taxcalc/reforms/CARES.out.csv +10 -0
  18. taxcalc/reforms/ConsolidatedAppropriationsAct2021.json +15 -0
  19. taxcalc/reforms/ConsolidatedAppropriationsAct2021.out.csv +10 -0
  20. taxcalc/reforms/Larson2019.json +36 -0
  21. taxcalc/reforms/Larson2019.out.csv +10 -0
  22. taxcalc/reforms/README.md +22 -0
  23. taxcalc/reforms/REFORMS.md +92 -0
  24. taxcalc/reforms/Renacci.json +61 -0
  25. taxcalc/reforms/Renacci.out.csv +10 -0
  26. taxcalc/reforms/SandersDeFazio.json +15 -0
  27. taxcalc/reforms/SandersDeFazio.out.csv +10 -0
  28. taxcalc/reforms/TCJA.json +160 -0
  29. taxcalc/reforms/TCJA.md +48 -0
  30. taxcalc/reforms/TCJA.out.csv +10 -0
  31. taxcalc/reforms/Trump2016.json +71 -0
  32. taxcalc/reforms/Trump2016.out.csv +10 -0
  33. taxcalc/reforms/Trump2017.json +51 -0
  34. taxcalc/reforms/Trump2017.out.csv +10 -0
  35. taxcalc/reforms/archive/Clinton2016.json +56 -0
  36. taxcalc/reforms/archive/RyanBrady.json +104 -0
  37. taxcalc/reforms/archive/TCJA_House.json +144 -0
  38. taxcalc/reforms/archive/TCJA_House_Amended.json +152 -0
  39. taxcalc/reforms/archive/TCJA_Reconciliation.json +187 -0
  40. taxcalc/reforms/archive/TCJA_Senate.json +116 -0
  41. taxcalc/reforms/archive/TCJA_Senate_111417.json +169 -0
  42. taxcalc/reforms/archive/TCJA_Senate_120117.json +174 -0
  43. taxcalc/reforms/cases.csv +10 -0
  44. taxcalc/reforms/clp.out.csv +10 -0
  45. taxcalc/reforms/ext.json +59 -0
  46. taxcalc/reforms/growfactors_ext.csv +65 -0
  47. taxcalc/reforms/ptaxes0.json +37 -0
  48. taxcalc/reforms/ptaxes0.out.csv +10 -0
  49. taxcalc/reforms/ptaxes1.json +21 -0
  50. taxcalc/reforms/ptaxes1.out.csv +10 -0
  51. taxcalc/reforms/ptaxes2.json +18 -0
  52. taxcalc/reforms/ptaxes2.out.csv +10 -0
  53. taxcalc/reforms/ptaxes3.json +28 -0
  54. taxcalc/reforms/ptaxes3.out.csv +10 -0
  55. taxcalc/taxcalcio.py +44 -22
  56. taxcalc/tests/benefits_expect.csv +169 -0
  57. taxcalc/tests/cmpi_cps_expect.txt +132 -0
  58. taxcalc/tests/cmpi_puf_expect.txt +132 -0
  59. taxcalc/tests/conftest.py +143 -0
  60. taxcalc/tests/cpscsv_agg_expect.csv +26 -0
  61. taxcalc/tests/puf_var_correl_coeffs_2016.csv +80 -0
  62. taxcalc/tests/puf_var_wght_means_by_year.csv +80 -0
  63. taxcalc/tests/pufcsv_agg_expect.csv +26 -0
  64. taxcalc/tests/pufcsv_mtr_expect.txt +63 -0
  65. taxcalc/tests/reforms.json +649 -0
  66. taxcalc/tests/reforms_expect.csv +65 -0
  67. taxcalc/tests/test_4package.py +67 -0
  68. taxcalc/tests/test_benefits.py +86 -0
  69. taxcalc/tests/test_calcfunctions.py +871 -0
  70. taxcalc/tests/test_calculator.py +1021 -0
  71. taxcalc/tests/test_compare.py +336 -0
  72. taxcalc/tests/test_compatible_data.py +338 -0
  73. taxcalc/tests/test_consumption.py +144 -0
  74. taxcalc/tests/test_cpscsv.py +163 -0
  75. taxcalc/tests/test_data.py +133 -0
  76. taxcalc/tests/test_decorators.py +332 -0
  77. taxcalc/tests/test_growdiff.py +102 -0
  78. taxcalc/tests/test_growfactors.py +94 -0
  79. taxcalc/tests/test_parameters.py +617 -0
  80. taxcalc/tests/test_policy.py +1557 -0
  81. taxcalc/tests/test_puf_var_stats.py +194 -0
  82. taxcalc/tests/test_pufcsv.py +385 -0
  83. taxcalc/tests/test_records.py +234 -0
  84. taxcalc/tests/test_reforms.py +386 -0
  85. taxcalc/tests/test_responses.py +41 -0
  86. taxcalc/tests/test_taxcalcio.py +755 -0
  87. taxcalc/tests/test_utils.py +792 -0
  88. taxcalc/validation/CSV_INPUT_VARS.md +29 -0
  89. taxcalc/validation/CSV_OUTPUT_VARS.md +63 -0
  90. taxcalc/validation/README.md +68 -0
  91. taxcalc/validation/taxsim35/Differences_Explained.md +54 -0
  92. taxcalc/validation/taxsim35/README.md +139 -0
  93. taxcalc/validation/taxsim35/expected_differences/a17-taxdiffs-expect.csv +25 -0
  94. taxcalc/validation/taxsim35/expected_differences/a18-taxdiffs-expect.csv +25 -0
  95. taxcalc/validation/taxsim35/expected_differences/a19-taxdiffs-expect.csv +25 -0
  96. taxcalc/validation/taxsim35/expected_differences/a20-taxdiffs-expect.csv +25 -0
  97. taxcalc/validation/taxsim35/expected_differences/a21-taxdiffs-expect.csv +25 -0
  98. taxcalc/validation/taxsim35/expected_differences/b17-taxdiffs-expect.csv +25 -0
  99. taxcalc/validation/taxsim35/expected_differences/b18-taxdiffs-expect.csv +25 -0
  100. taxcalc/validation/taxsim35/expected_differences/b19-taxdiffs-expect.csv +25 -0
  101. taxcalc/validation/taxsim35/expected_differences/b20-taxdiffs-expect.csv +25 -0
  102. taxcalc/validation/taxsim35/expected_differences/b21-taxdiffs-expect.csv +25 -0
  103. taxcalc/validation/taxsim35/expected_differences/c17-taxdiffs-expect.csv +25 -0
  104. taxcalc/validation/taxsim35/expected_differences/c18-taxdiffs-expect.csv +25 -0
  105. taxcalc/validation/taxsim35/expected_differences/c19-taxdiffs-expect.csv +25 -0
  106. taxcalc/validation/taxsim35/input_setup.py +67 -0
  107. taxcalc/validation/taxsim35/main_comparison.py +183 -0
  108. taxcalc/validation/taxsim35/prepare_taxcalc_input.py +161 -0
  109. taxcalc/validation/taxsim35/process_taxcalc_output.py +140 -0
  110. taxcalc/validation/taxsim35/taxsim_emulation.json +49 -0
  111. taxcalc/validation/taxsim35/taxsim_input.py +321 -0
  112. taxcalc/validation/taxsim35/tc_sims.py +98 -0
  113. taxcalc/validation/taxsim35/tests_35.py +80 -0
  114. taxcalc/validation/tests_35.sh +13 -0
  115. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/METADATA +3 -4
  116. taxcalc-4.3.0.dist-info/RECORD +139 -0
  117. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/WHEEL +1 -1
  118. taxcalc/tmd_growfactors.csv +0 -55
  119. taxcalc/tmd_weights.csv.gz +0 -0
  120. taxcalc-4.2.1.dist-info/RECORD +0 -34
  121. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/LICENSE +0 -0
  122. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/entry_points.txt +0 -0
  123. {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