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 CHANGED
@@ -14,6 +14,6 @@ from taxcalc.taxcalcio import *
14
14
  from taxcalc.utils import *
15
15
  from taxcalc.cli import *
16
16
 
17
- __version__ = '4.5.0'
17
+ __version__ = '4.6.1'
18
18
  __min_python3_version__ = 10
19
19
  __max_python3_version__ = 12
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 policy parameter is the only
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
- Schedule C business net profit/loss for filing unit
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('Tax-Calculator startup automatically ' +
133
- 'extrapolated your data to ' +
134
- str(self.__records.current_year) + '.')
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('Tax-Calculator startup did not ' +
138
- 'extrapolate your data.')
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 reform_warnings(self):
308
+ def reform_errors(self):
309
309
  """
310
- Calculator class embedded Policy object's parameter_warnings.
310
+ Calculator class embedded Policy object's parameter_errors.
311
311
  """
312
- return self.__policy.parameter_warnings
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 conda package.
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 {}{}{}{}{}'.format(
30
- '[--help]\n',
31
- (' '
32
- '[--baseline BASELINE] [--reform REFORM] [--assump ASSUMP]\n'),
33
- (' '
34
- '[--exact] [--tables] [--graphs] [--timings]\n'),
35
- (' '
36
- '[--dump] [--dvars DVARS] [--sqldb] [--outdir OUTDIR]\n'),
37
- (' '
38
- '[--test] [--version]'))
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 to a file the federal income and payroll tax '
43
- 'OUTPUT for each filing unit specified in the INPUT '
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 two '
68
- 'file names separated by a plus (+) character. '
69
- 'No --reform implies a "null" reform (that is, '
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('--timings',
94
- help=('optional flag that causes execution times to '
95
- 'be written to stdout.'),
96
- default=False,
97
- action="store_true")
98
- parser.add_argument('--dump',
99
- help=('optional flag that causes OUTPUT to contain '
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('--dvars',
112
- help=('DVARS is name of optional file containing a '
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 a partial dump OUTPUT file. No --dvars '
115
- 'implies a full dump containing all variables.'),
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('--sqldb',
118
- help=('optional flag that writes SQLite database '
119
- 'with two tables (baseline and reform) each '
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
- _write_expected_test_output()
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
- # instantiate TaxCalcIO object and do tax analysis
167
- tcio = tc.TaxCalcIO(input_data=inputfn, tax_year=taxyear,
168
- baseline=args.baseline,
169
- reform=args.reform, assump=args.assump,
170
- outdir=args.outdir)
171
- if tcio.errmsg:
172
- sys.stderr.write(tcio.errmsg)
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
- aging = (
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
- if args.timings:
181
- stime = time.time()
182
- tcio.init(input_data=inputfn, tax_year=taxyear,
183
- baseline=args.baseline,
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
- dumpvar_set = None
195
- if args.dvars and (args.dump or args.sqldb):
196
- if os.path.exists(args.dvars):
197
- with open(args.dvars, 'r', encoding='utf-8') as dfile:
198
- dump_vars_str = dfile.read()
199
- dumpvar_set = tcio.custom_dump_variables(dump_vars_str)
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: DVARS file {} does not exist\n'
206
- sys.stderr.write(msg.format(args.dvars))
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
- # conduct tax analysis
210
- if args.timings:
211
- stime = time.time()
212
- tcio.analyze(writing_output_file=True,
213
- output_tables=args.tables,
214
- output_graphs=args.graphs,
215
- dump_varset=dumpvar_set,
216
- output_dump=args.dump,
217
- output_sqldb=args.sqldb)
218
- if args.timings:
219
- xtime = time.time() - stime
220
- sys.stdout.write(f'TIMINGS: calc time = {xtime:.2f} secs\n')
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
- EXPECTED_TEST_OUTPUT_FILENAME = f'test-{str(TEST_TAXYEAR)[2:]}-out.csv'
230
- ACTUAL_TEST_OUTPUT_FILENAME = f'test-{str(TEST_TAXYEAR)[2:]}-#-#-#.csv'
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 _write_expected_test_output():
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(input_data)
244
- expected_output_data = (
245
- 'RECID,YEAR,WEIGHT,INCTAX,LSTAX,PAYTAX\n'
246
- '1,2018,0.00,131.88,0.00,6120.00\n'
247
- '2,2018,0.00,28879.00,0.00,21721.60\n'
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 output files;
378
+ Private function that compares expected and actual tc --test results;
256
379
  returns 0 if pass test, otherwise returns 1.
257
380
  """
258
- with open(EXPECTED_TEST_OUTPUT_FILENAME, 'r', encoding='utf-8') as efile:
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(ACTUAL_TEST_OUTPUT_FILENAME, 'r', encoding='utf-8') as afile:
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=EXPECTED_TEST_OUTPUT_FILENAME,
270
- tofile=ACTUAL_TEST_OUTPUT_FILENAME, n=0)
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
- extrapolation & reweighting for new current year if aged_data is True.
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
- # policy_current_law.json should not specify any non-zero values
174
- # for the parameter_indexing_CPI_offset parameter, so check this
175
- assert any(cpi_vals) is False
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