taxcalc 5.3.0__py3-none-any.whl → 6.0.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/calculator.py +1 -1
- taxcalc/cli/tc.py +1 -8
- taxcalc/data.py +1 -2
- taxcalc/policy.py +0 -18
- taxcalc/records.py +78 -82
- taxcalc/records_variables.json +106 -106
- taxcalc/taxcalcio.py +60 -51
- taxcalc/tests/conftest.py +19 -14
- taxcalc/tests/reforms_expect.csv +54 -54
- taxcalc/tests/test_calculator.py +197 -160
- taxcalc/tests/test_cpscsv.py +0 -22
- taxcalc/tests/test_data.py +11 -3
- taxcalc/tests/test_parameters.py +42 -0
- taxcalc/tests/test_records.py +139 -8
- taxcalc/tests/test_reforms.py +4 -6
- taxcalc/tests/test_taxcalcio.py +3 -58
- {taxcalc-5.3.0.dist-info → taxcalc-6.0.0.dist-info}/METADATA +1 -1
- {taxcalc-5.3.0.dist-info → taxcalc-6.0.0.dist-info}/RECORD +23 -29
- taxcalc/puf_ratios.csv +0 -26
- taxcalc/puf_weights.csv.gz +0 -0
- taxcalc/tests/test_compare.py +0 -330
- taxcalc/tests/test_compatible_data.py +0 -334
- taxcalc/tests/test_puf_var_stats.py +0 -194
- taxcalc/tests/test_pufcsv.py +0 -328
- {taxcalc-5.3.0.dist-info → taxcalc-6.0.0.dist-info}/WHEEL +0 -0
- {taxcalc-5.3.0.dist-info → taxcalc-6.0.0.dist-info}/entry_points.txt +0 -0
- {taxcalc-5.3.0.dist-info → taxcalc-6.0.0.dist-info}/licenses/LICENSE +0 -0
- {taxcalc-5.3.0.dist-info → taxcalc-6.0.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,24 +297,24 @@ 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):
|
@@ -322,11 +322,11 @@ def test_bad_json_names(tests_path):
|
|
322
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):
|
@@ -418,9 +418,11 @@ def test_json_assump_url():
|
|
418
418
|
}
|
419
419
|
}
|
420
420
|
"""
|
421
|
-
assump_url = (
|
422
|
-
|
423
|
-
|
421
|
+
assump_url = (
|
422
|
+
'https://raw.githubusercontent.com/PSLmodels/'
|
423
|
+
'Tax-Calculator/master/taxcalc/assumptions/'
|
424
|
+
'economic_assumptions_template.json'
|
425
|
+
)
|
424
426
|
params_str = Calculator.read_json_param_objects(None, assump_str)
|
425
427
|
assert params_str
|
426
428
|
params_url = Calculator.read_json_param_objects(None, assump_url)
|
@@ -428,8 +430,8 @@ def test_json_assump_url():
|
|
428
430
|
assert params_url == params_str
|
429
431
|
|
430
432
|
assump_gh_url = (
|
431
|
-
|
432
|
-
|
433
|
+
'github://PSLmodels:Tax-Calculator@master/taxcalc/assumptions/'
|
434
|
+
'economic_assumptions_template.json'
|
433
435
|
)
|
434
436
|
params_gh_url = Calculator.read_json_param_objects(None, assump_gh_url)
|
435
437
|
assert params_gh_url
|
@@ -452,19 +454,19 @@ def test_read_bad_json_assump_file():
|
|
452
454
|
with pytest.raises(ValueError):
|
453
455
|
Calculator.read_json_param_objects(None, badassump1)
|
454
456
|
with pytest.raises(ValueError):
|
455
|
-
Calculator.read_json_param_objects(None,
|
457
|
+
Calculator.read_json_param_objects(None, 'unknown_file_name')
|
456
458
|
with pytest.raises(TypeError):
|
457
459
|
Calculator.read_json_param_objects(None, [])
|
458
460
|
|
459
461
|
|
460
462
|
def test_json_doesnt_exist():
|
461
463
|
"""
|
462
|
-
Test JSON file which doesn
|
464
|
+
Test JSON file which doesn't exist
|
463
465
|
"""
|
464
466
|
with pytest.raises(ValueError):
|
465
|
-
Calculator.read_json_param_objects(None,
|
467
|
+
Calculator.read_json_param_objects(None, './reforms/doesnt_exist.json')
|
466
468
|
with pytest.raises(ValueError):
|
467
|
-
Calculator.read_json_param_objects(
|
469
|
+
Calculator.read_json_param_objects('./reforms/doesnt_exist.json', None)
|
468
470
|
|
469
471
|
|
470
472
|
def test_calc_all():
|
@@ -502,13 +504,13 @@ def test_noreform_documentation():
|
|
502
504
|
gfs = GrowFactors()
|
503
505
|
actual_doc = Calculator.reform_documentation(params, gfs)
|
504
506
|
expected_doc = (
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
507
|
+
'REFORM DOCUMENTATION\n'
|
508
|
+
'Baseline Growth-Difference Assumption Values by Year:\n'
|
509
|
+
'none: no baseline GrowDiff assumptions specified\n'
|
510
|
+
'Response Growth-Difference Assumption Values by Year:\n'
|
511
|
+
'none: no response GrowDiff assumptions specified\n'
|
512
|
+
'Policy Reform Parameter Values by Year:\n'
|
513
|
+
'none: using current-law policy parameters\n'
|
512
514
|
)
|
513
515
|
assert actual_doc == expected_doc
|
514
516
|
|
@@ -551,14 +553,14 @@ def test_reform_documentation():
|
|
551
553
|
"""
|
552
554
|
params = Calculator.read_json_param_objects(reform_json, assump_json)
|
553
555
|
assert isinstance(params, dict)
|
554
|
-
second_reform = {
|
556
|
+
second_reform = {'II_em': {2019: 6500}}
|
555
557
|
gfs = GrowFactors()
|
556
558
|
doc = Calculator.reform_documentation(params, gfs, [second_reform])
|
557
559
|
assert isinstance(doc, str)
|
558
560
|
dump = False # set to True to print documentation and force test failure
|
559
561
|
if dump:
|
560
562
|
print(doc)
|
561
|
-
assert False,
|
563
|
+
assert False, 'ERROR: reform_documentation above'
|
562
564
|
|
563
565
|
|
564
566
|
def test_distribution_tables(cps_subsample):
|
@@ -570,22 +572,22 @@ def test_distribution_tables(cps_subsample):
|
|
570
572
|
calc1 = Calculator(policy=pol, records=recs)
|
571
573
|
assert calc1.current_year == 2014
|
572
574
|
calc1.calc_all()
|
573
|
-
dt1, dt2 = calc1.distribution_tables(None,
|
575
|
+
dt1, dt2 = calc1.distribution_tables(None, 'weighted_deciles')
|
574
576
|
assert isinstance(dt1, pd.DataFrame)
|
575
577
|
assert dt2 is None
|
576
|
-
dt1, dt2 = calc1.distribution_tables(calc1,
|
578
|
+
dt1, dt2 = calc1.distribution_tables(calc1, 'weighted_deciles')
|
577
579
|
assert isinstance(dt1, pd.DataFrame)
|
578
580
|
assert isinstance(dt2, pd.DataFrame)
|
579
581
|
reform = {
|
580
|
-
|
581
|
-
|
582
|
-
|
582
|
+
'UBI_u18': {2014: 1000},
|
583
|
+
'UBI_1820': {2014: 1000},
|
584
|
+
'UBI_21': {2014: 1000}
|
583
585
|
}
|
584
586
|
pol.implement_reform(reform)
|
585
587
|
assert not pol.parameter_errors
|
586
588
|
calc2 = Calculator(policy=pol, records=recs)
|
587
589
|
calc2.calc_all()
|
588
|
-
dt1, dt2 = calc1.distribution_tables(calc2,
|
590
|
+
dt1, dt2 = calc1.distribution_tables(calc2, 'weighted_deciles')
|
589
591
|
assert isinstance(dt1, pd.DataFrame)
|
590
592
|
assert isinstance(dt2, pd.DataFrame)
|
591
593
|
|
@@ -599,13 +601,13 @@ def test_difference_table(cps_subsample):
|
|
599
601
|
recs = Records.cps_constructor(data=cps_subsample)
|
600
602
|
calc1 = Calculator(policy=pol, records=recs)
|
601
603
|
assert calc1.current_year == cyr
|
602
|
-
reform = {
|
604
|
+
reform = {'SS_Earnings_c': {cyr: 9e99}}
|
603
605
|
pol.implement_reform(reform)
|
604
606
|
calc2 = Calculator(policy=pol, records=recs)
|
605
607
|
assert calc2.current_year == cyr
|
606
608
|
calc1.calc_all()
|
607
609
|
calc2.calc_all()
|
608
|
-
diff = calc1.difference_table(calc2,
|
610
|
+
diff = calc1.difference_table(calc2, 'weighted_deciles', 'iitax')
|
609
611
|
assert isinstance(diff, pd.DataFrame)
|
610
612
|
|
611
613
|
|
@@ -627,13 +629,13 @@ def test_mtr_graph(cps_subsample):
|
|
627
629
|
calc = Calculator(policy=Policy(), records=recs)
|
628
630
|
fig = calc.mtr_graph(calc,
|
629
631
|
mars=2,
|
630
|
-
income_measure=
|
631
|
-
mtr_measure=
|
632
|
+
income_measure='wages',
|
633
|
+
mtr_measure='ptax',
|
632
634
|
pop_quantiles=False)
|
633
635
|
assert fig
|
634
636
|
fig = calc.mtr_graph(calc,
|
635
|
-
income_measure=
|
636
|
-
mtr_measure=
|
637
|
+
income_measure='agi',
|
638
|
+
mtr_measure='itax',
|
637
639
|
pop_quantiles=True)
|
638
640
|
assert fig
|
639
641
|
|
@@ -644,9 +646,9 @@ def test_atr_graph(cps_subsample):
|
|
644
646
|
"""
|
645
647
|
recs = Records.cps_constructor(data=cps_subsample)
|
646
648
|
calc = Calculator(policy=Policy(), records=recs)
|
647
|
-
fig = calc.atr_graph(calc, mars=2, atr_measure=
|
649
|
+
fig = calc.atr_graph(calc, mars=2, atr_measure='itax')
|
648
650
|
assert fig
|
649
|
-
fig = calc.atr_graph(calc, atr_measure=
|
651
|
+
fig = calc.atr_graph(calc, atr_measure='ptax')
|
650
652
|
assert fig
|
651
653
|
|
652
654
|
|
@@ -683,29 +685,27 @@ def test_ce_aftertax_income(cps_subsample):
|
|
683
685
|
rec = Records.cps_constructor(data=cps_subsample)
|
684
686
|
pol = Policy()
|
685
687
|
calc1 = Calculator(policy=pol, records=rec)
|
686
|
-
pol.implement_reform({
|
688
|
+
pol.implement_reform({'SS_Earnings_c': {2013: 9e99}})
|
687
689
|
calc2 = Calculator(policy=pol, records=rec)
|
688
690
|
res = calc1.ce_aftertax_income(calc2)
|
689
691
|
assert isinstance(res, dict)
|
690
692
|
|
691
693
|
|
692
694
|
@pytest.mark.itmded_vars
|
693
|
-
@pytest.mark.
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
(2018,
|
698
|
-
(2018,
|
699
|
-
(2018,
|
700
|
-
(
|
701
|
-
(
|
702
|
-
(2017,
|
703
|
-
(2017,
|
704
|
-
(2017,
|
705
|
-
(2017,
|
706
|
-
|
707
|
-
(2017, "c20800", "ID_Miscellaneous_hc")])
|
708
|
-
def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
|
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')])
|
708
|
+
def test_itemded_component_amounts(year, cvname, hcname, cps_fullsample):
|
709
709
|
"""
|
710
710
|
Check that all c04470 components are adjusted to reflect the filing
|
711
711
|
unit's standard-vs-itemized-deduction decision. Check for 2018
|
@@ -718,20 +718,20 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
|
|
718
718
|
here use c21060, instead of c04470, as the itemized deductions total.
|
719
719
|
"""
|
720
720
|
# pylint: disable=too-many-locals
|
721
|
-
recs = Records(data=
|
721
|
+
recs = Records.cps_constructor(data=cps_fullsample)
|
722
722
|
# policy1 such that everybody itemizes deductions and all are allowed
|
723
723
|
policy1 = Policy()
|
724
724
|
reform1 = {
|
725
|
-
|
726
|
-
|
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]}
|
727
727
|
}
|
728
728
|
policy1.implement_reform(reform1)
|
729
729
|
assert not policy1.parameter_errors
|
730
730
|
# policy2 such that everybody itemizes deductions but one is disallowed
|
731
731
|
policy2 = Policy()
|
732
732
|
reform2 = {
|
733
|
-
|
734
|
-
|
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]},
|
735
735
|
hcname: {year: 1.0}
|
736
736
|
}
|
737
737
|
policy2.implement_reform(reform2)
|
@@ -744,36 +744,36 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
|
|
744
744
|
calc2.advance_to_year(year)
|
745
745
|
calc2.calc_all()
|
746
746
|
# confirm that nobody is taking the standard deduction
|
747
|
-
assert np.allclose(calc1.array(
|
748
|
-
assert np.allclose(calc2.array(
|
747
|
+
assert np.allclose(calc1.array('standard'), 0.)
|
748
|
+
assert np.allclose(calc2.array('standard'), 0.)
|
749
749
|
# calculate different in total itemized deductions
|
750
750
|
if year == 2017:
|
751
751
|
# pre-Pease limitation total itemized deductions
|
752
|
-
itmded1 = calc1.weighted_total(
|
753
|
-
itmded2 = calc2.weighted_total(
|
752
|
+
itmded1 = calc1.weighted_total('c21060') * 1e-9
|
753
|
+
itmded2 = calc2.weighted_total('c21060') * 1e-9
|
754
754
|
elif year == 2018:
|
755
755
|
# total itemized deductions (no Pease-like limitation)
|
756
|
-
itmded1 = calc1.weighted_total(
|
757
|
-
itmded2 = calc2.weighted_total(
|
756
|
+
itmded1 = calc1.weighted_total('c04470') * 1e-9
|
757
|
+
itmded2 = calc2.weighted_total('c04470') * 1e-9
|
758
758
|
else:
|
759
|
-
raise ValueError(f
|
759
|
+
raise ValueError(f'illegal year value = {year}')
|
760
760
|
difference_in_total_itmded = itmded1 - itmded2
|
761
761
|
# calculate itemized component amount
|
762
762
|
component_amt = calc1.weighted_total(cvname) * 1e-9
|
763
763
|
# confirm that component amount is equal to difference in total deductions
|
764
|
-
if year == 2017 and cvname ==
|
764
|
+
if year == 2017 and cvname == 'c19700':
|
765
765
|
atol = 0.016
|
766
|
-
elif year == 2017 and cvname ==
|
766
|
+
elif year == 2017 and cvname == 'c19200':
|
767
767
|
atol = 0.010
|
768
|
-
elif year == 2017 and cvname ==
|
768
|
+
elif year == 2017 and cvname == 'c18300':
|
769
769
|
atol = 0.009
|
770
770
|
else:
|
771
771
|
atol = 0.00001
|
772
772
|
if not np.allclose(component_amt, difference_in_total_itmded, atol=atol):
|
773
773
|
msg = (
|
774
|
-
f
|
775
|
-
f
|
776
|
-
|
774
|
+
f'\n{cvname}={component_amt:.3f} != '
|
775
|
+
f'{difference_in_total_itmded:.3f}='
|
776
|
+
'difference_in_total_itemized_deductions'
|
777
777
|
)
|
778
778
|
raise ValueError(msg)
|
779
779
|
|
@@ -793,16 +793,16 @@ def test_qbid_calculation():
|
|
793
793
|
# and that the spouse has no business income and only earnings.
|
794
794
|
TPC_YEAR = 2018
|
795
795
|
TPC_VARS = (
|
796
|
-
|
797
|
-
|
796
|
+
'RECID,MARS,e00200s,e00200,e26270,e02000,PT_SSTB_income,'
|
797
|
+
'PT_binc_w2_wages,PT_ubia_property,pre_qbid_taxinc,qbid\n'
|
798
798
|
)
|
799
799
|
TPC_FUNITS = (
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
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'
|
806
806
|
)
|
807
807
|
# generate actual Calculator pre-qbid taxinc and qbid amounts
|
808
808
|
tpc_df = pd.read_csv(StringIO(TPC_VARS + TPC_FUNITS))
|
@@ -811,7 +811,7 @@ def test_qbid_calculation():
|
|
811
811
|
calc = Calculator(policy=Policy(), records=recs)
|
812
812
|
assert calc.current_year == TPC_YEAR
|
813
813
|
calc.calc_all()
|
814
|
-
varlist = [
|
814
|
+
varlist = ['RECID', 'c00100', 'standard', 'c04470', 'qbided']
|
815
815
|
tc_df = calc.dataframe(varlist, all_vars=True)
|
816
816
|
# compare actual amounts with expected amounts from TPC publication
|
817
817
|
act_taxinc = tc_df.c00100 - np.maximum(tc_df.standard, tc_df.c04470)
|
@@ -825,7 +825,7 @@ def test_calc_all_benefits_amounts(cps_subsample):
|
|
825
825
|
Testing how benefits are handled in the calc_all method
|
826
826
|
"""
|
827
827
|
# set a reform with a positive UBI amount
|
828
|
-
ubi_ref = {
|
828
|
+
ubi_ref = {'UBI_21': {2020: 1000}}
|
829
829
|
|
830
830
|
# create baseline calculator
|
831
831
|
pol = Policy()
|
@@ -843,14 +843,14 @@ def test_calc_all_benefits_amounts(cps_subsample):
|
|
843
843
|
|
844
844
|
# check that differences in benefits totals are equal to diffs in
|
845
845
|
# UBI
|
846
|
-
ubi_diff = (calc_ubi.weighted_total(
|
847
|
-
calc_base.weighted_total(
|
846
|
+
ubi_diff = (calc_ubi.weighted_total('ubi') -
|
847
|
+
calc_base.weighted_total('ubi')) / 1e9
|
848
848
|
benefit_cost_diff = (
|
849
|
-
calc_ubi.weighted_total(
|
850
|
-
calc_base.weighted_total(
|
849
|
+
calc_ubi.weighted_total('benefit_cost_total') -
|
850
|
+
calc_base.weighted_total('benefit_cost_total')) / 1e9
|
851
851
|
benefit_value_diff = (
|
852
|
-
calc_ubi.weighted_total(
|
853
|
-
calc_base.weighted_total(
|
852
|
+
calc_ubi.weighted_total('benefit_cost_total') -
|
853
|
+
calc_base.weighted_total('benefit_cost_total')) / 1e9
|
854
854
|
|
855
855
|
assert np.allclose(ubi_diff, benefit_cost_diff)
|
856
856
|
assert np.allclose(ubi_diff, benefit_value_diff)
|
@@ -865,18 +865,22 @@ def test_cg_top_rate():
|
|
865
865
|
cy = 2019
|
866
866
|
|
867
867
|
# set NIIT and STD to zero to isolate CG tax rates
|
868
|
-
base = {
|
869
|
-
|
868
|
+
base = {
|
869
|
+
'NIIT_rt': {2019: 0},
|
870
|
+
'STD': {2019: [0, 0, 0, 0, 0]}
|
871
|
+
}
|
870
872
|
|
871
873
|
# create additional top CG bracket and rate
|
872
|
-
ref = {
|
873
|
-
|
874
|
-
|
875
|
-
|
874
|
+
ref = {
|
875
|
+
'CG_brk3': {2019: [1000000, 1000000, 1000000, 1000000, 1000000]},
|
876
|
+
'CG_rt4': {2019: 0.4},
|
877
|
+
'NIIT_rt': {2019: 0},
|
878
|
+
'STD': {2019: [0, 0, 0, 0, 0]}
|
879
|
+
}
|
876
880
|
|
877
881
|
# create one record just below the top CG bracket and one just above
|
878
|
-
VARS =
|
879
|
-
FUNITS =
|
882
|
+
VARS = 'RECID,MARS,p23250\n'
|
883
|
+
FUNITS = '1,2,999999\n2,2,1000001\n'
|
880
884
|
|
881
885
|
pol_base = Policy()
|
882
886
|
pol_base.implement_reform(base)
|
@@ -895,23 +899,23 @@ def test_cg_top_rate():
|
|
895
899
|
calc_ref.calc_all()
|
896
900
|
|
897
901
|
# calculate MTRs wrt long term gains
|
898
|
-
mtr_base = calc_base.mtr(variable_str=
|
902
|
+
mtr_base = calc_base.mtr(variable_str='p23250',
|
899
903
|
calc_all_already_called=True,
|
900
904
|
wrt_full_compensation=False)
|
901
905
|
mtr_itax_base = mtr_base[1]
|
902
906
|
|
903
|
-
cg_rt3 = pol_base.to_array(
|
907
|
+
cg_rt3 = pol_base.to_array('CG_rt3', year=2019)
|
904
908
|
# check that MTR for both records is equal to CG_rt3
|
905
909
|
assert np.allclose(mtr_itax_base, cg_rt3)
|
906
910
|
|
907
911
|
# calculate MTRs under reform
|
908
|
-
mtr_ref = calc_ref.mtr(variable_str=
|
912
|
+
mtr_ref = calc_ref.mtr(variable_str='p23250',
|
909
913
|
calc_all_already_called=True,
|
910
914
|
wrt_full_compensation=False)
|
911
915
|
mtr_itax_ref = mtr_ref[1]
|
912
916
|
|
913
|
-
cg_rt3_ref = pol_ref.to_array(
|
914
|
-
cg_rt4_ref = pol_ref.to_array(param=
|
917
|
+
cg_rt3_ref = pol_ref.to_array('CG_rt3', year=2019)
|
918
|
+
cg_rt4_ref = pol_ref.to_array(param='CG_rt4', year=2019)
|
915
919
|
|
916
920
|
# check that MTR of houshold below top threshold is equal to
|
917
921
|
# CG_rt3
|
@@ -919,3 +923,36 @@ def test_cg_top_rate():
|
|
919
923
|
# check that MTR of household above top threshold is equal to
|
920
924
|
# CG_rt4
|
921
925
|
assert np.allclose(mtr_itax_ref[1], cg_rt4_ref)
|
926
|
+
|
927
|
+
|
928
|
+
def test_credit_reforms(cps_subsample):
|
929
|
+
"""
|
930
|
+
Test personal credit reforms using cps.csv subsample
|
931
|
+
"""
|
932
|
+
rec = Records.cps_constructor(data=cps_subsample)
|
933
|
+
reform_year = 2017
|
934
|
+
# create current-law Calculator object, calc1
|
935
|
+
pol = Policy()
|
936
|
+
calc1 = Calculator(policy=pol, records=rec)
|
937
|
+
calc1.advance_to_year(reform_year)
|
938
|
+
calc1.calc_all()
|
939
|
+
itax1 = calc1.weighted_total('iitax')
|
940
|
+
# create personal-refundable-credit-reform Calculator object, calc2
|
941
|
+
reform = {'II_credit': {reform_year: [1000, 1000, 1000, 1000, 1000]}}
|
942
|
+
pol.implement_reform(reform)
|
943
|
+
calc2 = Calculator(policy=pol, records=rec)
|
944
|
+
calc2.advance_to_year(reform_year)
|
945
|
+
calc2.calc_all()
|
946
|
+
itax2 = calc2.weighted_total('iitax')
|
947
|
+
# create personal-nonrefundable-credit-reform Calculator object, calc3
|
948
|
+
reform = {'II_credit_nr': {reform_year: [1000, 1000, 1000, 1000, 1000]}}
|
949
|
+
pol = Policy()
|
950
|
+
pol.implement_reform(reform)
|
951
|
+
calc3 = Calculator(policy=pol, records=rec)
|
952
|
+
calc3.advance_to_year(reform_year)
|
953
|
+
calc3.calc_all()
|
954
|
+
itax3 = calc3.weighted_total('iitax')
|
955
|
+
# check income tax revenues generated by the three Calculator objects
|
956
|
+
assert itax2 < itax1 # because refundable credits lower revenues
|
957
|
+
assert itax3 > itax2 # because nonrefundable credits lower revenues less
|
958
|
+
assert itax3 < itax1 # because nonrefundable credits lower revenues some
|