taxcalc 5.1.0__py3-none-any.whl → 5.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 +3 -3
- taxcalc/calcfunctions.py +21 -16
- taxcalc/calculator.py +3 -3
- taxcalc/cli/tc.py +15 -11
- taxcalc/data.py +1 -1
- taxcalc/decorators.py +9 -8
- taxcalc/growfactors.py +2 -1
- taxcalc/policy.py +13 -5
- taxcalc/policy_current_law.json +1191 -1395
- taxcalc/puf_ratios.csv +24 -24
- taxcalc/puf_weights.csv.gz +0 -0
- taxcalc/reforms/2017_law.json +2 -0
- taxcalc/reforms/ARPA.out.csv +9 -9
- taxcalc/taxcalcio.py +41 -26
- taxcalc/tests/conftest.py +1 -1
- taxcalc/tests/cpscsv_agg_expect.csv +26 -26
- taxcalc/tests/puf_var_correl_coeffs_2016.csv +24 -24
- taxcalc/tests/puf_var_wght_means_by_year.csv +80 -80
- taxcalc/tests/pufcsv_agg_expect.csv +26 -26
- taxcalc/tests/pufcsv_mtr_expect.txt +21 -21
- taxcalc/tests/reforms.json +3 -1
- taxcalc/tests/reforms_expect.csv +48 -48
- taxcalc/tests/test_4package.py +8 -9
- taxcalc/tests/test_calculator.py +152 -151
- taxcalc/tests/test_compare.py +2 -2
- taxcalc/tests/test_consumption.py +2 -2
- taxcalc/tests/test_cpscsv.py +4 -3
- taxcalc/tests/test_decorators.py +57 -52
- taxcalc/tests/test_growdiff.py +2 -2
- taxcalc/tests/test_parameters.py +59 -53
- taxcalc/tests/test_policy.py +229 -251
- taxcalc/tests/test_puf_var_stats.py +2 -2
- taxcalc/tests/test_pufcsv.py +5 -4
- taxcalc/tests/test_records.py +5 -1
- taxcalc/tests/test_reforms.py +101 -99
- taxcalc/tests/test_taxcalcio.py +10 -4
- taxcalc/utils.py +3 -3
- {taxcalc-5.1.0.dist-info → taxcalc-5.3.0.dist-info}/METADATA +3 -6
- {taxcalc-5.1.0.dist-info → taxcalc-5.3.0.dist-info}/RECORD +43 -44
- taxcalc/reforms/clp.out.csv +0 -10
- {taxcalc-5.1.0.dist-info → taxcalc-5.3.0.dist-info}/WHEEL +0 -0
- {taxcalc-5.1.0.dist-info → taxcalc-5.3.0.dist-info}/entry_points.txt +0 -0
- {taxcalc-5.1.0.dist-info → taxcalc-5.3.0.dist-info}/licenses/LICENSE +0 -0
- {taxcalc-5.1.0.dist-info → taxcalc-5.3.0.dist-info}/top_level.txt +0 -0
taxcalc/tests/test_calculator.py
CHANGED
@@ -26,7 +26,7 @@ def test_make_calculator(cps_subsample):
|
|
26
26
|
assert pol.current_year == start_year
|
27
27
|
rec = Records.cps_constructor(data=cps_subsample)
|
28
28
|
consump = Consumption()
|
29
|
-
consump.update_consumption({
|
29
|
+
consump.update_consumption({"MPC_e20400": {sim_year: 0.05}})
|
30
30
|
assert consump.current_year == start_year
|
31
31
|
calc = Calculator(policy=pol, records=rec,
|
32
32
|
consumption=consump, verbose=True)
|
@@ -61,10 +61,10 @@ def test_make_calculator_with_policy_reform(cps_subsample):
|
|
61
61
|
# create a Policy object and apply a policy reform
|
62
62
|
pol = Policy()
|
63
63
|
reform = {
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
"II_em": {2013: 4000},
|
65
|
+
"II_em-indexed": {2013: False},
|
66
|
+
"STD_Aged": {2013: [1600, 1300, 1300, 1600, 1600]},
|
67
|
+
"STD_Aged-indexed": {2013: False}
|
68
68
|
}
|
69
69
|
pol.implement_reform(reform)
|
70
70
|
# create a Calculator object using this policy reform
|
@@ -72,14 +72,14 @@ def test_make_calculator_with_policy_reform(cps_subsample):
|
|
72
72
|
assert calc.reform_errors == {}
|
73
73
|
# check that Policy object embedded in Calculator object is correct
|
74
74
|
assert calc.current_year == year
|
75
|
-
assert calc.policy_param(
|
76
|
-
assert np.allclose(calc.policy_param(
|
75
|
+
assert calc.policy_param("II_em") == 4000
|
76
|
+
assert np.allclose(calc.policy_param("_II_em"),
|
77
77
|
np.array([4000] * pol.num_years))
|
78
78
|
exp_STD_Aged = [[1600, 1300, 1300,
|
79
79
|
1600, 1600]] * pol.num_years
|
80
|
-
assert np.allclose(calc.policy_param(
|
80
|
+
assert np.allclose(calc.policy_param("_STD_Aged"),
|
81
81
|
np.array(exp_STD_Aged))
|
82
|
-
assert np.allclose(calc.policy_param(
|
82
|
+
assert np.allclose(calc.policy_param("STD_Aged"),
|
83
83
|
np.array([1600, 1300, 1300, 1600, 1600]))
|
84
84
|
|
85
85
|
|
@@ -92,23 +92,23 @@ def test_make_calculator_with_multiyear_reform(cps_subsample):
|
|
92
92
|
# create a Policy object and apply a policy reform
|
93
93
|
pol = Policy()
|
94
94
|
reform = {
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
"II_em": {2015: 5000, 2016: 6000},
|
96
|
+
"II_em-indexed": {2015: False},
|
97
|
+
"STD_Aged": {2016: [1600, 1300, 1600, 1300, 1600]}
|
98
98
|
}
|
99
99
|
pol.implement_reform(reform)
|
100
100
|
# create a Calculator object using this policy-reform
|
101
101
|
calc = Calculator(policy=pol, records=rec)
|
102
102
|
# check that Policy object embedded in Calculator object is correct
|
103
103
|
assert calc.current_year == year
|
104
|
-
assert calc.policy_param(
|
104
|
+
assert calc.policy_param("II_em") == 3950
|
105
105
|
exp_II_em = [3900, 3950, 5000] + [6000] * (pol.num_years - 3)
|
106
|
-
assert np.allclose(calc.policy_param(
|
106
|
+
assert np.allclose(calc.policy_param("_II_em"),
|
107
107
|
np.array(exp_II_em))
|
108
108
|
calc.increment_year()
|
109
109
|
calc.increment_year()
|
110
110
|
assert calc.current_year == 2016
|
111
|
-
assert np.allclose(calc.policy_param(
|
111
|
+
assert np.allclose(calc.policy_param("STD_Aged"),
|
112
112
|
np.array([1600, 1300, 1600, 1300, 1600]))
|
113
113
|
|
114
114
|
|
@@ -141,44 +141,44 @@ def test_calculator_mtr(cps_subsample):
|
|
141
141
|
rec = Records.cps_constructor(data=cps_subsample)
|
142
142
|
calcx = Calculator(policy=Policy(), records=rec)
|
143
143
|
calcx.calc_all()
|
144
|
-
combinedx = calcx.array(
|
145
|
-
c00100x = calcx.array(
|
144
|
+
combinedx = calcx.array("combined")
|
145
|
+
c00100x = calcx.array("c00100")
|
146
146
|
calc = Calculator(policy=Policy(), records=rec)
|
147
|
-
recs_pre_e00200p = copy.deepcopy(calc.array(
|
148
|
-
(mtr_ptx, mtr_itx, mtr_cmb) = calc.mtr(variable_str=
|
147
|
+
recs_pre_e00200p = copy.deepcopy(calc.array("e00200p"))
|
148
|
+
(mtr_ptx, mtr_itx, mtr_cmb) = calc.mtr(variable_str="e00200p",
|
149
149
|
zero_out_calculated_vars=True)
|
150
|
-
recs_post_e00200p = calc.array(
|
150
|
+
recs_post_e00200p = calc.array("e00200p")
|
151
151
|
assert np.allclose(recs_post_e00200p, recs_pre_e00200p)
|
152
|
-
assert np.allclose(calc.array(
|
153
|
-
assert np.allclose(calc.array(
|
152
|
+
assert np.allclose(calc.array("combined"), combinedx)
|
153
|
+
assert np.allclose(calc.array("c00100"), c00100x)
|
154
154
|
assert np.array_equal(mtr_cmb, mtr_ptx) is False
|
155
155
|
assert np.array_equal(mtr_ptx, mtr_itx) is False
|
156
156
|
with pytest.raises(ValueError):
|
157
|
-
calc.mtr(variable_str=
|
158
|
-
(_, _, mtr_combined) = calc.mtr(variable_str=
|
157
|
+
calc.mtr(variable_str="bad_income_type")
|
158
|
+
(_, _, mtr_combined) = calc.mtr(variable_str="e00200s",
|
159
159
|
calc_all_already_called=True)
|
160
160
|
assert isinstance(mtr_combined, np.ndarray)
|
161
|
-
(_, _, mtr_combined) = calc.mtr(variable_str=
|
161
|
+
(_, _, mtr_combined) = calc.mtr(variable_str="e00650",
|
162
162
|
negative_finite_diff=True,
|
163
163
|
calc_all_already_called=True)
|
164
164
|
assert isinstance(mtr_combined, np.ndarray)
|
165
|
-
(_, _, mtr_combined) = calc.mtr(variable_str=
|
165
|
+
(_, _, mtr_combined) = calc.mtr(variable_str="e00900p",
|
166
166
|
calc_all_already_called=True)
|
167
167
|
assert isinstance(mtr_combined, np.ndarray)
|
168
|
-
(_, _, mtr_combined) = calc.mtr(variable_str=
|
168
|
+
(_, _, mtr_combined) = calc.mtr(variable_str="e01700",
|
169
169
|
calc_all_already_called=True)
|
170
170
|
assert isinstance(mtr_combined, np.ndarray)
|
171
|
-
(_, _, mtr_combined) = calc.mtr(variable_str=
|
171
|
+
(_, _, mtr_combined) = calc.mtr(variable_str="e26270",
|
172
172
|
calc_all_already_called=True)
|
173
173
|
assert isinstance(mtr_combined, np.ndarray)
|
174
|
-
(_, _, mtr_combined) = calc.mtr(variable_str=
|
174
|
+
(_, _, mtr_combined) = calc.mtr(variable_str="k1bx14p",
|
175
175
|
calc_all_already_called=True)
|
176
176
|
assert isinstance(mtr_combined, np.ndarray)
|
177
|
-
(_, _, mtr_combined) = calc.mtr(variable_str=
|
177
|
+
(_, _, mtr_combined) = calc.mtr(variable_str="e00200p",
|
178
178
|
calc_all_already_called=True)
|
179
179
|
assert np.allclose(mtr_combined, mtr_cmb)
|
180
|
-
assert np.allclose(calc.array(
|
181
|
-
assert np.allclose(calc.array(
|
180
|
+
assert np.allclose(calc.array("combined"), combinedx)
|
181
|
+
assert np.allclose(calc.array("c00100"), c00100x)
|
182
182
|
|
183
183
|
|
184
184
|
def test_make_calculator_increment_years_first(cps_subsample):
|
@@ -190,10 +190,10 @@ def test_make_calculator_increment_years_first(cps_subsample):
|
|
190
190
|
pol = Policy()
|
191
191
|
std5 = 2000
|
192
192
|
reform = {
|
193
|
-
|
194
|
-
|
193
|
+
"STD_Aged": {2015: [std5, std5, std5, std5, std5]},
|
194
|
+
"II_em": {2015: 5000,
|
195
195
|
2016: 6000},
|
196
|
-
|
196
|
+
"II_em-indexed": {2016: False}
|
197
197
|
}
|
198
198
|
pol.implement_reform(reform)
|
199
199
|
# create Calculator object with Policy object as modified by reform
|
@@ -211,10 +211,10 @@ def test_make_calculator_increment_years_first(cps_subsample):
|
|
211
211
|
[std5, std5, std5, std5, std5],
|
212
212
|
[std6, std6, std6, std6, std6],
|
213
213
|
[std7, std7, std7, std7, std7]])
|
214
|
-
act_STD_Aged = calc.policy_param(
|
214
|
+
act_STD_Aged = calc.policy_param("_STD_Aged")
|
215
215
|
assert np.allclose(act_STD_Aged[:5], exp_STD_Aged)
|
216
216
|
exp_II_em = np.array([3900, 3950, 5000, 6000, 6000])
|
217
|
-
act_II_em = calc.policy_param(
|
217
|
+
act_II_em = calc.policy_param("_II_em")
|
218
218
|
assert np.allclose(act_II_em[:5], exp_II_em)
|
219
219
|
|
220
220
|
|
@@ -227,21 +227,21 @@ def test_ID_StateLocal_HC_vs_CRT(cps_subsample):
|
|
227
227
|
rec = Records.cps_constructor(data=cps_subsample)
|
228
228
|
# specify state/local complete haircut reform policy and Calculator object
|
229
229
|
hc_policy = Policy()
|
230
|
-
hc_reform = {
|
230
|
+
hc_reform = {"ID_StateLocalTax_hc": {2013: 1.0}}
|
231
231
|
hc_policy.implement_reform(hc_reform)
|
232
232
|
hc_calc = Calculator(policy=hc_policy, records=rec)
|
233
233
|
hc_calc.calc_all()
|
234
234
|
# specify AGI cap reform policy and Calculator object
|
235
235
|
crt_policy = Policy()
|
236
|
-
crt_reform = {
|
236
|
+
crt_reform = {"ID_StateLocalTax_crt": {2013: 0.0}}
|
237
237
|
crt_policy.implement_reform(crt_reform)
|
238
238
|
crt_calc = Calculator(policy=crt_policy, records=rec)
|
239
239
|
crt_calc.calc_all()
|
240
240
|
# compare calculated tax results generated by the two reforms
|
241
|
-
assert np.allclose(hc_calc.array(
|
242
|
-
crt_calc.array(
|
243
|
-
assert np.allclose(hc_calc.array(
|
244
|
-
crt_calc.array(
|
241
|
+
assert np.allclose(hc_calc.array("payrolltax"),
|
242
|
+
crt_calc.array("payrolltax"))
|
243
|
+
assert np.allclose(hc_calc.array("iitax"),
|
244
|
+
crt_calc.array("iitax"))
|
245
245
|
|
246
246
|
|
247
247
|
def test_ID_RealEstate_HC_vs_CRT(cps_subsample):
|
@@ -253,31 +253,31 @@ def test_ID_RealEstate_HC_vs_CRT(cps_subsample):
|
|
253
253
|
rec = Records.cps_constructor(data=cps_subsample)
|
254
254
|
# specify real estate complete haircut reform policy and Calculator object
|
255
255
|
hc_policy = Policy()
|
256
|
-
hc_reform = {
|
256
|
+
hc_reform = {"ID_RealEstate_hc": {2013: 1.0}}
|
257
257
|
hc_policy.implement_reform(hc_reform)
|
258
258
|
hc_calc = Calculator(policy=hc_policy, records=rec)
|
259
259
|
hc_calc.calc_all()
|
260
260
|
# specify AGI cap reform policy and Calculator object
|
261
261
|
crt_policy = Policy()
|
262
|
-
crt_reform = {
|
262
|
+
crt_reform = {"ID_RealEstate_crt": {2013: 0.0}}
|
263
263
|
crt_policy.implement_reform(crt_reform)
|
264
264
|
crt_calc = Calculator(policy=crt_policy, records=rec)
|
265
265
|
crt_calc.calc_all()
|
266
266
|
# compare calculated tax results generated by the two reforms
|
267
|
-
assert np.allclose(hc_calc.array(
|
268
|
-
crt_calc.array(
|
269
|
-
assert np.allclose(hc_calc.array(
|
270
|
-
crt_calc.array(
|
267
|
+
assert np.allclose(hc_calc.array("payrolltax"),
|
268
|
+
crt_calc.array("payrolltax"))
|
269
|
+
assert np.allclose(hc_calc.array("iitax"),
|
270
|
+
crt_calc.array("iitax"))
|
271
271
|
|
272
272
|
|
273
273
|
RAWINPUT_FUNITS = 4
|
274
274
|
RAWINPUT_YEAR = 2015
|
275
275
|
RAWINPUT_CONTENTS = (
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
276
|
+
"RECID,MARS,unknown,e00300\n"
|
277
|
+
" 1, 2, 9, 0\n"
|
278
|
+
" 2, 1, 9, 0\n"
|
279
|
+
" 3, 4, 9, 0\n"
|
280
|
+
" 4, 3, 9, 0\n"
|
281
281
|
)
|
282
282
|
|
283
283
|
|
@@ -297,36 +297,36 @@ def test_calculator_using_nonstd_input():
|
|
297
297
|
sync_years=False) # keeps raw data unchanged
|
298
298
|
assert calc.current_year == RAWINPUT_YEAR
|
299
299
|
calc.calc_all()
|
300
|
-
assert calc.weighted_total(
|
300
|
+
assert calc.weighted_total("e00200") == 0
|
301
301
|
assert calc.total_weight() == 0
|
302
|
-
varlist = [
|
302
|
+
varlist = ["RECID", "MARS"]
|
303
303
|
dframe = calc.dataframe(varlist)
|
304
304
|
assert isinstance(dframe, pd.DataFrame)
|
305
305
|
assert dframe.shape == (RAWINPUT_FUNITS, len(varlist))
|
306
|
-
mars = calc.array(
|
306
|
+
mars = calc.array("MARS")
|
307
307
|
assert isinstance(mars, np.ndarray)
|
308
308
|
assert mars.shape == (RAWINPUT_FUNITS,)
|
309
309
|
exp_iitax = np.zeros((nonstd.array_length,))
|
310
|
-
assert np.allclose(calc.array(
|
310
|
+
assert np.allclose(calc.array("iitax"), exp_iitax)
|
311
311
|
mtr_ptax, _, _ = calc.mtr(wrt_full_compensation=False)
|
312
312
|
exp_mtr_ptax = np.zeros((nonstd.array_length,))
|
313
313
|
exp_mtr_ptax.fill(0.153)
|
314
314
|
assert np.allclose(mtr_ptax, exp_mtr_ptax)
|
315
315
|
# misc calls for code coverage
|
316
|
-
calc.incarray(
|
317
|
-
calc.policy_param(
|
316
|
+
calc.incarray("e00300", np.ones_like(calc.array("e00300")))
|
317
|
+
calc.policy_param("ID_c", param_value=50e3)
|
318
318
|
|
319
319
|
|
320
320
|
def test_bad_json_names(tests_path):
|
321
321
|
"""
|
322
|
-
Test that ValueError raised with assump or reform do not end in
|
322
|
+
Test that ValueError raised with assump or reform do not end in ".json"
|
323
323
|
"""
|
324
324
|
test_url = (
|
325
|
-
|
326
|
-
|
327
|
-
|
325
|
+
"https://raw.githubusercontent.com/PSLmodels/"
|
326
|
+
"Tax-Calculator/master/taxcalc/reforms/"
|
327
|
+
"2017_law.out.csv"
|
328
328
|
)
|
329
|
-
csvname = os.path.join(tests_path,
|
329
|
+
csvname = os.path.join(tests_path, "..", "growfactors.csv")
|
330
330
|
with pytest.raises(ValueError):
|
331
331
|
Calculator.read_json_param_objects(csvname, None)
|
332
332
|
with pytest.raises(ValueError):
|
@@ -337,6 +337,7 @@ def test_bad_json_names(tests_path):
|
|
337
337
|
Calculator.read_json_param_objects(None, test_url)
|
338
338
|
|
339
339
|
|
340
|
+
@pytest.mark.local
|
340
341
|
def test_json_assump_url():
|
341
342
|
"""
|
342
343
|
Test reading JSON assumption file using URL.
|
@@ -417,9 +418,9 @@ def test_json_assump_url():
|
|
417
418
|
}
|
418
419
|
}
|
419
420
|
"""
|
420
|
-
assump_url = (
|
421
|
-
|
422
|
-
|
421
|
+
assump_url = ("https://raw.githubusercontent.com/PSLmodels/"
|
422
|
+
"Tax-Calculator/master/taxcalc/assumptions/"
|
423
|
+
"economic_assumptions_template.json")
|
423
424
|
params_str = Calculator.read_json_param_objects(None, assump_str)
|
424
425
|
assert params_str
|
425
426
|
params_url = Calculator.read_json_param_objects(None, assump_url)
|
@@ -451,19 +452,19 @@ def test_read_bad_json_assump_file():
|
|
451
452
|
with pytest.raises(ValueError):
|
452
453
|
Calculator.read_json_param_objects(None, badassump1)
|
453
454
|
with pytest.raises(ValueError):
|
454
|
-
Calculator.read_json_param_objects(None,
|
455
|
+
Calculator.read_json_param_objects(None, "unknown_file_name")
|
455
456
|
with pytest.raises(TypeError):
|
456
457
|
Calculator.read_json_param_objects(None, [])
|
457
458
|
|
458
459
|
|
459
460
|
def test_json_doesnt_exist():
|
460
461
|
"""
|
461
|
-
Test JSON file which doesn
|
462
|
+
Test JSON file which doesn"t exist
|
462
463
|
"""
|
463
464
|
with pytest.raises(ValueError):
|
464
|
-
Calculator.read_json_param_objects(None,
|
465
|
+
Calculator.read_json_param_objects(None, "./reforms/doesnt_exist.json")
|
465
466
|
with pytest.raises(ValueError):
|
466
|
-
Calculator.read_json_param_objects(
|
467
|
+
Calculator.read_json_param_objects("./reforms/doesnt_exist.json", None)
|
467
468
|
|
468
469
|
|
469
470
|
def test_calc_all():
|
@@ -501,13 +502,13 @@ def test_noreform_documentation():
|
|
501
502
|
gfs = GrowFactors()
|
502
503
|
actual_doc = Calculator.reform_documentation(params, gfs)
|
503
504
|
expected_doc = (
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
505
|
+
"REFORM DOCUMENTATION\n"
|
506
|
+
"Baseline Growth-Difference Assumption Values by Year:\n"
|
507
|
+
"none: no baseline GrowDiff assumptions specified\n"
|
508
|
+
"Response Growth-Difference Assumption Values by Year:\n"
|
509
|
+
"none: no response GrowDiff assumptions specified\n"
|
510
|
+
"Policy Reform Parameter Values by Year:\n"
|
511
|
+
"none: using current-law policy parameters\n"
|
511
512
|
)
|
512
513
|
assert actual_doc == expected_doc
|
513
514
|
|
@@ -550,14 +551,14 @@ def test_reform_documentation():
|
|
550
551
|
"""
|
551
552
|
params = Calculator.read_json_param_objects(reform_json, assump_json)
|
552
553
|
assert isinstance(params, dict)
|
553
|
-
second_reform = {
|
554
|
+
second_reform = {"II_em": {2019: 6500}}
|
554
555
|
gfs = GrowFactors()
|
555
556
|
doc = Calculator.reform_documentation(params, gfs, [second_reform])
|
556
557
|
assert isinstance(doc, str)
|
557
558
|
dump = False # set to True to print documentation and force test failure
|
558
559
|
if dump:
|
559
560
|
print(doc)
|
560
|
-
assert False,
|
561
|
+
assert False, "ERROR: reform_documentation above"
|
561
562
|
|
562
563
|
|
563
564
|
def test_distribution_tables(cps_subsample):
|
@@ -569,22 +570,22 @@ def test_distribution_tables(cps_subsample):
|
|
569
570
|
calc1 = Calculator(policy=pol, records=recs)
|
570
571
|
assert calc1.current_year == 2014
|
571
572
|
calc1.calc_all()
|
572
|
-
dt1, dt2 = calc1.distribution_tables(None,
|
573
|
+
dt1, dt2 = calc1.distribution_tables(None, "weighted_deciles")
|
573
574
|
assert isinstance(dt1, pd.DataFrame)
|
574
575
|
assert dt2 is None
|
575
|
-
dt1, dt2 = calc1.distribution_tables(calc1,
|
576
|
+
dt1, dt2 = calc1.distribution_tables(calc1, "weighted_deciles")
|
576
577
|
assert isinstance(dt1, pd.DataFrame)
|
577
578
|
assert isinstance(dt2, pd.DataFrame)
|
578
579
|
reform = {
|
579
|
-
|
580
|
-
|
581
|
-
|
580
|
+
"UBI_u18": {2014: 1000},
|
581
|
+
"UBI_1820": {2014: 1000},
|
582
|
+
"UBI_21": {2014: 1000}
|
582
583
|
}
|
583
584
|
pol.implement_reform(reform)
|
584
585
|
assert not pol.parameter_errors
|
585
586
|
calc2 = Calculator(policy=pol, records=recs)
|
586
587
|
calc2.calc_all()
|
587
|
-
dt1, dt2 = calc1.distribution_tables(calc2,
|
588
|
+
dt1, dt2 = calc1.distribution_tables(calc2, "weighted_deciles")
|
588
589
|
assert isinstance(dt1, pd.DataFrame)
|
589
590
|
assert isinstance(dt2, pd.DataFrame)
|
590
591
|
|
@@ -598,13 +599,13 @@ def test_difference_table(cps_subsample):
|
|
598
599
|
recs = Records.cps_constructor(data=cps_subsample)
|
599
600
|
calc1 = Calculator(policy=pol, records=recs)
|
600
601
|
assert calc1.current_year == cyr
|
601
|
-
reform = {
|
602
|
+
reform = {"SS_Earnings_c": {cyr: 9e99}}
|
602
603
|
pol.implement_reform(reform)
|
603
604
|
calc2 = Calculator(policy=pol, records=recs)
|
604
605
|
assert calc2.current_year == cyr
|
605
606
|
calc1.calc_all()
|
606
607
|
calc2.calc_all()
|
607
|
-
diff = calc1.difference_table(calc2,
|
608
|
+
diff = calc1.difference_table(calc2, "weighted_deciles", "iitax")
|
608
609
|
assert isinstance(diff, pd.DataFrame)
|
609
610
|
|
610
611
|
|
@@ -626,13 +627,13 @@ def test_mtr_graph(cps_subsample):
|
|
626
627
|
calc = Calculator(policy=Policy(), records=recs)
|
627
628
|
fig = calc.mtr_graph(calc,
|
628
629
|
mars=2,
|
629
|
-
income_measure=
|
630
|
-
mtr_measure=
|
630
|
+
income_measure="wages",
|
631
|
+
mtr_measure="ptax",
|
631
632
|
pop_quantiles=False)
|
632
633
|
assert fig
|
633
634
|
fig = calc.mtr_graph(calc,
|
634
|
-
income_measure=
|
635
|
-
mtr_measure=
|
635
|
+
income_measure="agi",
|
636
|
+
mtr_measure="itax",
|
636
637
|
pop_quantiles=True)
|
637
638
|
assert fig
|
638
639
|
|
@@ -643,9 +644,9 @@ def test_atr_graph(cps_subsample):
|
|
643
644
|
"""
|
644
645
|
recs = Records.cps_constructor(data=cps_subsample)
|
645
646
|
calc = Calculator(policy=Policy(), records=recs)
|
646
|
-
fig = calc.atr_graph(calc, mars=2, atr_measure=
|
647
|
+
fig = calc.atr_graph(calc, mars=2, atr_measure="itax")
|
647
648
|
assert fig
|
648
|
-
fig = calc.atr_graph(calc, atr_measure=
|
649
|
+
fig = calc.atr_graph(calc, atr_measure="ptax")
|
649
650
|
assert fig
|
650
651
|
|
651
652
|
|
@@ -682,7 +683,7 @@ def test_ce_aftertax_income(cps_subsample):
|
|
682
683
|
rec = Records.cps_constructor(data=cps_subsample)
|
683
684
|
pol = Policy()
|
684
685
|
calc1 = Calculator(policy=pol, records=rec)
|
685
|
-
pol.implement_reform({
|
686
|
+
pol.implement_reform({"SS_Earnings_c": {2013: 9e99}})
|
686
687
|
calc2 = Calculator(policy=pol, records=rec)
|
687
688
|
res = calc1.ce_aftertax_income(calc2)
|
688
689
|
assert isinstance(res, dict)
|
@@ -691,19 +692,19 @@ def test_ce_aftertax_income(cps_subsample):
|
|
691
692
|
@pytest.mark.itmded_vars
|
692
693
|
@pytest.mark.pre_release
|
693
694
|
@pytest.mark.requires_pufcsv
|
694
|
-
@pytest.mark.parametrize(
|
695
|
-
[(2018,
|
696
|
-
(2018,
|
697
|
-
(2018,
|
698
|
-
(2018,
|
699
|
-
(2018,
|
700
|
-
(2018,
|
701
|
-
(2017,
|
702
|
-
(2017,
|
703
|
-
(2017,
|
704
|
-
(2017,
|
705
|
-
(2017,
|
706
|
-
(2017,
|
695
|
+
@pytest.mark.parametrize("year, cvname, hcname",
|
696
|
+
[(2018, "c17000", "ID_Medical_hc"),
|
697
|
+
(2018, "c18300", "ID_AllTaxes_hc"),
|
698
|
+
(2018, "c19200", "ID_InterestPaid_hc"),
|
699
|
+
(2018, "c19700", "ID_Charity_hc"),
|
700
|
+
(2018, "c20500", "ID_Casualty_hc"),
|
701
|
+
(2018, "c20800", "ID_Miscellaneous_hc"),
|
702
|
+
(2017, "c17000", "ID_Medical_hc"),
|
703
|
+
(2017, "c18300", "ID_AllTaxes_hc"),
|
704
|
+
(2017, "c19200", "ID_InterestPaid_hc"),
|
705
|
+
(2017, "c19700", "ID_Charity_hc"),
|
706
|
+
(2017, "c20500", "ID_Casualty_hc"),
|
707
|
+
(2017, "c20800", "ID_Miscellaneous_hc")])
|
707
708
|
def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
|
708
709
|
"""
|
709
710
|
Check that all c04470 components are adjusted to reflect the filing
|
@@ -721,16 +722,16 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
|
|
721
722
|
# policy1 such that everybody itemizes deductions and all are allowed
|
722
723
|
policy1 = Policy()
|
723
724
|
reform1 = {
|
724
|
-
|
725
|
-
|
725
|
+
"STD_Aged": {year: [0.0, 0.0, 0.0, 0.0, 0.0]},
|
726
|
+
"STD": {year: [0.0, 0.0, 0.0, 0.0, 0.0]}
|
726
727
|
}
|
727
728
|
policy1.implement_reform(reform1)
|
728
729
|
assert not policy1.parameter_errors
|
729
730
|
# policy2 such that everybody itemizes deductions but one is disallowed
|
730
731
|
policy2 = Policy()
|
731
732
|
reform2 = {
|
732
|
-
|
733
|
-
|
733
|
+
"STD_Aged": {year: [0.0, 0.0, 0.0, 0.0, 0.0]},
|
734
|
+
"STD": {year: [0.0, 0.0, 0.0, 0.0, 0.0]},
|
734
735
|
hcname: {year: 1.0}
|
735
736
|
}
|
736
737
|
policy2.implement_reform(reform2)
|
@@ -743,36 +744,36 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
|
|
743
744
|
calc2.advance_to_year(year)
|
744
745
|
calc2.calc_all()
|
745
746
|
# confirm that nobody is taking the standard deduction
|
746
|
-
assert np.allclose(calc1.array(
|
747
|
-
assert np.allclose(calc2.array(
|
747
|
+
assert np.allclose(calc1.array("standard"), 0.)
|
748
|
+
assert np.allclose(calc2.array("standard"), 0.)
|
748
749
|
# calculate different in total itemized deductions
|
749
750
|
if year == 2017:
|
750
751
|
# pre-Pease limitation total itemized deductions
|
751
|
-
itmded1 = calc1.weighted_total(
|
752
|
-
itmded2 = calc2.weighted_total(
|
752
|
+
itmded1 = calc1.weighted_total("c21060") * 1e-9
|
753
|
+
itmded2 = calc2.weighted_total("c21060") * 1e-9
|
753
754
|
elif year == 2018:
|
754
755
|
# total itemized deductions (no Pease-like limitation)
|
755
|
-
itmded1 = calc1.weighted_total(
|
756
|
-
itmded2 = calc2.weighted_total(
|
756
|
+
itmded1 = calc1.weighted_total("c04470") * 1e-9
|
757
|
+
itmded2 = calc2.weighted_total("c04470") * 1e-9
|
757
758
|
else:
|
758
|
-
raise ValueError(f
|
759
|
+
raise ValueError(f"illegal year value = {year}")
|
759
760
|
difference_in_total_itmded = itmded1 - itmded2
|
760
761
|
# calculate itemized component amount
|
761
762
|
component_amt = calc1.weighted_total(cvname) * 1e-9
|
762
763
|
# confirm that component amount is equal to difference in total deductions
|
763
|
-
if year == 2017 and cvname ==
|
764
|
+
if year == 2017 and cvname == "c19700":
|
764
765
|
atol = 0.016
|
765
|
-
elif year == 2017 and cvname ==
|
766
|
+
elif year == 2017 and cvname == "c19200":
|
766
767
|
atol = 0.010
|
767
|
-
elif year == 2017 and cvname ==
|
768
|
+
elif year == 2017 and cvname == "c18300":
|
768
769
|
atol = 0.009
|
769
770
|
else:
|
770
771
|
atol = 0.00001
|
771
772
|
if not np.allclose(component_amt, difference_in_total_itmded, atol=atol):
|
772
773
|
msg = (
|
773
|
-
f
|
774
|
-
f
|
775
|
-
|
774
|
+
f"\n{cvname}={component_amt:.3f} != "
|
775
|
+
f"{difference_in_total_itmded:.3f}="
|
776
|
+
"difference_in_total_itemized_deductions"
|
776
777
|
)
|
777
778
|
raise ValueError(msg)
|
778
779
|
|
@@ -792,16 +793,16 @@ def test_qbid_calculation():
|
|
792
793
|
# and that the spouse has no business income and only earnings.
|
793
794
|
TPC_YEAR = 2018
|
794
795
|
TPC_VARS = (
|
795
|
-
|
796
|
-
|
796
|
+
"RECID,MARS,e00200s,e00200,e26270,e02000,PT_SSTB_income,"
|
797
|
+
"PT_binc_w2_wages,PT_ubia_property,pre_qbid_taxinc,qbid\n"
|
797
798
|
)
|
798
799
|
TPC_FUNITS = (
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
800
|
+
"1,2, 99000, 99000,75000,75000,1,20000,90000,150000,15000.00\n"
|
801
|
+
"2,2,349000,349000,75000,75000,1,20000,90000,400000, 1612.50\n"
|
802
|
+
"3,2,524000,524000,75000,75000,1,20000,90000,575000, 0.00\n"
|
803
|
+
"4,2, 99000, 99000,75000,75000,0,20000,90000,150000,15000.00\n"
|
804
|
+
"5,2,349000,349000,75000,75000,0,20000,90000,400000,10750.00\n"
|
805
|
+
"6,2,524000,524000,75000,75000,0,20000,90000,575000,10000.00\n"
|
805
806
|
)
|
806
807
|
# generate actual Calculator pre-qbid taxinc and qbid amounts
|
807
808
|
tpc_df = pd.read_csv(StringIO(TPC_VARS + TPC_FUNITS))
|
@@ -810,7 +811,7 @@ def test_qbid_calculation():
|
|
810
811
|
calc = Calculator(policy=Policy(), records=recs)
|
811
812
|
assert calc.current_year == TPC_YEAR
|
812
813
|
calc.calc_all()
|
813
|
-
varlist = [
|
814
|
+
varlist = ["RECID", "c00100", "standard", "c04470", "qbided"]
|
814
815
|
tc_df = calc.dataframe(varlist, all_vars=True)
|
815
816
|
# compare actual amounts with expected amounts from TPC publication
|
816
817
|
act_taxinc = tc_df.c00100 - np.maximum(tc_df.standard, tc_df.c04470)
|
@@ -820,11 +821,11 @@ def test_qbid_calculation():
|
|
820
821
|
|
821
822
|
|
822
823
|
def test_calc_all_benefits_amounts(cps_subsample):
|
823
|
-
|
824
|
+
"""
|
824
825
|
Testing how benefits are handled in the calc_all method
|
825
|
-
|
826
|
+
"""
|
826
827
|
# set a reform with a positive UBI amount
|
827
|
-
ubi_ref = {
|
828
|
+
ubi_ref = {"UBI_21": {2020: 1000}}
|
828
829
|
|
829
830
|
# create baseline calculator
|
830
831
|
pol = Policy()
|
@@ -842,14 +843,14 @@ def test_calc_all_benefits_amounts(cps_subsample):
|
|
842
843
|
|
843
844
|
# check that differences in benefits totals are equal to diffs in
|
844
845
|
# UBI
|
845
|
-
ubi_diff = (calc_ubi.weighted_total(
|
846
|
-
calc_base.weighted_total(
|
846
|
+
ubi_diff = (calc_ubi.weighted_total("ubi") -
|
847
|
+
calc_base.weighted_total("ubi")) / 1e9
|
847
848
|
benefit_cost_diff = (
|
848
|
-
calc_ubi.weighted_total(
|
849
|
-
calc_base.weighted_total(
|
849
|
+
calc_ubi.weighted_total("benefit_cost_total") -
|
850
|
+
calc_base.weighted_total("benefit_cost_total")) / 1e9
|
850
851
|
benefit_value_diff = (
|
851
|
-
calc_ubi.weighted_total(
|
852
|
-
calc_base.weighted_total(
|
852
|
+
calc_ubi.weighted_total("benefit_cost_total") -
|
853
|
+
calc_base.weighted_total("benefit_cost_total")) / 1e9
|
853
854
|
|
854
855
|
assert np.allclose(ubi_diff, benefit_cost_diff)
|
855
856
|
assert np.allclose(ubi_diff, benefit_value_diff)
|
@@ -874,8 +875,8 @@ def test_cg_top_rate():
|
|
874
875
|
"STD": {2019: [0, 0, 0, 0, 0]}}
|
875
876
|
|
876
877
|
# create one record just below the top CG bracket and one just above
|
877
|
-
VARS =
|
878
|
-
FUNITS =
|
878
|
+
VARS = "RECID,MARS,p23250\n"
|
879
|
+
FUNITS = "1,2,999999\n2,2,1000001\n"
|
879
880
|
|
880
881
|
pol_base = Policy()
|
881
882
|
pol_base.implement_reform(base)
|
@@ -894,23 +895,23 @@ def test_cg_top_rate():
|
|
894
895
|
calc_ref.calc_all()
|
895
896
|
|
896
897
|
# calculate MTRs wrt long term gains
|
897
|
-
mtr_base = calc_base.mtr(variable_str=
|
898
|
+
mtr_base = calc_base.mtr(variable_str="p23250",
|
898
899
|
calc_all_already_called=True,
|
899
900
|
wrt_full_compensation=False)
|
900
901
|
mtr_itax_base = mtr_base[1]
|
901
902
|
|
902
|
-
cg_rt3 = pol_base.to_array(
|
903
|
+
cg_rt3 = pol_base.to_array("CG_rt3", year=2019)
|
903
904
|
# check that MTR for both records is equal to CG_rt3
|
904
905
|
assert np.allclose(mtr_itax_base, cg_rt3)
|
905
906
|
|
906
907
|
# calculate MTRs under reform
|
907
|
-
mtr_ref = calc_ref.mtr(variable_str=
|
908
|
+
mtr_ref = calc_ref.mtr(variable_str="p23250",
|
908
909
|
calc_all_already_called=True,
|
909
910
|
wrt_full_compensation=False)
|
910
911
|
mtr_itax_ref = mtr_ref[1]
|
911
912
|
|
912
|
-
cg_rt3_ref = pol_ref.to_array(
|
913
|
-
cg_rt4_ref = pol_ref.to_array(param=
|
913
|
+
cg_rt3_ref = pol_ref.to_array("CG_rt3", year=2019)
|
914
|
+
cg_rt4_ref = pol_ref.to_array(param="CG_rt4", year=2019)
|
914
915
|
|
915
916
|
# check that MTR of houshold below top threshold is equal to
|
916
917
|
# CG_rt3
|