taxcalc 4.2.1__py3-none-any.whl → 4.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.
Files changed (123) hide show
  1. taxcalc/__init__.py +1 -1
  2. taxcalc/assumptions/ASSUMPTIONS.md +53 -0
  3. taxcalc/assumptions/README.md +17 -0
  4. taxcalc/assumptions/economic_assumptions_template.json +77 -0
  5. taxcalc/calcfunctions.py +7 -4
  6. taxcalc/data.py +10 -5
  7. taxcalc/policy.py +1 -1
  8. taxcalc/policy_current_law.json +4649 -288
  9. taxcalc/records.py +20 -15
  10. taxcalc/reforms/2017_law.json +125 -0
  11. taxcalc/reforms/2017_law.out.csv +10 -0
  12. taxcalc/reforms/ARPA.json +78 -0
  13. taxcalc/reforms/ARPA.out.csv +10 -0
  14. taxcalc/reforms/BrownKhanna.json +23 -0
  15. taxcalc/reforms/BrownKhanna.out.csv +10 -0
  16. taxcalc/reforms/CARES.json +40 -0
  17. taxcalc/reforms/CARES.out.csv +10 -0
  18. taxcalc/reforms/ConsolidatedAppropriationsAct2021.json +15 -0
  19. taxcalc/reforms/ConsolidatedAppropriationsAct2021.out.csv +10 -0
  20. taxcalc/reforms/Larson2019.json +36 -0
  21. taxcalc/reforms/Larson2019.out.csv +10 -0
  22. taxcalc/reforms/README.md +22 -0
  23. taxcalc/reforms/REFORMS.md +92 -0
  24. taxcalc/reforms/Renacci.json +61 -0
  25. taxcalc/reforms/Renacci.out.csv +10 -0
  26. taxcalc/reforms/SandersDeFazio.json +15 -0
  27. taxcalc/reforms/SandersDeFazio.out.csv +10 -0
  28. taxcalc/reforms/TCJA.json +160 -0
  29. taxcalc/reforms/TCJA.md +48 -0
  30. taxcalc/reforms/TCJA.out.csv +10 -0
  31. taxcalc/reforms/Trump2016.json +71 -0
  32. taxcalc/reforms/Trump2016.out.csv +10 -0
  33. taxcalc/reforms/Trump2017.json +51 -0
  34. taxcalc/reforms/Trump2017.out.csv +10 -0
  35. taxcalc/reforms/archive/Clinton2016.json +56 -0
  36. taxcalc/reforms/archive/RyanBrady.json +104 -0
  37. taxcalc/reforms/archive/TCJA_House.json +144 -0
  38. taxcalc/reforms/archive/TCJA_House_Amended.json +152 -0
  39. taxcalc/reforms/archive/TCJA_Reconciliation.json +187 -0
  40. taxcalc/reforms/archive/TCJA_Senate.json +116 -0
  41. taxcalc/reforms/archive/TCJA_Senate_111417.json +169 -0
  42. taxcalc/reforms/archive/TCJA_Senate_120117.json +174 -0
  43. taxcalc/reforms/cases.csv +10 -0
  44. taxcalc/reforms/clp.out.csv +10 -0
  45. taxcalc/reforms/ext.json +59 -0
  46. taxcalc/reforms/growfactors_ext.csv +65 -0
  47. taxcalc/reforms/ptaxes0.json +37 -0
  48. taxcalc/reforms/ptaxes0.out.csv +10 -0
  49. taxcalc/reforms/ptaxes1.json +21 -0
  50. taxcalc/reforms/ptaxes1.out.csv +10 -0
  51. taxcalc/reforms/ptaxes2.json +18 -0
  52. taxcalc/reforms/ptaxes2.out.csv +10 -0
  53. taxcalc/reforms/ptaxes3.json +28 -0
  54. taxcalc/reforms/ptaxes3.out.csv +10 -0
  55. taxcalc/taxcalcio.py +44 -22
  56. taxcalc/tests/benefits_expect.csv +169 -0
  57. taxcalc/tests/cmpi_cps_expect.txt +132 -0
  58. taxcalc/tests/cmpi_puf_expect.txt +132 -0
  59. taxcalc/tests/conftest.py +143 -0
  60. taxcalc/tests/cpscsv_agg_expect.csv +26 -0
  61. taxcalc/tests/puf_var_correl_coeffs_2016.csv +80 -0
  62. taxcalc/tests/puf_var_wght_means_by_year.csv +80 -0
  63. taxcalc/tests/pufcsv_agg_expect.csv +26 -0
  64. taxcalc/tests/pufcsv_mtr_expect.txt +63 -0
  65. taxcalc/tests/reforms.json +649 -0
  66. taxcalc/tests/reforms_expect.csv +65 -0
  67. taxcalc/tests/test_4package.py +67 -0
  68. taxcalc/tests/test_benefits.py +86 -0
  69. taxcalc/tests/test_calcfunctions.py +871 -0
  70. taxcalc/tests/test_calculator.py +1021 -0
  71. taxcalc/tests/test_compare.py +336 -0
  72. taxcalc/tests/test_compatible_data.py +338 -0
  73. taxcalc/tests/test_consumption.py +144 -0
  74. taxcalc/tests/test_cpscsv.py +163 -0
  75. taxcalc/tests/test_data.py +133 -0
  76. taxcalc/tests/test_decorators.py +332 -0
  77. taxcalc/tests/test_growdiff.py +102 -0
  78. taxcalc/tests/test_growfactors.py +94 -0
  79. taxcalc/tests/test_parameters.py +617 -0
  80. taxcalc/tests/test_policy.py +1557 -0
  81. taxcalc/tests/test_puf_var_stats.py +194 -0
  82. taxcalc/tests/test_pufcsv.py +385 -0
  83. taxcalc/tests/test_records.py +234 -0
  84. taxcalc/tests/test_reforms.py +386 -0
  85. taxcalc/tests/test_responses.py +41 -0
  86. taxcalc/tests/test_taxcalcio.py +755 -0
  87. taxcalc/tests/test_utils.py +792 -0
  88. taxcalc/validation/CSV_INPUT_VARS.md +29 -0
  89. taxcalc/validation/CSV_OUTPUT_VARS.md +63 -0
  90. taxcalc/validation/README.md +68 -0
  91. taxcalc/validation/taxsim35/Differences_Explained.md +54 -0
  92. taxcalc/validation/taxsim35/README.md +139 -0
  93. taxcalc/validation/taxsim35/expected_differences/a17-taxdiffs-expect.csv +25 -0
  94. taxcalc/validation/taxsim35/expected_differences/a18-taxdiffs-expect.csv +25 -0
  95. taxcalc/validation/taxsim35/expected_differences/a19-taxdiffs-expect.csv +25 -0
  96. taxcalc/validation/taxsim35/expected_differences/a20-taxdiffs-expect.csv +25 -0
  97. taxcalc/validation/taxsim35/expected_differences/a21-taxdiffs-expect.csv +25 -0
  98. taxcalc/validation/taxsim35/expected_differences/b17-taxdiffs-expect.csv +25 -0
  99. taxcalc/validation/taxsim35/expected_differences/b18-taxdiffs-expect.csv +25 -0
  100. taxcalc/validation/taxsim35/expected_differences/b19-taxdiffs-expect.csv +25 -0
  101. taxcalc/validation/taxsim35/expected_differences/b20-taxdiffs-expect.csv +25 -0
  102. taxcalc/validation/taxsim35/expected_differences/b21-taxdiffs-expect.csv +25 -0
  103. taxcalc/validation/taxsim35/expected_differences/c17-taxdiffs-expect.csv +25 -0
  104. taxcalc/validation/taxsim35/expected_differences/c18-taxdiffs-expect.csv +25 -0
  105. taxcalc/validation/taxsim35/expected_differences/c19-taxdiffs-expect.csv +25 -0
  106. taxcalc/validation/taxsim35/input_setup.py +67 -0
  107. taxcalc/validation/taxsim35/main_comparison.py +183 -0
  108. taxcalc/validation/taxsim35/prepare_taxcalc_input.py +161 -0
  109. taxcalc/validation/taxsim35/process_taxcalc_output.py +140 -0
  110. taxcalc/validation/taxsim35/taxsim_emulation.json +49 -0
  111. taxcalc/validation/taxsim35/taxsim_input.py +321 -0
  112. taxcalc/validation/taxsim35/tc_sims.py +98 -0
  113. taxcalc/validation/taxsim35/tests_35.py +80 -0
  114. taxcalc/validation/tests_35.sh +13 -0
  115. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/METADATA +3 -4
  116. taxcalc-4.3.0.dist-info/RECORD +139 -0
  117. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/WHEEL +1 -1
  118. taxcalc/tmd_growfactors.csv +0 -55
  119. taxcalc/tmd_weights.csv.gz +0 -0
  120. taxcalc-4.2.1.dist-info/RECORD +0 -34
  121. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/LICENSE +0 -0
  122. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/entry_points.txt +0 -0
  123. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,617 @@
1
+ """
2
+ Tests for Tax-Calculator Parameters class and JSON parameter files.
3
+ """
4
+ # CODING-STYLE CHECKS:
5
+ # pycodestyle test_parameters.py
6
+ # pylint --disable=locally-disabled test_parameters.py
7
+
8
+ import copy
9
+ import os
10
+ import json
11
+ import math
12
+ import tempfile
13
+ import numpy as np
14
+ import paramtools
15
+ import pytest
16
+ # pylint: disable=import-error
17
+ from taxcalc import (
18
+ Parameters,
19
+ Policy,
20
+ Consumption,
21
+ GrowFactors,
22
+ is_paramtools_format,
23
+ )
24
+ from taxcalc.growdiff import GrowDiff
25
+
26
+
27
+ # Test specification and use of simple Parameters-derived class that has
28
+ # no vector parameters and has no (wage or price) indexed parameters.
29
+ # This derived class is called Params and it contains one of each of the
30
+ # four types of parameters.
31
+ #
32
+ # The following pytest fixture specifies the JSON DEFAULTS file for the
33
+ # Params class, which is defined in the test_params_class function.
34
+
35
+
36
+ PARAMS_JSON = json.dumps({
37
+ "schema": {
38
+ "labels": {
39
+ "year": {
40
+ "type": "int",
41
+ "validators": {"range": {"min": 2001, "max": 2010}}
42
+ },
43
+ "label": {
44
+ "type": "str",
45
+ "validators": {"choice": {"choices": ["label1", "label2"]}}
46
+ }
47
+ },
48
+ "operators": {
49
+ "array_first": True,
50
+ "label_to_extend": "year"
51
+ }
52
+ },
53
+ "real_param": {
54
+ "title": "Real (float) parameter",
55
+ "description": "",
56
+ "type": "float",
57
+ "value": 0.5,
58
+ "validators": {"range": {"min": 0, "max": 1}}
59
+ },
60
+ "int_param": {
61
+ "title": "Integer parameter",
62
+ "description": "",
63
+ "type": "int",
64
+ "value": 2,
65
+ "validators": {"range": {"min": 0, "max": 9}}
66
+ },
67
+ "bool_param": {
68
+ "title": "Boolean parameter",
69
+ "description": "",
70
+ "type": "bool",
71
+ "value": True,
72
+ },
73
+ "str_param": {
74
+ "title": "String parameter",
75
+ "description": "",
76
+ "type": "str",
77
+ "value": "linear",
78
+ "validators": {"choice": {"choices": ["linear", "nonlinear", "cubic"]}}
79
+ },
80
+ "label_param": {
81
+ "title": "Parameter that uses labels.",
82
+ "description": "",
83
+ "type": "int",
84
+ "value": [
85
+ {"label": "label1", "year": 2001, "value": 2},
86
+ {"label": "label2", "year": 2001, "value": 3}
87
+ ],
88
+ "validators": {"range": {"min": 0, "max": 9}}
89
+ }
90
+ })
91
+
92
+
93
+ @pytest.fixture(scope='module', name='params_json_file')
94
+ def fixture_params_json_file():
95
+ """
96
+ Define JSON DEFAULTS file for Parameters-derived Params class.
97
+ """
98
+ with tempfile.NamedTemporaryFile(mode='a', delete=False) as pfile:
99
+ pfile.write(PARAMS_JSON + '\n')
100
+ pfile.close()
101
+ yield pfile
102
+ os.remove(pfile.name)
103
+
104
+
105
+ @pytest.mark.parametrize("revision, expect", [
106
+ ({}, ""),
107
+ ({'real_param': {2004: 1.9}}, "error"),
108
+ ({'int_param': {2004: [3.6]}}, "raise"),
109
+ ({"int_param": {2004: [3]}}, "raise"),
110
+ ({"label_param": {2004: [1, 2]}}, "noerror"),
111
+ ({"label_param": {2004: [[1, 2]]}}, "raise"),
112
+ ({"label_param": {2004: [1, 2, 3]}}, "raise"),
113
+ ({'bool_param': {2004: [4.9]}}, "raise"),
114
+ ({'str_param': {2004: [9]}}, "raise"),
115
+ ({'str_param': {2004: 'nonlinear'}}, "noerror"),
116
+ ({'str_param': {2004: 'unknownvalue'}}, "error"),
117
+ ({'str_param': {2004: ['nonlinear']}}, "raise"),
118
+ ({'real_param': {2004: 'linear'}}, "raise"),
119
+ ({'real_param': {2004: [0.2, 0.3]}}, "raise"),
120
+ ({'real_param-indexed': {2004: True}}, "raise"),
121
+ ({'unknown_param-indexed': {2004: False}}, "raise")
122
+ ])
123
+ def test_params_class(revision, expect, params_json_file):
124
+ """
125
+ Specifies Params class and tests it.
126
+ """
127
+
128
+ class Params(Parameters):
129
+ """
130
+ The Params class is derived from the abstract base Parameter class.
131
+ """
132
+ DEFAULTS_FILE_NAME = params_json_file.name
133
+ DEFAULTS_FILE_PATH = ''
134
+ START_YEAR = 2001
135
+ LAST_YEAR = 2010
136
+ NUM_YEARS = LAST_YEAR - START_YEAR + 1
137
+
138
+ def __init__(self):
139
+ super().__init__()
140
+ self.initialize(Params.START_YEAR, Params.NUM_YEARS)
141
+
142
+ def update_params(self, revision,
143
+ print_warnings=True, raise_errors=True):
144
+ """
145
+ Update parameters given specified revision dictionary.
146
+ """
147
+ self._update(revision, print_warnings, raise_errors)
148
+
149
+ # test Params class
150
+ prms = Params()
151
+
152
+ with pytest.raises(NotImplementedError):
153
+ prms.set_rates()
154
+
155
+ if revision == {}:
156
+ assert isinstance(prms, Params)
157
+ assert prms.start_year == 2001
158
+ assert prms.current_year == 2001
159
+ assert prms.end_year == 2010
160
+ assert prms.inflation_rates() == list()
161
+ assert prms.wage_growth_rates() == list()
162
+ prms.set_year(2010)
163
+ assert prms.current_year == 2010
164
+ with pytest.raises(paramtools.ValidationError):
165
+ prms.set_year(2011)
166
+ return
167
+
168
+ if expect == 'raise':
169
+ with pytest.raises(paramtools.ValidationError):
170
+ prms.update_params(revision)
171
+ elif expect == 'noerror':
172
+ prms.update_params(revision)
173
+ assert not prms.errors
174
+ elif expect == 'error':
175
+ with pytest.raises(paramtools.ValidationError):
176
+ prms.update_params(revision)
177
+ assert prms.errors
178
+ elif expect == 'warn':
179
+ with pytest.raises(paramtools.ValidationError):
180
+ prms.update_params(revision)
181
+ assert prms.warnings
182
+
183
+
184
+ @pytest.mark.parametrize("fname",
185
+ [("consumption.json"),
186
+ ("policy_current_law.json"),
187
+ ("growdiff.json")])
188
+ def test_json_file_contents(tests_path, fname):
189
+ """
190
+ Check contents of JSON parameter files in Tax-Calculator/taxcalc directory.
191
+ """
192
+ first_year = Policy.JSON_START_YEAR
193
+ last_known_year = Policy.LAST_KNOWN_YEAR # for indexed parameter values
194
+ known_years = set(range(first_year, last_known_year + 1))
195
+ long_params = ['II_brk1', 'II_brk2', 'II_brk3', 'II_brk4',
196
+ 'II_brk5', 'II_brk6', 'II_brk7',
197
+ 'PT_brk1', 'PT_brk2', 'PT_brk3', 'PT_brk4',
198
+ 'PT_brk5', 'PT_brk6', 'PT_brk7',
199
+ 'PT_qbid_taxinc_thd',
200
+ 'ALD_BusinessLosses_c',
201
+ 'STD', 'II_em', 'II_em_ps',
202
+ 'AMT_em', 'AMT_em_ps', 'AMT_em_pe',
203
+ 'ID_ps', 'ID_AllTaxes_c']
204
+ # for TCJA-reverting long_params
205
+ long_known_years = set(range(first_year, last_known_year + 1))
206
+ long_known_years.add(2026)
207
+ # check elements in each parameter sub-dictionary
208
+ failures = ''
209
+ with open(os.path.join(tests_path, "..", fname)) as f:
210
+ allparams = json.loads(f.read())
211
+ for pname in allparams:
212
+ if pname == "schema":
213
+ continue
214
+ # check that param contains required keys
215
+ param = allparams[pname]
216
+ # check that indexable and indexed are False in many files
217
+ if fname != 'policy_current_law.json':
218
+ assert param.get('indexable', False) is False
219
+ assert param.get('indexed', False) is False
220
+ # check that indexable is True when indexed is True
221
+ if param.get('indexed', False) and not param.get('indexable', False):
222
+ msg = 'param:<{}>; indexed={}; indexable={}'
223
+ fail = msg.format(pname,
224
+ param.get('indexed', False),
225
+ param.get('indexable', False))
226
+ failures += fail + '\n'
227
+ # check that indexable param has value_type float
228
+ if param.get('indexable', False) and param['type'] != 'float':
229
+ msg = 'param:<{}>; type={}; indexable={}'
230
+ fail = msg.format(pname, param['type'],
231
+ param.get('indexable', False))
232
+ failures += fail + '\n'
233
+ # ensure that indexable is False when value_type is not real
234
+ if param.get('indexable', False) and param['type'] != 'float':
235
+ msg = 'param:<{}>; indexable={}; type={}'
236
+ fail = msg.format(pname,
237
+ param.get('indexable', False),
238
+ param['value_type'])
239
+ failures += fail + '\n'
240
+ if fname == "consumption.json":
241
+ o = Consumption()
242
+ elif fname == "policy_current_law.json":
243
+ o = Policy()
244
+ elif fname == "growdiff.json":
245
+ o = GrowDiff()
246
+ param_list = []
247
+ for k in o:
248
+ if k[0].isupper(): # find parameters by case of first letter
249
+ param_list.append(k)
250
+ for param in param_list:
251
+ for y in known_years:
252
+ o.set_year(y)
253
+ if np.isnan(getattr(o, param)).any():
254
+ msg = 'param:<{}>; not found in year={}'
255
+ fail = msg.format(param, y)
256
+ failures += fail + '\n'
257
+ if failures:
258
+ raise ValueError(failures)
259
+
260
+
261
+ @pytest.mark.parametrize("jfname, pfname",
262
+ [("consumption.json", "consumption.py"),
263
+ ("policy_current_law.json", "calcfunctions.py"),
264
+ ("growdiff.json", "growdiff.py")])
265
+ def test_parameters_mentioned(tests_path, jfname, pfname):
266
+ """
267
+ Make sure each JSON parameter is mentioned in PYTHON code file.
268
+ """
269
+ # read JSON parameter file into a dictionary
270
+ path = os.path.join(tests_path, '..', jfname)
271
+ pfile = open(path, 'r')
272
+ allparams = json.load(pfile)
273
+ pfile.close()
274
+ assert isinstance(allparams, dict)
275
+ # read PYTHON code file text
276
+ if pfname == 'consumption.py':
277
+ # consumption.py does not explicitly name the parameters
278
+ code_text = ''
279
+ for var in Consumption.RESPONSE_VARS:
280
+ code_text += 'MPC_{}\n'.format(var)
281
+ for var in Consumption.BENEFIT_VARS:
282
+ code_text += 'BEN_{}_value\n'.format(var)
283
+ elif pfname == 'growdiff.py':
284
+ # growdiff.py does not explicitly name the parameters
285
+ code_text = ''
286
+ for var in GrowFactors.VALID_NAMES:
287
+ code_text += '{}\n'.format(var)
288
+ else:
289
+ # parameters are explicitly named in PYTHON file
290
+ path = os.path.join(tests_path, '..', pfname)
291
+ pfile = open(path, 'r')
292
+ code_text = pfile.read()
293
+ pfile.close()
294
+ # check that each param (without leading _) is mentioned in code text
295
+ for pname in allparams:
296
+ if pname == "schema":
297
+ continue
298
+ assert pname[1:] in code_text
299
+
300
+
301
+ # following tests access private methods, so pylint: disable=protected-access
302
+
303
+ class ArrayParams(Parameters):
304
+ defaults = {
305
+ "schema": {
306
+ "labels": {
307
+ "year": {
308
+ "type": "int",
309
+ "validators": {"range": {"min": 2013, "max": 2028}}
310
+ },
311
+ "MARS": {
312
+ "type": "str",
313
+ "validators": {
314
+ "choice": {
315
+ "choices": [
316
+ "single",
317
+ "joint",
318
+ "mseparate",
319
+ "headhh",
320
+ "widow",
321
+ # test value of II_brk2 has 6 columns
322
+ "extra",
323
+ ]
324
+ }
325
+ }
326
+ },
327
+ "idedtype": {
328
+ "type": "str",
329
+ "validators": {
330
+ "choice": {"choices": ["med", "sltx", "retx"]}
331
+ }
332
+ }
333
+ },
334
+ "additional_members": {
335
+ "indexable": {
336
+ "type": "bool"
337
+ },
338
+ "indexed": {
339
+ "type": "bool"
340
+ },
341
+ },
342
+ "operators": {
343
+ "array_first": True,
344
+ "label_to_extend": "year"
345
+ }
346
+ },
347
+ "one_dim": {
348
+ "title": "One dimension parameter",
349
+ "description": "",
350
+ "type": "float",
351
+ "indexed": True,
352
+ "indexable": True,
353
+ "value": [{"year": 2013, "value": 5}]
354
+ },
355
+ "two_dim": {
356
+ "title": "Two dimension parameter",
357
+ "description": "",
358
+ "type": "float",
359
+ "indexed": True,
360
+ "indexable": True,
361
+ "value": [
362
+ {"year": 2013, "idedtype": "med", "value": 1},
363
+ {"year": 2013, "idedtype": "sltx", "value": 2},
364
+ {"year": 2013, "idedtype": "retx", "value": 3}
365
+ ]
366
+ },
367
+ "II_brk2": {
368
+ "title": "II_brk2",
369
+ "description": "",
370
+ "type": "float",
371
+ "indexed": True,
372
+ "indexable": True,
373
+ "value": [
374
+ {"year": 2013, "MARS": "single", "value": 1},
375
+ {"year": 2013, "MARS": "joint", "value": 2},
376
+ {"year": 2013, "MARS": "mseparate", "value": 3},
377
+ {"year": 2013, "MARS": "headhh", "value": 2},
378
+ {"year": 2013, "MARS": "widow", "value": 3},
379
+ {"year": 2013, "MARS": "extra", "value": 3},
380
+ ]
381
+ }
382
+ }
383
+
384
+ # These will be controlled directly through the extend method.
385
+ label_to_extend = None
386
+ array_first = False
387
+
388
+ START_YEAR = 2013
389
+ LAST_YEAR = 2034
390
+ NUM_YEARS = LAST_YEAR - START_YEAR + 1
391
+
392
+ def __init__(self, **kwargs):
393
+ super().__init__(
394
+ ArrayParams.START_YEAR,
395
+ ArrayParams.NUM_YEARS,
396
+ **kwargs
397
+ )
398
+ self._inflation_rates = [0.02] * self.num_years
399
+ self._wage_growth_rates = [0.03] * self.num_years
400
+
401
+ def update_params(self, revision,
402
+ print_warnings=True, raise_errors=True):
403
+ """
404
+ Update parameters given specified revision dictionary.
405
+ """
406
+ self._update(revision, print_warnings, raise_errors)
407
+
408
+ def set_rates(self):
409
+ pass
410
+
411
+
412
+ def test_expand_xd_errors():
413
+ """
414
+ One of several _expand_?D tests.
415
+ """
416
+ params = ArrayParams(label_to_extend=None, array_first=False)
417
+ with pytest.raises(paramtools.ValidationError):
418
+ params.extend(label="year", label_values=[1, 2, 3])
419
+
420
+
421
+ def test_expand_empty():
422
+ params = ArrayParams(label_to_extend=None, array_first=False)
423
+ params.sort_values()
424
+ one_dim = copy.deepcopy(params.one_dim)
425
+
426
+ params.extend(label="year", label_values=[])
427
+
428
+ params.sort_values()
429
+ assert params.one_dim == one_dim
430
+
431
+
432
+ def test_expand_1d_scalar():
433
+ yrs = 12
434
+ val = 10.0
435
+ exp = np.array([val * math.pow(1.02, i) for i in range(0, yrs)])
436
+
437
+ yrslist = list(range(2013, 2013 + 12))
438
+ params = ArrayParams(label_to_extend=None, array_first=False)
439
+ params.adjust({"one_dim": val})
440
+ params.extend(params=["one_dim"], label="year", label_values=yrslist)
441
+ res = params.to_array("one_dim", year=yrslist)
442
+ assert np.allclose(exp, res, atol=0.01, rtol=0.0)
443
+
444
+ params = ArrayParams(label_to_extend=None, array_first=False)
445
+ params.adjust({"one_dim": val})
446
+ params.extend(params=["one_dim"], label="year", label_values=[2013])
447
+ res = params.to_array("one_dim", year=2013)
448
+ assert np.allclose(np.array([val]), res, atol=0.01, rtol=0.0)
449
+
450
+
451
+ def test_expand_2d_short_array():
452
+ """
453
+ One of several _expand_?D tests.
454
+ """
455
+ ary = np.array([[1., 2., 3.]])
456
+ val = np.array([1., 2., 3.])
457
+ exp2 = np.array([val * math.pow(1.02, i) for i in range(1, 5)])
458
+ exp1 = np.array([1., 2., 3.])
459
+ exp = np.zeros((5, 3))
460
+ exp[:1] = exp1
461
+ exp[1:] = exp2
462
+
463
+ params = ArrayParams(array_first=False, label_to_extend=None)
464
+ years = [2013, 2014, 2015, 2016, 2017]
465
+ params.extend(
466
+ params=["two_dim"],
467
+ label="year",
468
+ label_values=years,
469
+ )
470
+ res = params.to_array("two_dim", year=years)
471
+ assert np.allclose(exp, res, atol=0.01, rtol=0.0)
472
+
473
+
474
+ def test_expand_2d_variable_rates():
475
+ """
476
+ One of several _expand_?D tests.
477
+ """
478
+ ary = np.array([[1., 2., 3.]])
479
+ cur = np.array([1., 2., 3.])
480
+ irates = [0.02, 0.02, 0.02, 0.03, 0.035]
481
+ exp2 = []
482
+ for i in range(0, 4):
483
+ idx = i + len(ary) - 1
484
+ cur = np.array(cur * (1.0 + irates[idx]))
485
+ print('cur is ', cur)
486
+ exp2.append(cur)
487
+ exp1 = np.array([1., 2., 3.])
488
+ exp = np.zeros((5, 3))
489
+ exp[:1] = exp1
490
+ exp[1:] = exp2
491
+
492
+ params = ArrayParams(array_first=False, label_to_extend=None)
493
+ params._inflation_rates = irates
494
+ years = [2013, 2014, 2015, 2016, 2017]
495
+ params.extend(params=["two_dim"], label="year", label_values=years)
496
+ res = params.to_array("two_dim", year=years)
497
+ assert np.allclose(exp, res, atol=0.01, rtol=0.0)
498
+
499
+
500
+ def test_expand_2d_already_filled():
501
+ """
502
+ One of several _expand_?D tests.
503
+ """
504
+ # pylint doesn't like caps in var name, so pylint: disable=invalid-name
505
+ _II_brk2 = [[36000., 72250., 36500., 48600., 72500., 36250.],
506
+ [38000., 74000., 36900., 49400., 73800., 36900.],
507
+ [40000., 74900., 37450., 50200., 74900., 37450.]]
508
+
509
+ years = [2013, 2014, 2015]
510
+ params = ArrayParams(
511
+ array_first=False,
512
+ label_to_extend=None,
513
+ )
514
+ params.adjust({
515
+ "II_brk2": params.from_array("II_brk2", np.array(_II_brk2), year=years)
516
+ })
517
+
518
+ params.extend(
519
+ params=["II_brk2"], label="year", label_values=years
520
+ )
521
+ res = params.to_array("II_brk2", year=years)
522
+ assert np.allclose(res, np.array(_II_brk2), atol=0.01, rtol=0.0)
523
+
524
+
525
+ def test_expand_2d_partial_expand():
526
+ """
527
+ One of several _expand_?D tests.
528
+ """
529
+ # pylint doesn't like caps in var name, so pylint: disable=invalid-name
530
+ _II_brk2 = [[36000.0, 72250.0, 36500.0, 48600.0, 72500.0, 36250.0],
531
+ [38000.0, 74000.0, 36900.0, 49400.0, 73800.0, 36900.0],
532
+ [40000.0, 74900.0, 37450.0, 50200.0, 74900.0, 37450.0]]
533
+ # We have three years worth of data, need 4 years worth,
534
+ # but we only need the inflation rate for year 3 to go
535
+ # from year 3 -> year 4
536
+ inf_rates = [0.02, 0.02, 0.03]
537
+ exp1 = 40000. * 1.03
538
+ exp2 = 74900. * 1.03
539
+ exp3 = 37450. * 1.03
540
+ exp4 = 50200. * 1.03
541
+ exp5 = 74900. * 1.03
542
+ exp6 = 37450. * 1.03
543
+ exp = [[36000.0, 72250.0, 36500.0, 48600.0, 72500.0, 36250.0],
544
+ [38000.0, 74000.0, 36900.0, 49400.0, 73800.0, 36900.0],
545
+ [40000.0, 74900.0, 37450.0, 50200.0, 74900.0, 37450.0],
546
+ [exp1, exp2, exp3, exp4, exp5, exp6]]
547
+
548
+ years = [2013, 2014, 2015]
549
+ params = ArrayParams(array_first=False, label_to_extend=None)
550
+ params.adjust({
551
+ "II_brk2": params.from_array(
552
+ "II_brk2",
553
+ np.array(_II_brk2),
554
+ year=years
555
+ )
556
+ })
557
+ params._inflation_rates[:3] = inf_rates
558
+ params.extend(
559
+ params=["II_brk2"], label="year", label_values=years + [2016]
560
+ )
561
+ res = params.to_array("II_brk2", year=years + [2016])
562
+ assert np.allclose(res, exp, atol=0.01, rtol=0.0)
563
+
564
+
565
+ taxcalc_revision = """
566
+ {
567
+ "consumption": {"BEN_mcaid_value": {"2013": 0.9}}
568
+ }
569
+ """
570
+
571
+ paramtools_revision = """
572
+ {
573
+ "consumption": {"BEN_mcaid_value": [{"year": "2013", "value": 0.9}]}
574
+ }
575
+ """
576
+
577
+ paramtools_revision2 = """
578
+ {
579
+ "consumption": {"BEN_mcaid_value": 0.9}
580
+ }
581
+ """
582
+
583
+
584
+ @pytest.mark.parametrize("good_revision", [
585
+ taxcalc_revision,
586
+ paramtools_revision,
587
+ ])
588
+ def test_read_json_revision(good_revision):
589
+ """
590
+ Check _read_json_revision logic.
591
+ """
592
+ # pllint: disable=private-method
593
+ with pytest.raises(TypeError):
594
+ # error because first obj argument is neither None nor a string
595
+ Parameters._read_json_revision(list(), '')
596
+ with pytest.raises(ValueError):
597
+ # error because second topkey argument must be a string
598
+ Parameters._read_json_revision(good_revision, 999)
599
+ with pytest.raises(ValueError):
600
+ # error because second topkey argument is not in good_revision
601
+ Parameters._read_json_revision(good_revision, 'unknown_topkey')
602
+
603
+
604
+ @pytest.mark.parametrize("params,is_paramtools", [
605
+ (taxcalc_revision, False),
606
+ (paramtools_revision, True),
607
+ (paramtools_revision2, True),
608
+ ])
609
+ def test_read_json_revision_foramts(params, is_paramtools):
610
+ """
611
+ Check _read_json_revision for ParamTools and Tax-Calculator
612
+ styled parameters.
613
+ """
614
+ result = Parameters._read_json_revision(params, "consumption")
615
+ assert is_paramtools_format(result) is is_paramtools
616
+ if is_paramtools:
617
+ assert result == json.loads(params)["consumption"]