taxcalc 4.5.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/calcfunctions.py +2 -6
- taxcalc/calculator.py +18 -18
- taxcalc/cli/tc.py +251 -118
- taxcalc/data.py +2 -2
- taxcalc/parameters.py +0 -5
- taxcalc/policy.py +3 -12
- taxcalc/policy_current_law.json +7 -3
- taxcalc/reforms/ext.json +5 -2
- taxcalc/taxcalcio.py +350 -325
- taxcalc/tests/test_4package.py +1 -0
- taxcalc/tests/test_calculator.py +3 -3
- taxcalc/tests/test_reforms.py +8 -8
- taxcalc/tests/test_taxcalcio.py +78 -120
- taxcalc/utils.py +4 -10
- {taxcalc-4.5.0.dist-info → taxcalc-4.6.1.dist-info}/METADATA +3 -2
- {taxcalc-4.5.0.dist-info → taxcalc-4.6.1.dist-info}/RECORD +21 -21
- {taxcalc-4.5.0.dist-info → taxcalc-4.6.1.dist-info}/WHEEL +1 -1
- {taxcalc-4.5.0.dist-info → taxcalc-4.6.1.dist-info}/entry_points.txt +0 -0
- {taxcalc-4.5.0.dist-info → taxcalc-4.6.1.dist-info/licenses}/LICENSE +0 -0
- {taxcalc-4.5.0.dist-info → taxcalc-4.6.1.dist-info}/top_level.txt +0 -0
taxcalc/__init__.py
CHANGED
taxcalc/calcfunctions.py
CHANGED
@@ -3,11 +3,7 @@ Tax-Calculator functions that calculate payroll and individual income taxes.
|
|
3
3
|
|
4
4
|
These functions are imported into the Calculator class.
|
5
5
|
|
6
|
-
Note: the parameter_indexing_CPI_offset
|
7
|
-
policy parameter that does not appear here; it is used in the policy.py
|
8
|
-
file to possibly adjust the price inflation rate used to index policy
|
9
|
-
parameters (as would be done in a reform that introduces chained-CPI
|
10
|
-
indexing).
|
6
|
+
Note: the parameter_indexing_CPI_offset parameter is no longer used.
|
11
7
|
"""
|
12
8
|
# CODING-STYLE CHECKS:
|
13
9
|
# pycodestyle calcfunctions.py
|
@@ -2059,7 +2055,7 @@ def AMT(e07300, dwks13, standard, f6251, c00100, c18300, taxbc,
|
|
2059
2055
|
e62900: float
|
2060
2056
|
Alternative Minimum Tax foreign tax credit from Form 6251
|
2061
2057
|
e00700: float
|
2062
|
-
|
2058
|
+
Taxable refunds of state and local income taxes
|
2063
2059
|
dwks10: float
|
2064
2060
|
Sum of dwks6 + dwks9
|
2065
2061
|
age_head: int
|
taxcalc/calculator.py
CHANGED
@@ -113,29 +113,29 @@ class Calculator():
|
|
113
113
|
raise ValueError('consumption must be None or Consumption object')
|
114
114
|
if self.__consumption.current_year < self.__policy.current_year:
|
115
115
|
self.__consumption.set_year(self.__policy.current_year)
|
116
|
-
if verbose:
|
117
|
-
if self.__records.IGNORED_VARS:
|
118
|
-
print('Your data include the following unused ' +
|
119
|
-
'variables that will be ignored:')
|
120
|
-
for var in self.__records.IGNORED_VARS:
|
121
|
-
print(' ' +
|
122
|
-
var)
|
123
116
|
current_year_is_data_year = (
|
124
117
|
self.__records.current_year == self.__records.data_year)
|
125
118
|
if sync_years and current_year_is_data_year:
|
126
|
-
if verbose:
|
127
|
-
print('You loaded data for ' +
|
128
|
-
str(self.__records.data_year) + '.')
|
129
119
|
while self.__records.current_year < self.__policy.current_year:
|
130
120
|
self.__records.increment_year()
|
131
121
|
if verbose:
|
132
|
-
print(
|
133
|
-
|
134
|
-
|
122
|
+
print(
|
123
|
+
f'Read input data for {self.__records.data_year}; '
|
124
|
+
'input data were extrapolated to '
|
125
|
+
f'{self.__records.current_year}'
|
126
|
+
)
|
135
127
|
else:
|
136
128
|
if verbose:
|
137
|
-
print(
|
138
|
-
|
129
|
+
print( # pragma: no cover
|
130
|
+
'Read input data that were not extrapolated in any way'
|
131
|
+
)
|
132
|
+
if verbose and self.__records.IGNORED_VARS: # pragma: no cover
|
133
|
+
print(
|
134
|
+
'Input data include the following unused '
|
135
|
+
'variables that will be ignored:'
|
136
|
+
)
|
137
|
+
for var in self.__records.IGNORED_VARS:
|
138
|
+
print(f' {var}')
|
139
139
|
assert self.__policy.current_year == self.__records.current_year
|
140
140
|
assert self.__policy.current_year == self.__consumption.current_year
|
141
141
|
self.__stored_records = None
|
@@ -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
|
@@ -9,6 +9,7 @@ which can be accessed as 'tc' from an installed taxcalc conda package.
|
|
9
9
|
import os
|
10
10
|
import sys
|
11
11
|
import time
|
12
|
+
import sqlite3
|
12
13
|
import argparse
|
13
14
|
import difflib
|
14
15
|
import taxcalc as tc
|
@@ -25,26 +26,31 @@ def cli_tc_main():
|
|
25
26
|
# pylint: disable=too-many-statements,too-many-branches
|
26
27
|
# pylint: disable=too-many-return-statements,too-many-locals
|
27
28
|
|
29
|
+
start_time = time.time()
|
30
|
+
|
28
31
|
# parse command-line arguments:
|
29
|
-
usage_str = 'tc INPUT TAXYEAR {}{}{}{}
|
30
|
-
'[--help]\n',
|
31
|
-
(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
usage_str = 'tc INPUT TAXYEAR {}{}{}{}'.format(
|
33
|
+
'[--help] [--numyears N]\n',
|
34
|
+
(
|
35
|
+
' '
|
36
|
+
'[--baseline BASELINE] [--reform REFORM] '
|
37
|
+
'[--assump ASSUMP] [--exact]\n'
|
38
|
+
),
|
39
|
+
(
|
40
|
+
' '
|
41
|
+
'[--params] [--tables] [--graphs] '
|
42
|
+
'[--dumpdb] [--dumpvars DUMPVARS]\n'
|
43
|
+
),
|
44
|
+
(
|
45
|
+
' '
|
46
|
+
'[--silent] [--test] [--version] [--usage]'
|
47
|
+
)
|
48
|
+
)
|
39
49
|
parser = argparse.ArgumentParser(
|
40
50
|
prog='',
|
41
51
|
usage=usage_str,
|
42
|
-
description=('Writes
|
43
|
-
'
|
44
|
-
'file, with the OUTPUT computed from the INPUT for the '
|
45
|
-
'TAXYEAR using Tax-Calculator. The OUTPUT file is a '
|
46
|
-
'CSV-formatted file that contains tax information for '
|
47
|
-
'each INPUT filing unit under the reform(s).'))
|
52
|
+
description=('Writes several output files computed from the INPUT '
|
53
|
+
'for the TAXYEAR using Tax-Calculator.'))
|
48
54
|
parser.add_argument('INPUT', nargs='?',
|
49
55
|
help=('INPUT is name of CSV-formatted file that '
|
50
56
|
'contains for each filing unit variables used '
|
@@ -57,16 +63,27 @@ def cli_tc_main():
|
|
57
63
|
'are computed.'),
|
58
64
|
type=int,
|
59
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)
|
60
75
|
parser.add_argument('--baseline',
|
61
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). '
|
62
79
|
'No --baseline implies baseline policy is '
|
63
80
|
'current-law policy.'),
|
64
81
|
default=None)
|
65
82
|
parser.add_argument('--reform',
|
66
83
|
help=('REFORM is name of optional JSON reform file. '
|
67
|
-
'A compound reform can be specified using
|
68
|
-
'file names separated by
|
69
|
-
'No --reform implies
|
84
|
+
'A compound reform can be specified using 2+ '
|
85
|
+
'file names separated by plus (+) character(s). '
|
86
|
+
'No --reform implies reform policy is '
|
70
87
|
'current-law policy).'),
|
71
88
|
default=None)
|
72
89
|
parser.add_argument('--assump',
|
@@ -80,6 +97,12 @@ def cli_tc_main():
|
|
80
97
|
'complicate marginal-tax-rate calculations.'),
|
81
98
|
default=False,
|
82
99
|
action="store_true")
|
100
|
+
parser.add_argument('--params',
|
101
|
+
help=('optional flag that causes policy parameter '
|
102
|
+
'values for baseline and reform to be written '
|
103
|
+
'to separate text files.'),
|
104
|
+
default=False,
|
105
|
+
action="store_true")
|
83
106
|
parser.add_argument('--tables',
|
84
107
|
help=('optional flag that causes distributional '
|
85
108
|
'tables to be written to a text file.'),
|
@@ -90,47 +113,33 @@ def cli_tc_main():
|
|
90
113
|
'to HTML files for viewing in browser.'),
|
91
114
|
default=False,
|
92
115
|
action="store_true")
|
93
|
-
parser.add_argument('--
|
94
|
-
help=('optional flag that causes
|
95
|
-
'
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
'all INPUT variables (extrapolated to TAXYEAR) '
|
101
|
-
'and all calculated tax variables for the '
|
102
|
-
'reform, where all the variables are named '
|
103
|
-
'using their internal Tax-Calculator names. '
|
104
|
-
'No --dump option implies OUTPUT contains '
|
105
|
-
'minimal tax output for the reform. NOTE: '
|
106
|
-
'use the --dvars option to point to a file '
|
107
|
-
'containing a custom set of dump variables.'
|
108
|
-
''),
|
116
|
+
parser.add_argument('--dumpdb',
|
117
|
+
help=('optional flag that causes TAXYEAR variable '
|
118
|
+
'values for each tax-unit under both '
|
119
|
+
'baseline and reform policies to be written '
|
120
|
+
'to a SQLite database (where the variables '
|
121
|
+
'included in the database are controlled by '
|
122
|
+
'the --dumpvars option).'),
|
109
123
|
default=False,
|
110
124
|
action="store_true")
|
111
|
-
parser.add_argument('--
|
112
|
-
help=('
|
125
|
+
parser.add_argument('--dumpvars',
|
126
|
+
help=('DUMPVARS is name of optional file containing a '
|
113
127
|
'space-delimited list of variables to include '
|
114
|
-
'in
|
115
|
-
'implies a
|
128
|
+
'in the dump database. No --dumpvars '
|
129
|
+
'implies a minimal set of variables. Valid '
|
130
|
+
'variable names include all variables in the '
|
131
|
+
'records_variables.json file plus mtr_itax and '
|
132
|
+
'mtr_ptax (MTRs wrt taxpayer earnings).'),
|
116
133
|
default=None)
|
117
|
-
parser.add_argument('--
|
118
|
-
help=('optional flag that
|
119
|
-
'
|
120
|
-
'containing same output variables as '
|
121
|
-
'produced by --dump option.'),
|
134
|
+
parser.add_argument('--silent',
|
135
|
+
help=('optional flag that suppresses messages about '
|
136
|
+
'input and output actions.'),
|
122
137
|
default=False,
|
123
138
|
action="store_true")
|
124
|
-
parser.add_argument('--outdir',
|
125
|
-
help=('OUTDIR is name of optional output directory '
|
126
|
-
'in which all output files are written. '
|
127
|
-
'No --outdir implies output files are written '
|
128
|
-
'in the current directory.'),
|
129
|
-
default=None)
|
130
139
|
parser.add_argument('--test',
|
131
140
|
help=('optional flag that conducts installation '
|
132
141
|
'test, writes test result to stdout, '
|
133
|
-
'and quits.'),
|
142
|
+
'and quits leaving the test-related files.'),
|
134
143
|
default=False,
|
135
144
|
action="store_true")
|
136
145
|
parser.add_argument('--version',
|
@@ -138,6 +147,11 @@ def cli_tc_main():
|
|
138
147
|
'release version to stdout and quits.'),
|
139
148
|
default=False,
|
140
149
|
action="store_true")
|
150
|
+
parser.add_argument('--usage',
|
151
|
+
help=('optional flag that writes short usage '
|
152
|
+
'reminder to stdout and quits.'),
|
153
|
+
default=False,
|
154
|
+
action="store_true")
|
141
155
|
args = parser.parse_args()
|
142
156
|
# check Python version
|
143
157
|
pyv = sys.version_info
|
@@ -155,109 +169,228 @@ def cli_tc_main():
|
|
155
169
|
pyver = f'Python 3.{pyv[1]}'
|
156
170
|
sys.stdout.write(f'Tax-Calculator {tc.__version__} on {pyver}\n')
|
157
171
|
return 0
|
172
|
+
# show short usage reminder and quit if --usage option is specified
|
173
|
+
if args.usage:
|
174
|
+
sys.stdout.write(f'USAGE: {usage_str}\n')
|
175
|
+
return 0
|
158
176
|
# write test input and expected output files if --test option is specified
|
159
177
|
if args.test:
|
160
|
-
|
178
|
+
_write_test_files()
|
161
179
|
inputfn = TEST_INPUT_FILENAME
|
162
180
|
taxyear = TEST_TAXYEAR
|
181
|
+
args.numyears = 1
|
182
|
+
args.dumpdb = True
|
163
183
|
else:
|
164
184
|
inputfn = args.INPUT
|
165
185
|
taxyear = args.TAXYEAR
|
166
|
-
#
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
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)
|
173
196
|
sys.stderr.write('USAGE: tc --help\n')
|
174
197
|
return 1
|
175
|
-
|
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 = (
|
176
206
|
inputfn.endswith('puf.csv') or
|
177
207
|
inputfn.endswith('cps.csv') or
|
178
208
|
inputfn.endswith('tmd.csv')
|
179
209
|
)
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
reform=args.reform, assump=args.assump,
|
185
|
-
aging_input_data=aging,
|
186
|
-
exact_calculations=args.exact)
|
187
|
-
if args.timings:
|
188
|
-
xtime = time.time() - stime
|
189
|
-
sys.stdout.write(f'TIMINGS: init time = {xtime:.2f} secs\n')
|
190
|
-
if tcio.errmsg:
|
191
|
-
sys.stderr.write(tcio.errmsg)
|
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)
|
192
214
|
sys.stderr.write('USAGE: tc --help\n')
|
193
215
|
return 1
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
if tcio.errmsg:
|
201
|
-
sys.stderr.write(tcio.errmsg)
|
202
|
-
sys.stderr.write('USAGE: tc --help\n')
|
203
|
-
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()
|
204
222
|
else:
|
205
|
-
msg = 'ERROR:
|
206
|
-
sys.stderr.write(msg
|
223
|
+
msg = f'ERROR: DUMPVARS file {args.dumpvars} does not exist\n'
|
224
|
+
sys.stderr.write(msg)
|
207
225
|
sys.stderr.write('USAGE: tc --help\n')
|
208
226
|
return 1
|
209
|
-
#
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
227
|
+
# do calculations for taxyear
|
228
|
+
# ... initialize TaxCalcIO object for taxyear
|
229
|
+
tcio = tc.TaxCalcIO(
|
230
|
+
input_data=inputfn,
|
231
|
+
tax_year=taxyear,
|
232
|
+
baseline=args.baseline,
|
233
|
+
reform=args.reform,
|
234
|
+
assump=args.assump,
|
235
|
+
silent=args.silent,
|
236
|
+
)
|
237
|
+
if tcio.errmsg:
|
238
|
+
if tcio.errmsg.endswith('\n'):
|
239
|
+
sys.stderr.write(tcio.errmsg)
|
240
|
+
else:
|
241
|
+
sys.stderr.write(tcio.errmsg + '\n')
|
242
|
+
sys.stderr.write('USAGE: tc --help\n')
|
243
|
+
return 1
|
244
|
+
tcio.init(
|
245
|
+
input_data=inputfn,
|
246
|
+
tax_year=taxyear,
|
247
|
+
baseline=args.baseline,
|
248
|
+
reform=args.reform,
|
249
|
+
assump=args.assump,
|
250
|
+
aging_input_data=aging_data,
|
251
|
+
exact_calculations=args.exact,
|
252
|
+
)
|
253
|
+
if tcio.errmsg:
|
254
|
+
if tcio.errmsg.endswith('\n'):
|
255
|
+
sys.stderr.write(tcio.errmsg)
|
256
|
+
else:
|
257
|
+
sys.stderr.write(tcio.errmsg + '\n')
|
258
|
+
sys.stderr.write('USAGE: tc --help\n')
|
259
|
+
return 1
|
260
|
+
# ... conduct tax analysis for taxyear
|
261
|
+
dumpvars_list = tcio.dump_variables(dumpvars_str)
|
262
|
+
if tcio.errmsg:
|
263
|
+
if tcio.errmsg.endswith('\n'):
|
264
|
+
sys.stderr.write(tcio.errmsg)
|
265
|
+
else:
|
266
|
+
sys.stderr.write(tcio.errmsg + '\n')
|
267
|
+
sys.stderr.write('USAGE: tc --help\n')
|
268
|
+
return 1
|
269
|
+
tcio.analyze(
|
270
|
+
output_params=args.params,
|
271
|
+
output_tables=args.tables,
|
272
|
+
output_graphs=args.graphs,
|
273
|
+
output_dump=args.dumpdb,
|
274
|
+
dump_varlist=dumpvars_list,
|
275
|
+
)
|
221
276
|
# compare test output with expected test output if --test option specified
|
222
277
|
if args.test:
|
223
278
|
retcode = _compare_test_output_files()
|
224
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
|
+
)
|
297
|
+
if not args.silent:
|
298
|
+
print( # pragma: no cover
|
299
|
+
f'Execution time is {(time.time() - start_time):.1f} seconds'
|
300
|
+
)
|
225
301
|
return 0
|
226
302
|
# end of cli_tc_main function code
|
227
303
|
|
228
304
|
|
229
|
-
|
230
|
-
|
305
|
+
TEST_INPUT_DATA = (
|
306
|
+
'RECID,MARS,XTOT,EIC,e00200,e00200p,e00200s,p23250,e18400,e19800,s006\n'
|
307
|
+
'1, 2, 3, 1, 40000, 40000, 0, 0, 3000, 4000, 1e7\n'
|
308
|
+
'2, 2, 3, 1,200000, 200000, 0, 0, 15000, 20000, 1e7\n'
|
309
|
+
)
|
310
|
+
EXPECTED_TEST_FILENAME = f'test-{str(TEST_TAXYEAR)[2:]}.exp'
|
311
|
+
EXPECTED_TEST_OUTPUT = (
|
312
|
+
'id|itax\n'
|
313
|
+
'1|131.88\n'
|
314
|
+
'2|28879.00\n'
|
315
|
+
)
|
316
|
+
TEST_DUMPDB_FILENAME = f'test-{str(TEST_TAXYEAR)[2:]}-#-#-#.db'
|
317
|
+
TEST_SQLITE_QUERY = """
|
318
|
+
SELECT
|
319
|
+
RECID AS id,
|
320
|
+
ROUND(iitax, 2) AS itax
|
321
|
+
FROM baseline;
|
322
|
+
"""
|
323
|
+
ACTUAL_TEST_FILENAME = f'test-{str(TEST_TAXYEAR)[2:]}.act'
|
324
|
+
TEST_TABULATE_FILENAME = 'test-tabulate.sql'
|
325
|
+
TEST_TABULATE_SQLCODE = (
|
326
|
+
f'-- USAGE: sqlite3 {TEST_DUMPDB_FILENAME} < {TEST_TABULATE_FILENAME}\n'
|
327
|
+
'\n'
|
328
|
+
'-- sepecify base.income_group values\n'
|
329
|
+
'UPDATE base SET income_group =\n'
|
330
|
+
' CASE -- specify the income_group brackets as desired\n'
|
331
|
+
' WHEN expanded_income < 0.0 THEN 0\n'
|
332
|
+
' WHEN expanded_income < 50.0e3 THEN 1\n'
|
333
|
+
' WHEN expanded_income < 100.0e3 THEN 2\n'
|
334
|
+
' WHEN expanded_income < 500.0e3 THEN 3\n'
|
335
|
+
' WHEN expanded_income < 1.0e6 THEN 4\n'
|
336
|
+
' ELSE 5\n'
|
337
|
+
' END;\n'
|
338
|
+
'\n'
|
339
|
+
'-- tabulate baseline and reform iitax for joint filers by income_group\n'
|
340
|
+
'.separator "\t"\n'
|
341
|
+
'.headers on\n'
|
342
|
+
'SELECT\n'
|
343
|
+
' income_group AS g,\n'
|
344
|
+
' COUNT(*) AS units,\n'
|
345
|
+
' ROUND(SUM(b.iitax*s006)*1e-9, 3) AS b_iitax,\n'
|
346
|
+
' ROUND(SUM(r.iitax*s006)*1e-9, 3) AS r_iitax\n'
|
347
|
+
'FROM base JOIN baseline AS b USING(RECID) JOIN reform AS r USING(RECID)\n'
|
348
|
+
'WHERE MARS == 2\n'
|
349
|
+
'GROUP BY income_group;\n'
|
350
|
+
'.headers off\n'
|
351
|
+
'SELECT\n'
|
352
|
+
" 'A' AS g,\n"
|
353
|
+
' COUNT(*) AS units,\n'
|
354
|
+
' ROUND(SUM(b.iitax*s006)*1e-9, 3) AS b_iitax,\n'
|
355
|
+
' ROUND(SUM(r.iitax*s006)*1e-9, 3) AS r_iitax\n'
|
356
|
+
'FROM base JOIN baseline AS b USING(RECID) JOIN reform AS r USING(RECID)\n'
|
357
|
+
'WHERE MARS == 2;\n'
|
358
|
+
'\n'
|
359
|
+
'-- Documentation on the sqlite3 CLI program is available at\n'
|
360
|
+
'-- https://sqlite.org/cli.html\n'
|
361
|
+
)
|
231
362
|
|
232
363
|
|
233
|
-
def
|
364
|
+
def _write_test_files():
|
234
365
|
"""
|
235
366
|
Private function that writes tc --test input and expected output files.
|
236
367
|
"""
|
237
|
-
input_data = (
|
238
|
-
'RECID,MARS,XTOT,EIC,e00200,e00200p,e00200s,p23250,e18400,e19800\n'
|
239
|
-
'1, 2, 3, 1, 40000, 40000, 0, 0, 3000, 4000\n'
|
240
|
-
'2, 2, 3, 1,200000, 200000, 0, 0, 15000, 20000\n'
|
241
|
-
)
|
242
368
|
with open(TEST_INPUT_FILENAME, 'w', encoding='utf-8') as ifile:
|
243
|
-
ifile.write(
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
)
|
249
|
-
with open(EXPECTED_TEST_OUTPUT_FILENAME, 'w', encoding='utf-8') as ofile:
|
250
|
-
ofile.write(expected_output_data)
|
369
|
+
ifile.write(TEST_INPUT_DATA)
|
370
|
+
with open(EXPECTED_TEST_FILENAME, 'w', encoding='utf-8') as ofile:
|
371
|
+
ofile.write(EXPECTED_TEST_OUTPUT)
|
372
|
+
with open(TEST_TABULATE_FILENAME, 'w', encoding='utf-8') as tfile:
|
373
|
+
tfile.write(TEST_TABULATE_SQLCODE)
|
251
374
|
|
252
375
|
|
253
376
|
def _compare_test_output_files():
|
254
377
|
"""
|
255
|
-
Private function that compares expected and actual tc --test
|
378
|
+
Private function that compares expected and actual tc --test results;
|
256
379
|
returns 0 if pass test, otherwise returns 1.
|
257
380
|
"""
|
258
|
-
|
381
|
+
# use TEST_SQLITE_QUERY to extract results from TEST_DUMPDB_FILENAME
|
382
|
+
with sqlite3.connect(TEST_DUMPDB_FILENAME) as connection:
|
383
|
+
cursor = connection.cursor()
|
384
|
+
cursor.execute(TEST_SQLITE_QUERY)
|
385
|
+
results = cursor.fetchall()
|
386
|
+
with open(ACTUAL_TEST_FILENAME, 'w', encoding='utf-8') as afile:
|
387
|
+
afile.write('id|itax\n')
|
388
|
+
for row in results:
|
389
|
+
afile.write(f'{row[0]}|{row[1]:.2f}\n')
|
390
|
+
# compare results in ACTUAL_TEST_FILENAME and in EXPECTED_TEST_FILENAME
|
391
|
+
with open(EXPECTED_TEST_FILENAME, 'r', encoding='utf-8') as efile:
|
259
392
|
explines = efile.readlines()
|
260
|
-
with open(
|
393
|
+
with open(ACTUAL_TEST_FILENAME, 'r', encoding='utf-8') as afile:
|
261
394
|
actlines = afile.readlines()
|
262
395
|
if ''.join(explines) == ''.join(actlines):
|
263
396
|
sys.stdout.write('PASSED TEST\n')
|
@@ -266,8 +399,8 @@ def _compare_test_output_files():
|
|
266
399
|
retcode = 1
|
267
400
|
sys.stdout.write('FAILED TEST\n')
|
268
401
|
diff = difflib.unified_diff(explines, actlines,
|
269
|
-
fromfile=
|
270
|
-
tofile=
|
402
|
+
fromfile=EXPECTED_TEST_FILENAME,
|
403
|
+
tofile=ACTUAL_TEST_FILENAME, n=0)
|
271
404
|
sys.stdout.writelines(diff)
|
272
405
|
return retcode
|
273
406
|
|
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.py
CHANGED
@@ -62,15 +62,6 @@ class Policy(Parameters):
|
|
62
62
|
'DependentCredit_before_CTC': 'is a removed parameter name',
|
63
63
|
'FilerCredit_c': 'is a removed parameter name',
|
64
64
|
'ALD_InvInc_ec_base_RyanBrady': 'is a removed parameter name',
|
65
|
-
# following parameter renamed in PR 2292 merged on 2019-04-15
|
66
|
-
"cpi_offset": (
|
67
|
-
"was renamed parameter_indexing_CPI_offset. "
|
68
|
-
"See documentation for change in usage."
|
69
|
-
),
|
70
|
-
"CPI_offset": (
|
71
|
-
"was renamed parameter_indexing_CPI_offset. "
|
72
|
-
"See documentation for change in usage."
|
73
|
-
),
|
74
65
|
# following parameters renamed in PR 2345 merged on 2019-06-24
|
75
66
|
'PT_excl_rt':
|
76
67
|
'was renamed PT_qbid_rt in release 2.4.0',
|
@@ -170,9 +161,9 @@ class Policy(Parameters):
|
|
170
161
|
vo["value"] for
|
171
162
|
vo in self._data["parameter_indexing_CPI_offset"]["value"]
|
172
163
|
]
|
173
|
-
#
|
174
|
-
|
175
|
-
|
164
|
+
# parameter_indexing_CPI_offset parameter is no longer used, so check:
|
165
|
+
assert any(cpi_vals) is False, \
|
166
|
+
'obsolete parameter_indexing_CPI_offset values must all be zero'
|
176
167
|
syr = max(self.start_year, self._gfactors.first_year)
|
177
168
|
self._inflation_rates = self._gfactors.price_inflation_rates(
|
178
169
|
syr, self.end_year
|