From ed000d79b8673ba818790f592a61ac14889e9c5e Mon Sep 17 00:00:00 2001 From: "martin.holmer@gmail.com" Date: Sun, 29 Sep 2024 10:27:22 -0400 Subject: [PATCH 1/8] Fix policy_current_law.json --- taxcalc/policy_current_law.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/taxcalc/policy_current_law.json b/taxcalc/policy_current_law.json index ef7aaf872..14fb6b27d 100644 --- a/taxcalc/policy_current_law.json +++ b/taxcalc/policy_current_law.json @@ -1586,27 +1586,27 @@ "value": 610000.0 }, { - "year": 2026, + "year": 2029, "MARS": "single", "value": 9e+99 }, { - "year": 2026, + "year": 2029, "MARS": "mjoint", "value": 9e+99 }, { - "year": 2026, + "year": 2029, "MARS": "mseparate", "value": 9e+99 }, { - "year": 2026, + "year": 2029, "MARS": "headhh", "value": 9e+99 }, { - "year": 2026, + "year": 2029, "MARS": "widow", "value": 9e+99 } From 461eb718db4b28fa2e8c4f921b41defe83c71717 Mon Sep 17 00:00:00 2001 From: "martin.holmer@gmail.com" Date: Sun, 29 Sep 2024 10:28:48 -0400 Subject: [PATCH 2/8] Fix extend_tcja.py to handle ALD_BusinessLosses_c revert timing --- extend_tcja.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/extend_tcja.py b/extend_tcja.py index 803047123..193273e72 100644 --- a/extend_tcja.py +++ b/extend_tcja.py @@ -3,7 +3,9 @@ extend_tcja.json, that can serve as an alternative baseline to current-law policy (which ends TCJA temporary provisions after 2025). -USAGE: (taxcalc-dev) ~% python extend_tcja.py +USAGE: (taxcalc-dev) Tax-Calculator% python extend_tcja.py > ext.json + THEN CHECK: % diff ext.json taxcalc/reforms/ext.json + IF DIFFS: % mv ext.json taxcalc/reforms/ext.json WHEN TO USE: use this script to update reforms/ext.json in these situations: (a) whenever inflation rates in the growfactors.csv files are changed @@ -92,7 +94,8 @@ def main(): # calculate 2025-to-2026 parameters indexing factor pol = taxcalc.Policy() pirates = pol.inflation_rates() - ifactor = 1.0 + pirates[2025-taxcalc.Policy.JSON_START_YEAR] + ifactor25 = 1.0 + pirates[2025-taxcalc.Policy.JSON_START_YEAR] + ifactor28 = 1.0 + pirates[2028-taxcalc.Policy.JSON_START_YEAR] # specify extend-TCJA-beyond-2025 reform # ... get 2025 parameter values pol.set_year(2025) @@ -100,28 +103,42 @@ def main(): # ... write reform header comments print( '// REFORM TO EXTEND TEMPORARY TCJA PROVISIONS BEYOND 2025') print(f'// USING TAX-CALCULATOR {taxcalc.__version__}') - print(f'// WITH 2025-to-2026 INDEXING FACTOR = {ifactor:.6f}') + print(f'// WITH 2025-to-2026 INDEXING FACTOR = {ifactor25:.6f}') + print(f'// AND 2028-to-2029 INDEXING FACTOR = {ifactor28:.6f}') if TCJA_CATEGORY: print(f'// ONLY TCJA PROVISIONS IN CATEGORY {TCJA_CATEGORY}') print('{') - # ... set 2026 nonreverted values for the parameters set to revert + # ... set 2026/29 nonreverted values for the parameters set to revert + left_brace = '{' + year = 2026 for pname, pinfo in TCJA_PARAMETERS.items(): if TCJA_CATEGORY and pinfo['category'] != TCJA_CATEGORY: continue # skip this parameter + if pname == 'ALD_BusinessLosses_c': + ifactor = ifactor28 + year = 2029 + pol.set_year(2028) + pdata = dict(pol.items()) + else: + if year != 2026: + pol.set_year(2028) + pdata = dict(pol.items()) + ifactor = ifactor25 + year = 2026 if pinfo['indexed']: pval = pdata[pname][0] * ifactor if isinstance(pval, numpy.ndarray): # handle vector parameter pval = numpy.minimum(9e99, pval.round(2)) sys.stdout.write(f' "{pname}": ') - sys.stdout.write('{"2026": ') + sys.stdout.write(f'{left_brace}"{year}": ') sys.stdout.write(f'{pval.tolist()}') sys.stdout.write('},\n') else: # handle scalar parameter pval = min(9e99, pval) sys.stdout.write(f' "{pname}": ') - sys.stdout.write('{"2026": ') + sys.stdout.write(f'{left_brace}"{year}": ') sys.stdout.write(f'{pval*ifactor:.2f}') sys.stdout.write('},\n') else: # if parameter is not indexed @@ -130,13 +147,13 @@ def main(): # handle vector parameter pval = numpy.minimum(9e99, pval.round(2)) sys.stdout.write(f' "{pname}": ') - sys.stdout.write('{"2026": ') + sys.stdout.write(f'{left_brace}"{year}": ') sys.stdout.write(f'{pval.tolist()}') sys.stdout.write('},\n') else: # handle scalar parameter sys.stdout.write(f' "{pname}": ') - sys.stdout.write('{"2026": ') + sys.stdout.write(f'{left_brace}"{year}": ') sys.stdout.write(f'{pval:.2f}') sys.stdout.write('},\n') print('}') From 50e41108fb253ee08ddb8656ee35d9c82b38f4be Mon Sep 17 00:00:00 2001 From: "martin.holmer@gmail.com" Date: Sun, 29 Sep 2024 10:29:37 -0400 Subject: [PATCH 3/8] Revise reforms/ext.json to handle ALD_BusinessLosses_c revert timing --- taxcalc/reforms/ext.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/taxcalc/reforms/ext.json b/taxcalc/reforms/ext.json index f0f2a90e6..aee966334 100644 --- a/taxcalc/reforms/ext.json +++ b/taxcalc/reforms/ext.json @@ -1,6 +1,7 @@ // REFORM TO EXTEND TEMPORARY TCJA PROVISIONS BEYOND 2025 // USING TAX-CALCULATOR 4.2.2b // WITH 2025-to-2026 INDEXING FACTOR = 1.022000 +// AND 2028-to-2029 INDEXING FACTOR = 1.019400 { "II_rt1": {"2026": 0.10}, "II_brk1": {"2026": [12157.51, 24315.02, 12157.51, 17345.41, 24315.02]}, @@ -54,5 +55,5 @@ "PT_qbid_w2_wages_rt": {"2026": 0.50}, "PT_qbid_alt_w2_wages_rt": {"2026": 0.25}, "PT_qbid_alt_property_rt": {"2026": 0.03}, - "ALD_BusinessLosses_c": {"2026": [319658.6, 639317.21, 319658.6, 319658.6, 639317.21]} + "ALD_BusinessLosses_c": {"2029": [339091.08, 678182.18, 339091.08, 339091.08, 678182.18]}, } From 9eeec8c63e68b2663b3f1db6df2a7ff04eff31c8 Mon Sep 17 00:00:00 2001 From: "martin.holmer@gmail.com" Date: Sun, 29 Sep 2024 10:30:48 -0400 Subject: [PATCH 4/8] Add extend_tcja step to docs/contributing/RELEASING.md --- docs/contributing/RELEASING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing/RELEASING.md b/docs/contributing/RELEASING.md index 59e43c0a0..41f57c904 100755 --- a/docs/contributing/RELEASING.md +++ b/docs/contributing/RELEASING.md @@ -13,6 +13,8 @@ Create new `taxcalc` packages --> merge master branch into X-Y-Z branch +--> run `python extend_tcja.py` [update taxcalc/reforms/ext.json if needed] + --> run `make tctest-jit` [to make sure JIT decorators are not hiding bugs] --> run `make pytest-all` [or `pytest -m pre_release -n4` in taxcalc subdir] From 46909c45b7cdc44804d865d10c3c6394c6abc5a7 Mon Sep 17 00:00:00 2001 From: "martin.holmer@gmail.com" Date: Sun, 29 Sep 2024 10:44:04 -0400 Subject: [PATCH 5/8] Fix typo in extend_tcja.py script --- extend_tcja.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extend_tcja.py b/extend_tcja.py index 193273e72..a9c843c9d 100644 --- a/extend_tcja.py +++ b/extend_tcja.py @@ -121,7 +121,7 @@ def main(): pdata = dict(pol.items()) else: if year != 2026: - pol.set_year(2028) + pol.set_year(2025) pdata = dict(pol.items()) ifactor = ifactor25 year = 2026 From 7b1618409d2a7862bea868f0642e0043d4a809b5 Mon Sep 17 00:00:00 2001 From: "martin.holmer@gmail.com" Date: Sun, 29 Sep 2024 11:14:14 -0400 Subject: [PATCH 6/8] Fix typo in ext.json --- taxcalc/reforms/ext.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taxcalc/reforms/ext.json b/taxcalc/reforms/ext.json index aee966334..baf2c81c7 100644 --- a/taxcalc/reforms/ext.json +++ b/taxcalc/reforms/ext.json @@ -55,5 +55,5 @@ "PT_qbid_w2_wages_rt": {"2026": 0.50}, "PT_qbid_alt_w2_wages_rt": {"2026": 0.25}, "PT_qbid_alt_property_rt": {"2026": 0.03}, - "ALD_BusinessLosses_c": {"2029": [339091.08, 678182.18, 339091.08, 339091.08, 678182.18]}, + "ALD_BusinessLosses_c": {"2029": [339091.08, 678182.18, 339091.08, 339091.08, 678182.18]} } From 8a4208d771c9a4e0c8c83d7a15a1d87b0ff916d9 Mon Sep 17 00:00:00 2001 From: "martin.holmer@gmail.com" Date: Sun, 29 Sep 2024 16:13:40 -0400 Subject: [PATCH 7/8] Update tests/pufcsv_agg_expect.csv results --- taxcalc/tests/pufcsv_agg_expect.csv | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/taxcalc/tests/pufcsv_agg_expect.csv b/taxcalc/tests/pufcsv_agg_expect.csv index c4190a2c9..8b7b27a3e 100644 --- a/taxcalc/tests/pufcsv_agg_expect.csv +++ b/taxcalc/tests/pufcsv_agg_expect.csv @@ -1,25 +1,25 @@ ,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026 Returns (#m),190.9,194.3,197.3,200.1,202.9,205.6,208.4,211.2,214.0,216.8 -AGI ($b),11078.7,11816.6,12247.2,12722.3,14930.0,14973.9,15955.0,16597.4,17310.1,17868.8 +AGI ($b),11078.7,11816.6,12247.2,12722.3,14930.0,14973.9,15955.0,16597.4,17310.1,18001.3 Itemizers (#m),45.7,19.4,20.0,21.0,22.6,22.8,21.7,21.2,21.3,52.0 -Itemized Deduction ($b),1274.3,602.7,633.9,692.3,761.9,782.7,788.7,808.1,835.2,2048.0 +Itemized Deduction ($b),1274.3,602.7,633.9,692.3,761.9,782.7,788.7,808.1,835.2,2047.5 Standard Deduction Filers (#m),145.2,174.8,177.2,178.5,179.6,182.8,186.7,190.0,192.6,164.8 Standard Deduction ($b),1239.3,2865.3,2954.5,3025.8,3081.1,3234.0,3537.5,3798.4,3952.6,1853.9 -Personal Exemption ($b),1365.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1959.1 -Taxable Income ($b),8112.2,9179.2,9520.5,9907.3,12003.2,11927.7,12697.8,13130.7,13703.8,13394.9 -Regular Tax ($b),1656.8,1712.3,1778.2,1838.3,2281.5,2282.7,2423.4,2489.9,2601.1,2798.5 -AMT Income ($b),10512.4,11343.5,11749.7,12180.1,14330.8,14356.1,15323.1,15943.0,16630.5,16950.0 -AMT Liability ($b),51.3,22.1,23.0,25.1,27.8,27.4,28.8,30.3,31.8,85.1 +Personal Exemption ($b),1365.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1959.0 +Taxable Income ($b),8112.2,9179.2,9520.5,9907.3,12003.2,11927.7,12697.8,13130.7,13703.8,13460.3 +Regular Tax ($b),1656.8,1712.3,1778.2,1838.3,2281.5,2282.7,2423.4,2489.9,2601.1,2816.2 +AMT Income ($b),10512.4,11343.5,11749.7,12180.1,14330.8,14356.1,15323.1,15943.0,16630.5,17082.5 +AMT Liability ($b),51.3,22.1,23.0,25.1,27.8,27.4,28.8,30.3,31.8,87.9 AMT Filers (#m),5.7,0.2,0.2,0.3,0.4,0.3,0.3,0.3,0.3,7.4 -Tax before Credits ($b),1708.1,1734.4,1801.1,1863.4,2309.4,2310.1,2452.2,2520.2,2632.9,2883.5 -Refundable Credits ($b),102.9,117.5,118.5,642.0,802.6,119.2,126.9,132.8,135.0,121.8 +Tax before Credits ($b),1708.1,1734.4,1801.1,1863.4,2309.4,2310.1,2452.2,2520.2,2632.9,2904.0 +Refundable Credits ($b),102.9,117.5,118.5,642.0,802.6,119.2,126.9,132.8,135.0,121.7 Nonrefundable Credits ($b),67.0,127.3,129.2,128.5,47.6,141.0,143.3,144.0,145.7,77.7 Reform Surtaxes ($b),0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -Other Taxes ($b),40.0,44.8,43.6,52.9,84.9,61.5,66.5,65.2,66.0,64.3 -Ind Income Tax ($b),1578.2,1534.3,1597.0,1145.8,1544.0,2111.5,2248.5,2308.6,2418.2,2748.4 +Other Taxes ($b),40.0,44.8,43.6,52.9,84.9,61.5,66.5,65.2,66.0,66.3 +Ind Income Tax ($b),1578.2,1534.3,1597.0,1145.8,1544.0,2111.5,2248.5,2308.6,2418.2,2770.9 Payroll Taxes ($b),1083.8,1133.3,1185.4,1209.0,1306.0,1403.4,1492.6,1568.0,1642.1,1715.4 -Combined Liability ($b),2662.0,2667.7,2782.4,2354.8,2850.0,3514.9,3741.1,3876.6,4060.3,4463.7 -With Income Tax <= 0 (#m),92.8,98.6,99.7,131.7,125.0,100.3,101.8,103.4,104.3,101.0 +Combined Liability ($b),2662.0,2667.7,2782.4,2354.8,2850.0,3514.9,3741.1,3876.6,4060.3,4486.3 +With Income Tax <= 0 (#m),92.8,98.6,99.7,131.7,125.0,100.3,101.8,103.4,104.3,100.9 With Combined Tax <= 0 (#m),63.4,65.6,66.8,102.1,94.5,68.9,70.2,71.6,72.6,72.3 UBI Benefits ($b),0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "Total Benefits, Consumption Value ($b)",1052.3,1104.9,1175.3,1243.9,1476.4,1411.5,1569.5,1707.8,1818.1,1924.4 From 32530c732fa9d2a9715e5034dccb2e5b30f470a6 Mon Sep 17 00:00:00 2001 From: "martin.holmer@gmail.com" Date: Mon, 30 Sep 2024 09:13:43 -0400 Subject: [PATCH 8/8] Better handle tailing comma in extend_tcja.py --- extend_tcja.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/extend_tcja.py b/extend_tcja.py index a9c843c9d..7246e379a 100644 --- a/extend_tcja.py +++ b/extend_tcja.py @@ -12,9 +12,6 @@ OR (b) whenever inflation-indexed parameters are updated (usually as part of changes that increase the value of Policy.LAST_KNOWN_YEAR). - -IMPORTANT NOTE: be sure to remove the trailing comma after the last item - in the reform JSON object generated by this script. """ import sys @@ -91,6 +88,8 @@ def main(): """ High-level script logic. """ + # identify last parameter name in TCJA_PARAMETERS + last_pname = list(TCJA_PARAMETERS.keys())[-1] # calculate 2025-to-2026 parameters indexing factor pol = taxcalc.Policy() pirates = pol.inflation_rates() @@ -110,6 +109,7 @@ def main(): print('{') # ... set 2026/29 nonreverted values for the parameters set to revert left_brace = '{' + right_brace = '}' year = 2026 for pname, pinfo in TCJA_PARAMETERS.items(): if TCJA_CATEGORY and pinfo['category'] != TCJA_CATEGORY: @@ -125,6 +125,7 @@ def main(): pdata = dict(pol.items()) ifactor = ifactor25 year = 2026 + trailing_comma = '' if pname == last_pname else ',' if pinfo['indexed']: pval = pdata[pname][0] * ifactor if isinstance(pval, numpy.ndarray): @@ -133,14 +134,14 @@ def main(): sys.stdout.write(f' "{pname}": ') sys.stdout.write(f'{left_brace}"{year}": ') sys.stdout.write(f'{pval.tolist()}') - sys.stdout.write('},\n') + sys.stdout.write(f'{right_brace}{trailing_comma}\n') else: # handle scalar parameter pval = min(9e99, pval) sys.stdout.write(f' "{pname}": ') sys.stdout.write(f'{left_brace}"{year}": ') sys.stdout.write(f'{pval*ifactor:.2f}') - sys.stdout.write('},\n') + sys.stdout.write(f'{right_brace}{trailing_comma}\n') else: # if parameter is not indexed pval = pdata[pname][0] if isinstance(pval, numpy.ndarray): @@ -149,13 +150,13 @@ def main(): sys.stdout.write(f' "{pname}": ') sys.stdout.write(f'{left_brace}"{year}": ') sys.stdout.write(f'{pval.tolist()}') - sys.stdout.write('},\n') + sys.stdout.write(f'{right_brace}{trailing_comma}\n') else: # handle scalar parameter sys.stdout.write(f' "{pname}": ') sys.stdout.write(f'{left_brace}"{year}": ') sys.stdout.write(f'{pval:.2f}') - sys.stdout.write('},\n') + sys.stdout.write(f'{right_brace}{trailing_comma}\n') print('}') return 0 # end main function code