taxcalc 4.6.0__py3-none-any.whl → 4.6.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/calculator.py +3 -3
- taxcalc/cli/tc.py +80 -30
- taxcalc/data.py +2 -2
- taxcalc/parameters.py +0 -5
- taxcalc/policy_current_law.json +6 -2
- taxcalc/taxcalcio.py +91 -53
- taxcalc/tests/test_calculator.py +1 -1
- taxcalc/tests/test_reforms.py +7 -7
- taxcalc/tests/test_taxcalcio.py +9 -30
- {taxcalc-4.6.0.dist-info → taxcalc-4.6.1.dist-info}/METADATA +1 -1
- {taxcalc-4.6.0.dist-info → taxcalc-4.6.1.dist-info}/RECORD +16 -16
- {taxcalc-4.6.0.dist-info → taxcalc-4.6.1.dist-info}/WHEEL +1 -1
- {taxcalc-4.6.0.dist-info → taxcalc-4.6.1.dist-info}/entry_points.txt +0 -0
- {taxcalc-4.6.0.dist-info → taxcalc-4.6.1.dist-info}/licenses/LICENSE +0 -0
- {taxcalc-4.6.0.dist-info → taxcalc-4.6.1.dist-info}/top_level.txt +0 -0
taxcalc/__init__.py
CHANGED
taxcalc/calculator.py
CHANGED
@@ -305,11 +305,11 @@ class Calculator():
|
|
305
305
|
return self.__consumption.benval_params()
|
306
306
|
|
307
307
|
@property
|
308
|
-
def
|
308
|
+
def reform_errors(self):
|
309
309
|
"""
|
310
|
-
Calculator class embedded Policy object's
|
310
|
+
Calculator class embedded Policy object's parameter_errors.
|
311
311
|
"""
|
312
|
-
return self.__policy.
|
312
|
+
return self.__policy.parameter_errors
|
313
313
|
|
314
314
|
@property
|
315
315
|
def current_year(self):
|
taxcalc/cli/tc.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"""
|
2
2
|
Command-line interface (CLI) to Tax-Calculator,
|
3
|
-
which can be accessed as 'tc' from an installed taxcalc
|
3
|
+
which can be accessed as 'tc' from an installed taxcalc package.
|
4
4
|
"""
|
5
5
|
# CODING-STYLE CHECKS:
|
6
6
|
# pycodestyle tc.py
|
@@ -30,7 +30,7 @@ def cli_tc_main():
|
|
30
30
|
|
31
31
|
# parse command-line arguments:
|
32
32
|
usage_str = 'tc INPUT TAXYEAR {}{}{}{}'.format(
|
33
|
-
'[--help]\n',
|
33
|
+
'[--help] [--numyears N]\n',
|
34
34
|
(
|
35
35
|
' '
|
36
36
|
'[--baseline BASELINE] [--reform REFORM] '
|
@@ -63,15 +63,26 @@ def cli_tc_main():
|
|
63
63
|
'are computed.'),
|
64
64
|
type=int,
|
65
65
|
default=0)
|
66
|
+
parser.add_argument('--numyears', metavar='N',
|
67
|
+
help=('N is an integer indicating for how many '
|
68
|
+
'years taxes are calculated. No --numyears '
|
69
|
+
'implies calculations are done only for '
|
70
|
+
'TAXYEAR. N greater than one implies output '
|
71
|
+
'is written to separate files for each year '
|
72
|
+
'beginning with TAXYEAR.'),
|
73
|
+
type=int,
|
74
|
+
default=1)
|
66
75
|
parser.add_argument('--baseline',
|
67
76
|
help=('BASELINE is name of optional JSON reform file. '
|
77
|
+
'A compound reform can be specified using 2+ '
|
78
|
+
'file names separated by plus (+) character(s). '
|
68
79
|
'No --baseline implies baseline policy is '
|
69
80
|
'current-law policy.'),
|
70
81
|
default=None)
|
71
82
|
parser.add_argument('--reform',
|
72
83
|
help=('REFORM is name of optional JSON reform file. '
|
73
|
-
'A compound reform can be specified using
|
74
|
-
'file names separated by
|
84
|
+
'A compound reform can be specified using 2+ '
|
85
|
+
'file names separated by plus (+) character(s). '
|
75
86
|
'No --reform implies reform policy is '
|
76
87
|
'current-law policy).'),
|
77
88
|
default=None)
|
@@ -167,11 +178,54 @@ def cli_tc_main():
|
|
167
178
|
_write_test_files()
|
168
179
|
inputfn = TEST_INPUT_FILENAME
|
169
180
|
taxyear = TEST_TAXYEAR
|
181
|
+
args.numyears = 1
|
170
182
|
args.dumpdb = True
|
171
183
|
else:
|
172
184
|
inputfn = args.INPUT
|
173
185
|
taxyear = args.TAXYEAR
|
174
|
-
#
|
186
|
+
# check taxyear value
|
187
|
+
if taxyear > tc.Policy.LAST_BUDGET_YEAR:
|
188
|
+
msg = f'ERROR: TAXYEAR is greater than {tc.Policy.LAST_BUDGET_YEAR}\n'
|
189
|
+
sys.stderr.write(msg)
|
190
|
+
sys.stderr.write('USAGE: tc --help\n')
|
191
|
+
return 1
|
192
|
+
# check numyears value
|
193
|
+
if args.numyears < 1:
|
194
|
+
msg = 'ERROR: --numyears parameter N is less than one\n'
|
195
|
+
sys.stderr.write(msg)
|
196
|
+
sys.stderr.write('USAGE: tc --help\n')
|
197
|
+
return 1
|
198
|
+
max_numyears = tc.Policy.LAST_BUDGET_YEAR - taxyear + 1
|
199
|
+
if args.numyears > max_numyears:
|
200
|
+
msg = f'ERROR: --numyears parameter N is greater than {max_numyears}\n'
|
201
|
+
sys.stderr.write(msg)
|
202
|
+
sys.stderr.write('USAGE: tc --help\n')
|
203
|
+
return 1
|
204
|
+
# specify if aging input data
|
205
|
+
aging_data = (
|
206
|
+
inputfn.endswith('puf.csv') or
|
207
|
+
inputfn.endswith('cps.csv') or
|
208
|
+
inputfn.endswith('tmd.csv')
|
209
|
+
)
|
210
|
+
# check args.dumpdb and args.dumpvars consistency
|
211
|
+
if not args.dumpdb and args.dumpvars:
|
212
|
+
msg = 'ERROR: DUMPVARS file specified without --dumpdb option\n'
|
213
|
+
sys.stderr.write(msg)
|
214
|
+
sys.stderr.write('USAGE: tc --help\n')
|
215
|
+
return 1
|
216
|
+
# specify dumpvars_str from args.dumpvars file
|
217
|
+
dumpvars_str = ''
|
218
|
+
if args.dumpvars:
|
219
|
+
if os.path.exists(args.dumpvars):
|
220
|
+
with open(args.dumpvars, 'r', encoding='utf-8') as dfile:
|
221
|
+
dumpvars_str = dfile.read()
|
222
|
+
else:
|
223
|
+
msg = f'ERROR: DUMPVARS file {args.dumpvars} does not exist\n'
|
224
|
+
sys.stderr.write(msg)
|
225
|
+
sys.stderr.write('USAGE: tc --help\n')
|
226
|
+
return 1
|
227
|
+
# do calculations for taxyear
|
228
|
+
# ... initialize TaxCalcIO object for taxyear
|
175
229
|
tcio = tc.TaxCalcIO(
|
176
230
|
input_data=inputfn,
|
177
231
|
tax_year=taxyear,
|
@@ -187,17 +241,13 @@ def cli_tc_main():
|
|
187
241
|
sys.stderr.write(tcio.errmsg + '\n')
|
188
242
|
sys.stderr.write('USAGE: tc --help\n')
|
189
243
|
return 1
|
190
|
-
aging = (
|
191
|
-
inputfn.endswith('puf.csv') or
|
192
|
-
inputfn.endswith('cps.csv') or
|
193
|
-
inputfn.endswith('tmd.csv')
|
194
|
-
)
|
195
244
|
tcio.init(
|
196
245
|
input_data=inputfn,
|
197
246
|
tax_year=taxyear,
|
198
247
|
baseline=args.baseline,
|
199
|
-
reform=args.reform,
|
200
|
-
|
248
|
+
reform=args.reform,
|
249
|
+
assump=args.assump,
|
250
|
+
aging_input_data=aging_data,
|
201
251
|
exact_calculations=args.exact,
|
202
252
|
)
|
203
253
|
if tcio.errmsg:
|
@@ -207,23 +257,7 @@ def cli_tc_main():
|
|
207
257
|
sys.stderr.write(tcio.errmsg + '\n')
|
208
258
|
sys.stderr.write('USAGE: tc --help\n')
|
209
259
|
return 1
|
210
|
-
#
|
211
|
-
if not args.dumpdb and args.dumpvars:
|
212
|
-
msg = 'ERROR: DUMPVARS file specified without --dumpdb option\n'
|
213
|
-
sys.stderr.write(msg)
|
214
|
-
sys.stderr.write('USAGE: tc --help\n')
|
215
|
-
return 1
|
216
|
-
# construct dumpvars set from dumpvars_str
|
217
|
-
dumpvars_str = ''
|
218
|
-
if args.dumpvars:
|
219
|
-
if os.path.exists(args.dumpvars):
|
220
|
-
with open(args.dumpvars, 'r', encoding='utf-8') as dfile:
|
221
|
-
dumpvars_str = dfile.read()
|
222
|
-
else:
|
223
|
-
msg = f'ERROR: DUMPVARS file {args.dumpvars} does not exist\n'
|
224
|
-
sys.stderr.write(msg)
|
225
|
-
sys.stderr.write('USAGE: tc --help\n')
|
226
|
-
return 1
|
260
|
+
# ... conduct tax analysis for taxyear
|
227
261
|
dumpvars_list = tcio.dump_variables(dumpvars_str)
|
228
262
|
if tcio.errmsg:
|
229
263
|
if tcio.errmsg.endswith('\n'):
|
@@ -232,7 +266,6 @@ def cli_tc_main():
|
|
232
266
|
sys.stderr.write(tcio.errmsg + '\n')
|
233
267
|
sys.stderr.write('USAGE: tc --help\n')
|
234
268
|
return 1
|
235
|
-
# conduct tax analysis
|
236
269
|
tcio.analyze(
|
237
270
|
output_params=args.params,
|
238
271
|
output_tables=args.tables,
|
@@ -244,6 +277,23 @@ def cli_tc_main():
|
|
244
277
|
if args.test:
|
245
278
|
retcode = _compare_test_output_files()
|
246
279
|
return retcode
|
280
|
+
# quit if args.numyears is equal to one
|
281
|
+
if args.numyears == 1:
|
282
|
+
if not args.silent:
|
283
|
+
print( # pragma: no cover
|
284
|
+
f'Execution time is {(time.time() - start_time):.1f} seconds'
|
285
|
+
)
|
286
|
+
return 0
|
287
|
+
# analyze years after taxyear if args.numyears is greater than one
|
288
|
+
for xyear in range(1, args.numyears):
|
289
|
+
tcio.advance_to_year(taxyear + xyear, aging_data)
|
290
|
+
tcio.analyze(
|
291
|
+
output_params=args.params,
|
292
|
+
output_tables=args.tables,
|
293
|
+
output_graphs=args.graphs,
|
294
|
+
output_dump=args.dumpdb,
|
295
|
+
dump_varlist=dumpvars_list,
|
296
|
+
)
|
247
297
|
if not args.silent:
|
248
298
|
print( # pragma: no cover
|
249
299
|
f'Execution time is {(time.time() - start_time):.1f} seconds'
|
taxcalc/data.py
CHANGED
@@ -147,8 +147,8 @@ class Data():
|
|
147
147
|
|
148
148
|
def increment_year(self):
|
149
149
|
"""
|
150
|
-
Add one to current year; and also does
|
151
|
-
|
150
|
+
Add one to current year; and also does extrapolation & reweighting
|
151
|
+
of data for the new current year if self._aging_data is True.
|
152
152
|
"""
|
153
153
|
# move to next year
|
154
154
|
self.__current_year += 1
|
taxcalc/parameters.py
CHANGED
@@ -706,11 +706,6 @@ class Parameters(pt.Parameters):
|
|
706
706
|
"""Propery docstring"""
|
707
707
|
return self.end_year - self.start_year + 1
|
708
708
|
|
709
|
-
@property
|
710
|
-
def parameter_warnings(self):
|
711
|
-
"""Propery docstring"""
|
712
|
-
return self.errors or {}
|
713
|
-
|
714
709
|
@property
|
715
710
|
def parameter_errors(self):
|
716
711
|
"""Propery docstring"""
|
taxcalc/policy_current_law.json
CHANGED
@@ -76,8 +76,8 @@
|
|
76
76
|
}
|
77
77
|
},
|
78
78
|
"parameter_indexing_CPI_offset": {
|
79
|
-
"title": "
|
80
|
-
"description": "
|
79
|
+
"title": "Decimal offset added to chained CPI-U inflation rate to get policy parameter indexing rate",
|
80
|
+
"description": "Always zero in policy_current_law.json, but non-zero values are allowed in reforms.",
|
81
81
|
"notes": "",
|
82
82
|
"section_1": "Parameter Indexing",
|
83
83
|
"section_2": "Offsets",
|
@@ -104,6 +104,10 @@
|
|
104
104
|
{
|
105
105
|
"year": 2017,
|
106
106
|
"value": 0.0
|
107
|
+
},
|
108
|
+
{
|
109
|
+
"year": 2018,
|
110
|
+
"value": 0.0
|
107
111
|
}
|
108
112
|
],
|
109
113
|
"validators": {
|
taxcalc/taxcalcio.py
CHANGED
@@ -115,23 +115,37 @@ class TaxCalcIO():
|
|
115
115
|
else:
|
116
116
|
msg = 'INPUT is neither string nor Pandas DataFrame'
|
117
117
|
self.errmsg += f'ERROR: {msg}\n'
|
118
|
-
# check name and existence of BASELINE file
|
118
|
+
# check name(s) and existence of BASELINE file(s)
|
119
119
|
bas = '-x'
|
120
120
|
if baseline is None:
|
121
|
+
self.specified_baseline = False
|
121
122
|
bas = '-#'
|
122
123
|
elif isinstance(baseline, str):
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
124
|
+
self.specified_baseline = True
|
125
|
+
# split any compound baseline into list of simple reforms
|
126
|
+
basnames = []
|
127
|
+
baselines = baseline.split('+')
|
128
|
+
for bas in baselines:
|
129
|
+
# remove any leading directory path from bas filename
|
130
|
+
fname = os.path.basename(bas)
|
131
|
+
# check if fname ends with ".json"
|
132
|
+
if not fname.endswith('.json'):
|
133
|
+
msg = f'{fname} does not end in .json'
|
134
|
+
self.errmsg += f'ERROR: BASELINE file name {msg}\n'
|
135
|
+
# check existence of BASELINE file
|
136
|
+
if not os.path.isfile(bas):
|
137
|
+
msg = f'{bas} could not be found'
|
138
|
+
self.errmsg += f'ERROR: BASELINE file {msg}\n'
|
139
|
+
# add fname to list of basnames used in output file names
|
140
|
+
basnames.append(fname)
|
141
|
+
# create (possibly compound) baseline name for output file names
|
142
|
+
bas = '-'
|
143
|
+
num_basnames = 0
|
144
|
+
for basname in basnames:
|
145
|
+
num_basnames += 1
|
146
|
+
if num_basnames > 1:
|
147
|
+
bas += '+'
|
148
|
+
bas += f'{basname[:-5]}'
|
135
149
|
else:
|
136
150
|
msg = 'TaxCalcIO.ctor: baseline is neither None nor str'
|
137
151
|
self.errmsg += f'ERROR: {msg}\n'
|
@@ -191,6 +205,15 @@ class TaxCalcIO():
|
|
191
205
|
self.errmsg += f'ERROR: {msg}\n'
|
192
206
|
# create OUTPUT file name and delete any existing output files
|
193
207
|
self.output_filename = f'{inp}{bas}{ref}{asm}.xxx'
|
208
|
+
self.delete_output_files()
|
209
|
+
# initialize variables whose values are set in init method
|
210
|
+
self.calc_ref = None
|
211
|
+
self.calc_bas = None
|
212
|
+
|
213
|
+
def delete_output_files(self):
|
214
|
+
"""
|
215
|
+
Delete all output files derived from self.output_filename.
|
216
|
+
"""
|
194
217
|
extensions = [
|
195
218
|
'-params.bas',
|
196
219
|
'-params.ref',
|
@@ -202,9 +225,6 @@ class TaxCalcIO():
|
|
202
225
|
]
|
203
226
|
for ext in extensions:
|
204
227
|
delete_file(self.output_filename.replace('.xxx', ext))
|
205
|
-
# initialize variables whose values are set in init method
|
206
|
-
self.calc_ref = None
|
207
|
-
self.calc_bas = None
|
208
228
|
|
209
229
|
def init(self, input_data, tax_year, baseline, reform, assump,
|
210
230
|
aging_input_data, exact_calculations):
|
@@ -258,8 +278,12 @@ class TaxCalcIO():
|
|
258
278
|
return
|
259
279
|
# get assumption sub-dictionaries
|
260
280
|
assumpdict = Calculator.read_json_param_objects(None, assump)
|
261
|
-
# get policy parameter
|
262
|
-
|
281
|
+
# get policy parameter dictionaries from --baseline file(s)
|
282
|
+
poldicts_bas = []
|
283
|
+
if self.specified_baseline:
|
284
|
+
for bas in baseline.split('+'):
|
285
|
+
pdict = Calculator.read_json_param_objects(bas, None)
|
286
|
+
poldicts_bas.append(pdict['policy'])
|
263
287
|
# get policy parameter dictionaries from --reform file(s)
|
264
288
|
poldicts_ref = []
|
265
289
|
if self.specified_reform:
|
@@ -288,20 +312,29 @@ class TaxCalcIO():
|
|
288
312
|
self.gf_reform = copy.deepcopy(gfactors_ref)
|
289
313
|
# create Policy objects:
|
290
314
|
# ... the baseline Policy object
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
315
|
+
if self.specified_baseline:
|
316
|
+
pol_bas = Policy(
|
317
|
+
gfactors=gfactors_bas,
|
318
|
+
last_budget_year=last_b_year,
|
319
|
+
)
|
320
|
+
for poldict in poldicts_bas:
|
321
|
+
try:
|
322
|
+
pol_bas.implement_reform(
|
323
|
+
poldict,
|
324
|
+
print_warnings=True,
|
325
|
+
raise_errors=False,
|
326
|
+
)
|
327
|
+
if self.errmsg:
|
328
|
+
self.errmsg += "\n"
|
329
|
+
for _, errors in pol_bas.parameter_errors.items():
|
330
|
+
self.errmsg += "\n".join(errors)
|
331
|
+
except paramtools.ValidationError as valerr_msg:
|
332
|
+
self.errmsg += str(valerr_msg)
|
333
|
+
else:
|
334
|
+
pol_bas = Policy(
|
335
|
+
gfactors=gfactors_bas,
|
336
|
+
last_budget_year=last_b_year,
|
300
337
|
)
|
301
|
-
for _, errors in pol_bas.parameter_errors.items():
|
302
|
-
self.errmsg += "\n".join(errors)
|
303
|
-
except paramtools.ValidationError as valerr_msg:
|
304
|
-
self.errmsg += str(valerr_msg)
|
305
338
|
# ... the reform Policy object
|
306
339
|
if self.specified_reform:
|
307
340
|
pol_ref = Policy(
|
@@ -419,6 +452,22 @@ class TaxCalcIO():
|
|
419
452
|
dirpath = os.path.abspath(os.path.dirname(__file__))
|
420
453
|
return os.path.join(dirpath, self.output_filename)
|
421
454
|
|
455
|
+
def advance_to_year(self, year, aging_data):
|
456
|
+
"""
|
457
|
+
Update self.output_filename and advance Calculator objects to year.
|
458
|
+
"""
|
459
|
+
# update self.output_filename and delete output files
|
460
|
+
parts = self.output_filename.split('-')
|
461
|
+
parts[1] = str(year)[2:]
|
462
|
+
self.output_filename = '-'.join(parts)
|
463
|
+
self.delete_output_files()
|
464
|
+
# advance baseline and reform Calculator objects to specified year
|
465
|
+
self.calc_bas.advance_to_year(year)
|
466
|
+
self.calc_ref.advance_to_year(year)
|
467
|
+
idata = 'Advance input data and ' if aging_data else 'Advance'
|
468
|
+
if not self.silent:
|
469
|
+
print(f'{idata} policy to {year}')
|
470
|
+
|
422
471
|
def analyze(
|
423
472
|
self,
|
424
473
|
output_params=False,
|
@@ -458,47 +507,36 @@ class TaxCalcIO():
|
|
458
507
|
"""
|
459
508
|
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
460
509
|
# pylint: disable=too-many-branches,too-many-locals
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
510
|
+
doing_calcs = output_tables or output_graphs or output_dump
|
511
|
+
# optionally write --params output to text files
|
512
|
+
if output_params:
|
513
|
+
self.write_policy_params_files()
|
514
|
+
if not doing_calcs:
|
515
|
+
return
|
516
|
+
# do output calculations
|
517
|
+
self.calc_bas.calc_all()
|
469
518
|
self.calc_ref.calc_all()
|
470
519
|
if output_dump:
|
471
520
|
assert isinstance(dump_varlist, list)
|
472
521
|
assert len(dump_varlist) > 0
|
473
|
-
# might need marginal tax rates
|
522
|
+
# might need marginal tax rates for dumpdb
|
474
523
|
(mtr_ptax_ref, mtr_itax_ref,
|
475
524
|
_) = self.calc_ref.mtr(wrt_full_compensation=False,
|
476
525
|
calc_all_already_called=True)
|
477
|
-
self.calc_bas.calc_all()
|
478
|
-
calc_base_calculated = True
|
479
526
|
(mtr_ptax_bas, mtr_itax_bas,
|
480
527
|
_) = self.calc_bas.mtr(wrt_full_compensation=False,
|
481
528
|
calc_all_already_called=True)
|
482
529
|
else:
|
483
|
-
#
|
530
|
+
# do not need marginal tax rates for dumpdb
|
484
531
|
mtr_ptax_ref = None
|
485
532
|
mtr_itax_ref = None
|
486
533
|
mtr_ptax_bas = None
|
487
534
|
mtr_itax_bas = None
|
488
|
-
# optionally write --params output to text files
|
489
|
-
if output_params:
|
490
|
-
self.write_policy_params_files()
|
491
535
|
# optionally write --tables output to text file
|
492
536
|
if output_tables:
|
493
|
-
if not calc_base_calculated:
|
494
|
-
self.calc_bas.calc_all()
|
495
|
-
calc_base_calculated = True
|
496
537
|
self.write_tables_file()
|
497
538
|
# optionally write --graphs output to HTML files
|
498
539
|
if output_graphs:
|
499
|
-
if not calc_base_calculated:
|
500
|
-
self.calc_bas.calc_all()
|
501
|
-
calc_base_calculated = True
|
502
540
|
self.write_graph_files()
|
503
541
|
# optionally write --dumpdb output to SQLite database file
|
504
542
|
if output_dump:
|
@@ -731,7 +769,7 @@ class TaxCalcIO():
|
|
731
769
|
|
732
770
|
def dump_variables(self, dumpvars_str):
|
733
771
|
"""
|
734
|
-
Return
|
772
|
+
Return list of variable names extracted from dumpvars_str, plus
|
735
773
|
minimal baseline/reform variables even if not in dumpvars_str.
|
736
774
|
Also, builds self.errmsg if any specified variables are not valid.
|
737
775
|
"""
|
taxcalc/tests/test_calculator.py
CHANGED
@@ -69,7 +69,7 @@ def test_make_calculator_with_policy_reform(cps_subsample):
|
|
69
69
|
pol.implement_reform(reform)
|
70
70
|
# create a Calculator object using this policy reform
|
71
71
|
calc = Calculator(policy=pol, records=rec)
|
72
|
-
assert calc.
|
72
|
+
assert calc.reform_errors == {}
|
73
73
|
# check that Policy object embedded in Calculator object is correct
|
74
74
|
assert calc.current_year == year
|
75
75
|
assert calc.policy_param('II_em') == 4000
|
taxcalc/tests/test_reforms.py
CHANGED
@@ -28,7 +28,7 @@ def test_2017_law_reform(tests_path):
|
|
28
28
|
with open(reform_file, 'r', encoding='utf-8') as rfile:
|
29
29
|
rtext = rfile.read()
|
30
30
|
pol.implement_reform(Policy.read_json_reform(rtext))
|
31
|
-
assert not pol.
|
31
|
+
assert not pol.parameter_errors
|
32
32
|
pol.set_year(2018)
|
33
33
|
pre_mdata = dict(pol.items())
|
34
34
|
# check some policy parameter values against expected values under 2017 law
|
@@ -102,14 +102,14 @@ def test_round_trip_reforms(fyear, tests_path):
|
|
102
102
|
with open(reform_file, 'r', encoding='utf-8') as rfile:
|
103
103
|
rtext = rfile.read()
|
104
104
|
rtr_pol.implement_reform(Policy.read_json_reform(rtext))
|
105
|
-
assert not rtr_pol.
|
105
|
+
assert not rtr_pol.parameter_errors
|
106
106
|
assert not rtr_pol.errors
|
107
107
|
# Layer on TCJA
|
108
108
|
reform_file = os.path.join(tests_path, '..', 'reforms', 'TCJA.json')
|
109
109
|
with open(reform_file, 'r', encoding='utf-8') as rfile:
|
110
110
|
rtext = rfile.read()
|
111
111
|
rtr_pol.implement_reform(Policy.read_json_reform(rtext))
|
112
|
-
assert not rtr_pol.
|
112
|
+
assert not rtr_pol.parameter_errors
|
113
113
|
assert not rtr_pol.errors
|
114
114
|
# Layer on the CARES Act
|
115
115
|
reform_file = os.path.join(tests_path, '..', 'reforms', 'CARES.json')
|
@@ -123,21 +123,21 @@ def test_round_trip_reforms(fyear, tests_path):
|
|
123
123
|
with open(reform_file, 'r', encoding='utf-8') as rfile:
|
124
124
|
rtext = rfile.read()
|
125
125
|
rtr_pol.implement_reform(Policy.read_json_reform(rtext))
|
126
|
-
assert not rtr_pol.
|
126
|
+
assert not rtr_pol.parameter_errors
|
127
127
|
assert not rtr_pol.errors
|
128
128
|
# Layer on ARPA
|
129
129
|
reform_file = os.path.join(tests_path, '..', 'reforms', 'ARPA.json')
|
130
130
|
with open(reform_file, 'r', encoding='utf-8') as rfile:
|
131
131
|
rtext = rfile.read()
|
132
132
|
rtr_pol.implement_reform(Policy.read_json_reform(rtext))
|
133
|
-
assert not rtr_pol.
|
133
|
+
assert not rtr_pol.parameter_errors
|
134
134
|
assert not rtr_pol.errors
|
135
135
|
# Layer on rounding from IRS through Policy.LAST_KNOWN_YEAR
|
136
136
|
reform_file = os.path.join(tests_path, '..', 'reforms', 'rounding.json')
|
137
137
|
with open(reform_file, 'r', encoding='utf-8') as rfile:
|
138
138
|
rtext = rfile.read()
|
139
139
|
rtr_pol.implement_reform(Policy.read_json_reform(rtext))
|
140
|
-
assert not rtr_pol.
|
140
|
+
assert not rtr_pol.parameter_errors
|
141
141
|
assert not rtr_pol.errors
|
142
142
|
rtr_pol.set_year(fyear)
|
143
143
|
rtr_mdata = dict(rtr_pol.items())
|
@@ -371,7 +371,7 @@ def test_ext_reform(tests_path):
|
|
371
371
|
with open(reform_file, 'r', encoding='utf-8') as rfile:
|
372
372
|
rtext = rfile.read()
|
373
373
|
ext.implement_reform(Policy.read_json_reform(rtext))
|
374
|
-
assert not ext.
|
374
|
+
assert not ext.parameter_errors
|
375
375
|
ext.set_year(2026)
|
376
376
|
assert ext.II_em < end.II_em
|
377
377
|
# test tax output generated by ext.json reform file using public CPS data
|
taxcalc/tests/test_taxcalcio.py
CHANGED
@@ -357,6 +357,10 @@ def test_ctor_init_with_cps_files():
|
|
357
357
|
exact_calculations=False)
|
358
358
|
assert not tcio.errmsg
|
359
359
|
assert tcio.tax_year() == txyr
|
360
|
+
# test advance_to_year method
|
361
|
+
tcio.silent = False
|
362
|
+
tcio.advance_to_year(txyr + 1, True)
|
363
|
+
assert tcio.tax_year() == txyr + 1
|
360
364
|
# specify invalid tax_year for cps.csv input data
|
361
365
|
txyr = 2013
|
362
366
|
tcio = TaxCalcIO('cps.csv', txyr, None, None, None)
|
@@ -484,14 +488,14 @@ def test_write_policy_param_files(reformfile1):
|
|
484
488
|
tcio = TaxCalcIO(
|
485
489
|
input_data=pd.read_csv(StringIO(RAWINPUT)),
|
486
490
|
tax_year=taxyear,
|
487
|
-
baseline=
|
491
|
+
baseline=compound_reform,
|
488
492
|
reform=compound_reform,
|
489
493
|
assump=None,
|
490
494
|
)
|
491
495
|
assert not tcio.errmsg
|
492
496
|
tcio.init(input_data=pd.read_csv(StringIO(RAWINPUT)),
|
493
497
|
tax_year=taxyear,
|
494
|
-
baseline=
|
498
|
+
baseline=compound_reform,
|
495
499
|
reform=compound_reform,
|
496
500
|
assump=None,
|
497
501
|
aging_input_data=False,
|
@@ -539,19 +543,7 @@ def test_no_tables_or_graphs(reformfile1):
|
|
539
543
|
output_tables=True,
|
540
544
|
output_graphs=True)
|
541
545
|
# delete tables and graph files
|
542
|
-
|
543
|
-
extensions = [
|
544
|
-
'-params.bas',
|
545
|
-
'-params.ref',
|
546
|
-
'-tables.text',
|
547
|
-
'-atr.html',
|
548
|
-
'-mtr.html',
|
549
|
-
'-pch.html',
|
550
|
-
]
|
551
|
-
for ext in extensions:
|
552
|
-
fname = output_filename.replace('.xxx', ext)
|
553
|
-
if os.path.isfile(fname):
|
554
|
-
os.remove(fname)
|
546
|
+
tcio.delete_output_files()
|
555
547
|
|
556
548
|
|
557
549
|
def test_tables(reformfile1):
|
@@ -584,11 +576,7 @@ def test_tables(reformfile1):
|
|
584
576
|
assert not tcio.errmsg
|
585
577
|
# create TaxCalcIO tables file
|
586
578
|
tcio.analyze(output_tables=True)
|
587
|
-
|
588
|
-
output_filename = tcio.output_filepath()
|
589
|
-
fname = output_filename.replace('.xxx', '-tables.text')
|
590
|
-
if os.path.isfile(fname):
|
591
|
-
os.remove(fname)
|
579
|
+
tcio.delete_output_files()
|
592
580
|
|
593
581
|
|
594
582
|
def test_graphs(reformfile1):
|
@@ -622,16 +610,7 @@ def test_graphs(reformfile1):
|
|
622
610
|
assert not tcio.errmsg
|
623
611
|
tcio.analyze(output_graphs=True)
|
624
612
|
# delete graph files
|
625
|
-
|
626
|
-
fname = output_filename.replace('.xxx', '-atr.html')
|
627
|
-
if os.path.isfile(fname):
|
628
|
-
os.remove(fname)
|
629
|
-
fname = output_filename.replace('.xxx', '-mtr.html')
|
630
|
-
if os.path.isfile(fname):
|
631
|
-
os.remove(fname)
|
632
|
-
fname = output_filename.replace('.xxx', '-pch.html')
|
633
|
-
if os.path.isfile(fname):
|
634
|
-
os.remove(fname)
|
613
|
+
tcio.delete_output_files()
|
635
614
|
|
636
615
|
|
637
616
|
@pytest.fixture(scope='session', name='warnreformfile')
|
@@ -1,32 +1,32 @@
|
|
1
|
-
taxcalc/__init__.py,sha256=
|
1
|
+
taxcalc/__init__.py,sha256=_SNXt6U2NMWDx1hqcUw-N6_SVHp4pydp4-U1VFEPldY,536
|
2
2
|
taxcalc/calcfunctions.py,sha256=G62sQeW-YHJ2gvqOfidRKPBpufSHzXYIdI2PGcApOuU,148423
|
3
|
-
taxcalc/calculator.py,sha256=
|
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
|
6
6
|
taxcalc/consumption.py,sha256=pkXhFGpFqu7hW62KaTctfRSzR-pXzMB1ai8XCQRAgXk,3480
|
7
7
|
taxcalc/cps.csv.gz,sha256=SS6tSduU_Eu0EJwzpslnmqMsQQQucVMzzITfH-SeV40,9851074
|
8
8
|
taxcalc/cps_weights.csv.gz,sha256=-k31Swqss0WEGA3Zo8AoReLR_C7BRUk4PDmfh-oVVyo,13657706
|
9
|
-
taxcalc/data.py,sha256=
|
9
|
+
taxcalc/data.py,sha256=QRyLsq250OsxUIjsuCFtREJsVyEOGaivwcON3teivMI,11698
|
10
10
|
taxcalc/decorators.py,sha256=EwyVH4fSDf8x_BHzccf4-DRopo6KMVidYSYZFy_dJy0,11307
|
11
11
|
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=
|
15
|
+
taxcalc/parameters.py,sha256=pxW53fOJkW7yM7XxN04RDNs-f7CwKOjE4vMmMvPtZ8E,33121
|
16
16
|
taxcalc/policy.py,sha256=4bY3beSYhLKk_X4CTgG7LGnVnILM0D4Invt7uCp8dlA,6725
|
17
|
-
taxcalc/policy_current_law.json,sha256=
|
17
|
+
taxcalc/policy_current_law.json,sha256=enemNPLg0ZlwNQVVK51XJru_YzDzPnV7ClNhdJHlhJQ,689915
|
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=
|
22
|
+
taxcalc/taxcalcio.py,sha256=1xZ17wZ0yqZeDDa5glEQpCG6xvXJ4wGxbUQPkmTLTD0,34752
|
23
23
|
taxcalc/utils.py,sha256=noHnQ-tw0AXhEH-OgdTUiPedH8luVOJ5NdfpKI3_obw,62401
|
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=StZo-46v1c3ozP-64wQWz0uyHOEVqZPAzgTr1JuoFjU,16614
|
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
|
@@ -86,7 +86,7 @@ taxcalc/tests/reforms_expect.csv,sha256=6m0bSH8S6ReMYdHoQC9iWYuJAof5sZ0OONVBi7zX
|
|
86
86
|
taxcalc/tests/test_4package.py,sha256=I9i5rWFsg-VCtTLmUWIi9dnusieTZeodrgH8ba_Fbng,3681
|
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
|
-
taxcalc/tests/test_calculator.py,sha256=
|
89
|
+
taxcalc/tests/test_calculator.py,sha256=lcnBli5giNFxqgCLW-MF4J_wsV3gSFqCjzJdCJkihek,36085
|
90
90
|
taxcalc/tests/test_compare.py,sha256=WglH4ZJOEQnav_mAmnGjpb7dooXcQsB1m04hgQeoBUQ,10873
|
91
91
|
taxcalc/tests/test_compatible_data.py,sha256=XpfnE96HDvlgJM_8KEasgufxeiePTFfNMBBVlfzHP9Y,13477
|
92
92
|
taxcalc/tests/test_consumption.py,sha256=c6zi9GqNK54cgfzxiWmY10UxOMJZ9vd9fOTwUKU1zMk,6318
|
@@ -100,9 +100,9 @@ taxcalc/tests/test_policy.py,sha256=hJrFqqptMoUWk3abIJ2sdADQtCqvGaUeW5as1aNwhR8,
|
|
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=djVxMOE2RytmDDYvzS55AnThRRBcVc_calPbfHuvQ-k,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=PV7hCntwp_1LHQYlft7WelbzKSoi5aWzUZqhJAcC5AE,23135
|
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.1.dist-info/licenses/LICENSE,sha256=m5epLdB-_NXiY7NsEDgcHP4jDtJ4vOlRf5S3Jb-jraY,1299
|
135
|
+
taxcalc-4.6.1.dist-info/METADATA,sha256=wvnDftJBQ7SKgJAF-hCYRKf_RJX3RNSPj2LLe-nL59s,3509
|
136
|
+
taxcalc-4.6.1.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
137
|
+
taxcalc-4.6.1.dist-info/entry_points.txt,sha256=a3ZE1piRv683p27fOLdWZvVJXESkoslTOp5iXV7uVco,50
|
138
|
+
taxcalc-4.6.1.dist-info/top_level.txt,sha256=Wh8wTDHkA_cm4dn8IoUCviDyGgVQqwEQKPJnl8z6d4c,8
|
139
|
+
taxcalc-4.6.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|