taxcalc 4.6.1__py3-none-any.whl → 4.6.3__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/calcfunctions.py +2 -2
- taxcalc/cli/tc.py +85 -29
- taxcalc/parameters.py +188 -118
- taxcalc/policy.py +26 -4
- taxcalc/policy_current_law.json +2 -2
- taxcalc/reforms/REFORMS.md +0 -2
- taxcalc/reforms/ext.json +0 -2
- taxcalc/taxcalcio.py +95 -24
- taxcalc/tests/conftest.py +1 -1
- taxcalc/tests/reforms.json +8 -19
- taxcalc/tests/reforms_expect.csv +9 -10
- taxcalc/tests/test_4package.py +0 -1
- taxcalc/tests/test_parameters.py +18 -22
- taxcalc/tests/test_policy.py +153 -41
- taxcalc/tests/test_reforms.py +2 -2
- taxcalc/tests/test_taxcalcio.py +35 -13
- taxcalc/utils.py +32 -10
- {taxcalc-4.6.1.dist-info → taxcalc-4.6.3.dist-info}/METADATA +5 -2
- {taxcalc-4.6.1.dist-info → taxcalc-4.6.3.dist-info}/RECORD +24 -24
- {taxcalc-4.6.1.dist-info → taxcalc-4.6.3.dist-info}/WHEEL +1 -1
- {taxcalc-4.6.1.dist-info → taxcalc-4.6.3.dist-info}/entry_points.txt +0 -0
- {taxcalc-4.6.1.dist-info → taxcalc-4.6.3.dist-info}/licenses/LICENSE +0 -0
- {taxcalc-4.6.1.dist-info → taxcalc-4.6.3.dist-info}/top_level.txt +0 -0
taxcalc/tests/test_policy.py
CHANGED
@@ -12,7 +12,7 @@ import os
|
|
12
12
|
import json
|
13
13
|
import numpy as np
|
14
14
|
import pytest
|
15
|
-
import paramtools
|
15
|
+
import paramtools
|
16
16
|
from taxcalc.policy import Policy
|
17
17
|
|
18
18
|
|
@@ -45,21 +45,20 @@ def test_incorrect_class_instantiation():
|
|
45
45
|
Policy(gfactors=[])
|
46
46
|
|
47
47
|
|
48
|
-
def
|
48
|
+
def test_incorrect_implement_reform_usage():
|
49
49
|
"""
|
50
|
-
Test
|
50
|
+
Test for incorrect implement_reform usage.
|
51
51
|
"""
|
52
52
|
pol = Policy()
|
53
53
|
assert pol
|
54
|
-
|
55
|
-
with pytest.raises(pt.ValidationError):
|
54
|
+
with pytest.raises(paramtools.ValidationError):
|
56
55
|
pol.implement_reform([])
|
57
|
-
with pytest.raises(
|
56
|
+
with pytest.raises(paramtools.ValidationError):
|
58
57
|
pol.implement_reform({2099: {'II_em': 99000}})
|
59
58
|
pol.set_year(2019)
|
60
|
-
with pytest.raises(
|
59
|
+
with pytest.raises(paramtools.ValidationError):
|
61
60
|
pol.implement_reform({2018: {'II_em': 99000}})
|
62
|
-
with pytest.raises(
|
61
|
+
with pytest.raises(paramtools.ValidationError):
|
63
62
|
pol.implement_reform({2020: {'II_em': -1000}})
|
64
63
|
|
65
64
|
|
@@ -142,7 +141,7 @@ REFORM_JSON = """
|
|
142
141
|
"""
|
143
142
|
|
144
143
|
|
145
|
-
# pylint: disable=protected-access
|
144
|
+
# pylint: disable=protected-access
|
146
145
|
|
147
146
|
|
148
147
|
@pytest.mark.parametrize("set_year", [False, True])
|
@@ -156,7 +155,6 @@ def test_read_json_reform_file_and_implement_reform(set_year):
|
|
156
155
|
pol.set_year(2015)
|
157
156
|
pol.implement_reform(Policy.read_json_reform(REFORM_JSON))
|
158
157
|
syr = pol.start_year
|
159
|
-
# pylint: disable=protected-access
|
160
158
|
amt_brk1 = pol._AMT_brk1
|
161
159
|
assert amt_brk1[2015 - syr] == 200000
|
162
160
|
assert amt_brk1[2016 - syr] > 200000
|
@@ -414,7 +412,7 @@ def test_implement_reform_raises_on_no_year():
|
|
414
412
|
"""
|
415
413
|
reform = {'STD_Aged': [1400, 1200, 1400, 1400, 1400]}
|
416
414
|
ppo = Policy()
|
417
|
-
with pytest.raises(
|
415
|
+
with pytest.raises(paramtools.ValidationError):
|
418
416
|
ppo.implement_reform(reform)
|
419
417
|
|
420
418
|
|
@@ -424,7 +422,7 @@ def test_implement_reform_raises_on_early_year():
|
|
424
422
|
"""
|
425
423
|
ppo = Policy()
|
426
424
|
reform = {'STD_Aged': {2010: [1400, 1100, 1100, 1400, 1400]}}
|
427
|
-
with pytest.raises(
|
425
|
+
with pytest.raises(paramtools.ValidationError):
|
428
426
|
ppo.implement_reform(reform)
|
429
427
|
|
430
428
|
|
@@ -811,37 +809,24 @@ def test_get_index_rate():
|
|
811
809
|
assert pol.wage_growth_rates() == pol._wage_growth_rates
|
812
810
|
|
813
811
|
|
814
|
-
def test_reform_with_bad_ctc_levels():
|
815
|
-
"""
|
816
|
-
Implement a reform with _ACTC > _CTC_c values.
|
817
|
-
"""
|
818
|
-
pol = Policy()
|
819
|
-
child_credit_reform = {
|
820
|
-
'CTC_c': {2020: 2200},
|
821
|
-
'ACTC_c': {2020: 2500}
|
822
|
-
}
|
823
|
-
with pytest.raises(pt.ValidationError):
|
824
|
-
pol.implement_reform(child_credit_reform)
|
825
|
-
|
826
|
-
|
827
812
|
def test_reform_with_removed_parameter(monkeypatch):
|
828
813
|
"""
|
829
814
|
Try to use removed parameter in a reform.
|
830
815
|
"""
|
831
816
|
policy1 = Policy()
|
832
817
|
reform1 = {'FilerCredit_c': {2020: 1000}}
|
833
|
-
with pytest.raises(
|
818
|
+
with pytest.raises(paramtools.ValidationError):
|
834
819
|
policy1.implement_reform(reform1)
|
835
820
|
policy2 = Policy()
|
836
821
|
reform2 = {'FilerCredit_c-indexed': {2020: True}}
|
837
|
-
with pytest.raises(
|
822
|
+
with pytest.raises(paramtools.ValidationError):
|
838
823
|
policy2.implement_reform(reform2)
|
839
824
|
|
840
825
|
redefined_msg = {"some_redefined": "some_redefined was redefined."}
|
841
826
|
monkeypatch.setattr(Policy, "REDEFINED_PARAMS", redefined_msg)
|
842
827
|
|
843
828
|
pol = Policy()
|
844
|
-
with pytest.raises(
|
829
|
+
with pytest.raises(paramtools.ValidationError):
|
845
830
|
pol.implement_reform({"some_redefined": "hello world"})
|
846
831
|
|
847
832
|
|
@@ -884,28 +869,28 @@ def test_reform_with_scalar_vector_errors():
|
|
884
869
|
"""
|
885
870
|
policy1 = Policy()
|
886
871
|
reform1 = {'SS_thd85': {2020: 30000}}
|
887
|
-
with pytest.raises(
|
872
|
+
with pytest.raises(paramtools.ValidationError):
|
888
873
|
policy1.implement_reform(reform1)
|
889
874
|
|
890
875
|
policy2 = Policy()
|
891
876
|
reform2 = {'ID_Medical_frt': {2020: [0.08]}}
|
892
|
-
with pytest.raises(
|
877
|
+
with pytest.raises(paramtools.ValidationError):
|
893
878
|
policy2.implement_reform(reform2)
|
894
879
|
|
895
880
|
policy3 = Policy()
|
896
881
|
reform3 = {'ID_Medical_frt': [{"year": 2020, "value": [0.08]}]}
|
897
|
-
with pytest.raises(
|
882
|
+
with pytest.raises(paramtools.ValidationError):
|
898
883
|
policy3.adjust(reform3)
|
899
884
|
|
900
885
|
# Check that error is thrown if there are extra elements in array.
|
901
886
|
policy4 = Policy()
|
902
887
|
ref4 = {"II_brk1": {2020: [9700, 19400, 9700, 13850, 19400, 19400]}}
|
903
|
-
with pytest.raises(
|
888
|
+
with pytest.raises(paramtools.ValidationError):
|
904
889
|
policy4.implement_reform(ref4)
|
905
890
|
|
906
891
|
policy5 = Policy()
|
907
892
|
ref5 = {"II_rt1": {2029: [.2, .3]}}
|
908
|
-
with pytest.raises(
|
893
|
+
with pytest.raises(paramtools.ValidationError):
|
909
894
|
policy5.implement_reform(ref5)
|
910
895
|
|
911
896
|
|
@@ -1416,10 +1401,7 @@ def test_multiple_cpi_swaps2():
|
|
1416
1401
|
)
|
1417
1402
|
|
1418
1403
|
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
def test_adj_CPI_offset_and_index_status():
|
1404
|
+
def test_adj_cpi_offset_and_index_status():
|
1423
1405
|
"""
|
1424
1406
|
Test changing parameter_indexing_CPI_offset and another
|
1425
1407
|
parameter simultaneously.
|
@@ -1491,10 +1473,10 @@ def test_adj_related_parameters_and_index_status():
|
|
1491
1473
|
)
|
1492
1474
|
assert res.isel[0]["value"] == [445400]
|
1493
1475
|
|
1494
|
-
|
1495
|
-
|
1476
|
+
ii_brk7 = pol.to_array("II_brk7", year=[2021, 2022])
|
1477
|
+
ii_brk7_single = ii_brk7[:, 0]
|
1496
1478
|
np.testing.assert_equal(
|
1497
|
-
(
|
1479
|
+
(ii_brk7_single[1] / ii_brk7_single[0] - 1).round(4),
|
1498
1480
|
pol.inflation_rates(year=2021),
|
1499
1481
|
)
|
1500
1482
|
|
@@ -1509,7 +1491,7 @@ def test_indexed_status_parsing():
|
|
1509
1491
|
pol2.adjust({"EITC_c-indexed": False})
|
1510
1492
|
cmp_policy_objs(pol1, pol2)
|
1511
1493
|
|
1512
|
-
with pytest.raises(
|
1494
|
+
with pytest.raises(paramtools.ValidationError):
|
1513
1495
|
pol2.adjust({"EITC_c-indexed": 123})
|
1514
1496
|
|
1515
1497
|
|
@@ -1557,3 +1539,133 @@ def test_two_sets_of_tax_brackets():
|
|
1557
1539
|
emsg += f' PT_brk{bnum} is {pt_val}\n'
|
1558
1540
|
if emsg:
|
1559
1541
|
raise ValueError(emsg)
|
1542
|
+
|
1543
|
+
|
1544
|
+
def test_ext_plus_ctc1_reform(tests_path):
|
1545
|
+
"""
|
1546
|
+
Test ext.json plus ctc1 compound reform relative to ext.json baseline.
|
1547
|
+
"""
|
1548
|
+
# specify baseline policy, bas, as the extend-TCJA reform
|
1549
|
+
bas = Policy()
|
1550
|
+
filename = os.path.join(tests_path, '..', 'reforms', 'ext.json')
|
1551
|
+
with open(filename, 'r', encoding='utf-8') as rfile:
|
1552
|
+
ext_text = rfile.read()
|
1553
|
+
bas.implement_reform(Policy.read_json_reform(ext_text))
|
1554
|
+
assert not bas.parameter_errors
|
1555
|
+
# specify reform policy, ref, as extend-TCJA plus liberalization of CTC
|
1556
|
+
ref = Policy()
|
1557
|
+
ref.implement_reform(Policy.read_json_reform(ext_text))
|
1558
|
+
ctc1_reform = {
|
1559
|
+
# one possible child-tax-credit revision to the extend-TCJA reform
|
1560
|
+
'CTC_c': {
|
1561
|
+
2026: 2500.00,
|
1562
|
+
2027: 2500.00,
|
1563
|
+
2028: 2500.00,
|
1564
|
+
2029: 2000.00,
|
1565
|
+
},
|
1566
|
+
'CTC_c-indexed': {2029: True},
|
1567
|
+
}
|
1568
|
+
ref.implement_reform(ctc1_reform)
|
1569
|
+
assert not ref.parameter_errors
|
1570
|
+
# check bas and ref parameter values against expected parameter values
|
1571
|
+
exp_ctc_c_bas = {
|
1572
|
+
2025: 2000,
|
1573
|
+
2026: 2000,
|
1574
|
+
2027: 2000,
|
1575
|
+
2028: 2000,
|
1576
|
+
2029: 2000,
|
1577
|
+
2030: 2000,
|
1578
|
+
}
|
1579
|
+
exp_ctc_c_ref = {
|
1580
|
+
2025: 2000,
|
1581
|
+
2026: 2500,
|
1582
|
+
2027: 2500,
|
1583
|
+
2028: 2500,
|
1584
|
+
2029: 2000,
|
1585
|
+
2030: 2044.80,
|
1586
|
+
}
|
1587
|
+
exp_actc_c = {
|
1588
|
+
2025: 1700,
|
1589
|
+
2026: 1776.67,
|
1590
|
+
2027: 1819.84,
|
1591
|
+
2028: 1861.88,
|
1592
|
+
2029: 1903.96,
|
1593
|
+
2030: 1946.61,
|
1594
|
+
}
|
1595
|
+
for year in range(2025, 2031):
|
1596
|
+
bas.set_year(year)
|
1597
|
+
assert np.allclose([bas.CTC_c], [exp_ctc_c_bas[year]])
|
1598
|
+
assert np.allclose([bas.ACTC_c], [exp_actc_c[year]])
|
1599
|
+
ref.set_year(year)
|
1600
|
+
assert np.allclose([ref.CTC_c], [exp_ctc_c_ref[year]])
|
1601
|
+
assert np.allclose([ref.ACTC_c], [exp_actc_c[year]])
|
1602
|
+
|
1603
|
+
|
1604
|
+
def test_ext_plus_ctc2_reform(tests_path):
|
1605
|
+
"""
|
1606
|
+
Test ext.json plus ctc2 compound reform relative to ext.json baseline.
|
1607
|
+
"""
|
1608
|
+
# specify baseline policy, bas, as the extend-TCJA reform
|
1609
|
+
bas = Policy()
|
1610
|
+
filename = os.path.join(tests_path, '..', 'reforms', 'ext.json')
|
1611
|
+
with open(filename, 'r', encoding='utf-8') as rfile:
|
1612
|
+
ext_text = rfile.read()
|
1613
|
+
bas.implement_reform(Policy.read_json_reform(ext_text))
|
1614
|
+
assert not bas.parameter_errors
|
1615
|
+
# specify reform policy, ref, as extend-TCJA plus liberalization of CTC
|
1616
|
+
ref = Policy()
|
1617
|
+
ref.implement_reform(Policy.read_json_reform(ext_text))
|
1618
|
+
ctc2_reform = {
|
1619
|
+
# one possible child-tax-credit revision to the extend-TCJA reform
|
1620
|
+
'CTC_c': {
|
1621
|
+
2026: 2500.00,
|
1622
|
+
2027: 2500.00,
|
1623
|
+
2028: 2500.00,
|
1624
|
+
2029: 2000.00,
|
1625
|
+
},
|
1626
|
+
'CTC_c-indexed': {2029: True},
|
1627
|
+
'ACTC_c': {2029: 1750},
|
1628
|
+
'ACTC_c-indexed': {2029: False},
|
1629
|
+
}
|
1630
|
+
ref.implement_reform(ctc2_reform)
|
1631
|
+
assert not ref.parameter_errors
|
1632
|
+
# check bas and ref parameter values against expected parameter values
|
1633
|
+
exp_ctc_c_bas = {
|
1634
|
+
2025: 2000,
|
1635
|
+
2026: 2000,
|
1636
|
+
2027: 2000,
|
1637
|
+
2028: 2000,
|
1638
|
+
2029: 2000,
|
1639
|
+
2030: 2000,
|
1640
|
+
}
|
1641
|
+
exp_ctc_c_ref = {
|
1642
|
+
2025: 2000,
|
1643
|
+
2026: 2500,
|
1644
|
+
2027: 2500,
|
1645
|
+
2028: 2500,
|
1646
|
+
2029: 2000,
|
1647
|
+
2030: 2044.80,
|
1648
|
+
}
|
1649
|
+
exp_actc_c_bas = {
|
1650
|
+
2025: 1700,
|
1651
|
+
2026: 1776.67,
|
1652
|
+
2027: 1819.84,
|
1653
|
+
2028: 1861.88,
|
1654
|
+
2029: 1903.96,
|
1655
|
+
2030: 1946.61,
|
1656
|
+
}
|
1657
|
+
exp_actc_c_ref = {
|
1658
|
+
2025: 1700,
|
1659
|
+
2026: 1776.67,
|
1660
|
+
2027: 1819.84,
|
1661
|
+
2028: 1861.88,
|
1662
|
+
2029: 1750,
|
1663
|
+
2030: 1750,
|
1664
|
+
}
|
1665
|
+
for year in range(2025, 2031):
|
1666
|
+
bas.set_year(year)
|
1667
|
+
assert np.allclose([bas.CTC_c], [exp_ctc_c_bas[year]])
|
1668
|
+
assert np.allclose([bas.ACTC_c], [exp_actc_c_bas[year]])
|
1669
|
+
ref.set_year(year)
|
1670
|
+
assert np.allclose([ref.CTC_c], [exp_ctc_c_ref[year]])
|
1671
|
+
assert np.allclose([ref.ACTC_c], [exp_actc_c_ref[year]])
|
taxcalc/tests/test_reforms.py
CHANGED
@@ -338,7 +338,7 @@ def fixture_reforms_dict(tests_path):
|
|
338
338
|
return json.loads(rjson)
|
339
339
|
|
340
340
|
|
341
|
-
NUM_REFORMS =
|
341
|
+
NUM_REFORMS = 63 # when changing this also change num_reforms in conftest.py
|
342
342
|
|
343
343
|
|
344
344
|
@pytest.mark.requires_pufcsv
|
@@ -386,4 +386,4 @@ def test_ext_reform(tests_path):
|
|
386
386
|
iitax_ext = calc_ext.array('iitax')
|
387
387
|
rdiff = iitax_ext - iitax_end
|
388
388
|
weighted_sum_rdiff = (rdiff * calc_end.array('s006')).sum() * 1.0e-9
|
389
|
-
assert np.allclose([weighted_sum_rdiff], [-
|
389
|
+
assert np.allclose([weighted_sum_rdiff], [-214.393], rtol=0.0, atol=0.01)
|
taxcalc/tests/test_taxcalcio.py
CHANGED
@@ -153,6 +153,24 @@ def fixture_errorreformfile():
|
|
153
153
|
pass # sometimes we can't remove a generated temporary file
|
154
154
|
|
155
155
|
|
156
|
+
@pytest.fixture(scope='session', name='ereformfile')
|
157
|
+
def fixture_ereformfile():
|
158
|
+
"""
|
159
|
+
Temporary reform file with .json extension.
|
160
|
+
"""
|
161
|
+
contents = '{"II_em": {"2022": 1000},}'
|
162
|
+
with tempfile.NamedTemporaryFile(
|
163
|
+
suffix='.json', mode='a', delete=False
|
164
|
+
) as rfile:
|
165
|
+
rfile.write(contents)
|
166
|
+
yield rfile
|
167
|
+
if os.path.isfile(rfile.name):
|
168
|
+
try:
|
169
|
+
os.remove(rfile.name)
|
170
|
+
except OSError:
|
171
|
+
pass # sometimes we can't remove a generated temporary file
|
172
|
+
|
173
|
+
|
156
174
|
@pytest.fixture(scope='session', name='errorassumpfile')
|
157
175
|
def fixture_errorassumpfile():
|
158
176
|
"""
|
@@ -249,6 +267,7 @@ def fixture_assumpfile2():
|
|
249
267
|
'no-dot-json-filename'),
|
250
268
|
([], [], [], [],),
|
251
269
|
('no-exist.csv', 'no-exist.json', 'no-exist.json', 'no-exist.json'),
|
270
|
+
('cps.csv', 'ereformfile', 'ereformfile', 'no-exist.json'),
|
252
271
|
])
|
253
272
|
def test_ctor_errors(input_data, baseline, reform, assump):
|
254
273
|
"""
|
@@ -351,16 +370,19 @@ def test_ctor_init_with_cps_files():
|
|
351
370
|
"""
|
352
371
|
# specify valid tax_year for cps.csv input data
|
353
372
|
txyr = 2020
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
373
|
+
for rid in [0, 99]:
|
374
|
+
tcio = TaxCalcIO('cps.csv', txyr, None, None, None, runid=rid)
|
375
|
+
tcio.init(
|
376
|
+
'cps.csv', txyr, None, None, None,
|
377
|
+
aging_input_data=True,
|
378
|
+
exact_calculations=False,
|
379
|
+
)
|
380
|
+
assert not tcio.errmsg
|
381
|
+
assert tcio.tax_year() == txyr
|
382
|
+
# test advance_to_year method
|
383
|
+
tcio.silent = False
|
384
|
+
tcio.advance_to_year(txyr + 1, True)
|
385
|
+
assert tcio.tax_year() == txyr + 1
|
364
386
|
# specify invalid tax_year for cps.csv input data
|
365
387
|
txyr = 2013
|
366
388
|
tcio = TaxCalcIO('cps.csv', txyr, None, None, None)
|
@@ -426,7 +448,7 @@ def test_output_options_min(reformfile1, assumpfile1):
|
|
426
448
|
aging_input_data=False,
|
427
449
|
exact_calculations=False)
|
428
450
|
assert not tcio.errmsg
|
429
|
-
dumppath = tcio.output_filepath().replace('.xxx', '.
|
451
|
+
dumppath = tcio.output_filepath().replace('.xxx', '.dumpdb')
|
430
452
|
# minimal dump output
|
431
453
|
dumpvars = TaxCalcIO.MINIMAL_DUMPVARS
|
432
454
|
try:
|
@@ -461,7 +483,7 @@ def test_output_options_mtr(reformfile1, assumpfile1):
|
|
461
483
|
aging_input_data=False,
|
462
484
|
exact_calculations=False)
|
463
485
|
assert not tcio.errmsg
|
464
|
-
dumppath = tcio.output_filepath().replace('.xxx', '.
|
486
|
+
dumppath = tcio.output_filepath().replace('.xxx', '.dumpdb')
|
465
487
|
# minimal+mtr_* dump output
|
466
488
|
dumpvars = TaxCalcIO.MINIMAL_DUMPVARS
|
467
489
|
for var in TaxCalcIO.MTR_DUMPVARS:
|
@@ -503,7 +525,7 @@ def test_write_policy_param_files(reformfile1):
|
|
503
525
|
assert not tcio.errmsg
|
504
526
|
tcio.write_policy_params_files()
|
505
527
|
outfilepath = tcio.output_filepath()
|
506
|
-
for ext in ['-params.
|
528
|
+
for ext in ['-params.baseline', '-params.reform']:
|
507
529
|
filepath = outfilepath.replace('.xxx', ext)
|
508
530
|
if os.path.isfile(filepath):
|
509
531
|
os.remove(filepath)
|
taxcalc/utils.py
CHANGED
@@ -8,6 +8,7 @@ PUBLIC low-level utility functions for Tax-Calculator.
|
|
8
8
|
# pylint: disable=too-many-lines
|
9
9
|
|
10
10
|
import os
|
11
|
+
import re
|
11
12
|
import math
|
12
13
|
import json
|
13
14
|
import copy
|
@@ -930,8 +931,8 @@ def mtr_graph_data(vdf, year,
|
|
930
931
|
).values[:, 1]
|
931
932
|
# construct DataFrame containing the two mtr?_series
|
932
933
|
lines = pd.DataFrame()
|
933
|
-
lines['base'] = mtr1_series
|
934
|
-
lines['reform'] = mtr2_series
|
934
|
+
lines['base'] = np.round(mtr1_series, decimals=4)
|
935
|
+
lines['reform'] = np.round(mtr2_series, decimals=4)
|
935
936
|
# construct dictionary containing merged data and auto-generated labels
|
936
937
|
data = {}
|
937
938
|
data['lines'] = lines
|
@@ -1064,8 +1065,8 @@ def atr_graph_data(vdf, year,
|
|
1064
1065
|
where=avginc_series[included] != 0)
|
1065
1066
|
# construct DataFrame containing the two atr?_series
|
1066
1067
|
lines = pd.DataFrame()
|
1067
|
-
lines['base'] = atr1_series
|
1068
|
-
lines['reform'] = atr2_series
|
1068
|
+
lines['base'] = np.round(atr1_series, decimals=4)
|
1069
|
+
lines['reform'] = np.round(atr2_series, decimals=4)
|
1069
1070
|
# include only percentiles with average income no less than min_avginc
|
1070
1071
|
lines = lines[included]
|
1071
1072
|
# construct dictionary containing plot lines and auto-generated labels
|
@@ -1236,7 +1237,7 @@ def pch_graph_data(vdf, year, pop_quantiles=False):
|
|
1236
1237
|
where=avginc_series[included] != 0)
|
1237
1238
|
# construct DataFrame containing the pch_series expressed as percent
|
1238
1239
|
line = pd.DataFrame()
|
1239
|
-
line['pch'] = pch_series * 100
|
1240
|
+
line['pch'] = np.round(pch_series * 100, decimals=2)
|
1240
1241
|
# include only percentiles with average income no less than min_avginc
|
1241
1242
|
line = line[included]
|
1242
1243
|
# construct dictionary containing plot line and auto-generated labels
|
@@ -1574,25 +1575,45 @@ def bootstrap_se_ci(data, seed, num_samples, statistic, alpha):
|
|
1574
1575
|
return bsest
|
1575
1576
|
|
1576
1577
|
|
1577
|
-
def json_to_dict(
|
1578
|
+
def json_to_dict(jsontext):
|
1578
1579
|
"""
|
1579
1580
|
Convert specified JSON text into an ordered Python dictionary.
|
1580
1581
|
|
1581
1582
|
Parameters
|
1582
1583
|
----------
|
1583
|
-
|
1584
|
-
JSON text
|
1584
|
+
jsontext: string
|
1585
|
+
JSON text that may contain comments, which will be removed
|
1585
1586
|
|
1586
1587
|
Raises
|
1587
1588
|
------
|
1588
1589
|
ValueError:
|
1589
|
-
if
|
1590
|
+
if jsontext contains a JSON syntax error after comments are removed
|
1590
1591
|
|
1591
1592
|
Returns
|
1592
1593
|
-------
|
1593
1594
|
dictionary: collections.OrderedDict
|
1594
|
-
JSON data expressed as an ordered Python dictionary
|
1595
|
+
JSON data expressed as an ordered Python dictionary
|
1595
1596
|
"""
|
1597
|
+
def remove_comments(string):
|
1598
|
+
"""
|
1599
|
+
Remove single and multiline comments from JSON.
|
1600
|
+
Logic follows https://stackoverflow.com/a/18381470/9100772
|
1601
|
+
"""
|
1602
|
+
def _replacer(match):
|
1603
|
+
# if the 2nd group (capturing comments) is not None,
|
1604
|
+
# it means we have captured a non-quoted (real) comment string.
|
1605
|
+
if match.group(2) is not None:
|
1606
|
+
return "\n" # preserve line numbers
|
1607
|
+
# otherwise, we will return the 1st group
|
1608
|
+
return match.group(1) # captured quoted-string
|
1609
|
+
# begin main remove_comments function logic
|
1610
|
+
pattern = r"(\".*?\"|\'.*?\')|(/\*.*?\*/|//[^\r\n]*$)"
|
1611
|
+
# first group captures quoted strings (double or single)
|
1612
|
+
# second group captures comments (//single-line or /* multi-line */)
|
1613
|
+
regex = re.compile(pattern, re.MULTILINE | re.DOTALL)
|
1614
|
+
return regex.sub(_replacer, string)
|
1615
|
+
# begin main json_to_dict function logic
|
1616
|
+
json_text = remove_comments(jsontext)
|
1596
1617
|
try:
|
1597
1618
|
ordered_dict = json.loads(json_text,
|
1598
1619
|
object_pairs_hook=collections.OrderedDict)
|
@@ -1610,5 +1631,6 @@ def json_to_dict(json_text):
|
|
1610
1631
|
linenum += 1
|
1611
1632
|
msg += f'{linenum:04d}{line}\n'
|
1612
1633
|
msg += bline + '\n'
|
1634
|
+
msg += 'If still puzzled, try using JSONLint online.\n'
|
1613
1635
|
raise ValueError(msg) from valerr
|
1614
1636
|
return ordered_dict
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: taxcalc
|
3
|
-
Version: 4.6.
|
3
|
+
Version: 4.6.3
|
4
4
|
Summary: Tax-Calculator
|
5
5
|
Home-page: https://github.com/PSLmodels/Tax-Calculator
|
6
6
|
Download-URL: https://github.com/PSLmodels/Tax-Calculator
|
@@ -22,7 +22,7 @@ Requires-Dist: numpy>=1.26
|
|
22
22
|
Requires-Dist: pandas>=2.2
|
23
23
|
Requires-Dist: bokeh>=2.4
|
24
24
|
Requires-Dist: numba
|
25
|
-
Requires-Dist: paramtools>=0.
|
25
|
+
Requires-Dist: paramtools>=0.20.0
|
26
26
|
Dynamic: classifier
|
27
27
|
Dynamic: description
|
28
28
|
Dynamic: description-content-type
|
@@ -57,3 +57,6 @@ explains the workflow involved in contributing model enhancements.
|
|
57
57
|
|
58
58
|
Complete documentation is available
|
59
59
|
[here](https://PSLmodels.github.io/Tax-Calculator/).
|
60
|
+
This documentation includes
|
61
|
+
[examples](https://taxcalc.pslmodels.org/usage/tcja_after_2025.html)
|
62
|
+
of how to analyze different ways of extending TCJA policy beyond 2025.
|
@@ -1,5 +1,5 @@
|
|
1
|
-
taxcalc/__init__.py,sha256=
|
2
|
-
taxcalc/calcfunctions.py,sha256=
|
1
|
+
taxcalc/__init__.py,sha256=9Esf49oClu0DBglso6q08J0YbCTnWQRRvM6TpVKX5ZE,536
|
2
|
+
taxcalc/calcfunctions.py,sha256=Rt2BN7rI9Hr86jSqGN7-HeqqXGlh1PN0wUGuivwbjos,148442
|
3
3
|
taxcalc/calculator.py,sha256=cCsis9yQSyw4eXvYppk7Z70JEaPH8Kd1AADlIqnJhVw,63930
|
4
4
|
taxcalc/conftest.py,sha256=nO4J7qu1sTHgjqrzhpRMvfMJUrNm6GP_IsSuuDt_MeQ,141
|
5
5
|
taxcalc/consumption.json,sha256=FBgDd72AZnviQRhGz5rPgpGpOmaOzNYfGB9GdTCeKPI,8102
|
@@ -12,21 +12,21 @@ taxcalc/growdiff.json,sha256=ReBAF6We9ZwTb0uDYQwbedPsQKdm6KSOERiddEYZbm0,15037
|
|
12
12
|
taxcalc/growdiff.py,sha256=Q3St-KPIUN2I_l1S0jwN0yr8O4LuzkNIU-_qbXTkrZw,2977
|
13
13
|
taxcalc/growfactors.csv,sha256=URIGSKApCY4McvdILkCaIm8EhCGEME2Du-ef5Q9c0uE,5134
|
14
14
|
taxcalc/growfactors.py,sha256=dW71yYKhFDbFtGpBT-kZBqY4MV7IswKcNI3_c-X_Nfg,6525
|
15
|
-
taxcalc/parameters.py,sha256=
|
16
|
-
taxcalc/policy.py,sha256=
|
17
|
-
taxcalc/policy_current_law.json,sha256=
|
15
|
+
taxcalc/parameters.py,sha256=VmezOOynj1W7hexnDgCzlyffIxHpFK6eSd6zNzn3aAk,36161
|
16
|
+
taxcalc/policy.py,sha256=FpzxNSAYmcu6ScWZwxta3reOSQL9aQyRhAqv-bf28_E,7581
|
17
|
+
taxcalc/policy_current_law.json,sha256=4NVEbt3Zv55s_i4GksIvKxSMrrWiPs2I74t1LVMcCE0,689913
|
18
18
|
taxcalc/puf_ratios.csv,sha256=USMM79UEX8PnSKY_LYLxvACER_9NHyj4ipNEk2iyykQ,3580
|
19
19
|
taxcalc/puf_weights.csv.gz,sha256=35iZhzFO0dHUI2zf4_liyk60E-3Sgr_AbxszGxw7LfM,13522484
|
20
20
|
taxcalc/records.py,sha256=K5QgP6Pm9PtEVDVzM7tpHYPu554Wio0KnrU7YTTBKgQ,18264
|
21
21
|
taxcalc/records_variables.json,sha256=_YKJiZQ1czp0VH9bkr5ZXmp9Mm1roHoHrt2XnLXAtfw,42975
|
22
|
-
taxcalc/taxcalcio.py,sha256=
|
23
|
-
taxcalc/utils.py,sha256=
|
22
|
+
taxcalc/taxcalcio.py,sha256=_ylnC-dZUpDFn79F8pjkZEq-wJhPCQA7Ig9SRLyhrUA,37691
|
23
|
+
taxcalc/utils.py,sha256=Wsvni2UP7WgnByN4bRIiLGgamDFwfQoexiy420o6ewY,63666
|
24
24
|
taxcalc/utilsprvt.py,sha256=iIyWp9-N3_XWjQj2jV2CWnJy7vrNlKB2_vIMwYjgbWY,1323
|
25
25
|
taxcalc/assumptions/ASSUMPTIONS.md,sha256=cFQqWn1nScaladVaQ7xNm1jDY8CsGdLmqZEzUZeRrb8,1917
|
26
26
|
taxcalc/assumptions/README.md,sha256=Ww55r2zH1neoRSl_MawrPmX-ugaztIZ7_ALrquuatdQ,809
|
27
27
|
taxcalc/assumptions/economic_assumptions_template.json,sha256=utMk38GwSQFrkOAtRrDVhMQLpfaZH3JmtTznKX7IouM,2610
|
28
28
|
taxcalc/cli/__init__.py,sha256=cyZ0tdx41j_vV_B6GAkqJmNKKG-B0wUC0ThC75lJlk4,104
|
29
|
-
taxcalc/cli/tc.py,sha256=
|
29
|
+
taxcalc/cli/tc.py,sha256=hGkP-XHkvx0MoFdHf-BjUnKqAxQBRtk8Vv4uqtIGuRY,18760
|
30
30
|
taxcalc/reforms/2017_law.json,sha256=u-xaPSvt5ubfZw1Nb-jNhTNcOPBUJeAX2kJVoEyMgC4,5860
|
31
31
|
taxcalc/reforms/2017_law.out.csv,sha256=nnNKXqY2kof8HC1nnU8srPsvNNepi6ISXQ9OJpQnT7M,473
|
32
32
|
taxcalc/reforms/ARPA.json,sha256=1H9LuJ_QitXRO9e8R3PWizajJgdioIzbGFdvdlt9FVg,3119
|
@@ -40,7 +40,7 @@ taxcalc/reforms/ConsolidatedAppropriationsAct2021.out.csv,sha256=qSUdI0LoQFGG6h2
|
|
40
40
|
taxcalc/reforms/Larson2019.json,sha256=bpfcrtwJO2tNKAG4ITXedCUggbkxXNuwxyrZ456KA-U,1662
|
41
41
|
taxcalc/reforms/Larson2019.out.csv,sha256=s9kVoVYOrznFx4bGiDewyHWRKf7-wgXqpMIMTyxC1zA,475
|
42
42
|
taxcalc/reforms/README.md,sha256=0Ua4RBUnLKcEwxHqncRFDg7QMNq1oblXVNeyYRYfae4,1193
|
43
|
-
taxcalc/reforms/REFORMS.md,sha256=
|
43
|
+
taxcalc/reforms/REFORMS.md,sha256=ewozCNudZfuL89FABQHOSxVn4DJ72hAQ2ghjE3s9kN4,3604
|
44
44
|
taxcalc/reforms/Renacci.json,sha256=U6rmbe1-IANG_H69xET5G8-v76ErbbHcm1JdRzAO8y4,2437
|
45
45
|
taxcalc/reforms/Renacci.out.csv,sha256=dBrDH-Sc5EYvsYzotJZShRxd1EbhdI3enOUqaAsAyuI,472
|
46
46
|
taxcalc/reforms/SandersDeFazio.json,sha256=BMSfl96ERD4SGd_PDMQkiDV5s4iD7Mh1BjS7uKxVD18,710
|
@@ -54,7 +54,7 @@ taxcalc/reforms/Trump2017.json,sha256=DZjCJQZYe98Skyss7z_Jhj8HJld_FPZeQGxwzGgQIn
|
|
54
54
|
taxcalc/reforms/Trump2017.out.csv,sha256=By1quzZONFLQGK5E76mbNNFuORZ8aCGHpD1BR5iwTS8,474
|
55
55
|
taxcalc/reforms/cases.csv,sha256=JQ0LSnNeyl6xSgW5mimGUJMr7xwCWTOpiOpfwx2ETsg,570
|
56
56
|
taxcalc/reforms/clp.out.csv,sha256=qSUdI0LoQFGG6h24eT-249pLEqmxmt7TvLrv1HX_y3Y,475
|
57
|
-
taxcalc/reforms/ext.json,sha256
|
57
|
+
taxcalc/reforms/ext.json,sha256=-IfEpGAAIOiQMp-fW1F1W5OMiuUgdXAnr0mUa364Dok,3058
|
58
58
|
taxcalc/reforms/growfactors_ext.csv,sha256=E0szWXtgV5jcpiyvREOz1yXw_poPIBC77bBQI1rlFxM,17733
|
59
59
|
taxcalc/reforms/ptaxes0.json,sha256=QkvqCVkI23sF7FvTHqaUYNpEJYuHNChbKwH0mH7Otp4,1718
|
60
60
|
taxcalc/reforms/ptaxes0.out.csv,sha256=DKGsyNWqo-ABUnjFjEGMpqqhmT2WDRGuU6sKTgH_obc,476
|
@@ -75,15 +75,15 @@ taxcalc/reforms/archive/TCJA_Senate_120117.json,sha256=hruGq8bVtJEMmSsOIuTcWiYON
|
|
75
75
|
taxcalc/tests/benefits_expect.csv,sha256=CFpMpg8a-5iNVSRnmCnl9dncwXx6eGn-KSnTJ2GqmS4,4833
|
76
76
|
taxcalc/tests/cmpi_cps_expect.txt,sha256=NCyG3XhgnV8qJe9TaF9l-9yUuwNfANNDvFn1HcSfZ1c,6262
|
77
77
|
taxcalc/tests/cmpi_puf_expect.txt,sha256=dtHBPDY23qttxjQsPpxhLYoUId1tnPZ4uNHx49NlZ0s,6264
|
78
|
-
taxcalc/tests/conftest.py,sha256=
|
78
|
+
taxcalc/tests/conftest.py,sha256=ySPrNaC3m8a7Jp4SaAkq2P4iNTVLCj7b8lqIfpTMxYY,5164
|
79
79
|
taxcalc/tests/cpscsv_agg_expect.csv,sha256=Do3gRVVKUCZtQ2Ooy5jn6gMS9_WbclJ5FhSSHR6gwX8,2089
|
80
80
|
taxcalc/tests/puf_var_correl_coeffs_2016.csv,sha256=2VtWUcTaE6c5cmmEDylv9XKVONLT6GZ10gozELxk-2g,57314
|
81
81
|
taxcalc/tests/puf_var_wght_means_by_year.csv,sha256=nou_pIKICyXmCfyj_UziNXp1EB4BQU7Qa-ZvqlE1WqM,20049
|
82
82
|
taxcalc/tests/pufcsv_agg_expect.csv,sha256=h0r6MtsFEBa1u5zwpRT4fDx2T__ZAkdx4oeLxidQI4s,2117
|
83
83
|
taxcalc/tests/pufcsv_mtr_expect.txt,sha256=xGsUfafzsZ04fFQw162ys-1Mf1CDC_PQ0QZNigS07VY,4265
|
84
|
-
taxcalc/tests/reforms.json,sha256=
|
85
|
-
taxcalc/tests/reforms_expect.csv,sha256=
|
86
|
-
taxcalc/tests/test_4package.py,sha256=
|
84
|
+
taxcalc/tests/reforms.json,sha256=udnp9vPmTQpQQ39LaYqGUWJrwEZnYGPiEdyVkWklp3c,18835
|
85
|
+
taxcalc/tests/reforms_expect.csv,sha256=FlyccVCTgnRSL8CNdNT5-m6_Vx88J935OEjA4PzTqxg,1440
|
86
|
+
taxcalc/tests/test_4package.py,sha256=1qhmDS3bdfNHNgz4pggaE6LduT3KKUtOsdtqP3QSIYQ,3601
|
87
87
|
taxcalc/tests/test_benefits.py,sha256=oaui5mO0TuW8Ht-uxvUCBL5zM3iTENq3Whyf_gEpY1U,3392
|
88
88
|
taxcalc/tests/test_calcfunctions.py,sha256=QtMgQg_WpCU8PZM3Hs8Pml4q6LnlLWV_blCzbpGN2sw,31939
|
89
89
|
taxcalc/tests/test_calculator.py,sha256=lcnBli5giNFxqgCLW-MF4J_wsV3gSFqCjzJdCJkihek,36085
|
@@ -95,14 +95,14 @@ taxcalc/tests/test_data.py,sha256=Zwuf23WeaF0N53X0eo3MlnkO2Pn4qqgGNUZPpD8FETc,44
|
|
95
95
|
taxcalc/tests/test_decorators.py,sha256=F31pt1S7jIgkgV62xMC-poWRzG7fzYVOJes9tOoCF40,10232
|
96
96
|
taxcalc/tests/test_growdiff.py,sha256=vXZTgPJTUi25mZrfmTPErytSC69Bs_36ydrQmWxgm9g,3420
|
97
97
|
taxcalc/tests/test_growfactors.py,sha256=L-DQMR2fh_rOQa3Lx1CDVnB2Q73zXUfTYYVunt0heto,2796
|
98
|
-
taxcalc/tests/test_parameters.py,sha256=
|
99
|
-
taxcalc/tests/test_policy.py,sha256=
|
98
|
+
taxcalc/tests/test_parameters.py,sha256=uVr7C_uKDJ5guOqYOa_yhtCxGAVM5RSSxyIZhINotoA,20000
|
99
|
+
taxcalc/tests/test_policy.py,sha256=dTrdJin2G2SKMShb1aOM5S7vDtQ6uxM3BxiQURfs54k,56540
|
100
100
|
taxcalc/tests/test_puf_var_stats.py,sha256=TG-sQtOkR6cBOw0am7MUsMSwjPxVdkvt0Xov342oii8,7786
|
101
101
|
taxcalc/tests/test_pufcsv.py,sha256=kQPwpMcLNPwQDiO-23xvvZggtHYvRz-UYEDn6JjNfbw,16352
|
102
102
|
taxcalc/tests/test_records.py,sha256=ncswnbCY7vZgJ_h6xwql4oFw-jZG2gWOMWvEJC2_jdc,8827
|
103
|
-
taxcalc/tests/test_reforms.py,sha256=
|
103
|
+
taxcalc/tests/test_reforms.py,sha256=3vDRnkQrQaRVl5qXEtCxz-nM_y-K2T6e2O-ilx0nZ6o,16033
|
104
104
|
taxcalc/tests/test_responses.py,sha256=2CkVVdaDNCSALMoUcGgweRlS2tfsK3kXogHtDkZMqJU,1663
|
105
|
-
taxcalc/tests/test_taxcalcio.py,sha256=
|
105
|
+
taxcalc/tests/test_taxcalcio.py,sha256=4WUqtC9OsTczZqsa5jTaXfOQ5YNJRTotg5I6l9859KA,23821
|
106
106
|
taxcalc/tests/test_utils.py,sha256=aUHVNxfSMdyyLAz3w98KLQa5D872rZxXqKbPkIqwLLA,29403
|
107
107
|
taxcalc/validation/CSV_INPUT_VARS.md,sha256=MqlZZGt_a1n8JAU-nY5MjnTmjz1pMOuhtpVYIGUgl38,1433
|
108
108
|
taxcalc/validation/CSV_OUTPUT_VARS.md,sha256=wr8oyCJDXcxl4Lu0H_wMofUQYhEIyHDif6vkbas1FGE,3000
|
@@ -131,9 +131,9 @@ taxcalc/validation/taxsim35/expected_differences/b21-taxdiffs-expect.csv,sha256=
|
|
131
131
|
taxcalc/validation/taxsim35/expected_differences/c17-taxdiffs-expect.csv,sha256=YhgojbLowH3yujdYu7SGkdvBZmTgpugu4wYc1Be069M,1125
|
132
132
|
taxcalc/validation/taxsim35/expected_differences/c18-taxdiffs-expect.csv,sha256=g9J4BPbTySV-h-RcLvReJq9v1jscgiRSSZzi0taEA-k,1225
|
133
133
|
taxcalc/validation/taxsim35/expected_differences/c19-taxdiffs-expect.csv,sha256=Ceh15N_Xr3L7cpYjzGa-8NLCV3obc8PNHEhE5ZxSPhI,1238
|
134
|
-
taxcalc-4.6.
|
135
|
-
taxcalc-4.6.
|
136
|
-
taxcalc-4.6.
|
137
|
-
taxcalc-4.6.
|
138
|
-
taxcalc-4.6.
|
139
|
-
taxcalc-4.6.
|
134
|
+
taxcalc-4.6.3.dist-info/licenses/LICENSE,sha256=m5epLdB-_NXiY7NsEDgcHP4jDtJ4vOlRf5S3Jb-jraY,1299
|
135
|
+
taxcalc-4.6.3.dist-info/METADATA,sha256=blEI-Z0ZGiWJHdI9xf4Hlw7h8PNNq37NChbPQr6PWcY,3677
|
136
|
+
taxcalc-4.6.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
137
|
+
taxcalc-4.6.3.dist-info/entry_points.txt,sha256=a3ZE1piRv683p27fOLdWZvVJXESkoslTOp5iXV7uVco,50
|
138
|
+
taxcalc-4.6.3.dist-info/top_level.txt,sha256=Wh8wTDHkA_cm4dn8IoUCviDyGgVQqwEQKPJnl8z6d4c,8
|
139
|
+
taxcalc-4.6.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|