taxcalc 5.3.0__py3-none-any.whl → 6.1.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 (40) hide show
  1. taxcalc/__init__.py +1 -1
  2. taxcalc/calcfunctions.py +11 -11
  3. taxcalc/calculator.py +1 -1
  4. taxcalc/cli/tc.py +1 -8
  5. taxcalc/data.py +1 -2
  6. taxcalc/policy.py +7 -22
  7. taxcalc/policy_current_law.json +6 -6
  8. taxcalc/records.py +78 -82
  9. taxcalc/records_variables.json +106 -106
  10. taxcalc/reforms/2017_law.json +1 -1
  11. taxcalc/reforms/ARPA.json +1 -1
  12. taxcalc/reforms/Renacci.json +1 -1
  13. taxcalc/reforms/TCJA.json +1 -1
  14. taxcalc/reforms/Trump2016.json +1 -1
  15. taxcalc/reforms/Trump2017.json +1 -1
  16. taxcalc/taxcalcio.py +60 -51
  17. taxcalc/tests/conftest.py +19 -14
  18. taxcalc/tests/reforms.json +1 -1
  19. taxcalc/tests/reforms_expect.csv +54 -54
  20. taxcalc/tests/test_4package.py +3 -15
  21. taxcalc/tests/test_calcfunctions.py +2 -2
  22. taxcalc/tests/test_calculator.py +197 -160
  23. taxcalc/tests/test_cpscsv.py +0 -22
  24. taxcalc/tests/test_data.py +11 -3
  25. taxcalc/tests/test_parameters.py +42 -0
  26. taxcalc/tests/test_records.py +139 -8
  27. taxcalc/tests/test_reforms.py +5 -7
  28. taxcalc/tests/test_taxcalcio.py +3 -58
  29. {taxcalc-5.3.0.dist-info → taxcalc-6.1.0.dist-info}/METADATA +1 -1
  30. {taxcalc-5.3.0.dist-info → taxcalc-6.1.0.dist-info}/RECORD +34 -40
  31. taxcalc/puf_ratios.csv +0 -26
  32. taxcalc/puf_weights.csv.gz +0 -0
  33. taxcalc/tests/test_compare.py +0 -330
  34. taxcalc/tests/test_compatible_data.py +0 -334
  35. taxcalc/tests/test_puf_var_stats.py +0 -194
  36. taxcalc/tests/test_pufcsv.py +0 -328
  37. {taxcalc-5.3.0.dist-info → taxcalc-6.1.0.dist-info}/WHEEL +0 -0
  38. {taxcalc-5.3.0.dist-info → taxcalc-6.1.0.dist-info}/entry_points.txt +0 -0
  39. {taxcalc-5.3.0.dist-info → taxcalc-6.1.0.dist-info}/licenses/LICENSE +0 -0
  40. {taxcalc-5.3.0.dist-info → taxcalc-6.1.0.dist-info}/top_level.txt +0 -0
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__ = '5.3.0'
17
+ __version__ = '6.1.0'
18
18
  __min_python3_version__ = 11
19
19
  __max_python3_version__ = 13
taxcalc/calcfunctions.py CHANGED
@@ -1871,7 +1871,7 @@ def AMT(e07300, dwks13, standard, f6251, c00100, c18300, taxbc,
1871
1871
  dwks14, c05700, e62900, e00700, dwks10, age_head, age_spouse,
1872
1872
  earned, cmbtp, qbided,
1873
1873
  AMT_child_em_c_age, AMT_brk1,
1874
- AMT_em, AMT_prt, AMT_rt1, AMT_rt2,
1874
+ AMT_em, AMT_prt, AMT_rt1, AMT_rt2_addon,
1875
1875
  AMT_child_em, AMT_em_ps, AMT_em_pe,
1876
1876
  AMT_CG_brk1, AMT_CG_brk2, AMT_CG_brk3, AMT_CG_rt1, AMT_CG_rt2,
1877
1877
  AMT_CG_rt3, AMT_CG_rt4, c05800, c09600, c62100):
@@ -1946,8 +1946,8 @@ def AMT(e07300, dwks13, standard, f6251, c00100, c18300, taxbc,
1946
1946
  AMT exemption phaseout rate
1947
1947
  AMT_rt1: float
1948
1948
  AMT rate 1
1949
- AMT_rt2: float
1950
- Additional AMT rate for AMT taxable income about AMT bracket 1
1949
+ AMT_rt2_addon: float
1950
+ Additional AMT rate for AMT taxable income above AMT bracket 1
1951
1951
  AMT_child_em: float
1952
1952
  Child AMT exemption additional income base
1953
1953
  AMT_em_ps: list
@@ -1977,14 +1977,14 @@ def AMT(e07300, dwks13, standard, f6251, c00100, c18300, taxbc,
1977
1977
  c09600: float
1978
1978
  Alternative Minimum Tax (AMT) liability
1979
1979
  c62100: float
1980
- Alternative Minimum Tax (AMT)
1980
+ Alternative Minimum Tax (AMT) taxable income
1981
1981
 
1982
1982
  Returns
1983
1983
  -------
1984
1984
  c62100: float
1985
- Alternative Minimum Tax (AMT)
1985
+ Alternative Minimum Tax (AMT) taxable income
1986
1986
  c09600: float
1987
- Alternative Minimum Tax (AMT) liability
1987
+ Alternative Minimum Tax (AMT) tax liability
1988
1988
  c05800: float
1989
1989
  Total (regular + AMT) income tax liability before credits
1990
1990
  """
@@ -2012,7 +2012,7 @@ def AMT(e07300, dwks13, standard, f6251, c00100, c18300, taxbc,
2012
2012
  line29 = min(line29, earned + AMT_child_em)
2013
2013
  line30 = max(0., c62100 - line29)
2014
2014
  line3163 = (AMT_rt1 * line30 +
2015
- AMT_rt2 * max(0., (line30 - (AMT_brk1 / sep))))
2015
+ AMT_rt2_addon * max(0., (line30 - (AMT_brk1 / sep))))
2016
2016
  if dwks10 > 0. or dwks13 > 0. or dwks14 > 0. or dwks19 > 0. or e24515 > 0.:
2017
2017
  # complete Form 6251, Part III (line36 is equal to line30)
2018
2018
  line37 = dwks13
@@ -2021,7 +2021,7 @@ def AMT(e07300, dwks13, standard, f6251, c00100, c18300, taxbc,
2021
2021
  line40 = min(line30, line39)
2022
2022
  line41 = max(0., line30 - line40)
2023
2023
  line42 = (AMT_rt1 * line41 +
2024
- AMT_rt2 * max(0., (line41 - (AMT_brk1 / sep))))
2024
+ AMT_rt2_addon * max(0., (line41 - (AMT_brk1 / sep))))
2025
2025
  line44 = dwks14
2026
2026
  line45 = max(0., AMT_CG_brk1[MARS - 1] - line44)
2027
2027
  line46 = min(line30, line37)
@@ -2268,7 +2268,7 @@ def EITCamount(basic_frac, phasein_rate, earnings, max_amount,
2268
2268
  @iterate_jit(nopython=True)
2269
2269
  def EITC(MARS, DSI, EIC, c00100, e00300, e00400, e00600, c01000,
2270
2270
  e02000, e26270, age_head, age_spouse, earned, earned_p, earned_s,
2271
- EITC_ps, EITC_MinEligAge, EITC_MaxEligAge, EITC_ps_MarriedJ,
2271
+ EITC_ps, EITC_MinEligAge, EITC_MaxEligAge, EITC_ps_addon_MarriedJ,
2272
2272
  EITC_rt, EITC_c, EITC_prt, EITC_basic_frac,
2273
2273
  EITC_InvestIncome_c, EITC_excess_InvestIncome_rt,
2274
2274
  EITC_indiv, EITC_sep_filers_elig, c59660):
@@ -2315,7 +2315,7 @@ def EITC(MARS, DSI, EIC, c00100, e00300, e00400, e00600, c01000,
2315
2315
  Minimum age for childless EITC eligibility
2316
2316
  EITC_MaxEligAge: int
2317
2317
  Maximum age for childless EITC eligibility
2318
- EITC_ps_MarriedJ: list
2318
+ EITC_ps_addon_MarriedJ: list
2319
2319
  Extra earned income credit phaseout start AGI for
2320
2320
  married filling jointly
2321
2321
  EITC_rt: list
@@ -2360,7 +2360,7 @@ def EITC(MARS, DSI, EIC, c00100, e00300, e00400, e00600, c01000,
2360
2360
  c59660 = eitc
2361
2361
 
2362
2362
  if MARS == 2:
2363
- po_start = EITC_ps[EIC] + EITC_ps_MarriedJ[EIC]
2363
+ po_start = EITC_ps[EIC] + EITC_ps_addon_MarriedJ[EIC]
2364
2364
  if not EITC_indiv:
2365
2365
  # filing unit EITC rather than individual EITC
2366
2366
  eitc = EITCamount(EITC_basic_frac,
taxcalc/calculator.py CHANGED
@@ -81,7 +81,7 @@ class Calculator():
81
81
  The most efficient way to specify current-law and reform Calculator
82
82
  objects is as follows:
83
83
  pol = Policy()
84
- rec = Records()
84
+ rec = Records.cps_constructor()
85
85
  calc1 = Calculator(policy=pol, records=rec) # current-law
86
86
  pol.implement_reform(...)
87
87
  calc2 = Calculator(policy=pol, records=rec) # reform
taxcalc/cli/tc.py CHANGED
@@ -229,12 +229,6 @@ def cli_tc_main():
229
229
  sys.stderr.write(msg)
230
230
  sys.stderr.write('USAGE: tc --help\n')
231
231
  return 1
232
- # specify if aging input data
233
- aging_data = (
234
- inputfn.endswith('puf.csv') or
235
- inputfn.endswith('cps.csv') or
236
- inputfn.endswith('tmd.csv')
237
- )
238
232
  # check args.dumpdb and args.dumpvars consistency
239
233
  if not args.dumpdb and args.dumpvars:
240
234
  msg = 'ERROR: DUMPVARS file specified without --dumpdb option\n'
@@ -299,7 +293,6 @@ def cli_tc_main():
299
293
  baseline=args.baseline,
300
294
  reform=args.reform,
301
295
  assump=args.assump,
302
- aging_input_data=aging_data,
303
296
  exact_calculations=args.exact,
304
297
  )
305
298
  if tcio.errmsg:
@@ -346,7 +339,7 @@ def cli_tc_main():
346
339
  return 0
347
340
  # analyze years after taxyear if args.numyears is greater than one
348
341
  for xyear in range(1, args.numyears):
349
- tcio.advance_to_year(taxyear + xyear, aging_data)
342
+ tcio.advance_to_year(taxyear + xyear)
350
343
  tcio.analyze(
351
344
  output_params=args.params,
352
345
  output_tables=args.tables,
taxcalc/data.py CHANGED
@@ -236,8 +236,7 @@ class Data():
236
236
  self.IGNORED_VARS.add(varname)
237
237
  # check that MUST_READ_VARS are all present in taxdf
238
238
  if not self.MUST_READ_VARS.issubset(READ_VARS):
239
- msg = 'data missing one or more MUST_READ_VARS'
240
- raise ValueError(msg)
239
+ raise ValueError('data missing one or more MUST_READ_VARS')
241
240
  # delete intermediate taxdf object
242
241
  del taxdf
243
242
  # create other class variables that are set to all zeros
taxcalc/policy.py CHANGED
@@ -7,7 +7,6 @@ Tax-Calculator federal tax policy Policy class.
7
7
 
8
8
  import os
9
9
  import json
10
- from pathlib import Path
11
10
  import paramtools
12
11
  from taxcalc.parameters import Parameters
13
12
  from taxcalc.growfactors import GrowFactors
@@ -56,8 +55,7 @@ class Policy(Parameters):
56
55
  return last_budget_year - Policy.JSON_START_YEAR + 1
57
56
 
58
57
  # NOTE: the following three data structures use internal parameter names:
59
- # (1) specify which Policy parameters have been removed or renamed recently
60
- # where "recently" means in the last major release
58
+ # (1) specify which Policy parameters have been removed or renamed
61
59
  REMOVED_PARAMS = {
62
60
  # following parameters were renamed in PR 2918
63
61
  'SS_thd50': 'was renamed SS_thd1 in Tax-Calculator 5.0.0',
@@ -111,9 +109,13 @@ class Policy(Parameters):
111
109
  'ID_reduction_other_rate': (
112
110
  'was renamed ID_reduction_rate in Tax-Calculator 5.1.0'
113
111
  ),
112
+ # following parameters were renamed in PR 2965
113
+ 'AMT_rt2': 'was renamed AMT_rt2_addon in Tax-Calculator 6.1.0',
114
+ 'EITC_ps_MarriedJ': (
115
+ 'was renamed EITC_ps_addon_MarriedJ in Tax-Calculator 6.1.0'
116
+ ),
114
117
  }
115
- # (2) specify which Policy parameters have been redefined recently
116
- # where "recently" means in the last major release
118
+ # (2) specify which Policy parameters have been redefined
117
119
  REDEFINED_PARAMS = {}
118
120
  # (3) specify which Policy parameters are wage (rather than price) indexed
119
121
  WAGE_INDEXED_PARAMS = ['SS_Earnings_c', 'SS_Earnings_thd']
@@ -141,23 +143,6 @@ class Policy(Parameters):
141
143
  Policy.REDEFINED_PARAMS,
142
144
  Policy.WAGE_INDEXED_PARAMS, **kwargs)
143
145
 
144
- @staticmethod
145
- def tmd_constructor(
146
- growfactors: Path | GrowFactors,
147
- last_budget_year=LAST_BUDGET_YEAR,
148
- ): # pragma: no cover
149
- """
150
- Static method returns a Policy object instantiated with TMD
151
- input data. This convenience method works in a analogous way
152
- to Policy(), which returns a Policy object instantiated with
153
- non-TMD input data.
154
- """
155
- if isinstance(growfactors, Path):
156
- growfactors = GrowFactors(growfactors_filename=str(growfactors))
157
- else:
158
- assert isinstance(growfactors, GrowFactors)
159
- return Policy(gfactors=growfactors, last_budget_year=last_budget_year)
160
-
161
146
  @staticmethod
162
147
  def read_json_reform(obj):
163
148
  """
@@ -17502,9 +17502,9 @@
17502
17502
  "cps": true
17503
17503
  }
17504
17504
  },
17505
- "AMT_rt2": {
17505
+ "AMT_rt2_addon": {
17506
17506
  "title": "Additional AMT rate for AMT taxable income above AMT bracket 1",
17507
- "description": "The additional tax rate applied to the portion of AMT income above the AMT bracket 1.",
17507
+ "description": "The additional tax rate applied to the portion of AMT income above the AMT bracket 1, which means that AMT_rt2_addon equals AMT_rt2 minus AMT_rt1.",
17508
17508
  "notes": "This is the additional tax rate (on top of AMT rate 1) for AMT income above AMT bracket 1.",
17509
17509
  "section_1": "Personal Income",
17510
17510
  "section_2": "Alternative Minimum Tax",
@@ -17519,8 +17519,8 @@
17519
17519
  ],
17520
17520
  "validators": {
17521
17521
  "range": {
17522
- "min": 0,
17523
- "max": 1
17522
+ "min": 0.0,
17523
+ "max": 0.1
17524
17524
  }
17525
17525
  },
17526
17526
  "compatible_data": {
@@ -19734,9 +19734,9 @@
19734
19734
  "cps": true
19735
19735
  }
19736
19736
  },
19737
- "EITC_ps_MarriedJ": {
19737
+ "EITC_ps_addon_MarriedJ": {
19738
19738
  "title": "Extra earned income credit phaseout start AGI for married filling jointly",
19739
- "description": "This is the additional amount added on the regular phaseout start amount for taxpayers with filling status of married filing jointly.",
19739
+ "description": "This is the additional amount added on the regular phaseout start amount for taxpayers with filling status of married filing jointly, which means that EITC_ps_addon_MarriedJ equals EITC_ps_MarriedJ minus EITC_ps.",
19740
19740
  "notes": "",
19741
19741
  "section_1": "Refundable Credits",
19742
19742
  "section_2": "Earned Income Tax Credit",
taxcalc/records.py CHANGED
@@ -23,10 +23,10 @@ class Records(Data):
23
23
 
24
24
  Parameters
25
25
  ----------
26
- data: string or Pandas DataFrame
26
+ data: string or Pandas DataFrame or None
27
27
  string describes CSV file in which records data reside;
28
28
  DataFrame already contains records data;
29
- default value is the string 'puf.csv'
29
+ default value is None.
30
30
  NOTE: when using custom data, set this argument to a DataFrame.
31
31
  NOTE: to use your own data for a specific year with Tax-Calculator,
32
32
  be sure to read the documentation on creating your own data file and
@@ -37,29 +37,28 @@ class Records(Data):
37
37
  NOTE: data=None is allowed but the returned instance contains only
38
38
  the data variable information in the specified VARINFO file.
39
39
 
40
- start_year: integer
40
+ start_year: integer or None
41
41
  specifies calendar year of the input data;
42
- default value is PUFCSV_YEAR.
42
+ default value is None.
43
43
  Note that if specifying your own data (see above NOTE) as being
44
44
  a custom data set, be sure to explicitly set start_year to the
45
45
  custom data's calendar year.
46
46
 
47
47
  gfactors: GrowFactors class instance or None
48
48
  containing record data growth (or extrapolation) factors.
49
+ default value is None.
49
50
 
50
- weights: string or Pandas DataFrame or None
51
- string describes CSV file in which weights reside;
52
- DataFrame already contains weights;
53
- None creates empty sample-weights DataFrame;
54
- default value is filename of the PUF weights.
51
+ weights: Pandas DataFrame or None
52
+ DataFrame contains data weights;
53
+ None creates empty weights DataFrame;
54
+ default value is None
55
55
  NOTE: when using custom weights, set this argument to a DataFrame.
56
56
  NOTE: see weights_scale documentation below.
57
57
 
58
- adjust_ratios: string or Pandas DataFrame or None
59
- string describes CSV file in which adjustment ratios reside;
60
- DataFrame already contains transposed/no-index adjustment ratios;
58
+ adjust_ratios: Pandas DataFrame or None
59
+ DataFrame contains transposed/no-index adjustment ratios;
61
60
  None creates empty adjustment-ratios DataFrame;
62
- default value is filename of the PUF adjustment ratios.
61
+ default value is None.
63
62
  NOTE: when using custom ratios, set this argument to a DataFrame.
64
63
  NOTE: if specifying a DataFrame, set adjust_ratios to my_df defined as:
65
64
  my_df = pd.read_csv('<my_ratios.csv>', index_col=0).transpose()
@@ -75,6 +74,7 @@ class Records(Data):
75
74
  generated in the taxdata repository use a weights_scale of 0.01,
76
75
  while TMD input data generated in the tax-microdata repository
77
76
  use a 1.0 weights_scale value.
77
+ default value is 0.01.
78
78
 
79
79
  Raises
80
80
  ------
@@ -92,20 +92,12 @@ class Records(Data):
92
92
 
93
93
  Notes
94
94
  -----
95
- Typical usage when using PUF input data is as follows::
96
-
97
- recs = Records()
98
-
99
- which uses all the default parameters of the constructor, and
100
- therefore, imputed variables are generated to augment the data and
101
- initial-year grow factors are applied to the data. There are
102
- situations in which you need to specify the values of the Record
103
- constructor's arguments, but be sure you know exactly what you are
104
- doing when attempting this.
105
-
106
95
  Use Records.cps_constructor() to get a Records object instantiated
107
96
  with CPS input data developed in the taxdata repository.
108
97
 
98
+ Use Records.puf_constructor() to get a Records object instantiated
99
+ with PUF input data developed in the taxdata repository.
100
+
109
101
  Use Records.tmd_constructor() to get a Records object instantiated
110
102
  with TMD input data developed in the tax-microdata repository.
111
103
  """
@@ -120,20 +112,16 @@ class Records(Data):
120
112
  CPSCSV_YEAR = 2014
121
113
  TMDCSV_YEAR = 2021
122
114
 
123
- PUF_WEIGHTS_FILENAME = 'puf_weights.csv.gz'
124
- PUF_RATIOS_FILENAME = 'puf_ratios.csv'
125
- CPS_WEIGHTS_FILENAME = 'cps_weights.csv.gz'
126
- CPS_RATIOS_FILENAME = None
127
115
  CODE_PATH = os.path.abspath(os.path.dirname(__file__))
128
116
  VARINFO_FILE_NAME = 'records_variables.json'
129
117
  VARINFO_FILE_PATH = CODE_PATH
130
118
 
131
119
  def __init__(self,
132
- data='puf.csv',
133
- start_year=PUFCSV_YEAR,
134
- gfactors=GrowFactors(),
135
- weights=PUF_WEIGHTS_FILENAME,
136
- adjust_ratios=PUF_RATIOS_FILENAME,
120
+ data=None,
121
+ start_year=None,
122
+ gfactors=None,
123
+ weights=None,
124
+ adjust_ratios=None,
137
125
  exact_calculations=False,
138
126
  weights_scale=0.01):
139
127
  # pylint: disable=too-many-positional-arguments
@@ -205,32 +193,58 @@ class Records(Data):
205
193
  raise ValueError('not all PT_SSTB_income values are 0 or 1')
206
194
 
207
195
  @staticmethod
208
- def cps_constructor(data=None,
209
- gfactors=GrowFactors(),
210
- exact_calculations=False):
196
+ def cps_constructor(
197
+ data=None,
198
+ gfactors=GrowFactors(),
199
+ exact_calculations=False
200
+ ):
211
201
  """
212
202
  Static method returns a Records object instantiated with CPS
213
- input data. This works in a analogous way to Records(), which
214
- returns a Records object instantiated with PUF input data.
215
- This is a convenience method that eliminates the need to
216
- specify all the details of the CPS input data just as the
217
- default values of the arguments of the Records class constructor
218
- eliminate the need to specify all the details of the PUF input
219
- data.
203
+ input data. This is a convenience method that eliminates the
204
+ need to specify all the details of the CPS input data.
220
205
  """
221
206
  if data is None:
222
207
  data = os.path.join(Records.CODE_PATH, 'cps.csv.gz')
223
208
  if gfactors is None:
224
209
  weights = None
225
210
  else:
226
- weights = os.path.join(Records.CODE_PATH,
227
- Records.CPS_WEIGHTS_FILENAME)
228
- return Records(data=data,
229
- start_year=Records.CPSCSV_YEAR,
230
- gfactors=gfactors,
231
- weights=weights,
232
- adjust_ratios=Records.CPS_RATIOS_FILENAME,
233
- exact_calculations=exact_calculations)
211
+ weights = os.path.join(Records.CODE_PATH, 'cps_weights.csv.gz')
212
+ return Records(
213
+ data=data,
214
+ start_year=Records.CPSCSV_YEAR,
215
+ gfactors=gfactors,
216
+ weights=weights,
217
+ adjust_ratios=None,
218
+ exact_calculations=exact_calculations,
219
+ weights_scale=0.01,
220
+ )
221
+
222
+ @staticmethod
223
+ def puf_constructor(
224
+ data='puf.csv',
225
+ gfactors=GrowFactors(),
226
+ weights='puf_weights.csv.gz',
227
+ ratios='puf_ratios.csv',
228
+ exact_calculations=False
229
+ ): # pragma: no cover
230
+ """
231
+ Static method returns a Records object instantiated with PUF
232
+ input data. This is a convenience method that eliminates the
233
+ need to specify all the details of the PUF input data.
234
+ """
235
+ assert isinstance(data, str)
236
+ assert isinstance(gfactors, GrowFactors)
237
+ assert isinstance(weights, str)
238
+ assert isinstance(ratios, str)
239
+ return Records(
240
+ data=pd.read_csv(data),
241
+ start_year=Records.PUFCSV_YEAR,
242
+ gfactors=gfactors,
243
+ weights=pd.read_csv(weights),
244
+ adjust_ratios=pd.read_csv(ratios, index_col=0).transpose(),
245
+ exact_calculations=exact_calculations,
246
+ weights_scale=0.01,
247
+ )
234
248
 
235
249
  @staticmethod
236
250
  def tmd_constructor(
@@ -241,13 +255,8 @@ class Records(Data):
241
255
  ): # pragma: no cover
242
256
  """
243
257
  Static method returns a Records object instantiated with TMD
244
- input data. This works in a analogous way to Records(), which
245
- returns a Records object instantiated with PUF input data.
246
- This is a convenience method that eliminates the need to
247
- specify all the details of the TMD input data just as the
248
- default values of the arguments of the Records class constructor
249
- eliminate the need to specify all the details of the PUF input
250
- data.
258
+ input data. This is a convenience method that eliminates the
259
+ need to specify all the details of the TMD input data.
251
260
  """
252
261
  assert isinstance(data_path, Path)
253
262
  assert isinstance(weights_path, Path)
@@ -395,42 +404,29 @@ class Records(Data):
395
404
 
396
405
  def _adjust(self, year):
397
406
  """
398
- Adjust value of income variables to match SOI distributions
407
+ Adjust value of PUF income variables to match SOI distributions
399
408
  Note: adjustment must leave variables as numpy.ndarray type
400
409
  """
401
410
  # pylint: disable=no-member
402
- if self.ADJ.size > 0:
411
+ if self.ADJ.size > 0: # pragma: no cover
403
412
  # Interest income
404
413
  self.e00300 *= self.ADJ[f'INT{year}'].iloc[self.agi_bin].values
405
414
 
406
415
  def _read_ratios(self, ratios):
407
416
  """
408
- Read Records adjustment ratios from file or
409
- use specified transposed/no-index DataFrame as ratios or
410
- create empty DataFrame if None
417
+ Read Records PUF-related adjustment ratios using
418
+ specified transposed/no-index DataFrame as ratios or
419
+ create empty DataFrame if ratios is None.
411
420
  """
421
+ assert ratios is None or isinstance(ratios, pd.DataFrame)
412
422
  if ratios is None:
413
423
  setattr(self, 'ADJ', pd.DataFrame({'nothing': []}))
414
424
  return
415
- if isinstance(ratios, pd.DataFrame):
425
+ if isinstance(ratios, pd.DataFrame): # pragma: no cover
416
426
  assert 'INT2013' in ratios.columns # check for transposed
417
427
  assert ratios.index.name is None # check for no-index
418
428
  ADJ = ratios
419
- elif isinstance(ratios, str):
420
- ratios_path = os.path.join(Records.CODE_PATH, ratios)
421
- if os.path.isfile(ratios_path):
422
- ADJ = pd.read_csv(ratios_path,
423
- index_col=0)
424
- else: # find file in conda package
425
- ADJ = read_egg_csv(os.path.basename(ratios_path),
426
- index_col=0) # pragma: no cover
427
- ADJ = ADJ.transpose()
428
- else:
429
- msg = 'ratios is neither None nor a Pandas DataFrame nor a string'
430
- raise ValueError(msg)
431
- assert isinstance(ADJ, pd.DataFrame)
432
- if ADJ.index.name != 'agi_bin':
433
- ADJ.index.name = 'agi_bin'
434
- self.ADJ = pd.DataFrame()
435
- setattr(self, 'ADJ', ADJ.astype(np.float32))
436
- del ADJ
429
+ self.ADJ = pd.DataFrame()
430
+ if ADJ.index.name != 'agi_bin':
431
+ ADJ.index.name = 'agi_bin'
432
+ setattr(self, 'ADJ', ADJ.astype(np.float32))