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_policy.py
CHANGED
@@ -54,14 +54,15 @@ def test_incorrect_implement_reform_usage():
|
|
54
54
|
with pytest.raises(paramtools.ValidationError):
|
55
55
|
pol.implement_reform([])
|
56
56
|
with pytest.raises(paramtools.ValidationError):
|
57
|
-
pol.implement_reform({2099: {
|
57
|
+
pol.implement_reform({2099: {"II_em": 99000}})
|
58
58
|
pol.set_year(2019)
|
59
59
|
with pytest.raises(paramtools.ValidationError):
|
60
|
-
pol.implement_reform({2018: {
|
60
|
+
pol.implement_reform({2018: {"II_em": 99000}})
|
61
61
|
with pytest.raises(paramtools.ValidationError):
|
62
|
-
pol.implement_reform({2020: {
|
62
|
+
pol.implement_reform({2020: {"II_em": -1000}})
|
63
63
|
|
64
64
|
|
65
|
+
@pytest.mark.local
|
65
66
|
def test_json_reform_url():
|
66
67
|
"""
|
67
68
|
Test reading a JSON reform from a URL. Results from the URL are expected
|
@@ -89,8 +90,8 @@ def test_json_reform_url():
|
|
89
90
|
}
|
90
91
|
}
|
91
92
|
"""
|
92
|
-
reform_url = (
|
93
|
-
|
93
|
+
reform_url = ("https://raw.githubusercontent.com/PSLmodels/"
|
94
|
+
"Tax-Calculator/master/taxcalc/reforms/ptaxes0.json")
|
94
95
|
params_str = Policy.read_json_reform(reform_str)
|
95
96
|
params_url = Policy.read_json_reform(reform_url)
|
96
97
|
assert params_str == params_url
|
@@ -191,7 +192,7 @@ def test_constant_inflation_rate_with_reform():
|
|
191
192
|
fyr = 2034
|
192
193
|
ryr = fyr - 1
|
193
194
|
reform = {
|
194
|
-
|
195
|
+
"II_em": {(ryr - 3): 1000, # to avoid divide-by-zero under TCJA
|
195
196
|
ryr: 20000}
|
196
197
|
}
|
197
198
|
pol.implement_reform(reform)
|
@@ -217,7 +218,7 @@ def test_variable_inflation_rate_with_reform():
|
|
217
218
|
assert pol._II_em[2013 - syr] == 3900
|
218
219
|
# implement reform in 2020 which is two years before the last year, 2022
|
219
220
|
reform = {
|
220
|
-
|
221
|
+
"II_em": {2018: 1000, # to avoid divide-by-zero under TCJA
|
221
222
|
2020: 20000}
|
222
223
|
}
|
223
224
|
pol.implement_reform(reform)
|
@@ -257,15 +258,14 @@ def test_multi_year_reform():
|
|
257
258
|
wfactor[syr + i] = 1.0 + wratelist[i]
|
258
259
|
# specify multi-year reform using a param:year:value-fomatted dictionary
|
259
260
|
reform = {
|
260
|
-
|
261
|
+
"SS_Earnings_c": {2016: 300000,
|
261
262
|
2017: 500000,
|
262
263
|
2019: 700000},
|
263
|
-
|
264
|
+
"SS_Earnings_c-indexed": {2017: False,
|
264
265
|
2019: True},
|
265
|
-
|
266
|
-
'EITC_c': {2016: [900, 5000, 8000, 9000],
|
266
|
+
"EITC_c": {2016: [900, 5000, 8000, 9000],
|
267
267
|
2019: [1200, 7000, 10000, 12000]},
|
268
|
-
|
268
|
+
"II_em": {2016: 7000,
|
269
269
|
2019: 9000}
|
270
270
|
}
|
271
271
|
# implement multi-year reform
|
@@ -280,42 +280,16 @@ def test_multi_year_reform():
|
|
280
280
|
check_eitc_c(pol, reform, ifactor)
|
281
281
|
check_ii_em(pol, reform, ifactor)
|
282
282
|
check_ss_earnings_c(pol, reform, wfactor)
|
283
|
-
check_ctc_c(pol, reform)
|
284
283
|
# end of test_multi_year_reform with the check_* functions below:
|
285
284
|
|
286
285
|
|
287
|
-
def check_ctc_c(ppo, reform):
|
288
|
-
"""
|
289
|
-
Compare actual and expected _CTC_c parameter values
|
290
|
-
generated by the test_multi_year_reform() function above.
|
291
|
-
Ensure that future-year values in policy_current_law.json
|
292
|
-
are overwritten by reform.
|
293
|
-
"""
|
294
|
-
actual = {}
|
295
|
-
arr = getattr(ppo, '_CTC_c')
|
296
|
-
for i in range(0, ppo.num_years):
|
297
|
-
actual[ppo.start_year + i] = arr[i]
|
298
|
-
assert actual[2013] == 1000
|
299
|
-
assert actual[2014] == 1000
|
300
|
-
e2015 = reform['CTC_c'][2015]
|
301
|
-
assert actual[2015] == e2015
|
302
|
-
e2016 = actual[2015]
|
303
|
-
assert actual[2016] == e2016
|
304
|
-
e2017 = actual[2016]
|
305
|
-
assert actual[2017] == e2017
|
306
|
-
e2018 = actual[2017]
|
307
|
-
assert actual[2018] == e2018
|
308
|
-
e2019 = actual[2018]
|
309
|
-
assert actual[2019] == e2019
|
310
|
-
|
311
|
-
|
312
286
|
def check_eitc_c(ppo, reform, ifactor):
|
313
287
|
"""
|
314
288
|
Compare actual and expected _EITC_c parameter values
|
315
289
|
generated by the test_multi_year_reform() function above.
|
316
290
|
"""
|
317
291
|
actual = {}
|
318
|
-
arr = getattr(ppo,
|
292
|
+
arr = getattr(ppo, "_EITC_c")
|
319
293
|
alen = len(arr[0])
|
320
294
|
for i in range(0, ppo.num_years):
|
321
295
|
actual[ppo.start_year + i] = arr[i]
|
@@ -325,13 +299,13 @@ def check_eitc_c(ppo, reform, ifactor):
|
|
325
299
|
atol=0.01, rtol=0.0)
|
326
300
|
assert np.allclose(actual[2015], [503, 3359, 5548, 6242],
|
327
301
|
atol=0.01, rtol=0.0)
|
328
|
-
e2016 = reform[
|
302
|
+
e2016 = reform["EITC_c"][2016]
|
329
303
|
assert np.allclose(actual[2016], e2016, atol=0.01, rtol=0.0)
|
330
304
|
e2017 = [ifactor[2016] * actual[2016][j] for j in range(0, alen)]
|
331
305
|
assert np.allclose(actual[2017], e2017, atol=0.01, rtol=0.0)
|
332
306
|
e2018 = [ifactor[2017] * actual[2017][j] for j in range(0, alen)]
|
333
307
|
assert np.allclose(actual[2018], e2018, atol=0.01, rtol=0.0)
|
334
|
-
e2019 = reform[
|
308
|
+
e2019 = reform["EITC_c"][2019]
|
335
309
|
assert np.allclose(actual[2019], e2019, atol=0.01, rtol=0.0)
|
336
310
|
e2020 = [ifactor[2019] * actual[2019][j] for j in range(0, alen)]
|
337
311
|
assert np.allclose(actual[2020], e2020, atol=0.01, rtol=0.0)
|
@@ -347,19 +321,19 @@ def check_ii_em(ppo, reform, ifactor):
|
|
347
321
|
generated by the test_multi_year_reform() function above.
|
348
322
|
"""
|
349
323
|
actual = {}
|
350
|
-
arr = getattr(ppo,
|
324
|
+
arr = getattr(ppo, "_II_em")
|
351
325
|
for i in range(0, ppo.num_years):
|
352
326
|
actual[ppo.start_year + i] = arr[i]
|
353
327
|
assert actual[2013] == 3900
|
354
328
|
assert actual[2014] == 3950
|
355
329
|
assert actual[2015] == 4000
|
356
|
-
e2016 = reform[
|
330
|
+
e2016 = reform["II_em"][2016]
|
357
331
|
assert actual[2016] == e2016
|
358
332
|
e2017 = ifactor[2016] * actual[2016]
|
359
333
|
assert np.allclose([actual[2017]], [e2017], atol=0.01, rtol=0.0)
|
360
334
|
e2018 = ifactor[2017] * actual[2017]
|
361
335
|
assert np.allclose([actual[2018]], [e2018], atol=0.01, rtol=0.0)
|
362
|
-
e2019 = reform[
|
336
|
+
e2019 = reform["II_em"][2019]
|
363
337
|
assert actual[2019] == e2019
|
364
338
|
e2020 = ifactor[2019] * actual[2019]
|
365
339
|
assert np.allclose([actual[2020]], [e2020], atol=0.01, rtol=0.0)
|
@@ -375,19 +349,19 @@ def check_ss_earnings_c(ppo, reform, wfactor):
|
|
375
349
|
generated by the test_multi_year_reform() function above.
|
376
350
|
"""
|
377
351
|
actual = {}
|
378
|
-
arr = getattr(ppo,
|
352
|
+
arr = getattr(ppo, "_SS_Earnings_c")
|
379
353
|
for i in range(0, ppo.num_years):
|
380
354
|
actual[ppo.start_year + i] = arr[i]
|
381
355
|
assert actual[2013] == 113700
|
382
356
|
assert actual[2014] == 117000
|
383
357
|
assert actual[2015] == 118500
|
384
|
-
e2016 = reform[
|
358
|
+
e2016 = reform["SS_Earnings_c"][2016]
|
385
359
|
assert actual[2016] == e2016
|
386
|
-
e2017 = reform[
|
360
|
+
e2017 = reform["SS_Earnings_c"][2017]
|
387
361
|
assert actual[2017] == e2017
|
388
362
|
e2018 = actual[2017] # no indexing after 2017
|
389
363
|
assert actual[2018] == e2018
|
390
|
-
e2019 = reform[
|
364
|
+
e2019 = reform["SS_Earnings_c"][2019]
|
391
365
|
assert actual[2019] == e2019
|
392
366
|
e2020 = wfactor[2019] * actual[2019] # indexing after 2019
|
393
367
|
assert np.allclose([actual[2020]], [e2020], atol=0.01, rtol=0.0)
|
@@ -410,7 +384,7 @@ def test_implement_reform_raises_on_no_year():
|
|
410
384
|
"""
|
411
385
|
Test that implement_reform raises error for missing year.
|
412
386
|
"""
|
413
|
-
reform = {
|
387
|
+
reform = {"STD_Aged": [1400, 1200, 1400, 1400, 1400]}
|
414
388
|
ppo = Policy()
|
415
389
|
with pytest.raises(paramtools.ValidationError):
|
416
390
|
ppo.implement_reform(reform)
|
@@ -421,7 +395,7 @@ def test_implement_reform_raises_on_early_year():
|
|
421
395
|
Test that implement_reform raises error for early year.
|
422
396
|
"""
|
423
397
|
ppo = Policy()
|
424
|
-
reform = {
|
398
|
+
reform = {"STD_Aged": {2010: [1400, 1100, 1100, 1400, 1400]}}
|
425
399
|
with pytest.raises(paramtools.ValidationError):
|
426
400
|
ppo.implement_reform(reform)
|
427
401
|
|
@@ -431,7 +405,7 @@ def test_reform_with_default_indexed():
|
|
431
405
|
Test that implement_reform indexes after first reform year.
|
432
406
|
"""
|
433
407
|
ppo = Policy()
|
434
|
-
reform = {
|
408
|
+
reform = {"II_em": {2015: 4300}}
|
435
409
|
ppo.implement_reform(reform)
|
436
410
|
# II_em has a default indexing status of true, so
|
437
411
|
# in 2016 its value should be greater than 4300
|
@@ -444,7 +418,7 @@ def test_reform_makes_no_changes_before_year():
|
|
444
418
|
Test that implement_reform makes no changes before first reform year.
|
445
419
|
"""
|
446
420
|
ppo = Policy()
|
447
|
-
reform = {
|
421
|
+
reform = {"II_em": {2015: 4400}, "II_em-indexed": {2015: True}}
|
448
422
|
ppo.implement_reform(reform)
|
449
423
|
ppo.set_year(2015)
|
450
424
|
assert np.allclose(ppo._II_em[:3], np.array([3900, 3950, 4400]),
|
@@ -545,7 +519,7 @@ def test_pop_the_cap_reform():
|
|
545
519
|
assert mte[2015 - syr] == 118500
|
546
520
|
assert mte[2016 - syr] == 118500
|
547
521
|
# specify a "pop the cap" reform that eliminates MTE cap in 2016
|
548
|
-
reform = {
|
522
|
+
reform = {"SS_Earnings_c": {2016: 9e99}}
|
549
523
|
ppo.implement_reform(reform)
|
550
524
|
mte = ppo._SS_Earnings_c
|
551
525
|
assert mte[2015 - syr] == 118500
|
@@ -561,13 +535,13 @@ def test_order_of_indexing_and_level_reforms():
|
|
561
535
|
# specify two reforms that raises the MTE and stops its indexing in 2015
|
562
536
|
reforms = [
|
563
537
|
{
|
564
|
-
|
565
|
-
|
538
|
+
"SS_Earnings_c": {2015: 500000},
|
539
|
+
"SS_Earnings_c-indexed": {2015: False}
|
566
540
|
},
|
567
541
|
# now reverse the order of the two reform provisions
|
568
542
|
{
|
569
|
-
|
570
|
-
|
543
|
+
"SS_Earnings_c-indexed": {2015: False},
|
544
|
+
"SS_Earnings_c": {2015: 500000}
|
571
545
|
}
|
572
546
|
]
|
573
547
|
# specify two Policy objects
|
@@ -598,12 +572,12 @@ def test_misspecified_reform_dictionary():
|
|
598
572
|
"""
|
599
573
|
# specify apparently the same reform in two different ways, forgetting
|
600
574
|
# that Python dictionaries have unique keys
|
601
|
-
reform1 = {
|
575
|
+
reform1 = {"II_em": {2019: 1000, 2020: 2000}}
|
602
576
|
# pylint: disable=duplicate-key
|
603
|
-
reform2 = {
|
577
|
+
reform2 = {"II_em": {2019: 1000}, "II_em": {2020: 2000}}
|
604
578
|
# these two reform dictionaries are not the same: the second
|
605
|
-
#
|
606
|
-
# the first
|
579
|
+
# "II_em" key value for 2020 in reform2 OVERWRITES and REPLACES
|
580
|
+
# the first "II_em" key value for 2019 in reform2
|
607
581
|
assert reform1 != reform2
|
608
582
|
|
609
583
|
|
@@ -622,114 +596,114 @@ def test_section_titles(tests_path):
|
|
622
596
|
for line in md_text.splitlines():
|
623
597
|
# This is shown as an empty case in current law policy and
|
624
598
|
# validation.
|
625
|
-
if line.startswith(
|
626
|
-
sdict[
|
627
|
-
sdict[
|
599
|
+
if line.startswith("## Other Parameters (not in Tax-Brain webapp"):
|
600
|
+
sdict[""] = {}
|
601
|
+
sdict[""][""] = 0
|
628
602
|
continue
|
629
|
-
sec2line = line.startswith(
|
630
|
-
sec1line = line.startswith(
|
603
|
+
sec2line = line.startswith("### ")
|
604
|
+
sec1line = line.startswith("## ")
|
631
605
|
# Create outer-layer dictionary entry for sec1.
|
632
606
|
if sec1line:
|
633
|
-
sec1 = line.replace(
|
607
|
+
sec1 = line.replace("##", "", 1).strip()
|
634
608
|
sdict[sec1] = {}
|
635
609
|
# Create inner dictionary entry for sec1-sec2.
|
636
610
|
# Note that sec1 will have been defined from a previous loop.
|
637
611
|
if sec2line:
|
638
|
-
sec2 = line.replace(
|
612
|
+
sec2 = line.replace("###", "", 1).strip()
|
639
613
|
sdict[sec1][sec2] = 0
|
640
614
|
return sdict
|
641
615
|
# begin main logic of test_section_titles
|
642
616
|
# specify expected section titles ordered as on the Tax-Brain webapp
|
643
|
-
cgqd_tax_same = (
|
644
|
-
|
617
|
+
cgqd_tax_same = ("Tax All Capital Gains And Dividends The Same "
|
618
|
+
"As Regular Taxable Income")
|
645
619
|
valid_dict = {
|
646
|
-
|
647
|
-
|
620
|
+
"": { # empty section_1 implies parameter not displayed in Tax-Brain
|
621
|
+
"": 0
|
648
622
|
},
|
649
|
-
|
650
|
-
|
623
|
+
"Parameter Indexing": {
|
624
|
+
"Offsets": 0
|
651
625
|
},
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
626
|
+
"Payroll Taxes": {
|
627
|
+
"Social Security FICA": 0,
|
628
|
+
"Medicare FICA": 0,
|
629
|
+
"Additional Medicare FICA": 0
|
656
630
|
},
|
657
|
-
|
658
|
-
|
631
|
+
"Social Security Taxability": {
|
632
|
+
"Social Security Benefit Taxability": 0,
|
659
633
|
},
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
634
|
+
"Above The Line Deductions": {
|
635
|
+
"Misc. Adjustment Haircuts": 0,
|
636
|
+
"Misc. Exclusions": 0,
|
637
|
+
"Child And Elderly Care": 0
|
664
638
|
},
|
665
|
-
|
666
|
-
|
667
|
-
#
|
668
|
-
|
669
|
-
|
639
|
+
"Personal Exemptions": {
|
640
|
+
"Personal And Dependent Exemption Amount": 0,
|
641
|
+
# "Personal Exemption Phaseout Starting Income": 0,
|
642
|
+
"Personal Exemption Phaseout Rate": 0,
|
643
|
+
"Repeal for Dependents Under Age 18": 0
|
670
644
|
},
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
#
|
645
|
+
"Standard Deduction": {
|
646
|
+
"Standard Deduction Amount": 0,
|
647
|
+
"Additional Standard Deduction For Blind And Aged": 0
|
648
|
+
# "Standard Deduction For Dependents": 0
|
675
649
|
},
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
650
|
+
"Nonrefundable Credits": {
|
651
|
+
"Misc. Credit Limits": 0,
|
652
|
+
"Child And Dependent Care": 0,
|
653
|
+
"Personal Nonrefundable Credit": 0
|
680
654
|
},
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
655
|
+
"Child/Dependent Credits": {
|
656
|
+
"Child Tax Credit": 0,
|
657
|
+
"Additional Child Tax Credit": 0,
|
658
|
+
"Other Dependent Tax Credit": 0
|
685
659
|
},
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
660
|
+
"Itemized Deductions": {
|
661
|
+
"Medical Expenses": 0,
|
662
|
+
"State And Local Income And Sales Taxes": 0,
|
663
|
+
"State, Local, And Foreign Real Estate Taxes": 0,
|
664
|
+
"State And Local Taxes And Real Estate Taxes": 0,
|
665
|
+
"Interest Paid": 0,
|
666
|
+
"Charity": 0,
|
667
|
+
"Casualty": 0,
|
668
|
+
"Miscellaneous": 0,
|
669
|
+
"Itemized Deduction Limitation": 0, # Pease
|
670
|
+
"Ceiling On The Amount Of Itemized Deductions Allowed": 0 # ID_c
|
697
671
|
},
|
698
|
-
|
699
|
-
|
700
|
-
|
672
|
+
"Capital Gains And Dividends": {
|
673
|
+
"Regular - Long Term Capital Gains And Qualified Dividends": 0,
|
674
|
+
"AMT - Long Term Capital Gains And Qualified Dividends": 0,
|
701
675
|
cgqd_tax_same: 0
|
702
676
|
},
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
677
|
+
"Personal Income": {
|
678
|
+
"Regular: Non-AMT": 0,
|
679
|
+
"Pass-Through": 0,
|
680
|
+
"Alternative Minimum Tax": 0
|
707
681
|
},
|
708
|
-
|
709
|
-
|
682
|
+
"Other Taxes": {
|
683
|
+
"Net Investment Income Tax": 0
|
710
684
|
},
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
685
|
+
"Refundable Credits": {
|
686
|
+
"Earned Income Tax Credit": 0,
|
687
|
+
"New Refundable Child Tax Credit": 0,
|
688
|
+
"Personal Refundable Credit": 0,
|
689
|
+
"Refundable Payroll Tax Credit": 0
|
716
690
|
},
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
691
|
+
"Surtaxes": {
|
692
|
+
"New Minimum Tax": 0,
|
693
|
+
"New AGI Surtax": 0,
|
694
|
+
"Lump-Sum Tax": 0
|
721
695
|
},
|
722
|
-
|
723
|
-
|
724
|
-
|
696
|
+
"Universal Basic Income": {
|
697
|
+
"UBI Benefits": 0,
|
698
|
+
"UBI Taxability": 0
|
725
699
|
},
|
726
|
-
|
727
|
-
|
700
|
+
"Benefits": {
|
701
|
+
"Benefit Repeal": 0,
|
728
702
|
}
|
729
703
|
}
|
730
704
|
# check validity of parameter section titles in policy_current_law.json
|
731
|
-
path = os.path.join(tests_path,
|
732
|
-
with open(path,
|
705
|
+
path = os.path.join(tests_path, "..", "policy_current_law.json")
|
706
|
+
with open(path, "r", encoding="utf-8") as clpfile:
|
733
707
|
clpdict = json.load(clpfile)
|
734
708
|
clpdict.pop("schema", None)
|
735
709
|
# ... make sure ever clpdict section title is in valid_dict
|
@@ -737,9 +711,9 @@ def test_section_titles(tests_path):
|
|
737
711
|
for pname in clpdict:
|
738
712
|
param = clpdict[pname]
|
739
713
|
assert isinstance(param, dict)
|
740
|
-
sec1title = param[
|
714
|
+
sec1title = param["section_1"]
|
741
715
|
assert sec1title in valid_dict
|
742
|
-
sec2title = param[
|
716
|
+
sec2title = param["section_2"]
|
743
717
|
assert sec2title in valid_dict[sec1title]
|
744
718
|
if sec1title not in clp_dict:
|
745
719
|
clp_dict[sec1title] = {}
|
@@ -752,9 +726,9 @@ def test_section_titles(tests_path):
|
|
752
726
|
for sec2title in secdict:
|
753
727
|
assert sec2title in clp_dict[sec1title]
|
754
728
|
# check validity of parameter section titles in docs/uguide.htmx skeleton
|
755
|
-
path = os.path.join(tests_path,
|
756
|
-
|
757
|
-
with open(path,
|
729
|
+
path = os.path.join(tests_path, "..", "..", "docs", "guide",
|
730
|
+
"policy_params.md")
|
731
|
+
with open(path, "r", encoding="utf-8") as md_file:
|
758
732
|
md_text = md_file.read()
|
759
733
|
md_dict = generate_section_dictionary(md_text)
|
760
734
|
# ... make sure every md_dict section title is in valid_dict
|
@@ -776,17 +750,17 @@ def test_description_punctuation(tests_path):
|
|
776
750
|
Check that each description ends in a period.
|
777
751
|
"""
|
778
752
|
# read JSON file into a dictionary
|
779
|
-
path = os.path.join(tests_path,
|
780
|
-
with open(path,
|
753
|
+
path = os.path.join(tests_path, "..", "policy_current_law.json")
|
754
|
+
with open(path, "r", encoding="utf-8") as jsonfile:
|
781
755
|
dct = json.load(jsonfile)
|
782
756
|
dct.pop("schema", None)
|
783
757
|
all_desc_ok = True
|
784
758
|
for param in dct.keys():
|
785
|
-
if not dct[param][
|
759
|
+
if not dct[param]["description"].endswith("."):
|
786
760
|
all_desc_ok = False
|
787
|
-
print(
|
761
|
+
print("param,description=",
|
788
762
|
str(param),
|
789
|
-
dct[param][
|
763
|
+
dct[param]["description"])
|
790
764
|
assert all_desc_ok
|
791
765
|
|
792
766
|
|
@@ -795,8 +769,8 @@ def test_get_index_rate():
|
|
795
769
|
Test Parameters.get_index_rate.
|
796
770
|
"""
|
797
771
|
pol = Policy()
|
798
|
-
wgrates = pol.get_index_rate(
|
799
|
-
pirates = pol.get_index_rate(
|
772
|
+
wgrates = pol.get_index_rate("SS_Earnings_c", 2017)
|
773
|
+
pirates = pol.get_index_rate("II_em", 2017)
|
800
774
|
assert isinstance(wgrates, np.float64)
|
801
775
|
assert wgrates == pol.wage_growth_rates(2017)
|
802
776
|
assert pirates == pol.inflation_rates(2017)
|
@@ -810,11 +784,11 @@ def test_reform_with_removed_parameter(monkeypatch):
|
|
810
784
|
Try to use removed parameter in a reform.
|
811
785
|
"""
|
812
786
|
policy1 = Policy()
|
813
|
-
reform1 = {
|
787
|
+
reform1 = {"FilerCredit_c": {2020: 1000}}
|
814
788
|
with pytest.raises(paramtools.ValidationError):
|
815
789
|
policy1.implement_reform(reform1)
|
816
790
|
policy2 = Policy()
|
817
|
-
reform2 = {
|
791
|
+
reform2 = {"FilerCredit_c-indexed": {2020: True}}
|
818
792
|
with pytest.raises(paramtools.ValidationError):
|
819
793
|
policy2.implement_reform(reform2)
|
820
794
|
|
@@ -831,7 +805,7 @@ def test_reform_with_out_of_range_error():
|
|
831
805
|
Try to use out-of-range values versus other parameter values in a reform.
|
832
806
|
"""
|
833
807
|
pol = Policy()
|
834
|
-
reform = {
|
808
|
+
reform = {"SS_thd2": {2020: [20000, 20000, 20000, 20000, 20000]}}
|
835
809
|
pol.implement_reform(reform, raise_errors=False)
|
836
810
|
assert pol.parameter_errors
|
837
811
|
|
@@ -841,12 +815,12 @@ def test_reform_with_warning():
|
|
841
815
|
Try to use warned out-of-range parameter value in reform.
|
842
816
|
"""
|
843
817
|
exp_warnings = {
|
844
|
-
|
845
|
-
|
818
|
+
"ID_Medical_frt": [
|
819
|
+
"ID_Medical_frt[year=2020] 0.05 < min 0.075 "
|
846
820
|
]
|
847
821
|
}
|
848
822
|
pol = Policy()
|
849
|
-
reform = {
|
823
|
+
reform = {"ID_Medical_frt": {2020: 0.05}}
|
850
824
|
|
851
825
|
pol.implement_reform(reform, print_warnings=True)
|
852
826
|
assert pol.warnings == exp_warnings
|
@@ -864,17 +838,17 @@ def test_reform_with_scalar_vector_errors():
|
|
864
838
|
Test catching scalar-vector confusion.
|
865
839
|
"""
|
866
840
|
policy1 = Policy()
|
867
|
-
reform1 = {
|
841
|
+
reform1 = {"SS_thd2": {2020: 30000}}
|
868
842
|
with pytest.raises(paramtools.ValidationError):
|
869
843
|
policy1.implement_reform(reform1)
|
870
844
|
|
871
845
|
policy2 = Policy()
|
872
|
-
reform2 = {
|
846
|
+
reform2 = {"ID_Medical_frt": {2020: [0.08]}}
|
873
847
|
with pytest.raises(paramtools.ValidationError):
|
874
848
|
policy2.implement_reform(reform2)
|
875
849
|
|
876
850
|
policy3 = Policy()
|
877
|
-
reform3 = {
|
851
|
+
reform3 = {"ID_Medical_frt": [{"year": 2020, "value": [0.08]}]}
|
878
852
|
with pytest.raises(paramtools.ValidationError):
|
879
853
|
policy3.adjust(reform3)
|
880
854
|
|
@@ -893,35 +867,35 @@ def test_reform_with_scalar_vector_errors():
|
|
893
867
|
def test_index_offset_reform():
|
894
868
|
"""
|
895
869
|
Test a reform that includes both a change in parameter_indexing_CPI_offset
|
896
|
-
and a change in a variable
|
870
|
+
and a change in a variable"s indexed status in the same year.
|
897
871
|
"""
|
898
872
|
# create policy0 to extract inflation rates before any
|
899
873
|
# parameter_indexing_CPI_offset
|
900
874
|
policy0 = Policy()
|
901
|
-
policy0.implement_reform({
|
875
|
+
policy0.implement_reform({"parameter_indexing_CPI_offset": {2017: 0}})
|
902
876
|
cpiu_rates = policy0.inflation_rates()
|
903
877
|
|
904
|
-
reform1 = {
|
878
|
+
reform1 = {"ODC_c-indexed": {2020: True}}
|
905
879
|
policy1 = Policy()
|
906
880
|
policy1.implement_reform(reform1)
|
907
881
|
offset = -0.005
|
908
|
-
reform2 = {
|
909
|
-
|
882
|
+
reform2 = {"ODC_c-indexed": {2020: True},
|
883
|
+
"parameter_indexing_CPI_offset": {2020: offset}}
|
910
884
|
policy2 = Policy()
|
911
|
-
policy2.implement_reform(reform2)
|
912
|
-
# extract from policy1 and policy2 the parameter values of
|
885
|
+
policy2.implement_reform(reform2)
|
886
|
+
# extract from policy1 and policy2 the parameter values of ODC_c
|
913
887
|
pvalue1 = {}
|
914
888
|
pvalue2 = {}
|
915
889
|
for cyr in [2019, 2020, 2021]:
|
916
890
|
policy1.set_year(cyr)
|
917
|
-
pvalue1[cyr] = policy1.
|
891
|
+
pvalue1[cyr] = policy1.ODC_c[0]
|
918
892
|
policy2.set_year(cyr)
|
919
|
-
pvalue2[cyr] = policy2.
|
893
|
+
pvalue2[cyr] = policy2.ODC_c[0]
|
920
894
|
# check that pvalue1 and pvalue2 dictionaries contain the expected values
|
921
895
|
assert pvalue2[2019] == pvalue1[2019]
|
922
896
|
assert pvalue2[2020] == pvalue1[2020]
|
923
897
|
assert pvalue2[2020] == pvalue2[2019]
|
924
|
-
# ... indexing of
|
898
|
+
# ... indexing of ODC_c begins shows up first in 2021 parameter values
|
925
899
|
assert pvalue1[2021] > pvalue1[2020]
|
926
900
|
assert pvalue2[2021] > pvalue2[2020]
|
927
901
|
# ... calculate expected pvalue2[2021] from inflation rates and offset
|
@@ -937,8 +911,8 @@ def test_cpi_offset_affect_on_prior_years():
|
|
937
911
|
Test that parameter_indexing_CPI_offset does not have affect
|
938
912
|
on inflation rates in earlier years.
|
939
913
|
"""
|
940
|
-
reform1 = {
|
941
|
-
reform2 = {
|
914
|
+
reform1 = {"parameter_indexing_CPI_offset": {2022: 0}}
|
915
|
+
reform2 = {"parameter_indexing_CPI_offset": {2022: -0.005}}
|
942
916
|
p1 = Policy()
|
943
917
|
p2 = Policy()
|
944
918
|
p1.implement_reform(reform1)
|
@@ -966,11 +940,11 @@ def test_cpi_offset_on_reverting_params():
|
|
966
940
|
Test that params that revert to their pre-TCJA values
|
967
941
|
in 2026 revert if a parameter_indexing_CPI_offset is specified.
|
968
942
|
"""
|
969
|
-
reform0 = {
|
970
|
-
reform1 = {
|
971
|
-
|
972
|
-
reform2 = {
|
973
|
-
|
943
|
+
reform0 = {"parameter_indexing_CPI_offset": {2020: -0.001}}
|
944
|
+
reform1 = {"STD": {2017: [6350, 12700, 6350, 9350, 12700]},
|
945
|
+
"parameter_indexing_CPI_offset": {2020: -0.001}}
|
946
|
+
reform2 = {"STD": {2020: [10000, 20000, 10000, 10000, 20000]},
|
947
|
+
"parameter_indexing_CPI_offset": {2020: -0.001}}
|
974
948
|
|
975
949
|
p0 = Policy()
|
976
950
|
p1 = Policy()
|
@@ -998,11 +972,15 @@ def test_raise_errors_regression():
|
|
998
972
|
"""
|
999
973
|
This tests that raise_errors prevents the error from being thrown. The
|
1000
974
|
correct behavior is to exit the `adjust` function and store the errors.
|
975
|
+
** From the parameters.py docstring for the adjust method:
|
976
|
+
raise_errors: Boolean
|
977
|
+
Raise errors as a ValidationError. If False, they will be stored
|
978
|
+
in the errors attribute.
|
1001
979
|
"""
|
1002
980
|
ref = {
|
1003
|
-
"II_brk7-indexed": [{"value":
|
981
|
+
"II_brk7-indexed": [{"value": False}],
|
1004
982
|
"II_brk6": [{"value": 316700, "MARS": "single", "year": 2020}],
|
1005
|
-
"II_brk7": [{"value":
|
983
|
+
"II_brk7": [{"value": 320700, "MARS": "single", "year": 2020}],
|
1006
984
|
|
1007
985
|
}
|
1008
986
|
pol = Policy()
|
@@ -1177,14 +1155,14 @@ def test_activate_index():
|
|
1177
1155
|
"""
|
1178
1156
|
pol1 = Policy()
|
1179
1157
|
pol1.implement_reform({
|
1180
|
-
"
|
1181
|
-
"
|
1158
|
+
"ODC_c": {2022: 1000},
|
1159
|
+
"ODC_c-indexed": {2022: True}
|
1182
1160
|
})
|
1183
1161
|
pol2 = Policy()
|
1184
1162
|
pol2.adjust(
|
1185
1163
|
{
|
1186
|
-
"
|
1187
|
-
"
|
1164
|
+
"ODC_c": [{"year": 2022, "value": 1000}],
|
1165
|
+
"ODC_c-indexed": [{"year": 2022, "value": True}],
|
1188
1166
|
}
|
1189
1167
|
)
|
1190
1168
|
cmp_policy_objs(pol1, pol2)
|
@@ -1193,12 +1171,12 @@ def test_activate_index():
|
|
1193
1171
|
pol0.set_year(year=2021)
|
1194
1172
|
pol2.set_state(year=[2021, 2022, 2023])
|
1195
1173
|
exp = np.array([
|
1196
|
-
pol0.
|
1197
|
-
|
1198
|
-
|
1174
|
+
pol0.ODC_c[0],
|
1175
|
+
1000,
|
1176
|
+
1000 * (1 + pol2.inflation_rates(year=2022))
|
1199
1177
|
]).round(2)
|
1200
1178
|
|
1201
|
-
np.testing.assert_allclose(pol2.
|
1179
|
+
np.testing.assert_allclose(pol2.ODC_c, exp)
|
1202
1180
|
|
1203
1181
|
|
1204
1182
|
def test_apply_cpi_offset():
|
@@ -1243,7 +1221,7 @@ def test_apply_cpi_offset():
|
|
1243
1221
|
|
1244
1222
|
def test_multiple_cpi_swaps():
|
1245
1223
|
"""
|
1246
|
-
Test changing a parameter
|
1224
|
+
Test changing a parameter"s indexed status multiple times.
|
1247
1225
|
"""
|
1248
1226
|
pol1 = Policy()
|
1249
1227
|
pol1.implement_reform(
|
@@ -1404,7 +1382,7 @@ def test_adj_cpi_offset_and_index_status():
|
|
1404
1382
|
"""
|
1405
1383
|
pol1 = Policy()
|
1406
1384
|
pol1.implement_reform({
|
1407
|
-
"
|
1385
|
+
"ODC_c-indexed": {2020: True},
|
1408
1386
|
"parameter_indexing_CPI_offset": {2020: -0.005}},
|
1409
1387
|
)
|
1410
1388
|
pol2 = Policy()
|
@@ -1412,7 +1390,7 @@ def test_adj_cpi_offset_and_index_status():
|
|
1412
1390
|
{
|
1413
1391
|
"parameter_indexing_CPI_offset":
|
1414
1392
|
[{"year": 2020, "value": -0.005}],
|
1415
|
-
"
|
1393
|
+
"ODC_c-indexed": [{"year": 2020, "value": True}],
|
1416
1394
|
}
|
1417
1395
|
)
|
1418
1396
|
cmp_policy_objs(pol1, pol2)
|
@@ -1429,7 +1407,7 @@ def test_adj_cpi_offset_and_index_status():
|
|
1429
1407
|
|
1430
1408
|
pol2.set_state(year=[2021, 2022])
|
1431
1409
|
np.testing.assert_equal(
|
1432
|
-
(pol2.
|
1410
|
+
(pol2.ODC_c[1] / pol2.ODC_c[0] - 1).round(4),
|
1433
1411
|
round(pol0.inflation_rates(year=2021) + (-0.005), 4),
|
1434
1412
|
)
|
1435
1413
|
|
@@ -1515,48 +1493,48 @@ def test_cpi_offset_does_not_affect_wage_indexed_params():
|
|
1515
1493
|
np.testing.assert_equal(act_before_2025, exp_before_2025)
|
1516
1494
|
|
1517
1495
|
|
1518
|
-
def
|
1496
|
+
def test_ext_plus_odc1_reform(tests_path):
|
1519
1497
|
"""
|
1520
|
-
Test ext.json plus
|
1498
|
+
Test ext.json plus odc1 compound reform relative to ext.json baseline.
|
1521
1499
|
"""
|
1522
1500
|
# specify baseline policy, bas, as the extend-TCJA reform
|
1523
1501
|
bas = Policy()
|
1524
|
-
filename = os.path.join(tests_path,
|
1525
|
-
with open(filename,
|
1502
|
+
filename = os.path.join(tests_path, "..", "reforms", "ext.json")
|
1503
|
+
with open(filename, "r", encoding="utf-8") as rfile:
|
1526
1504
|
ext_text = rfile.read()
|
1527
1505
|
bas.implement_reform(Policy.read_json_reform(ext_text))
|
1528
1506
|
assert not bas.parameter_errors
|
1529
|
-
# specify reform policy, ref, as extend-TCJA plus liberalization of
|
1507
|
+
# specify reform policy, ref, as extend-TCJA plus liberalization of ODC
|
1530
1508
|
ref = Policy()
|
1531
1509
|
ref.implement_reform(Policy.read_json_reform(ext_text))
|
1532
|
-
|
1533
|
-
# one possible
|
1534
|
-
|
1535
|
-
2026:
|
1536
|
-
2027:
|
1537
|
-
2028:
|
1538
|
-
2029:
|
1510
|
+
odc1_reform = {
|
1511
|
+
# one possible other-dependent-credit revision to extend-TCJA reform
|
1512
|
+
"ODC_c": {
|
1513
|
+
2026: 1000.00,
|
1514
|
+
2027: 1000.00,
|
1515
|
+
2028: 1000.00,
|
1516
|
+
2029: 1000.00,
|
1539
1517
|
},
|
1540
|
-
|
1518
|
+
"ODC_c-indexed": {2029: True},
|
1541
1519
|
}
|
1542
|
-
ref.implement_reform(
|
1520
|
+
ref.implement_reform(odc1_reform)
|
1543
1521
|
assert not ref.parameter_errors
|
1544
1522
|
# check bas and ref parameter values against expected parameter values
|
1545
|
-
|
1546
|
-
2025:
|
1547
|
-
2026:
|
1548
|
-
2027:
|
1549
|
-
2028:
|
1550
|
-
2029:
|
1551
|
-
2030:
|
1523
|
+
exp_odc_c_bas = {
|
1524
|
+
2025: 500,
|
1525
|
+
2026: 500,
|
1526
|
+
2027: 500,
|
1527
|
+
2028: 500,
|
1528
|
+
2029: 500,
|
1529
|
+
2030: 500,
|
1552
1530
|
}
|
1553
|
-
|
1554
|
-
2025:
|
1555
|
-
2026:
|
1556
|
-
2027:
|
1557
|
-
2028:
|
1558
|
-
2029:
|
1559
|
-
2030:
|
1531
|
+
exp_odc_c_ref = {
|
1532
|
+
2025: 500,
|
1533
|
+
2026: 1000,
|
1534
|
+
2027: 1000,
|
1535
|
+
2028: 1000,
|
1536
|
+
2029: 1000,
|
1537
|
+
2030: 1022.4,
|
1560
1538
|
}
|
1561
1539
|
exp_actc_c = {
|
1562
1540
|
2025: 1700,
|
@@ -1568,57 +1546,57 @@ def test_ext_plus_ctc1_reform(tests_path):
|
|
1568
1546
|
}
|
1569
1547
|
for year in range(2025, 2031):
|
1570
1548
|
bas.set_year(year)
|
1571
|
-
assert np.allclose([bas.
|
1549
|
+
assert np.allclose([bas.ODC_c], [exp_odc_c_bas[year]])
|
1572
1550
|
assert np.allclose([bas.ACTC_c], [exp_actc_c[year]])
|
1573
1551
|
ref.set_year(year)
|
1574
|
-
assert np.allclose([ref.
|
1552
|
+
assert np.allclose([ref.ODC_c], [exp_odc_c_ref[year]])
|
1575
1553
|
assert np.allclose([ref.ACTC_c], [exp_actc_c[year]])
|
1576
1554
|
|
1577
1555
|
|
1578
|
-
def
|
1556
|
+
def test_ext_plus_odc2_reform(tests_path):
|
1579
1557
|
"""
|
1580
|
-
Test ext.json plus
|
1558
|
+
Test ext.json plus odc2 compound reform relative to ext.json baseline.
|
1581
1559
|
"""
|
1582
1560
|
# specify baseline policy, bas, as the extend-TCJA reform
|
1583
1561
|
bas = Policy()
|
1584
|
-
filename = os.path.join(tests_path,
|
1585
|
-
with open(filename,
|
1562
|
+
filename = os.path.join(tests_path, "..", "reforms", "ext.json")
|
1563
|
+
with open(filename, "r", encoding="utf-8") as rfile:
|
1586
1564
|
ext_text = rfile.read()
|
1587
1565
|
bas.implement_reform(Policy.read_json_reform(ext_text))
|
1588
1566
|
assert not bas.parameter_errors
|
1589
|
-
# specify reform policy, ref, as extend-TCJA plus liberalization of
|
1567
|
+
# specify reform policy, ref, as extend-TCJA plus liberalization of ODC
|
1590
1568
|
ref = Policy()
|
1591
1569
|
ref.implement_reform(Policy.read_json_reform(ext_text))
|
1592
|
-
|
1593
|
-
# one possible
|
1594
|
-
|
1595
|
-
2026:
|
1596
|
-
2027:
|
1597
|
-
2028:
|
1598
|
-
2029:
|
1570
|
+
odc2_reform = {
|
1571
|
+
# one possible other-dependent-credit revision to extend-TCJA reform
|
1572
|
+
"ODC_c": {
|
1573
|
+
2026: 600.00,
|
1574
|
+
2027: 600.00,
|
1575
|
+
2028: 600.00,
|
1576
|
+
2029: 800.00,
|
1599
1577
|
},
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1578
|
+
"ODC_c-indexed": {2029: True},
|
1579
|
+
"ACTC_c": {2029: 1750},
|
1580
|
+
"ACTC_c-indexed": {2029: False},
|
1603
1581
|
}
|
1604
|
-
ref.implement_reform(
|
1582
|
+
ref.implement_reform(odc2_reform)
|
1605
1583
|
assert not ref.parameter_errors
|
1606
1584
|
# check bas and ref parameter values against expected parameter values
|
1607
|
-
|
1608
|
-
2025:
|
1609
|
-
2026:
|
1610
|
-
2027:
|
1611
|
-
2028:
|
1612
|
-
2029:
|
1613
|
-
2030:
|
1585
|
+
exp_odc_c_bas = {
|
1586
|
+
2025: 500,
|
1587
|
+
2026: 500,
|
1588
|
+
2027: 500,
|
1589
|
+
2028: 500,
|
1590
|
+
2029: 500,
|
1591
|
+
2030: 500,
|
1614
1592
|
}
|
1615
|
-
|
1616
|
-
2025:
|
1617
|
-
2026:
|
1618
|
-
2027:
|
1619
|
-
2028:
|
1620
|
-
2029:
|
1621
|
-
2030:
|
1593
|
+
exp_odc_c_ref = {
|
1594
|
+
2025: 500,
|
1595
|
+
2026: 600,
|
1596
|
+
2027: 600,
|
1597
|
+
2028: 600,
|
1598
|
+
2029: 800,
|
1599
|
+
2030: 817.92,
|
1622
1600
|
}
|
1623
1601
|
exp_actc_c_bas = {
|
1624
1602
|
2025: 1700,
|
@@ -1638,8 +1616,8 @@ def test_ext_plus_ctc2_reform(tests_path):
|
|
1638
1616
|
}
|
1639
1617
|
for year in range(2025, 2031):
|
1640
1618
|
bas.set_year(year)
|
1641
|
-
assert np.allclose([bas.
|
1619
|
+
assert np.allclose([bas.ODC_c], [exp_odc_c_bas[year]])
|
1642
1620
|
assert np.allclose([bas.ACTC_c], [exp_actc_c_bas[year]])
|
1643
1621
|
ref.set_year(year)
|
1644
|
-
assert np.allclose([ref.
|
1622
|
+
assert np.allclose([ref.ODC_c], [exp_odc_c_ref[year]])
|
1645
1623
|
assert np.allclose([ref.ACTC_c], [exp_actc_c_ref[year]])
|