taxcalc 5.2.0__py3-none-any.whl → 6.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- taxcalc/__init__.py +3 -3
- taxcalc/calcfunctions.py +2 -2
- taxcalc/calculator.py +4 -4
- taxcalc/cli/tc.py +16 -19
- taxcalc/data.py +2 -3
- taxcalc/decorators.py +9 -8
- taxcalc/growfactors.py +2 -1
- taxcalc/policy.py +6 -23
- taxcalc/policy_current_law.json +31 -631
- taxcalc/records.py +78 -82
- taxcalc/records_variables.json +106 -106
- taxcalc/reforms/ARPA.out.csv +9 -9
- taxcalc/taxcalcio.py +101 -77
- taxcalc/tests/conftest.py +20 -15
- taxcalc/tests/puf_var_correl_coeffs_2016.csv +24 -24
- taxcalc/tests/puf_var_wght_means_by_year.csv +11 -11
- taxcalc/tests/pufcsv_agg_expect.csv +20 -20
- taxcalc/tests/pufcsv_mtr_expect.txt +21 -21
- taxcalc/tests/reforms.json +3 -1
- taxcalc/tests/reforms_expect.csv +54 -54
- taxcalc/tests/test_4package.py +8 -9
- taxcalc/tests/test_calculator.py +55 -18
- taxcalc/tests/test_consumption.py +2 -2
- taxcalc/tests/test_cpscsv.py +2 -24
- taxcalc/tests/test_data.py +11 -3
- taxcalc/tests/test_decorators.py +57 -52
- taxcalc/tests/test_growdiff.py +2 -2
- taxcalc/tests/test_parameters.py +101 -53
- taxcalc/tests/test_policy.py +154 -154
- taxcalc/tests/test_records.py +144 -9
- taxcalc/tests/test_reforms.py +104 -104
- taxcalc/tests/test_taxcalcio.py +13 -62
- taxcalc/utils.py +3 -3
- {taxcalc-5.2.0.dist-info → taxcalc-6.0.0.dist-info}/METADATA +3 -6
- {taxcalc-5.2.0.dist-info → taxcalc-6.0.0.dist-info}/RECORD +39 -46
- taxcalc/puf_ratios.csv +0 -26
- taxcalc/puf_weights.csv.gz +0 -0
- taxcalc/reforms/clp.out.csv +0 -10
- taxcalc/tests/test_compare.py +0 -330
- taxcalc/tests/test_compatible_data.py +0 -334
- taxcalc/tests/test_puf_var_stats.py +0 -194
- taxcalc/tests/test_pufcsv.py +0 -328
- {taxcalc-5.2.0.dist-info → taxcalc-6.0.0.dist-info}/WHEEL +0 -0
- {taxcalc-5.2.0.dist-info → taxcalc-6.0.0.dist-info}/entry_points.txt +0 -0
- {taxcalc-5.2.0.dist-info → taxcalc-6.0.0.dist-info}/licenses/LICENSE +0 -0
- {taxcalc-5.2.0.dist-info → taxcalc-6.0.0.dist-info}/top_level.txt +0 -0
taxcalc/tests/test_decorators.py
CHANGED
@@ -24,20 +24,20 @@ from taxcalc.decorators import (
|
|
24
24
|
def test_create_apply_function_string():
|
25
25
|
"""Test docstring"""
|
26
26
|
ans = create_apply_function_string(['a', 'b', 'c'], ['d', 'e'], [])
|
27
|
-
exp = (
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
exp = ('def ap_func(x_0,x_1,x_2,x_3,x_4):\n'
|
28
|
+
' for i in range(len(x_0)):\n'
|
29
|
+
' x_0[i],x_1[i],x_2[i] = jitted_f(x_3[i],x_4[i])\n'
|
30
|
+
' return x_0,x_1,x_2\n')
|
31
31
|
assert ans == exp
|
32
32
|
|
33
33
|
|
34
34
|
def test_create_apply_function_string_with_params():
|
35
35
|
"""Test docstring"""
|
36
36
|
ans = create_apply_function_string(['a', 'b', 'c'], ['d', 'e'], ['d'])
|
37
|
-
exp = (
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
exp = ('def ap_func(x_0,x_1,x_2,x_3,x_4):\n'
|
38
|
+
' for i in range(len(x_0)):\n'
|
39
|
+
' x_0[i],x_1[i],x_2[i] = jitted_f(x_3,x_4[i])\n'
|
40
|
+
' return x_0,x_1,x_2\n')
|
41
41
|
assert ans == exp
|
42
42
|
|
43
43
|
|
@@ -45,24 +45,26 @@ def test_create_toplevel_function_string_mult_outputs():
|
|
45
45
|
"""Test docstring"""
|
46
46
|
ans = create_toplevel_function_string(['a', 'b'], ['d', 'e'],
|
47
47
|
['pm', 'pm', 'pf', 'pm'])
|
48
|
-
|
49
|
-
exp = (
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
48
|
+
# pylint: disable=inconsistent-quotes
|
49
|
+
exp = (
|
50
|
+
"def hl_func(pm, pf):\n"
|
51
|
+
" from pandas import DataFrame\n"
|
52
|
+
" import numpy as np\n"
|
53
|
+
" import pandas as pd\n"
|
54
|
+
" def get_values(x):\n"
|
55
|
+
" if isinstance(x, pd.Series):\n"
|
56
|
+
" return x.values\n"
|
57
|
+
" else:\n"
|
58
|
+
" return x\n"
|
59
|
+
" outputs = \\\n"
|
60
|
+
" (pm.a, pm.b) = \\\n"
|
61
|
+
" applied_f(get_values(pm.a[0]), get_values(pm.b[0]), "
|
62
|
+
"get_values(pf.d), get_values(pm.e[0]), )\n"
|
63
|
+
" header = ['a', 'b']\n"
|
64
|
+
" return DataFrame(data=np.column_stack(outputs),"
|
65
|
+
"columns=header)"
|
66
|
+
)
|
67
|
+
# pylint: enable=inconsistent-quotes
|
66
68
|
assert ans == exp
|
67
69
|
|
68
70
|
|
@@ -70,23 +72,26 @@ def test_create_toplevel_function_string():
|
|
70
72
|
"""Test docstring"""
|
71
73
|
ans = create_toplevel_function_string(['a'], ['d', 'e'],
|
72
74
|
['pm', 'pf', 'pm'])
|
73
|
-
|
74
|
-
exp = (
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
75
|
+
# pylint: disable=inconsistent-quotes
|
76
|
+
exp = (
|
77
|
+
"def hl_func(pm, pf):\n"
|
78
|
+
" from pandas import DataFrame\n"
|
79
|
+
" import numpy as np\n"
|
80
|
+
" import pandas as pd\n"
|
81
|
+
" def get_values(x):\n"
|
82
|
+
" if isinstance(x, pd.Series):\n"
|
83
|
+
" return x.values\n"
|
84
|
+
" else:\n"
|
85
|
+
" return x\n"
|
86
|
+
" outputs = \\\n"
|
87
|
+
" (pm.a) = \\\n"
|
88
|
+
" applied_f(get_values(pm.a[0]), get_values(pf.d), "
|
89
|
+
"get_values(pm.e[0]), )\n"
|
90
|
+
" header = ['a']\n"
|
91
|
+
" return DataFrame(data=outputs,"
|
92
|
+
"columns=header)"
|
93
|
+
)
|
94
|
+
# pylint: enable=inconsistent-quotes
|
90
95
|
assert ans == exp
|
91
96
|
|
92
97
|
|
@@ -107,7 +112,7 @@ def test_make_apply_function():
|
|
107
112
|
assert ans_no_jit
|
108
113
|
|
109
114
|
|
110
|
-
@apply_jit([
|
115
|
+
@apply_jit(['a', 'b'], ['x', 'y', 'z'], nopython=True)
|
111
116
|
def magic_calc(x, y, z):
|
112
117
|
"""Function docstring"""
|
113
118
|
a = x + y
|
@@ -178,7 +183,7 @@ def test_magic_apply_jit():
|
|
178
183
|
pf.y = np.ones((5,))
|
179
184
|
pf.z = np.ones((5,))
|
180
185
|
xx = magic(pm, pf)
|
181
|
-
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=[
|
186
|
+
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=['a', 'b'])
|
182
187
|
assert_frame_equal(xx, exp)
|
183
188
|
|
184
189
|
|
@@ -192,7 +197,7 @@ def test_magic_apply_jit_swap():
|
|
192
197
|
pf.y = np.ones((5,))
|
193
198
|
pf.z = np.ones((5,))
|
194
199
|
xx = magic(pf, pm) # pylint: disable=arguments-out-of-order
|
195
|
-
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=[
|
200
|
+
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=['a', 'b'])
|
196
201
|
assert_frame_equal(xx, exp)
|
197
202
|
|
198
203
|
|
@@ -209,7 +214,7 @@ def test_magic_iterate_jit():
|
|
209
214
|
pf.y = np.ones((5,))
|
210
215
|
pf.z = np.ones((5,))
|
211
216
|
xx = magic_calc2(pm, pf)
|
212
|
-
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=[
|
217
|
+
exp = DataFrame(data=[[2.0, 3.0]] * 5, columns=['a', 'b'])
|
213
218
|
assert_frame_equal(xx, exp)
|
214
219
|
|
215
220
|
|
@@ -236,7 +241,7 @@ def test_ret_everything_iterate_jit():
|
|
236
241
|
pf.f = np.ones((5,))
|
237
242
|
ans = ret_everything(pm, pf)
|
238
243
|
exp = DataFrame(data=[[2.0, 2.0, 2.0, 2.0]] * 5,
|
239
|
-
columns=[
|
244
|
+
columns=['c', 'd', 'e', 'f'])
|
240
245
|
assert_frame_equal(ans, exp)
|
241
246
|
|
242
247
|
|
@@ -259,7 +264,7 @@ def test_function_takes_kwarg():
|
|
259
264
|
pf.z = np.ones((5,))
|
260
265
|
ans = magic_calc3(pm, pf)
|
261
266
|
exp = DataFrame(data=[[2.0, 3.0]] * 5,
|
262
|
-
columns=[
|
267
|
+
columns=['a', 'b'])
|
263
268
|
assert_frame_equal(ans, exp)
|
264
269
|
|
265
270
|
|
@@ -282,7 +287,7 @@ def test_function_no_parameters_listed():
|
|
282
287
|
pf.z = np.ones((5,))
|
283
288
|
ans = magic_calc4(pm, pf)
|
284
289
|
exp = DataFrame(data=[[2.0, 3.0]] * 5,
|
285
|
-
columns=[
|
290
|
+
columns=['a', 'b'])
|
286
291
|
assert_frame_equal(ans, exp)
|
287
292
|
|
288
293
|
|
@@ -306,7 +311,7 @@ def test_function_parameters_optional():
|
|
306
311
|
pf.z = np.ones((5,))
|
307
312
|
ans = magic_calc5(pm, pf)
|
308
313
|
exp = DataFrame(data=[[2.0, 4.0]] * 5,
|
309
|
-
columns=[
|
314
|
+
columns=['a', 'b'])
|
310
315
|
assert_frame_equal(ans, exp)
|
311
316
|
|
312
317
|
|
@@ -377,7 +382,7 @@ def test_force_no_jit():
|
|
377
382
|
pf.z = np.ones((5,))
|
378
383
|
ans = magic_calc6_(pm, pf)
|
379
384
|
exp = DataFrame(data=[[2.0, 4.0]] * 5,
|
380
|
-
columns=[
|
385
|
+
columns=['a', 'b'])
|
381
386
|
assert_frame_equal(ans, exp)
|
382
387
|
# restore normal JIT operation of decorators module
|
383
388
|
del os.environ['NOTAXCALCJIT']
|
taxcalc/tests/test_growdiff.py
CHANGED
@@ -67,7 +67,7 @@ def test_description_punctuation(tests_path):
|
|
67
67
|
dct = json.load(jsonfile)
|
68
68
|
all_desc_ok = True
|
69
69
|
for param in dct.keys():
|
70
|
-
if param ==
|
70
|
+
if param == 'schema':
|
71
71
|
continue
|
72
72
|
if not dct[param]['description'].endswith('.'):
|
73
73
|
all_desc_ok = False
|
@@ -86,7 +86,7 @@ def test_boolean_value_infomation(tests_path):
|
|
86
86
|
with open(path, 'r', encoding='utf-8') as gddfile:
|
87
87
|
gdd = json.load(gddfile)
|
88
88
|
for param in gdd.keys():
|
89
|
-
if param ==
|
89
|
+
if param == 'schema':
|
90
90
|
continue
|
91
91
|
val = gdd[param]['value']
|
92
92
|
if isinstance(val, list):
|
taxcalc/tests/test_parameters.py
CHANGED
@@ -86,13 +86,13 @@ PARAMS_JSON = json.dumps({
|
|
86
86
|
})
|
87
87
|
|
88
88
|
|
89
|
-
@pytest.fixture(scope=
|
89
|
+
@pytest.fixture(scope="module", name="params_json_file")
|
90
90
|
def fixture_params_json_file():
|
91
91
|
"""
|
92
92
|
Define JSON DEFAULTS file for Parameters-derived Params class.
|
93
93
|
"""
|
94
|
-
with tempfile.NamedTemporaryFile(mode=
|
95
|
-
pfile.write(PARAMS_JSON +
|
94
|
+
with tempfile.NamedTemporaryFile(mode="a", delete=False) as pfile:
|
95
|
+
pfile.write(PARAMS_JSON + "\n")
|
96
96
|
pfile.close()
|
97
97
|
yield pfile
|
98
98
|
os.remove(pfile.name)
|
@@ -100,22 +100,22 @@ def fixture_params_json_file():
|
|
100
100
|
|
101
101
|
@pytest.mark.parametrize("revision, expect", [
|
102
102
|
({}, ""),
|
103
|
-
({
|
104
|
-
({
|
103
|
+
({"real_param": {2004: 1.9}}, "error"),
|
104
|
+
({"int_param": {2004: [3.6]}}, "raise"),
|
105
105
|
({"int_param": {2004: [3]}}, "raise"),
|
106
106
|
({"label_param": {2004: [1, 2]}}, "noerror"),
|
107
107
|
({"label_param": {2004: [[1, 2]]}}, "raise"),
|
108
108
|
({"label_param": {2004: [1, 2, 3]}}, "raise"),
|
109
|
-
({
|
110
|
-
({
|
111
|
-
({
|
112
|
-
({
|
113
|
-
({
|
114
|
-
({
|
115
|
-
({
|
116
|
-
({
|
117
|
-
({
|
118
|
-
({
|
109
|
+
({"bool_param": {2004: [4.9]}}, "raise"),
|
110
|
+
({"str_param": {2004: [9]}}, "raise"),
|
111
|
+
({"str_param": {2004: "nonlinear"}}, "noerror"),
|
112
|
+
({"str_param": {2004: "unknownvalue"}}, "error"),
|
113
|
+
({"str_param": {2004: ["nonlinear"]}}, "raise"),
|
114
|
+
({"real_param": {2004: "linear"}}, "raise"),
|
115
|
+
({"real_param": {2004: [0.2, 0.3]}}, "raise"),
|
116
|
+
({"removed_param": {2004: 0.1}}, "raise"),
|
117
|
+
({"real_param-indexed": {2004: True}}, "raise"),
|
118
|
+
({"unknown_param-indexed": {2004: False}}, "raise")
|
119
119
|
])
|
120
120
|
def test_params_class(revision, expect, params_json_file):
|
121
121
|
"""
|
@@ -129,12 +129,12 @@ def test_params_class(revision, expect, params_json_file):
|
|
129
129
|
# pylint: disable=abstract-method
|
130
130
|
|
131
131
|
DEFAULTS_FILE_NAME = params_json_file.name
|
132
|
-
DEFAULTS_FILE_PATH =
|
132
|
+
DEFAULTS_FILE_PATH = ""
|
133
133
|
START_YEAR = 2001
|
134
134
|
LAST_YEAR = 2010
|
135
135
|
NUM_YEARS = LAST_YEAR - START_YEAR + 1
|
136
136
|
REMOVED_PARAMS = {
|
137
|
-
|
137
|
+
"removed_param": "has been removed"
|
138
138
|
}
|
139
139
|
|
140
140
|
def __init__(self):
|
@@ -169,17 +169,17 @@ def test_params_class(revision, expect, params_json_file):
|
|
169
169
|
prms.set_year(2011)
|
170
170
|
return
|
171
171
|
|
172
|
-
if expect ==
|
172
|
+
if expect == "raise":
|
173
173
|
with pytest.raises(paramtools.ValidationError):
|
174
174
|
prms.update_params(revision)
|
175
|
-
elif expect ==
|
175
|
+
elif expect == "noerror":
|
176
176
|
prms.update_params(revision)
|
177
177
|
assert not prms.errors
|
178
|
-
elif expect ==
|
178
|
+
elif expect == "error":
|
179
179
|
with pytest.raises(paramtools.ValidationError):
|
180
180
|
prms.update_params(revision)
|
181
181
|
assert prms.errors
|
182
|
-
elif expect ==
|
182
|
+
elif expect == "warn":
|
183
183
|
with pytest.raises(paramtools.ValidationError):
|
184
184
|
prms.update_params(revision)
|
185
185
|
assert prms.warnings
|
@@ -198,9 +198,9 @@ def test_json_file_contents(tests_path, fname):
|
|
198
198
|
last_known_year = Policy.LAST_KNOWN_YEAR # for indexed parameter values
|
199
199
|
known_years = set(range(first_year, last_known_year + 1))
|
200
200
|
# check elements in each parameter sub-dictionary
|
201
|
-
failures =
|
201
|
+
failures = ""
|
202
202
|
path = os.path.join(tests_path, "..", fname)
|
203
|
-
with open(path,
|
203
|
+
with open(path, "r", encoding="utf-8") as f:
|
204
204
|
allparams = json.loads(f.read())
|
205
205
|
for pname in allparams:
|
206
206
|
if pname == "schema":
|
@@ -208,31 +208,37 @@ def test_json_file_contents(tests_path, fname):
|
|
208
208
|
# check that param contains required keys
|
209
209
|
param = allparams[pname]
|
210
210
|
# check that indexable and indexed are False in many files
|
211
|
-
if fname !=
|
212
|
-
assert param.get(
|
213
|
-
assert param.get(
|
211
|
+
if fname != "policy_current_law.json":
|
212
|
+
assert param.get("indexable", False) is False
|
213
|
+
assert param.get("indexed", False) is False
|
214
214
|
# check that indexable is True when indexed is True
|
215
|
-
if param.get(
|
215
|
+
if param.get("indexed", False) and not param.get("indexable", False):
|
216
|
+
pindexed = param.get("indexed", False)
|
217
|
+
pindexable = param.get("indexable", False)
|
216
218
|
msg = (
|
217
|
-
f
|
218
|
-
f
|
219
|
-
f
|
219
|
+
f"param:<{pname}>; "
|
220
|
+
f"indexed={pindexed}; "
|
221
|
+
f"indexable={pindexable}\n"
|
220
222
|
)
|
221
223
|
failures += msg
|
222
224
|
# check that indexable param has value_type float
|
223
|
-
if param.get(
|
225
|
+
if param.get("indexable", False) and param["type"] != "float":
|
226
|
+
ptype = param["type"]
|
227
|
+
pindexable = param.get("indexable", False)
|
224
228
|
msg = (
|
225
|
-
f
|
226
|
-
f
|
227
|
-
f
|
229
|
+
f"param:<{pname}>; "
|
230
|
+
f"type={ptype}; "
|
231
|
+
f"indexable={pindexable}\n"
|
228
232
|
)
|
229
233
|
failures += msg
|
230
234
|
# ensure that indexable is False when value_type is not real
|
231
|
-
if param.get(
|
235
|
+
if param.get("indexable", False) and param["type"] != "float":
|
236
|
+
pindexable = param.get("indexable", False)
|
237
|
+
ptype = param["value_type"]
|
232
238
|
msg = (
|
233
|
-
f
|
234
|
-
f
|
235
|
-
f
|
239
|
+
f"param:<{pname}>; "
|
240
|
+
f"indexable={pindexable}; "
|
241
|
+
f"type={ptype}\n"
|
236
242
|
)
|
237
243
|
failures += msg
|
238
244
|
o = None
|
@@ -250,7 +256,7 @@ def test_json_file_contents(tests_path, fname):
|
|
250
256
|
for y in known_years:
|
251
257
|
o.set_year(y)
|
252
258
|
if np.isnan(getattr(o, param)).any():
|
253
|
-
msg = f
|
259
|
+
msg = f"param:<{param}>; not found in year={y}\n"
|
254
260
|
failures += msg
|
255
261
|
if failures:
|
256
262
|
raise ValueError(failures)
|
@@ -265,28 +271,28 @@ def test_parameters_mentioned(tests_path, jfname, pfname):
|
|
265
271
|
Make sure each JSON parameter is mentioned in PYTHON code file.
|
266
272
|
"""
|
267
273
|
# read JSON parameter file into a dictionary
|
268
|
-
path = os.path.join(tests_path,
|
269
|
-
with open(path,
|
274
|
+
path = os.path.join(tests_path, "..", jfname)
|
275
|
+
with open(path, "r", encoding="utf-8") as pfile:
|
270
276
|
allparams = json.load(pfile)
|
271
277
|
assert isinstance(allparams, dict)
|
272
278
|
# read PYTHON code file text
|
273
279
|
# pylint: disable=consider-using-join
|
274
|
-
if pfname ==
|
280
|
+
if pfname == "consumption.py":
|
275
281
|
# consumption.py does not explicitly name the parameters
|
276
|
-
code_text =
|
282
|
+
code_text = ""
|
277
283
|
for var in Consumption.RESPONSE_VARS:
|
278
|
-
code_text += f
|
284
|
+
code_text += f"MPC_{var}\n"
|
279
285
|
for var in Consumption.BENEFIT_VARS:
|
280
|
-
code_text += f
|
281
|
-
elif pfname ==
|
286
|
+
code_text += f"BEN_{var}_value\n"
|
287
|
+
elif pfname == "growdiff.py":
|
282
288
|
# growdiff.py does not explicitly name the parameters
|
283
|
-
code_text =
|
289
|
+
code_text = ""
|
284
290
|
for var in GrowFactors.VALID_NAMES:
|
285
|
-
code_text += f
|
291
|
+
code_text += f"{var}\n"
|
286
292
|
else:
|
287
293
|
# parameters are explicitly named in PYTHON file
|
288
|
-
path = os.path.join(tests_path,
|
289
|
-
with open(path,
|
294
|
+
path = os.path.join(tests_path, "..", pfname)
|
295
|
+
with open(path, "r", encoding="utf-8") as pfile:
|
290
296
|
code_text = pfile.read()
|
291
297
|
# check that each param (without leading _) is mentioned in code text
|
292
298
|
for pname in allparams:
|
@@ -491,7 +497,7 @@ def test_expand_2d_variable_rates():
|
|
491
497
|
for i in range(0, 4):
|
492
498
|
idx = i + len(ary) - 1
|
493
499
|
cur = np.array(cur * (1.0 + irates[idx]))
|
494
|
-
print(
|
500
|
+
print("cur is ", cur)
|
495
501
|
exp2.append(cur)
|
496
502
|
exp1 = np.array([1., 2., 3., 4.])
|
497
503
|
exp = np.zeros((5, 4))
|
@@ -597,13 +603,13 @@ def test_read_json_revision(good_revision):
|
|
597
603
|
# pllint: disable=private-method
|
598
604
|
with pytest.raises(TypeError):
|
599
605
|
# error because first obj argument is neither None nor a string
|
600
|
-
Parameters._read_json_revision([],
|
606
|
+
Parameters._read_json_revision([], "")
|
601
607
|
with pytest.raises(ValueError):
|
602
608
|
# error because second topkey argument must be a string
|
603
609
|
Parameters._read_json_revision(good_revision, 999)
|
604
610
|
with pytest.raises(ValueError):
|
605
611
|
# error because second topkey argument is not in good_revision
|
606
|
-
Parameters._read_json_revision(good_revision,
|
612
|
+
Parameters._read_json_revision(good_revision, "unknown_topkey")
|
607
613
|
|
608
614
|
|
609
615
|
@pytest.mark.parametrize("params,is_paramtools", [
|
@@ -620,3 +626,45 @@ def test_read_json_revision_foramts(params, is_paramtools):
|
|
620
626
|
assert is_paramtools_format(result) is is_paramtools
|
621
627
|
if is_paramtools:
|
622
628
|
assert result == json.loads(params)["consumption"]
|
629
|
+
|
630
|
+
|
631
|
+
def test_compatible_data_presence():
|
632
|
+
"""
|
633
|
+
Test that every parameter in the policy_current_law.json file
|
634
|
+
has a compatible_data field that is a dictionary.
|
635
|
+
"""
|
636
|
+
compatible_data_keys_set = set(["puf", "cps"])
|
637
|
+
|
638
|
+
# nested function used only in test_compatible_data_presence test
|
639
|
+
def valid_compatible_data(compatible_data):
|
640
|
+
"""
|
641
|
+
Return True if compatible_data is a valid dictionary;
|
642
|
+
otherwise return False
|
643
|
+
"""
|
644
|
+
if not isinstance(compatible_data, dict):
|
645
|
+
return False
|
646
|
+
if set(compatible_data.keys()) != compatible_data_keys_set:
|
647
|
+
return False
|
648
|
+
for key in compatible_data:
|
649
|
+
boolean = (compatible_data[key] is True or
|
650
|
+
compatible_data[key] is False)
|
651
|
+
if not boolean:
|
652
|
+
return False
|
653
|
+
return True
|
654
|
+
|
655
|
+
# main logic of test_compatible_data_presence test
|
656
|
+
clp = Policy()
|
657
|
+
allparams = clp.metadata()
|
658
|
+
problem_pnames = []
|
659
|
+
for pname in allparams:
|
660
|
+
if "compatible_data" in allparams[pname]:
|
661
|
+
compatible_data = allparams[pname]["compatible_data"]
|
662
|
+
else:
|
663
|
+
compatible_data = None
|
664
|
+
if not valid_compatible_data(compatible_data):
|
665
|
+
problem_pnames.append(pname)
|
666
|
+
if problem_pnames:
|
667
|
+
msg = "{} has no or invalid compatible_data field"
|
668
|
+
for pname in problem_pnames:
|
669
|
+
print(msg.format(pname))
|
670
|
+
assert False, "ERROR: list of problem_pnames is above"
|