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.
@@ -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({"MPC_e20400": {sim_year: 0.05}})
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
- "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}
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("II_em") == 4000
76
- assert np.allclose(calc.policy_param("_II_em"),
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("_STD_Aged"),
80
+ assert np.allclose(calc.policy_param('_STD_Aged'),
81
81
  np.array(exp_STD_Aged))
82
- assert np.allclose(calc.policy_param("STD_Aged"),
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
- "II_em": {2015: 5000, 2016: 6000},
96
- "II_em-indexed": {2015: False},
97
- "STD_Aged": {2016: [1600, 1300, 1600, 1300, 1600]}
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("II_em") == 3950
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("_II_em"),
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("STD_Aged"),
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("combined")
145
- c00100x = calcx.array("c00100")
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("e00200p"))
148
- (mtr_ptx, mtr_itx, mtr_cmb) = calc.mtr(variable_str="e00200p",
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("e00200p")
150
+ recs_post_e00200p = calc.array('e00200p')
151
151
  assert np.allclose(recs_post_e00200p, recs_pre_e00200p)
152
- assert np.allclose(calc.array("combined"), combinedx)
153
- assert np.allclose(calc.array("c00100"), c00100x)
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="bad_income_type")
158
- (_, _, mtr_combined) = calc.mtr(variable_str="e00200s",
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="e00650",
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="e00900p",
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="e01700",
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="e26270",
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="k1bx14p",
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="e00200p",
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("combined"), combinedx)
181
- assert np.allclose(calc.array("c00100"), c00100x)
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
- "STD_Aged": {2015: [std5, std5, std5, std5, std5]},
194
- "II_em": {2015: 5000,
193
+ 'STD_Aged': {2015: [std5, std5, std5, std5, std5]},
194
+ 'II_em': {2015: 5000,
195
195
  2016: 6000},
196
- "II_em-indexed": {2016: False}
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("_STD_Aged")
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("_II_em")
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 = {"ID_StateLocalTax_hc": {2013: 1.0}}
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 = {"ID_StateLocalTax_crt": {2013: 0.0}}
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("payrolltax"),
242
- crt_calc.array("payrolltax"))
243
- assert np.allclose(hc_calc.array("iitax"),
244
- crt_calc.array("iitax"))
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 = {"ID_RealEstate_hc": {2013: 1.0}}
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 = {"ID_RealEstate_crt": {2013: 0.0}}
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("payrolltax"),
268
- crt_calc.array("payrolltax"))
269
- assert np.allclose(hc_calc.array("iitax"),
270
- crt_calc.array("iitax"))
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
- "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"
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("e00200") == 0
300
+ assert calc.weighted_total('e00200') == 0
301
301
  assert calc.total_weight() == 0
302
- varlist = ["RECID", "MARS"]
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("MARS")
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("iitax"), exp_iitax)
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("e00300", np.ones_like(calc.array("e00300")))
317
- calc.policy_param("ID_c", param_value=50e3)
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
- "https://raw.githubusercontent.com/PSLmodels/"
326
- "Tax-Calculator/master/taxcalc/reforms/"
327
- "2017_law.out.csv"
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, "..", "growfactors.csv")
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 = ("https://raw.githubusercontent.com/PSLmodels/"
422
- "Tax-Calculator/master/taxcalc/assumptions/"
423
- "economic_assumptions_template.json")
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
- "github://PSLmodels:Tax-Calculator@master/taxcalc/assumptions/"
432
- "economic_assumptions_template.json"
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, "unknown_file_name")
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"t exist
464
+ Test JSON file which doesn't exist
463
465
  """
464
466
  with pytest.raises(ValueError):
465
- Calculator.read_json_param_objects(None, "./reforms/doesnt_exist.json")
467
+ Calculator.read_json_param_objects(None, './reforms/doesnt_exist.json')
466
468
  with pytest.raises(ValueError):
467
- Calculator.read_json_param_objects("./reforms/doesnt_exist.json", None)
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
- "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"
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 = {"II_em": {2019: 6500}}
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, "ERROR: reform_documentation above"
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, "weighted_deciles")
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, "weighted_deciles")
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
- "UBI_u18": {2014: 1000},
581
- "UBI_1820": {2014: 1000},
582
- "UBI_21": {2014: 1000}
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, "weighted_deciles")
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 = {"SS_Earnings_c": {cyr: 9e99}}
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, "weighted_deciles", "iitax")
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="wages",
631
- mtr_measure="ptax",
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="agi",
636
- mtr_measure="itax",
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="itax")
649
+ fig = calc.atr_graph(calc, mars=2, atr_measure='itax')
648
650
  assert fig
649
- fig = calc.atr_graph(calc, atr_measure="ptax")
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({"SS_Earnings_c": {2013: 9e99}})
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.pre_release
694
- @pytest.mark.requires_pufcsv
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, 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=puf_fullsample)
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
- "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]}
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
- "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]},
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("standard"), 0.)
748
- assert np.allclose(calc2.array("standard"), 0.)
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("c21060") * 1e-9
753
- itmded2 = calc2.weighted_total("c21060") * 1e-9
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("c04470") * 1e-9
757
- itmded2 = calc2.weighted_total("c04470") * 1e-9
756
+ itmded1 = calc1.weighted_total('c04470') * 1e-9
757
+ itmded2 = calc2.weighted_total('c04470') * 1e-9
758
758
  else:
759
- raise ValueError(f"illegal year value = {year}")
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 == "c19700":
764
+ if year == 2017 and cvname == 'c19700':
765
765
  atol = 0.016
766
- elif year == 2017 and cvname == "c19200":
766
+ elif year == 2017 and cvname == 'c19200':
767
767
  atol = 0.010
768
- elif year == 2017 and cvname == "c18300":
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"\n{cvname}={component_amt:.3f} != "
775
- f"{difference_in_total_itmded:.3f}="
776
- "difference_in_total_itemized_deductions"
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
- "RECID,MARS,e00200s,e00200,e26270,e02000,PT_SSTB_income,"
797
- "PT_binc_w2_wages,PT_ubia_property,pre_qbid_taxinc,qbid\n"
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
- "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"
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 = ["RECID", "c00100", "standard", "c04470", "qbided"]
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 = {"UBI_21": {2020: 1000}}
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("ubi") -
847
- calc_base.weighted_total("ubi")) / 1e9
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("benefit_cost_total") -
850
- calc_base.weighted_total("benefit_cost_total")) / 1e9
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("benefit_cost_total") -
853
- calc_base.weighted_total("benefit_cost_total")) / 1e9
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 = {"NIIT_rt": {2019: 0},
869
- "STD": {2019: [0, 0, 0, 0, 0]}}
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 = {"CG_brk3": {2019: [1000000, 1000000, 1000000, 1000000, 1000000]},
873
- "CG_rt4": {2019: 0.4},
874
- "NIIT_rt": {2019: 0},
875
- "STD": {2019: [0, 0, 0, 0, 0]}}
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 = "RECID,MARS,p23250\n"
879
- FUNITS = "1,2,999999\n2,2,1000001\n"
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="p23250",
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("CG_rt3", year=2019)
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="p23250",
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("CG_rt3", year=2019)
914
- cg_rt4_ref = pol_ref.to_array(param="CG_rt4", year=2019)
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