taxcalc 4.6.1__py3-none-any.whl → 4.6.3__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/parameters.py CHANGED
@@ -7,13 +7,13 @@ import copy
7
7
  from collections import defaultdict
8
8
  from typing import Union, Mapping, Any, List
9
9
  import numpy as np
10
- import marshmallow as ma
11
- import paramtools as pt
10
+ import marshmallow
11
+ import paramtools
12
12
 
13
13
 
14
- class CompatibleDataSchema(ma.Schema):
14
+ class CompatibleDataSchema(marshmallow.Schema):
15
15
  """
16
- Schema for Compatible data object
16
+ Schema for compatible_data object
17
17
 
18
18
  .. code-block :: json
19
19
 
@@ -22,18 +22,17 @@ class CompatibleDataSchema(ma.Schema):
22
22
  }
23
23
 
24
24
  """
25
+ puf = marshmallow.fields.Boolean()
26
+ cps = marshmallow.fields.Boolean()
25
27
 
26
- puf = ma.fields.Boolean()
27
- cps = ma.fields.Boolean()
28
28
 
29
-
30
- pt.register_custom_type(
31
- "compatible_data",
32
- ma.fields.Nested(CompatibleDataSchema())
29
+ paramtools.register_custom_type(
30
+ 'compatible_data',
31
+ marshmallow.fields.Nested(CompatibleDataSchema())
33
32
  )
34
33
 
35
34
 
36
- class Parameters(pt.Parameters):
35
+ class Parameters(paramtools.Parameters):
37
36
  """
38
37
  Base class that wraps ParamTools, providing parameter indexing
39
38
  for tax policy in the ``adjust`` method and convenience methods
@@ -69,7 +68,7 @@ class Parameters(pt.Parameters):
69
68
  # pylint: disable=too-many-instance-attributes
70
69
  defaults = None
71
70
  array_first = True
72
- label_to_extend = "year"
71
+ label_to_extend = 'year'
73
72
  uses_extend_func = True
74
73
 
75
74
  REMOVED_PARAMS = None
@@ -113,15 +112,15 @@ class Parameters(pt.Parameters):
113
112
  self._wage_indexed = wage_indexed or self.WAGE_INDEXED_PARAMS
114
113
  if (
115
114
  (start_year or self.JSON_START_YEAR) and
116
- "initial_state" not in kwargs
115
+ 'initial_state' not in kwargs
117
116
  ):
118
- kwargs["initial_state"] = {
119
- "year": start_year or self.JSON_START_YEAR
117
+ kwargs['initial_state'] = {
118
+ 'year': start_year or self.JSON_START_YEAR
120
119
  }
121
120
  # update defaults to correspond to user-defined parameter years
122
121
  self.defaults = super().get_defaults()
123
- label = self.defaults["schema"]["labels"]["year"]
124
- label["validators"]["range"]["max"] = last_budget_year
122
+ label = self.defaults['schema']['labels']['year']
123
+ label['validators']['range']['max'] = last_budget_year
125
124
  super().__init__(**kwargs)
126
125
 
127
126
  def adjust( # pylint: disable=arguments-differ
@@ -166,9 +165,9 @@ class Parameters(pt.Parameters):
166
165
  """
167
166
  if print_warnings:
168
167
  _data = copy.deepcopy(self._data)
169
- kwargs["ignore_warnings"] = False
168
+ kwargs['ignore_warnings'] = False
170
169
  else:
171
- kwargs["ignore_warnings"] = True
170
+ kwargs['ignore_warnings'] = True
172
171
  self._warnings = {}
173
172
  self._errors = {}
174
173
  try:
@@ -178,20 +177,20 @@ class Parameters(pt.Parameters):
178
177
  with self.transaction(
179
178
  defer_validation=True,
180
179
  raise_errors=True,
181
- ignore_warnings=kwargs["ignore_warnings"],
180
+ ignore_warnings=kwargs['ignore_warnings'],
182
181
  ):
183
182
  return self.adjust_with_indexing(
184
183
  params_or_path, raise_errors=True, **kwargs
185
184
  )
186
- except pt.ValidationError as ve:
185
+ except paramtools.ValidationError as ve:
187
186
  if self.errors and raise_errors:
188
187
  raise ve
189
188
  if self.errors and not raise_errors:
190
189
  return {}
191
190
  if print_warnings:
192
- print("WARNING:")
191
+ print('WARNING:')
193
192
  print(self.warnings)
194
- kwargs["ignore_warnings"] = True
193
+ kwargs['ignore_warnings'] = True
195
194
  # pylint: disable=possibly-used-before-assignment
196
195
  self._data = _data
197
196
  # pylint: enable=possibly-used-before-assignment
@@ -244,7 +243,7 @@ class Parameters(pt.Parameters):
244
243
  3. Update all parameters that are not indexing related, i.e. they are
245
244
  not "parameter_indexing_CPI_offset" or do not end with "-indexed".
246
245
 
247
- 4. Return parsed adjustment with all adjustments, including "-indexed"
246
+ 4. Returns parsed adjustment with all adjustments, including "-indexed"
248
247
  parameters.
249
248
 
250
249
  Notable side-effects:
@@ -270,11 +269,11 @@ class Parameters(pt.Parameters):
270
269
  # reset values after the first year in which the
271
270
  # parameter_indexing_CPI_offset is changed.
272
271
  needs_reset = []
273
- if params.get("parameter_indexing_CPI_offset") is not None:
272
+ if params.get('parameter_indexing_CPI_offset') is not None:
274
273
  # Update parameter_indexing_CPI_offset with new value.
275
274
  cpi_adj = super().adjust(
276
- {"parameter_indexing_CPI_offset":
277
- params["parameter_indexing_CPI_offset"]}, **kwargs
275
+ {'parameter_indexing_CPI_offset':
276
+ params['parameter_indexing_CPI_offset']}, **kwargs
278
277
  )
279
278
  # turn off extend now that parameter_indexing_CPI_offset
280
279
  # has been updated.
@@ -282,42 +281,42 @@ class Parameters(pt.Parameters):
282
281
  # Get first year in which parameter_indexing_CPI_offset
283
282
  # is changed.
284
283
  cpi_min_year = min(
285
- cpi_adj["parameter_indexing_CPI_offset"],
286
- key=lambda vo: vo["year"]
284
+ cpi_adj['parameter_indexing_CPI_offset'],
285
+ key=lambda vo: vo['year']
287
286
  )
288
287
 
289
288
  rate_adjustment_vals = (
290
- self.sel["parameter_indexing_CPI_offset"]["year"]
291
- >= cpi_min_year["year"]
289
+ self.sel['parameter_indexing_CPI_offset']['year']
290
+ >= cpi_min_year['year']
292
291
  )
293
292
  # "Undo" any existing parameter_indexing_CPI_offset for
294
293
  # years after parameter_indexing_CPI_offset has
295
294
  # been updated.
296
295
  self._inflation_rates = self._inflation_rates[
297
- :cpi_min_year["year"] - self.start_year
296
+ :cpi_min_year['year'] - self.start_year
298
297
  ] + self._gfactors.price_inflation_rates(
299
- cpi_min_year["year"], self.LAST_BUDGET_YEAR)
298
+ cpi_min_year['year'], self.LAST_BUDGET_YEAR)
300
299
 
301
300
  # Then apply new parameter_indexing_CPI_offset values to
302
301
  # inflation rates
303
302
  for cpi_vo in rate_adjustment_vals:
304
303
  self._inflation_rates[
305
- cpi_vo["year"] - self.start_year
306
- ] += cpi_vo["value"]
304
+ cpi_vo['year'] - self.start_year
305
+ ] += cpi_vo['value']
307
306
  # 1. Delete all unknown values.
308
307
  # 1.a For revision, these are years specified after cpi_min_year.
309
308
  to_delete = {}
310
309
  for param in params:
311
310
  if (
312
- param == "parameter_indexing_CPI_offset" or
311
+ param == 'parameter_indexing_CPI_offset' or
313
312
  param in self._wage_indexed
314
313
  ):
315
314
  continue
316
- if param.endswith("-indexed"):
317
- param = param.split("-indexed")[0]
318
- if self._data[param].get("indexed", False):
315
+ if param.endswith('-indexed'):
316
+ param = param.split('-indexed')[0]
317
+ if self._data[param].get('indexed', False):
319
318
  to_delete[param] = (
320
- self.sel[param]["year"] > cpi_min_year["year"]
319
+ self.sel[param]['year'] > cpi_min_year['year']
321
320
  )
322
321
  needs_reset.append(param)
323
322
  self.delete(to_delete, **kwargs)
@@ -351,7 +350,7 @@ class Parameters(pt.Parameters):
351
350
  # only revert param in 2026 if it's not in revision
352
351
  if params.get(param) is None:
353
352
  # grab param values from 2017
354
- vos = self.sel[param]["year"] == pyear
353
+ vos = self.sel[param]['year'] == pyear
355
354
  # use final_ifactor to inflate from 2017 to 2026
356
355
  for vo in vos:
357
356
  long_param_vals[param].append(
@@ -359,7 +358,7 @@ class Parameters(pt.Parameters):
359
358
  dict(
360
359
  vo,
361
360
  value=min(9e99, round(
362
- vo["value"] * final_ifactor, 0)),
361
+ vo['value'] * final_ifactor, 0)),
363
362
  year=fyear,
364
363
  )
365
364
  )
@@ -370,36 +369,37 @@ class Parameters(pt.Parameters):
370
369
  for param in self._data:
371
370
  if (
372
371
  param in params or
373
- param == "parameter_indexing_CPI_offset" or
372
+ param == 'parameter_indexing_CPI_offset' or
374
373
  param in self._wage_indexed
375
374
  ):
376
375
  continue
377
- if self._data[param].get("indexed", False):
376
+ if self._data[param].get('indexed', False):
378
377
  # pylint: disable=singleton-comparison
379
- to_delete[param] = self.sel[param]["_auto"] == True
378
+ to_delete[param] = self.sel[param]['_auto'] == True
380
379
  # pylint warning message:
381
380
  # Comparison 'self.sel[param]['_auto'] == True' should
382
381
  # be 'self.sel[param]['_auto'] is True' if checking for
383
382
  # the singleton value True, or
384
383
  # 'bool(self.sel[param]['_auto'])' if testing for
385
384
  # truthiness
385
+ # NOTE: following either pylint suggestion causes errors
386
386
  # pylint: enable=singleton-comparison
387
387
  needs_reset.append(param)
388
388
 
389
389
  self.delete(to_delete, **kwargs)
390
390
 
391
- self.extend(label="year")
391
+ self.extend(label='year')
392
392
 
393
393
  # 2. Handle -indexed parameters.
394
394
  self.label_to_extend = None
395
395
  index_affected = set([])
396
396
  for param, values in params.items():
397
- if param.endswith("-indexed"):
398
- base_param = param.split("-indexed")[0]
399
- if not self._data[base_param].get("indexable", None):
400
- msg = f"Parameter {base_param} is not indexable."
401
- raise pt.ValidationError(
402
- {"errors": {base_param: msg}}, labels=None
397
+ if param.endswith('-indexed'):
398
+ base_param = param.split('-indexed')[0]
399
+ if not self._data[base_param].get('indexable', None):
400
+ msg = f'Parameter {base_param} is not indexable'
401
+ raise paramtools.ValidationError(
402
+ {'errors': {base_param: msg}}, labels=None
403
403
  )
404
404
  index_affected |= {param, base_param}
405
405
  indexed_changes = {}
@@ -407,39 +407,36 @@ class Parameters(pt.Parameters):
407
407
  indexed_changes[self.start_year] = values
408
408
  elif isinstance(values, list):
409
409
  for vo in values:
410
- indexed_changes[vo.get("year", self.start_year)] = vo[
411
- "value"
412
- ]
410
+ indexed_changes[
411
+ vo.get('year', self.start_year)
412
+ ] = vo['value']
413
413
  else:
414
- msg = (
415
- "Index adjustment parameter must be a boolean or "
416
- "list."
417
- )
418
- raise pt.ValidationError(
419
- {"errors": {base_param: msg}}, labels=None
414
+ msg = 'Index adjustment parameter must be boolean or list'
415
+ raise paramtools.ValidationError(
416
+ {'errors': {base_param: msg}}, labels=None
420
417
  )
421
418
  # 2.a Adjust values less than first year in which index status
422
419
  # was changed.
423
420
  if base_param in params:
424
421
  min_index_change_year = min(indexed_changes.keys())
425
- vos = self.sel[params[base_param]]["year"].lt(
422
+ vos = self.sel[params[base_param]]['year'].lt(
426
423
  min_index_change_year, strict=False
427
424
  )
428
425
 
429
426
  if list(vos):
430
- min_adj_year = min(vos, key=lambda vo: vo["year"])[
431
- "year"
432
- ]
427
+ min_adj_year = min(
428
+ vos, key=lambda vo: vo['year']
429
+ )['year']
433
430
  self.delete(
434
431
  {
435
432
  base_param:
436
- self.sel[base_param]["year"] > min_adj_year
433
+ self.sel[base_param]['year'] > min_adj_year
437
434
  }
438
435
  )
439
436
  super().adjust({base_param: vos}, **kwargs)
440
437
  self.extend(
441
438
  params=[base_param],
442
- label="year",
439
+ label='year',
443
440
  label_values=list(
444
441
  range(self.start_year, min_index_change_year)
445
442
  ),
@@ -450,7 +447,7 @@ class Parameters(pt.Parameters):
450
447
  # Get and delete all default values after year where
451
448
  # indexed status changed.
452
449
  self.delete(
453
- {base_param: self.sel[base_param]["year"] > year}
450
+ {base_param: self.sel[base_param]['year'] > year}
454
451
  )
455
452
 
456
453
  # 2.b Extend values for this parameter to the year where
@@ -458,25 +455,25 @@ class Parameters(pt.Parameters):
458
455
  if year > self.start_year:
459
456
  self.extend(
460
457
  params=[base_param],
461
- label="year",
458
+ label='year',
462
459
  label_values=list(
463
460
  range(self.start_year, year + 1)
464
461
  ),
465
462
  )
466
463
 
467
464
  # 2.c Set indexed status.
468
- self._data[base_param]["indexed"] = indexed_val
465
+ self._data[base_param]['indexed'] = indexed_val
469
466
 
470
467
  # 2.d Adjust with values greater than or equal to current
471
468
  # year in params
472
469
  if base_param in params:
473
- vos = self.sel[params[base_param]]["year"].gte(
470
+ vos = self.sel[params[base_param]]['year'].gte(
474
471
  year, strict=False
475
472
  )
476
473
  super().adjust({base_param: vos}, **kwargs)
477
474
 
478
475
  # 2.e Extend values through remaining years.
479
- self.extend(params=[base_param], label="year")
476
+ self.extend(params=[base_param], label='year')
480
477
 
481
478
  needs_reset.append(base_param)
482
479
  # Re-instate ops.
@@ -525,7 +522,7 @@ class Parameters(pt.Parameters):
525
522
 
526
523
  def wage_growth_rates(self, year=None):
527
524
  """
528
- Return wage growth rates used in parameter indexing.
525
+ Returns wage growth rates used in parameter indexing.
529
526
  """
530
527
  if year is not None:
531
528
  syr = max(self.start_year, self._gfactors.first_year)
@@ -534,7 +531,7 @@ class Parameters(pt.Parameters):
534
531
 
535
532
  def inflation_rates(self, year=None):
536
533
  """
537
- Return price inflation rates used in parameter indexing.
534
+ Returns price inflation rates used in parameter indexing.
538
535
  """
539
536
  if year is not None:
540
537
  syr = max(self.start_year, self._gfactors.first_year)
@@ -552,7 +549,7 @@ class Parameters(pt.Parameters):
552
549
  """
553
550
  # pylint: disable=too-many-arguments,too-many-positional-arguments
554
551
  # Handle case where project hasn't been initialized yet
555
- if getattr(self, "_data", None) is None:
552
+ if getattr(self, '_data', None) is None:
556
553
  return Parameters.__init__(
557
554
  self, start_year, num_years, last_known_year=last_known_year,
558
555
  removed=removed, redefined=redefined,
@@ -593,71 +590,67 @@ class Parameters(pt.Parameters):
593
590
  """
594
591
  # pylint: disable=too-many-branches
595
592
  if not isinstance(revision, dict):
596
- raise pt.ValidationError(
597
- {"errors": {"schema": "Revision must be a dictionary."}},
593
+ raise paramtools.ValidationError(
594
+ {'errors': {'schema': 'Revision must be a dictionary'}},
598
595
  None
599
596
  )
600
597
  new_params = defaultdict(list)
601
598
  for param, val in revision.items():
602
599
  if not isinstance(param, str):
603
- msg = f"Parameter {param} is not a string."
604
- raise pt.ValidationError(
605
- {"errors": {"schema": msg}},
600
+ msg = f'Parameter {param} is not a string'
601
+ raise paramtools.ValidationError(
602
+ {'errors': {'schema': msg}},
606
603
  None
607
604
  )
608
605
  if (
609
606
  param not in self._data and
610
- param.split("-indexed")[0] not in self._data
607
+ param.split('-indexed')[0] not in self._data
611
608
  ):
612
609
  if self._removed_params and param in self._removed_params:
613
- msg = f"{param} {self._removed_params[param]}"
610
+ msg = f'{param} {self._removed_params[param]}'
614
611
  elif (
615
612
  self._redefined_params and param in self._redefined_params
616
613
  ):
617
614
  msg = self._redefined_params[param]
618
615
  else:
619
- msg = f"Parameter {param} does not exist."
620
- raise pt.ValidationError(
621
- {"errors": {"schema": msg}},
616
+ msg = f'Parameter {param} does not exist'
617
+ raise paramtools.ValidationError(
618
+ {'errors': {'schema': msg}},
622
619
  None
623
620
  )
624
- if param.endswith("-indexed"):
621
+ if param.endswith('-indexed'):
625
622
  for year, yearval in val.items():
626
- new_params[param] += [{"year": year, "value": yearval}]
623
+ new_params[param] += [{'year': year, 'value': yearval}]
627
624
  elif isinstance(val, dict):
628
625
  for year, yearval in val.items():
629
626
  val = getattr(self, param)
630
627
  if (
631
- self._data[param].get("type", None) == "str" and
628
+ self._data[param].get('type', None) == 'str' and
632
629
  isinstance(yearval, str)
633
630
  ):
634
- new_params[param] += [{"value": yearval}]
631
+ new_params[param] += [{'value': yearval}]
635
632
  continue
636
633
 
637
634
  yearval = np.array(yearval)
638
635
  if (
639
- getattr(val, "shape", None) and
636
+ getattr(val, 'shape', None) and
640
637
  yearval.shape != val[0].shape
641
638
  ):
642
639
  exp_dims = val[0].shape
643
640
  if exp_dims == tuple():
644
- msg = (
645
- f"{param} is not an array "
646
- f"parameter."
647
- )
641
+ msg = f'{param} is not an array parameter'
648
642
  elif yearval.shape:
649
643
  msg = (
650
- f"{param} has {yearval.shape[0]} elements "
651
- f"but should only have {exp_dims[0]} "
652
- f"elements."
644
+ f'{param} has {yearval.shape[0]} elements '
645
+ f'but should only have {exp_dims[0]} elements'
653
646
  )
654
647
  else:
655
648
  msg = (
656
- f"{param} is an array parameter with "
657
- f"{exp_dims[0]} elements."
649
+ f'{param} is an array parameter with '
650
+ f'{exp_dims[0]} elements'
658
651
  )
659
- raise pt.ValidationError(
660
- {"errors": {"schema": msg}},
652
+ raise paramtools.ValidationError(
653
+ {'errors': {'schema': msg}},
661
654
  None
662
655
  )
663
656
 
@@ -669,11 +662,11 @@ class Parameters(pt.Parameters):
669
662
  new_params[param] += value_objects
670
663
  else:
671
664
  msg = (
672
- f"{param} must be a year:value dictionary "
673
- f"if you are not using the new adjust method."
665
+ f'{param} must be a year:value dictionary '
666
+ 'if you are not using the new adjust method'
674
667
  )
675
- raise pt.ValidationError(
676
- {"errors": {"schema": msg}},
668
+ raise paramtools.ValidationError(
669
+ {'errors': {'schema': msg}},
677
670
  None
678
671
  )
679
672
  return self.adjust(
@@ -689,17 +682,17 @@ class Parameters(pt.Parameters):
689
682
  @property
690
683
  def current_year(self):
691
684
  """Propery docstring"""
692
- return self.label_grid["year"][0]
685
+ return self.label_grid['year'][0]
693
686
 
694
687
  @property
695
688
  def start_year(self):
696
689
  """Propery docstring"""
697
- return self._stateless_label_grid["year"][0]
690
+ return self._stateless_label_grid['year'][0]
698
691
 
699
692
  @property
700
693
  def end_year(self):
701
694
  """Propery docstring"""
702
- return self._stateless_label_grid["year"][-1]
695
+ return self._stateless_label_grid['year'][-1]
703
696
 
704
697
  @property
705
698
  def num_years(self):
@@ -765,7 +758,7 @@ class Parameters(pt.Parameters):
765
758
  if obj is None:
766
759
  return {}
767
760
 
768
- full_dict = pt.read_json(obj)
761
+ full_dict = paramtools.read_json(obj)
769
762
 
770
763
  # check top-level key contents of dictionary
771
764
  if topkey in full_dict.keys():
@@ -781,14 +774,14 @@ class Parameters(pt.Parameters):
781
774
 
782
775
  def metadata(self):
783
776
  """
784
- Return parameter specification.
777
+ Returns parameter specification.
785
778
  """
786
779
  return self.specification(meta_data=True, use_state=False)
787
780
 
788
781
  @staticmethod
789
782
  def years_in_revision(revision):
790
783
  """
791
- Return list of years in specified revision dictionary, which is
784
+ Returns list of years in specified revision dictionary, which is
792
785
  assumed to have a param:year:value format.
793
786
  """
794
787
  assert isinstance(revision, dict)
@@ -808,17 +801,94 @@ class Parameters(pt.Parameters):
808
801
  ``pol.EITC_c``.
809
802
  """
810
803
  if (
811
- attr.startswith("_") and
812
- attr[1:] in super().__getattribute__("_data")
804
+ attr.startswith('_') and
805
+ attr[1:] in super().__getattribute__('_data')
813
806
  ):
814
807
  return self.to_array(
815
808
  attr[1:], year=list(range(self.start_year, self.end_year + 1))
816
809
  )
817
- raise AttributeError(f"{attr} is not defined.")
810
+ raise AttributeError(f'{attr} is not defined')
811
+
812
+ def extend_func(
813
+ self,
814
+ param: str,
815
+ extend_vo: paramtools.ValueObject,
816
+ known_vo: paramtools.ValueObject,
817
+ extend_grid: List,
818
+ label: str,
819
+ ):
820
+ """
821
+ Method for applying indexing rates to extended parameter values.
822
+ Returns:
823
+ - `extend_vo`: New `paramtools.ValueObject`.
824
+ """
825
+ # pylint: disable=too-many-arguments,too-many-positional-arguments
826
+ # pylint: disable=too-many-locals,too-many-branches
827
+ if not self.uses_extend_func or not self._data[param].get(
828
+ 'indexed', False
829
+ ):
830
+ return extend_vo
831
+ known_val = known_vo[label]
832
+ toext_val = extend_vo[label]
833
+ if toext_val == known_val:
834
+ return extend_vo
835
+
836
+ trace = False
837
+ # params_to_trace = ['II_em']
838
+ # params_to_trace = ['II_brk3']
839
+ params_to_trace = ['EITC_c']
840
+ # params_to_trace = ['ID_AmountCap_Switch']
841
+ if trace and param in params_to_trace: # pragma: no cover
842
+ vlabel = None
843
+ vvalue = None
844
+ if len(extend_vo) > 2:
845
+ extend_vo_keys = extend_vo.keys()
846
+ vo_labels = ['MARS', 'EIC', 'idedtype']
847
+ for vo_label in vo_labels:
848
+ if vo_label in extend_vo_keys:
849
+ vlabel = vo_label
850
+ vvalue = extend_vo[vlabel]
851
+ break
852
+ assert vlabel, f'{param} has no valid vector label'
853
+ print(
854
+ '***param,yr0,yr1,vlabel,vvalue=',
855
+ param, known_val, toext_val, vlabel, vvalue,
856
+ )
857
+ # print('extend_vo=', extend_vo)
858
+ # print('known_vo=', known_vo)
859
+ print('before:extend_vo[value]=', extend_vo['value'])
860
+
861
+ known_ix = extend_grid.index(known_val)
862
+ toext_ix = extend_grid.index(toext_val)
863
+ if toext_ix > known_ix:
864
+ # grow value according to the indexing rate supplied by
865
+ # the user defined self.get_index_rate method
866
+ for ix in range(known_ix, toext_ix):
867
+ v = extend_vo['value'] * (
868
+ 1 + self.get_index_rate(param, extend_grid[ix])
869
+ )
870
+ extend_vo['value'] = np.round(v, 2) if v < 9e99 else 9e99
871
+ else: # pragma: no cover
872
+ # shrink value according to the indexing rate supplied by
873
+ # the user defined self.get_index_rate method
874
+ for ix in reversed(range(toext_ix, known_ix)):
875
+ v = (
876
+ extend_vo['value']
877
+ * (1 + self.get_index_rate(param, extend_grid[ix])) ** -1
878
+ )
879
+ extend_vo['value'] = np.round(v, 2) if v < 9e99 else 9e99
880
+
881
+ if trace and param in params_to_trace: # pragma: no cover
882
+ print('after:extend_vo[value]=', extend_vo['value'])
883
+ if toext_val == 2035:
884
+ for pname in params_to_trace:
885
+ print(f'data[{pname}]=', self._data[pname])
886
+
887
+ return extend_vo
818
888
 
819
889
 
820
890
  TaxcalcReform = Union[str, Mapping[int, Any]]
821
- ParamToolsAdjustment = Union[str, List[pt.ValueObject]]
891
+ ParamToolsAdjustment = Union[str, List[paramtools.ValueObject]]
822
892
 
823
893
 
824
894
  def is_paramtools_format(params: Union[TaxcalcReform, ParamToolsAdjustment]):
@@ -845,11 +915,11 @@ def is_paramtools_format(params: Union[TaxcalcReform, ParamToolsAdjustment]):
845
915
  "ss_rate": [{"year": 2024, "value": 0.2}]}
846
916
  }
847
917
 
848
- Returns
918
+ Returns:
849
919
  -------
850
920
  bool:
851
- Whether ``params`` is likely to be a ParamTools formatted adjustment or
852
- not.
921
+ Whether ``params`` is likely to be a ParamTools formatted
922
+ adjustment or not.
853
923
  """
854
924
  for data in params.values():
855
925
  if isinstance(data, dict):