taxcalc 4.4.0__py3-none-any.whl → 4.4.1__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 +326 -171
- taxcalc/calculator.py +35 -34
- taxcalc/cli/tc.py +6 -7
- taxcalc/consumption.py +9 -4
- taxcalc/data.py +8 -8
- taxcalc/decorators.py +3 -3
- taxcalc/growdiff.py +5 -0
- taxcalc/growfactors.py +1 -1
- taxcalc/parameters.py +85 -42
- taxcalc/policy.py +1 -1
- taxcalc/records.py +1 -0
- taxcalc/records_variables.json +6 -0
- taxcalc/taxcalcio.py +49 -44
- taxcalc/tests/cmpi_cps_expect.txt +6 -6
- taxcalc/tests/cmpi_puf_expect.txt +6 -6
- taxcalc/tests/conftest.py +42 -41
- taxcalc/tests/test_4package.py +9 -7
- taxcalc/tests/test_benefits.py +9 -8
- taxcalc/tests/test_calcfunctions.py +55 -38
- taxcalc/tests/test_calculator.py +11 -6
- taxcalc/tests/test_compare.py +44 -50
- taxcalc/tests/test_compatible_data.py +9 -7
- taxcalc/tests/test_consumption.py +38 -18
- taxcalc/tests/test_cpscsv.py +33 -31
- taxcalc/tests/test_data.py +31 -24
- taxcalc/tests/test_decorators.py +84 -32
- taxcalc/tests/test_growdiff.py +16 -13
- taxcalc/tests/test_growfactors.py +8 -8
- taxcalc/tests/test_parameters.py +54 -58
- taxcalc/tests/test_policy.py +14 -12
- taxcalc/tests/test_puf_var_stats.py +14 -14
- taxcalc/tests/test_pufcsv.py +40 -40
- taxcalc/tests/test_records.py +73 -60
- taxcalc/tests/test_reforms.py +34 -31
- taxcalc/tests/test_responses.py +4 -4
- taxcalc/tests/test_taxcalcio.py +76 -62
- taxcalc/tests/test_utils.py +78 -46
- taxcalc/utils.py +49 -42
- taxcalc/validation/taxsim35/taxsim_emulation.json +1 -5
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/METADATA +19 -5
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/RECORD +46 -46
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/WHEEL +1 -1
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/LICENSE +0 -0
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/entry_points.txt +0 -0
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/top_level.txt +0 -0
taxcalc/tests/test_calculator.py
CHANGED
@@ -38,7 +38,7 @@ def test_make_calculator(cps_subsample):
|
|
38
38
|
with pytest.raises(ValueError):
|
39
39
|
Calculator(policy=pol, records=None)
|
40
40
|
with pytest.raises(ValueError):
|
41
|
-
Calculator(policy=pol, records=rec, consumption=
|
41
|
+
Calculator(policy=pol, records=rec, consumption=[])
|
42
42
|
|
43
43
|
|
44
44
|
def test_make_calculator_deepcopy(cps_subsample):
|
@@ -522,7 +522,7 @@ def test_read_bad_json_assump_file():
|
|
522
522
|
with pytest.raises(ValueError):
|
523
523
|
Calculator.read_json_param_objects(None, 'unknown_file_name')
|
524
524
|
with pytest.raises(TypeError):
|
525
|
-
Calculator.read_json_param_objects(None,
|
525
|
+
Calculator.read_json_param_objects(None, [])
|
526
526
|
|
527
527
|
|
528
528
|
def test_json_doesnt_exist():
|
@@ -629,7 +629,7 @@ def test_reform_documentation():
|
|
629
629
|
dump = False # set to True to print documentation and force test failure
|
630
630
|
if dump:
|
631
631
|
print(doc)
|
632
|
-
assert
|
632
|
+
assert False, 'ERROR: reform_documentation above'
|
633
633
|
|
634
634
|
|
635
635
|
def test_distribution_tables(cps_subsample):
|
@@ -827,7 +827,7 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
|
|
827
827
|
itmded1 = calc1.weighted_total('c04470') * 1e-9
|
828
828
|
itmded2 = calc2.weighted_total('c04470') * 1e-9
|
829
829
|
else:
|
830
|
-
raise ValueError('illegal year value = {}'
|
830
|
+
raise ValueError(f'illegal year value = {year}')
|
831
831
|
difference_in_total_itmded = itmded1 - itmded2
|
832
832
|
# calculate itemized component amount
|
833
833
|
component_amt = calc1.weighted_total(cvname) * 1e-9
|
@@ -841,8 +841,11 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
|
|
841
841
|
else:
|
842
842
|
atol = 0.00001
|
843
843
|
if not np.allclose(component_amt, difference_in_total_itmded, atol=atol):
|
844
|
-
|
845
|
-
|
844
|
+
msg = (
|
845
|
+
f'\n{cvname}={component_amt:.3f} != '
|
846
|
+
f'{difference_in_total_itmded:.3f}='
|
847
|
+
'difference_in_total_itemized_deductions'
|
848
|
+
)
|
846
849
|
raise ValueError(msg)
|
847
850
|
|
848
851
|
|
@@ -928,6 +931,8 @@ def test_cg_top_rate():
|
|
928
931
|
"""
|
929
932
|
Test top CG bracket and rate.
|
930
933
|
"""
|
934
|
+
# pylint: disable=too-many-locals
|
935
|
+
|
931
936
|
cy = 2019
|
932
937
|
|
933
938
|
# set NIIT and STD to zero to isolate CG tax rates
|
taxcalc/tests/test_compare.py
CHANGED
@@ -8,22 +8,21 @@ Compares Tax-Calculator PUF and CPS results with historical information.
|
|
8
8
|
import os
|
9
9
|
import pytest
|
10
10
|
import numpy as np
|
11
|
-
|
12
|
-
from taxcalc import
|
13
|
-
from taxcalc import
|
11
|
+
from taxcalc.policy import Policy
|
12
|
+
from taxcalc.records import Records
|
13
|
+
from taxcalc.calculator import Calculator
|
14
|
+
from taxcalc.utils import add_income_table_row_variable, SOI_AGI_BINS
|
14
15
|
|
15
16
|
|
16
|
-
"
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
to the nearest one-tenth of a million dollars.
|
26
|
-
"""
|
17
|
+
# 2015 IRS-SOI amounts by AGI category are from "Table 3.3 All Returns: Tax
|
18
|
+
# Liability, Tax Credits, and Tax Payments by Size of Adjusted Gross Income,
|
19
|
+
# Tax Year 2015" which is available as a spreadsheet at this URL:
|
20
|
+
# <https://www.irs.gov/statistics/soi-tax-stats-individual-
|
21
|
+
# statistical-tables-by-size-of-adjusted-gross-income>
|
22
|
+
# The IRS-SOI amounts are from 19 rows in the spreadsheet numbered from
|
23
|
+
# 11 (AGI under one dollar) through 29 (AGI $10M or more).
|
24
|
+
# Dollar IRS-SOI amounts are expressed in billions of dollars and rounded
|
25
|
+
# to the nearest one-tenth of a million dollars.
|
27
26
|
ITAX = {
|
28
27
|
'0:EITC': {
|
29
28
|
# Full earned income credit
|
@@ -204,11 +203,12 @@ def comparison(cname, calc, cmpdata, ofile):
|
|
204
203
|
# construct AGI table
|
205
204
|
vardf = add_income_table_row_variable(vardf, 'c00100', SOI_AGI_BINS)
|
206
205
|
gbydf = vardf.groupby('table_row', as_index=False)
|
207
|
-
# write AGI table with ALL row at bottom
|
208
|
-
ofile.write('TABLE for {
|
206
|
+
# write AGI table with ALL row at bottom of ofile
|
207
|
+
ofile.write(f'TABLE for {cname.split(":")[1]}\n')
|
209
208
|
results = '{:23s}\t{:8.3f}\t{:8.3f}\t{:+6.1f}\n'
|
210
|
-
colhead = '{:23s}\t{:>8s}\t{:>8s}\t{:>6s}\n'
|
211
|
-
ofile.write(colhead
|
209
|
+
colhead = f'{"AGIcategory":23s}\t{"T-C":>8s}\t{"SOI":>8s}\t{"%diff":>6s}\n'
|
210
|
+
ofile.write(colhead)
|
211
|
+
# pylint: disable=consider-using-f-string
|
212
212
|
txc_tot = 0.
|
213
213
|
soi_tot = 0.
|
214
214
|
idx = 0
|
@@ -221,12 +221,12 @@ def comparison(cname, calc, cmpdata, ofile):
|
|
221
221
|
pct_diff = 100. * ((txc / soi) - 1.)
|
222
222
|
else:
|
223
223
|
pct_diff = np.nan
|
224
|
-
glabel = '[{:.8g}, {:.8g})'
|
225
|
-
grp_interval.right)
|
224
|
+
glabel = f'[{grp_interval.left:.8g}, {grp_interval.right:.8g})'
|
226
225
|
ofile.write(results.format(glabel, txc, soi, pct_diff))
|
227
226
|
idx += 1
|
228
227
|
pct_diff = 100. * ((txc_tot / soi_tot) - 1.)
|
229
228
|
ofile.write(results.format('ALL', txc_tot, soi_tot, pct_diff))
|
229
|
+
# pylint: enable=consider-using-f-string
|
230
230
|
|
231
231
|
|
232
232
|
def nonsmall_diffs(linelist1, linelist2, small=0.0):
|
@@ -256,24 +256,20 @@ def nonsmall_diffs(linelist1, linelist2, small=0.0):
|
|
256
256
|
for line1, line2 in zip(linelist1, linelist2):
|
257
257
|
if line1 == line2:
|
258
258
|
continue
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
if
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
else:
|
274
|
-
return True
|
275
|
-
else:
|
276
|
-
return True
|
259
|
+
tokens1 = line1.replace(',', '').split()
|
260
|
+
tokens2 = line2.replace(',', '').split()
|
261
|
+
for tok1, tok2 in zip(tokens1, tokens2):
|
262
|
+
tok1_isfloat = isfloat(tok1)
|
263
|
+
tok2_isfloat = isfloat(tok2)
|
264
|
+
if tok1_isfloat and tok2_isfloat:
|
265
|
+
if abs(float(tok1) - float(tok2)) <= smallamt:
|
266
|
+
continue
|
267
|
+
return True
|
268
|
+
if not tok1_isfloat and not tok2_isfloat:
|
269
|
+
if tok1 == tok2:
|
270
|
+
continue
|
271
|
+
return True
|
272
|
+
return True
|
277
273
|
return False
|
278
274
|
|
279
275
|
|
@@ -281,9 +277,9 @@ def differences(afilename, efilename):
|
|
281
277
|
"""
|
282
278
|
Check for differences between results in afilename and efilename files.
|
283
279
|
"""
|
284
|
-
with open(afilename, 'r') as afile:
|
280
|
+
with open(afilename, 'r', encoding='utf-8') as afile:
|
285
281
|
actres = afile.read()
|
286
|
-
with open(efilename, 'r') as efile:
|
282
|
+
with open(efilename, 'r', encoding='utf-8') as efile:
|
287
283
|
expres = efile.read()
|
288
284
|
diffs = nonsmall_diffs(actres.splitlines(True),
|
289
285
|
expres.splitlines(True), 0.0)
|
@@ -292,12 +288,12 @@ def differences(afilename, efilename):
|
|
292
288
|
efname = os.path.basename(efilename)
|
293
289
|
msg = 'COMPARE RESULTS DIFFER\n'
|
294
290
|
msg += '-------------------------------------------------\n'
|
295
|
-
msg += '--- NEW RESULTS IN {} FILE
|
296
|
-
msg += '--- if new OK, copy {} to
|
297
|
-
msg += '--- {}
|
291
|
+
msg += f'--- NEW RESULTS IN {afname} FILE ---\n'
|
292
|
+
msg += f'--- if new OK, copy {afname} to ---\n'
|
293
|
+
msg += f'--- {efname} ---\n'
|
298
294
|
msg += '--- and rerun test. ---\n'
|
299
295
|
msg += '-------------------------------------------------\n'
|
300
|
-
raise ValueError(msg
|
296
|
+
raise ValueError(msg)
|
301
297
|
os.remove(afilename)
|
302
298
|
|
303
299
|
|
@@ -325,12 +321,10 @@ def test_itax_compare(tests_path, using_puf, puf_fullsample, cps_fullsample):
|
|
325
321
|
afilename = os.path.join(tests_path, 'cmpi_puf_actual.txt')
|
326
322
|
else:
|
327
323
|
afilename = os.path.join(tests_path, 'cmpi_cps_actual.txt')
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
# close actual output file
|
333
|
-
afile.close()
|
324
|
+
with open(afilename, 'w', encoding='utf-8') as afile:
|
325
|
+
# write compare results to afile
|
326
|
+
for cname in sorted(ITAX.keys()):
|
327
|
+
comparison(cname, calc, ITAX, afile)
|
334
328
|
# check for differences between actual and expect output files
|
335
329
|
efilename = afilename.replace('actual', 'expect')
|
336
330
|
differences(afilename, efilename)
|
@@ -12,7 +12,9 @@ plug-in pytest-xdist is able to run all parametrized functions in parallel
|
|
12
12
|
import copy
|
13
13
|
import pytest
|
14
14
|
import numpy as np
|
15
|
-
from taxcalc import Policy
|
15
|
+
from taxcalc.policy import Policy
|
16
|
+
from taxcalc.records import Records
|
17
|
+
from taxcalc.calculator import Calculator
|
16
18
|
|
17
19
|
|
18
20
|
@pytest.fixture(scope='module', name='allparams')
|
@@ -49,7 +51,7 @@ def test_compatible_data_presence(allparams):
|
|
49
51
|
return True
|
50
52
|
|
51
53
|
# Main logic of test_compatible_data_presence function
|
52
|
-
problem_pnames =
|
54
|
+
problem_pnames = []
|
53
55
|
for pname in allparams:
|
54
56
|
if 'compatible_data' in allparams[pname]:
|
55
57
|
compatible_data = allparams[pname]['compatible_data']
|
@@ -61,7 +63,7 @@ def test_compatible_data_presence(allparams):
|
|
61
63
|
msg = '{} has no or invalid compatible_data field'
|
62
64
|
for pname in problem_pnames:
|
63
65
|
print(msg.format(pname))
|
64
|
-
assert 'list of problem_pnames
|
66
|
+
assert False, 'ERROR: list of problem_pnames is above'
|
65
67
|
|
66
68
|
|
67
69
|
XX_YEAR = 2019
|
@@ -142,7 +144,7 @@ BATCHES = int(np.floor(NPARAMS / BATCHSIZE)) + 1
|
|
142
144
|
|
143
145
|
|
144
146
|
@pytest.fixture(scope='module', name='allparams_batch',
|
145
|
-
params=
|
147
|
+
params=list(range(0, BATCHES)))
|
146
148
|
def fixture_allparams_batch(request, allparams, sorted_param_names):
|
147
149
|
"""
|
148
150
|
Fixture for grouping Tax-Calculator parameters
|
@@ -229,8 +231,8 @@ def test_compatible_data(cps_subsample, puf_subsample,
|
|
229
231
|
at least one of these reforms when using datasets marked compatible
|
230
232
|
and does not differ when using datasets marked as incompatible.
|
231
233
|
"""
|
232
|
-
# pylint: disable=too-many-arguments,too-many-
|
233
|
-
# pylint: disable=too-many-statements,too-many-branches
|
234
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
235
|
+
# pylint: disable=too-many-statements,too-many-branches,too-many-locals
|
234
236
|
|
235
237
|
# Check NPARAMS value
|
236
238
|
assert NPARAMS == len(allparams)
|
@@ -335,4 +337,4 @@ def test_compatible_data(cps_subsample, puf_subsample,
|
|
335
337
|
# test failure if any errors
|
336
338
|
if errors:
|
337
339
|
print(errors)
|
338
|
-
assert 'compatible_data
|
340
|
+
assert False, 'ERROR: compatible_data is invalid; see errors above'
|
@@ -1,18 +1,24 @@
|
|
1
|
+
"""
|
2
|
+
Test Consumption class and its methods.
|
3
|
+
"""
|
1
4
|
# CODING-STYLE CHECKS:
|
2
5
|
# pycodestyle test_consumption.py
|
6
|
+
# pylint --disable=locally-disabled test_consumption.py
|
3
7
|
|
8
|
+
import copy
|
4
9
|
import numpy as np
|
5
|
-
import paramtools
|
6
10
|
import pytest
|
7
|
-
import
|
11
|
+
import paramtools
|
8
12
|
from taxcalc import Policy, Records, Calculator, Consumption
|
9
13
|
|
10
14
|
|
11
15
|
def test_start_year_consistency():
|
16
|
+
"""Test docstring"""
|
12
17
|
assert Consumption.JSON_START_YEAR == Policy.JSON_START_YEAR
|
13
18
|
|
14
19
|
|
15
20
|
def test_validity_of_consumption_vars_set():
|
21
|
+
"""Test docstring"""
|
16
22
|
records_varinfo = Records(data=None)
|
17
23
|
assert Consumption.RESPONSE_VARS.issubset(records_varinfo.USABLE_READ_VARS)
|
18
24
|
useable_vars = set(['housing', 'snap', 'tanf', 'vet', 'wic',
|
@@ -21,6 +27,7 @@ def test_validity_of_consumption_vars_set():
|
|
21
27
|
|
22
28
|
|
23
29
|
def test_update_consumption():
|
30
|
+
"""Test docstring"""
|
24
31
|
consump = Consumption()
|
25
32
|
consump.update_consumption({})
|
26
33
|
revision = {
|
@@ -33,21 +40,29 @@ def test_update_consumption():
|
|
33
40
|
expected_mpc_e20400 = np.full((consump.num_years,), 0.06)
|
34
41
|
expected_mpc_e20400[0] = 0.0
|
35
42
|
expected_mpc_e20400[1] = 0.05
|
36
|
-
assert np.allclose(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
assert np.allclose(
|
44
|
+
consump._MPC_e20400, # pylint: disable=protected-access
|
45
|
+
expected_mpc_e20400,
|
46
|
+
rtol=0.0
|
47
|
+
)
|
48
|
+
assert np.allclose(
|
49
|
+
consump._MPC_e17500, # pylint: disable=protected-access
|
50
|
+
np.zeros((consump.num_years,)),
|
51
|
+
rtol=0.0
|
52
|
+
)
|
42
53
|
expected_ben_mcare_value = np.full((consump.num_years,), 0.80)
|
43
54
|
expected_ben_mcare_value[0] = 1.0
|
44
55
|
expected_ben_mcare_value[1] = 0.75
|
45
|
-
assert np.allclose(
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
56
|
+
assert np.allclose(
|
57
|
+
consump._BEN_mcare_value, # pylint: disable=protected-access
|
58
|
+
expected_ben_mcare_value,
|
59
|
+
rtol=0.0
|
60
|
+
)
|
61
|
+
assert np.allclose(
|
62
|
+
consump._BEN_snap_value, # pylint: disable=protected-access
|
63
|
+
np.ones((consump.num_years,)),
|
64
|
+
rtol=0.0
|
65
|
+
)
|
51
66
|
consump.set_year(2015)
|
52
67
|
assert consump.current_year == 2015
|
53
68
|
assert consump.MPC_e20400 == 0.06
|
@@ -57,6 +72,7 @@ def test_update_consumption():
|
|
57
72
|
|
58
73
|
|
59
74
|
def test_incorrect_update_consumption():
|
75
|
+
"""Test docstring"""
|
60
76
|
with pytest.raises(paramtools.ValidationError):
|
61
77
|
Consumption().update_consumption([])
|
62
78
|
with pytest.raises(paramtools.ValidationError):
|
@@ -74,6 +90,7 @@ def test_incorrect_update_consumption():
|
|
74
90
|
|
75
91
|
|
76
92
|
def test_future_update_consumption():
|
93
|
+
"""Test docstring"""
|
77
94
|
consump = Consumption()
|
78
95
|
assert consump.current_year == consump.start_year
|
79
96
|
assert consump.has_response() is False
|
@@ -97,6 +114,7 @@ def test_future_update_consumption():
|
|
97
114
|
|
98
115
|
|
99
116
|
def test_consumption_default_data():
|
117
|
+
"""Test docstring"""
|
100
118
|
consump = Consumption()
|
101
119
|
pdata = consump.specification(meta_data=True, ignore_state=True)
|
102
120
|
for pname in pdata.keys():
|
@@ -107,24 +125,26 @@ def test_consumption_default_data():
|
|
107
125
|
|
108
126
|
|
109
127
|
def test_consumption_response(cps_subsample):
|
128
|
+
"""Test docstring"""
|
129
|
+
# pylint: disable=too-many-locals
|
110
130
|
consump = Consumption()
|
111
131
|
mpc = 0.5
|
112
132
|
consumption_response = {'MPC_e20400': {2013: mpc}}
|
113
133
|
consump.update_consumption(consumption_response)
|
114
134
|
# test incorrect call to response method
|
115
135
|
with pytest.raises(ValueError):
|
116
|
-
consump.response(
|
136
|
+
consump.response([], 1)
|
117
137
|
# test correct call to response method
|
118
138
|
rec = Records.cps_constructor(data=cps_subsample)
|
119
|
-
pre = copy.deepcopy(rec
|
139
|
+
pre = copy.deepcopy(getattr(rec, 'e20400'))
|
120
140
|
consump.response(rec, 1.0)
|
121
|
-
post = rec
|
141
|
+
post = getattr(rec, 'e20400')
|
122
142
|
actual_diff = post - pre
|
123
143
|
expected_diff = np.ones(rec.array_length) * mpc
|
124
144
|
assert np.allclose(actual_diff, expected_diff)
|
125
145
|
# compute earnings mtr with no consumption response
|
126
146
|
rec = Records.cps_constructor(data=cps_subsample)
|
127
|
-
ided0 = copy.deepcopy(rec
|
147
|
+
ided0 = copy.deepcopy(getattr(rec, 'e20400'))
|
128
148
|
calc0 = Calculator(policy=Policy(), records=rec, consumption=None)
|
129
149
|
(mtr0_ptax, mtr0_itax, _) = calc0.mtr(variable_str='e00200p',
|
130
150
|
wrt_full_compensation=False)
|
taxcalc/tests/test_cpscsv.py
CHANGED
@@ -17,8 +17,11 @@ import json
|
|
17
17
|
import pytest
|
18
18
|
import numpy as np
|
19
19
|
import pandas as pd
|
20
|
-
|
21
|
-
from taxcalc import
|
20
|
+
from taxcalc.growfactors import GrowFactors
|
21
|
+
from taxcalc.growdiff import GrowDiff
|
22
|
+
from taxcalc.policy import Policy
|
23
|
+
from taxcalc.records import Records
|
24
|
+
from taxcalc.calculator import Calculator
|
22
25
|
|
23
26
|
|
24
27
|
START_YEAR = 2017
|
@@ -52,7 +55,7 @@ def test_agg(tests_path, cps_fullsample):
|
|
52
55
|
if not np.allclose(adt[icol], edt[str(icol)]):
|
53
56
|
diffs = True
|
54
57
|
if diffs:
|
55
|
-
new_filename = '{
|
58
|
+
new_filename = f'{aggres_path[:-10]}actual.csv'
|
56
59
|
adt.to_csv(new_filename, float_format='%.1f')
|
57
60
|
msg = 'CPSCSV AGG RESULTS DIFFER\n'
|
58
61
|
msg += '-------------------------------------------------\n'
|
@@ -65,7 +68,7 @@ def test_agg(tests_path, cps_fullsample):
|
|
65
68
|
raise ValueError(msg)
|
66
69
|
# create aggregate diagnostic table using unweighted sub-sample of records
|
67
70
|
rn_seed = 180 # to ensure sub-sample is always the same
|
68
|
-
subfrac = 0.07
|
71
|
+
subfrac = 0.07 # sub-sample fraction
|
69
72
|
subsample = cps_fullsample.sample(frac=subfrac, random_state=rn_seed)
|
70
73
|
recs_subsample = Records.cps_constructor(data=subsample)
|
71
74
|
calc_subsample = Calculator(policy=baseline_policy, records=recs_subsample)
|
@@ -84,14 +87,17 @@ def test_agg(tests_path, cps_fullsample):
|
|
84
87
|
if not np.allclose(taxes_subsample[cyr], taxes_fullsample[cyr],
|
85
88
|
atol=0.0, rtol=reltol):
|
86
89
|
reldiff = (taxes_subsample[cyr] / taxes_fullsample[cyr]) - 1.
|
87
|
-
line1 = '\nCPSCSV AGG SUB-vs-FULL RESULTS DIFFER IN {}'
|
88
|
-
line2 =
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
90
|
+
line1 = f'\nCPSCSV AGG SUB-vs-FULL RESULTS DIFFER IN {cyr}'
|
91
|
+
line2 = (
|
92
|
+
f'\n when subfrac={subfrac:.3f}, rtol={reltol:.4f}, '
|
93
|
+
f'seed={rn_seed}'
|
94
|
+
)
|
95
|
+
line3 = (
|
96
|
+
f'\n with sub={taxes_subsample[cyr]:.3f}, '
|
97
|
+
f'full={taxes_fullsample[cyr]:.3f}, '
|
98
|
+
f'rdiff={reldiff:.4f}'
|
99
|
+
)
|
100
|
+
msg += line1 + line2 + line3
|
95
101
|
if msg:
|
96
102
|
raise ValueError(msg)
|
97
103
|
|
@@ -104,7 +110,7 @@ def test_cps_availability(tests_path, cps_path):
|
|
104
110
|
cpsvars = set(list(cpsdf))
|
105
111
|
# make set of variable names that are marked as cps.csv available
|
106
112
|
rvpath = os.path.join(tests_path, '..', 'records_variables.json')
|
107
|
-
with open(rvpath, 'r') as rvfile:
|
113
|
+
with open(rvpath, 'r', encoding='utf-8') as rvfile:
|
108
114
|
rvdict = json.load(rvfile)
|
109
115
|
recvars = set()
|
110
116
|
for vname, vdict in rvdict['read'].items():
|
@@ -142,24 +148,20 @@ def nonsmall_diffs(linelist1, linelist2, small=0.0):
|
|
142
148
|
for line1, line2 in zip(linelist1, linelist2):
|
143
149
|
if line1 == line2:
|
144
150
|
continue
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
if
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
else:
|
160
|
-
return True
|
161
|
-
else:
|
162
|
-
return True
|
151
|
+
tokens1 = line1.replace(',', '').split()
|
152
|
+
tokens2 = line2.replace(',', '').split()
|
153
|
+
for tok1, tok2 in zip(tokens1, tokens2):
|
154
|
+
tok1_isfloat = isfloat(tok1)
|
155
|
+
tok2_isfloat = isfloat(tok2)
|
156
|
+
if tok1_isfloat and tok2_isfloat:
|
157
|
+
if abs(float(tok1) - float(tok2)) <= smallamt:
|
158
|
+
continue
|
159
|
+
return True
|
160
|
+
if not tok1_isfloat and not tok2_isfloat:
|
161
|
+
if tok1 == tok2:
|
162
|
+
continue
|
163
|
+
return True
|
164
|
+
return True
|
163
165
|
return False
|
164
166
|
|
165
167
|
|
taxcalc/tests/test_data.py
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
"""
|
2
|
+
Test Data class and its methods.
|
3
|
+
"""
|
1
4
|
# CODING-STYLE CHECKS:
|
2
5
|
# pycodestyle test_data.py
|
6
|
+
# pylint --disable=locally-disabled test_data.py
|
3
7
|
|
4
8
|
import os
|
5
9
|
import tempfile
|
@@ -75,14 +79,17 @@ def test_recs_class(recs_varinfo_file, cps_subsample):
|
|
75
79
|
super().__init__(data, start_year, gfactors, weights)
|
76
80
|
|
77
81
|
def _extrapolate(self, year):
|
78
|
-
|
82
|
+
val = getattr(self, 'e00300')
|
83
|
+
setattr(
|
84
|
+
self, 'e00300', val * self.gfactors.factor_value('AINTS', year)
|
85
|
+
)
|
79
86
|
|
80
|
-
# test Recs class for incorrect instantiation
|
87
|
+
# test Recs class for incorrect instantiation:
|
81
88
|
with pytest.raises(ValueError):
|
82
|
-
Recs(data=
|
89
|
+
Recs(data=[], start_year=2000,
|
83
90
|
gfactors=None, weights=None)
|
84
91
|
with pytest.raises(ValueError):
|
85
|
-
Recs(data=cps_subsample, start_year=
|
92
|
+
Recs(data=cps_subsample, start_year=[],
|
86
93
|
gfactors=None, weights=None)
|
87
94
|
with pytest.raises(ValueError):
|
88
95
|
Recs(data=cps_subsample, start_year=2000,
|
@@ -93,19 +100,18 @@ def test_recs_class(recs_varinfo_file, cps_subsample):
|
|
93
100
|
with pytest.raises(ValueError):
|
94
101
|
Recs(data=cps_subsample, start_year=2000,
|
95
102
|
gfactors='', weights='')
|
96
|
-
# test Recs class for correct instantiation with no aging of data
|
103
|
+
# test Recs class for correct instantiation with no aging of data:
|
97
104
|
syr = 2014
|
98
105
|
rec = Recs(data=cps_subsample, start_year=syr,
|
99
106
|
gfactors=None, weights=None)
|
100
|
-
assert
|
101
|
-
assert
|
102
|
-
assert rec
|
103
|
-
|
104
|
-
sum_e00300_in_syr = rec.e00300.sum()
|
107
|
+
assert np.all(getattr(rec, 'MARS') != 0)
|
108
|
+
assert getattr(rec, 'data_year') == syr
|
109
|
+
assert getattr(rec, 'current_year') == syr
|
110
|
+
sum_e00300_in_syr = getattr(rec, 'e00300').sum()
|
105
111
|
rec.increment_year()
|
106
|
-
assert rec
|
107
|
-
assert rec
|
108
|
-
sum_e00300_in_syr_plus_one = rec
|
112
|
+
assert getattr(rec, 'data_year') == syr
|
113
|
+
assert getattr(rec, 'current_year') == syr + 1
|
114
|
+
sum_e00300_in_syr_plus_one = getattr(rec, 'e00300').sum()
|
109
115
|
assert np.allclose([sum_e00300_in_syr], [sum_e00300_in_syr_plus_one])
|
110
116
|
del rec
|
111
117
|
# test Recs class for correct instantiation with aging of data
|
@@ -114,20 +120,21 @@ def test_recs_class(recs_varinfo_file, cps_subsample):
|
|
114
120
|
rec = Recs(data=cps_subsample, start_year=syr,
|
115
121
|
gfactors=GrowFactors(), weights=wghts_df)
|
116
122
|
assert isinstance(rec, Recs)
|
117
|
-
assert np.all(rec
|
118
|
-
assert rec
|
119
|
-
assert rec
|
120
|
-
sum_s006_in_syr = rec
|
121
|
-
sum_e00300_in_syr = rec
|
123
|
+
assert np.all(getattr(rec, 'MARS') != 0)
|
124
|
+
assert getattr(rec, 'data_year') == syr
|
125
|
+
assert getattr(rec, 'current_year') == syr
|
126
|
+
sum_s006_in_syr = getattr(rec, 's006').sum()
|
127
|
+
sum_e00300_in_syr = getattr(rec, 'e00300').sum()
|
122
128
|
rec.increment_year()
|
123
|
-
assert rec
|
124
|
-
assert rec
|
125
|
-
sum_s006_in_syr_plus_one = rec
|
129
|
+
assert getattr(rec, 'data_year') == syr
|
130
|
+
assert getattr(rec, 'current_year') == syr + 1
|
131
|
+
sum_s006_in_syr_plus_one = getattr(rec, 's006').sum()
|
126
132
|
assert sum_s006_in_syr_plus_one > sum_s006_in_syr
|
127
|
-
sum_e00300_in_syr_plus_one = rec
|
133
|
+
sum_e00300_in_syr_plus_one = getattr(rec, 'e00300').sum()
|
128
134
|
assert sum_e00300_in_syr_plus_one > sum_e00300_in_syr
|
129
|
-
# test private methods
|
135
|
+
# test private methods:
|
136
|
+
# pylint: disable=protected-access
|
130
137
|
rec._read_data(data=None)
|
131
138
|
rec._read_weights(weights=None)
|
132
139
|
with pytest.raises(ValueError):
|
133
|
-
rec._read_weights(weights=
|
140
|
+
rec._read_weights(weights=[])
|