taxcalc 4.2.2__py3-none-any.whl → 4.3.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.
@@ -43,7 +43,7 @@ def test_incorrect_class_instantiation():
43
43
  Test incorrect instantiation of Policy class object.
44
44
  """
45
45
  with pytest.raises(ValueError):
46
- Policy(gfactors=list())
46
+ Policy(gfactors=[])
47
47
 
48
48
 
49
49
  def test_correct_class_instantiation():
@@ -54,7 +54,7 @@ def test_correct_class_instantiation():
54
54
  assert pol
55
55
  pol.implement_reform({})
56
56
  with pytest.raises(pt.ValidationError):
57
- pol.implement_reform(list())
57
+ pol.implement_reform([])
58
58
  with pytest.raises(pt.ValidationError):
59
59
  pol.implement_reform({2099: {'II_em': 99000}})
60
60
  pol.set_year(2019)
@@ -621,7 +621,7 @@ def test_section_titles(tests_path):
621
621
  structured like the VALID_SECTION dictionary (see below) and
622
622
  extracted from the specified html_text.
623
623
  """
624
- sdict = dict()
624
+ sdict = {}
625
625
  for line in md_text.splitlines():
626
626
  # This is shown as an empty case in current law policy and
627
627
  # validation.
@@ -647,7 +647,6 @@ def test_section_titles(tests_path):
647
647
  'As A Percent Of Deductible Expenses')
648
648
  cgqd_tax_same = ('Tax All Capital Gains And Dividends The Same '
649
649
  'As Regular Taxable Income')
650
- # pylint: disable=bad-continuation
651
650
  valid_dict = {
652
651
  '': { # empty section_1 implies parameter not displayed in Tax-Brain
653
652
  '': 0
@@ -737,11 +736,11 @@ def test_section_titles(tests_path):
737
736
  }
738
737
  # check validity of parameter section titles in policy_current_law.json
739
738
  path = os.path.join(tests_path, '..', 'policy_current_law.json')
740
- with open(path, 'r') as clpfile:
739
+ with open(path, 'r', encoding='utf-8') as clpfile:
741
740
  clpdict = json.load(clpfile)
742
741
  clpdict.pop("schema", None)
743
742
  # ... make sure ever clpdict section title is in valid_dict
744
- clp_dict = dict() # dictionary of clp section titles structured like valid
743
+ clp_dict = {} # dictionary of clp section titles structured like valid
745
744
  for pname in clpdict:
746
745
  param = clpdict[pname]
747
746
  assert isinstance(param, dict)
@@ -754,28 +753,28 @@ def test_section_titles(tests_path):
754
753
  if sec2title not in clp_dict[sec1title]:
755
754
  clp_dict[sec1title][sec2title] = 0
756
755
  # ... make sure every valid_dict section title is in clpdict
757
- for sec1title in valid_dict:
758
- assert isinstance(valid_dict[sec1title], dict)
756
+ for sec1title, secdict in valid_dict.items():
757
+ assert isinstance(secdict, dict)
759
758
  assert sec1title in clp_dict
760
- for sec2title in valid_dict[sec1title]:
759
+ for sec2title in secdict:
761
760
  assert sec2title in clp_dict[sec1title]
762
761
  # check validity of parameter section titles in docs/uguide.htmx skeleton
763
762
  path = os.path.join(tests_path, '..', '..', 'docs', 'guide',
764
763
  'policy_params.md')
765
- with open(path, 'r') as md_file:
764
+ with open(path, 'r', encoding='utf-8') as md_file:
766
765
  md_text = md_file.read()
767
766
  md_dict = generate_section_dictionary(md_text)
768
767
  # ... make sure every md_dict section title is in valid_dict
769
- for sec1title in md_dict:
770
- assert isinstance(md_dict[sec1title], dict)
768
+ for sec1title,secdict in md_dict.items():
769
+ assert isinstance(secdict, dict)
771
770
  assert sec1title in valid_dict
772
- for sec2title in md_dict[sec1title]:
771
+ for sec2title in secdict:
773
772
  assert sec2title in valid_dict[sec1title]
774
773
  # ... make sure every valid_dict section title is in md_dict
775
- for sec1title in valid_dict:
776
- assert isinstance(valid_dict[sec1title], dict)
774
+ for sec1title, secdict in valid_dict.items():
775
+ assert isinstance(secdict, dict)
777
776
  assert sec1title in md_dict
778
- for sec2title in valid_dict[sec1title]:
777
+ for sec2title in secdict:
779
778
  assert sec2title in md_dict[sec1title]
780
779
 
781
780
 
@@ -785,7 +784,7 @@ def test_description_punctuation(tests_path):
785
784
  """
786
785
  # read JSON file into a dictionary
787
786
  path = os.path.join(tests_path, '..', 'policy_current_law.json')
788
- with open(path, 'r') as jsonfile:
787
+ with open(path, 'r', encoding='utf-8') as jsonfile:
789
788
  dct = json.load(jsonfile)
790
789
  dct.pop("schema", None)
791
790
  all_desc_ok = True
@@ -931,8 +930,8 @@ def test_index_offset_reform():
931
930
  policy2 = Policy()
932
931
  policy2.implement_reform(reform2) # caused T-C crash before PR#2364
933
932
  # extract from policy1 and policy2 the parameter values of CTC_c
934
- pvalue1 = dict()
935
- pvalue2 = dict()
933
+ pvalue1 = {}
934
+ pvalue2 = {}
936
935
  for cyr in [2019, 2020, 2021]:
937
936
  policy1.set_year(cyr)
938
937
  pvalue1[cyr] = policy1.CTC_c[0]
@@ -945,8 +944,7 @@ def test_index_offset_reform():
945
944
  # ... indexing of CTC_c begins shows up first in 2021 parameter values
946
945
  assert pvalue1[2021] > pvalue1[2020]
947
946
  assert pvalue2[2021] > pvalue2[2020]
948
- # ... calculate expected pvalue2[2021] from offset and pvalue1 values
949
- indexrate1 = pvalue1[2021] / pvalue1[2020] - 1.
947
+ # ... calculate expected pvalue2[2021] from inflation rates and offset
950
948
  syear = Policy.JSON_START_YEAR
951
949
  expindexrate = cpiu_rates[2020 - syear] + offset
952
950
  expvalue = round(pvalue2[2020] * (1. + expindexrate), 2)
@@ -1032,525 +1030,509 @@ def test_raise_errors_regression():
1032
1030
  assert pol.errors
1033
1031
 
1034
1032
 
1035
- class TestAdjust:
1033
+ def test_simple_adj():
1036
1034
  """
1037
- Test update and indexing rules as defined in the Parameters docstring.
1038
-
1039
- Each test implements a Tax-Calculator style reform and a pt styled
1040
- reform, checks that the updated values are equal, and then, tests that
1041
- values were extended and indexed (or not indexed) correctly.
1035
+ Test updating a 2D parameter that is indexed to inflation.
1042
1036
  """
1043
-
1044
- def test_simple_adj(self):
1045
- """
1046
- Test updating a 2D parameter that is indexed to inflation.
1047
- """
1048
- pol1 = Policy()
1049
- pol1.implement_reform(
1050
- {
1051
- "EITC_c": {
1052
- 2020: [10000, 10001, 10002, 10003],
1053
- 2023: [20000, 20001, 20002, 20003],
1054
- }
1055
- }
1056
- )
1057
-
1058
- pol2 = Policy()
1059
- pol2.adjust(
1060
- {
1061
- "EITC_c": [
1062
- {"year": 2020, "EIC": "0kids", "value": 10000},
1063
- {"year": 2020, "EIC": "1kid", "value": 10001},
1064
- {"year": 2020, "EIC": "2kids", "value": 10002},
1065
- {"year": 2020, "EIC": "3+kids", "value": 10003},
1066
- {"year": 2023, "EIC": "0kids", "value": 20000},
1067
- {"year": 2023, "EIC": "1kid", "value": 20001},
1068
- {"year": 2023, "EIC": "2kids", "value": 20002},
1069
- {"year": 2023, "EIC": "3+kids", "value": 20003},
1070
- ]
1071
- }
1072
- )
1073
- cmp_policy_objs(pol1, pol2)
1074
-
1075
- pol0 = Policy()
1076
- pol0.set_year(2019)
1077
- pol2.set_year(2019)
1078
-
1079
- assert np.allclose(pol0.EITC_c, pol2.EITC_c)
1080
-
1081
- pol2.set_state(year=[2020, 2021, 2022, 2023, 2024])
1082
- val2020 = np.array([[10000, 10001, 10002, 10003]])
1083
- val2023 = np.array([[20000, 20001, 20002, 20003]])
1084
-
1085
- exp = np.vstack([
1086
- val2020,
1087
- val2020 * (1 + pol2.inflation_rates(year=2020)),
1088
- (
1089
- val2020 * (1 + pol2.inflation_rates(year=2020))
1090
- ).round(2) * (1 + pol2.inflation_rates(year=2021)),
1091
- val2023,
1092
- val2023 * (1 + pol2.inflation_rates(year=2023)),
1093
- ]).round(2)
1094
- np.testing.assert_allclose(pol2.EITC_c, exp)
1095
-
1096
- def test_adj_without_index_1(self):
1097
- """
1098
- Test update indexed parameter after turning off its
1099
- indexed status.
1100
- """
1101
- pol1 = Policy()
1102
- pol1.implement_reform(
1103
- {
1104
- "EITC_c": {
1105
- 2020: [10000, 10001, 10002, 10003],
1106
- 2023: [20000, 20001, 20002, 20003],
1107
- },
1108
- "EITC_c-indexed": {2019: False},
1109
- }
1110
- )
1111
-
1112
- pol2 = Policy()
1113
- pol2.adjust(
1114
- {
1115
- "EITC_c": [
1116
- {"year": 2020, "EIC": "0kids", "value": 10000},
1117
- {"year": 2020, "EIC": "1kid", "value": 10001},
1118
- {"year": 2020, "EIC": "2kids", "value": 10002},
1119
- {"year": 2020, "EIC": "3+kids", "value": 10003},
1120
- {"year": 2023, "EIC": "0kids", "value": 20000},
1121
- {"year": 2023, "EIC": "1kid", "value": 20001},
1122
- {"year": 2023, "EIC": "2kids", "value": 20002},
1123
- {"year": 2023, "EIC": "3+kids", "value": 20003},
1124
- ],
1125
- "EITC_c-indexed": [{"year": 2019, "value": False}],
1037
+ pol1 = Policy()
1038
+ pol1.implement_reform(
1039
+ {
1040
+ "EITC_c": {
1041
+ 2020: [10000, 10001, 10002, 10003],
1042
+ 2023: [20000, 20001, 20002, 20003],
1126
1043
  }
1127
- )
1128
- cmp_policy_objs(pol1, pol2)
1044
+ }
1045
+ )
1046
+ pol2 = Policy()
1047
+ pol2.adjust(
1048
+ {
1049
+ "EITC_c": [
1050
+ {"year": 2020, "EIC": "0kids", "value": 10000},
1051
+ {"year": 2020, "EIC": "1kid", "value": 10001},
1052
+ {"year": 2020, "EIC": "2kids", "value": 10002},
1053
+ {"year": 2020, "EIC": "3+kids", "value": 10003},
1054
+ {"year": 2023, "EIC": "0kids", "value": 20000},
1055
+ {"year": 2023, "EIC": "1kid", "value": 20001},
1056
+ {"year": 2023, "EIC": "2kids", "value": 20002},
1057
+ {"year": 2023, "EIC": "3+kids", "value": 20003},
1058
+ ]
1059
+ }
1060
+ )
1061
+ cmp_policy_objs(pol1, pol2)
1129
1062
 
1130
- pol0 = Policy()
1131
- pol0.set_year(2019)
1132
- pol2.set_year(2019)
1063
+ pol0 = Policy()
1064
+ pol0.set_year(2019)
1065
+ pol2.set_year(2019)
1133
1066
 
1134
- assert np.allclose(pol0.EITC_c, pol2.EITC_c)
1067
+ assert np.allclose(pol0.EITC_c, pol2.EITC_c)
1135
1068
 
1136
- pol2.set_state(year=[2020, 2021, 2022, 2023, 2024])
1069
+ pol2.set_state(year=[2020, 2021, 2022, 2023, 2024])
1070
+ val2020 = np.array([[10000, 10001, 10002, 10003]])
1071
+ val2023 = np.array([[20000, 20001, 20002, 20003]])
1137
1072
 
1138
- val2020 = np.array([[10000, 10001, 10002, 10003]])
1139
- val2023 = np.array([[20000, 20001, 20002, 20003]])
1073
+ exp = np.vstack([
1074
+ val2020,
1075
+ val2020 * (1 + pol2.inflation_rates(year=2020)),
1076
+ (
1077
+ val2020 * (1 + pol2.inflation_rates(year=2020))
1078
+ ).round(2) * (1 + pol2.inflation_rates(year=2021)),
1079
+ val2023,
1080
+ val2023 * (1 + pol2.inflation_rates(year=2023)),
1081
+ ]).round(2)
1082
+ np.testing.assert_allclose(pol2.EITC_c, exp)
1140
1083
 
1141
- exp = np.vstack([
1142
- val2020,
1143
- val2020,
1144
- val2020,
1145
- val2023,
1146
- val2023,
1147
- ]).round(2)
1148
- np.testing.assert_allclose(pol2.EITC_c, exp)
1149
1084
 
1150
- def test_adj_without_index_2(self):
1151
- """
1152
- Test updating an indexed parameter, making it unindexed,
1153
- and then adjusting it again.
1154
- """
1155
- pol1 = Policy()
1156
- pol1.implement_reform(
1157
- {
1158
- "EITC_c": {
1159
- 2020: [10000, 10001, 10002, 10003],
1160
- 2023: [20000, 20001, 20002, 20003],
1161
- },
1162
- "EITC_c-indexed": {2022: False},
1163
- }
1164
- )
1085
+ def test_adj_without_index_1():
1086
+ """
1087
+ Test update indexed parameter after turning off its indexed status.
1088
+ """
1089
+ pol1 = Policy()
1090
+ pol1.implement_reform(
1091
+ {
1092
+ "EITC_c": {
1093
+ 2020: [10000, 10001, 10002, 10003],
1094
+ 2023: [20000, 20001, 20002, 20003],
1095
+ },
1096
+ "EITC_c-indexed": {2019: False},
1097
+ }
1098
+ )
1099
+ pol2 = Policy()
1100
+ pol2.adjust(
1101
+ {
1102
+ "EITC_c": [
1103
+ {"year": 2020, "EIC": "0kids", "value": 10000},
1104
+ {"year": 2020, "EIC": "1kid", "value": 10001},
1105
+ {"year": 2020, "EIC": "2kids", "value": 10002},
1106
+ {"year": 2020, "EIC": "3+kids", "value": 10003},
1107
+ {"year": 2023, "EIC": "0kids", "value": 20000},
1108
+ {"year": 2023, "EIC": "1kid", "value": 20001},
1109
+ {"year": 2023, "EIC": "2kids", "value": 20002},
1110
+ {"year": 2023, "EIC": "3+kids", "value": 20003},
1111
+ ],
1112
+ "EITC_c-indexed": [{"year": 2019, "value": False}],
1113
+ }
1114
+ )
1115
+ cmp_policy_objs(pol1, pol2)
1165
1116
 
1166
- pol2 = Policy()
1167
- pol2.adjust(
1168
- {
1169
- "EITC_c": [
1170
- {"year": 2020, "EIC": "0kids", "value": 10000},
1171
- {"year": 2020, "EIC": "1kid", "value": 10001},
1172
- {"year": 2020, "EIC": "2kids", "value": 10002},
1173
- {"year": 2020, "EIC": "3+kids", "value": 10003},
1174
- {"year": 2023, "EIC": "0kids", "value": 20000},
1175
- {"year": 2023, "EIC": "1kid", "value": 20001},
1176
- {"year": 2023, "EIC": "2kids", "value": 20002},
1177
- {"year": 2023, "EIC": "3+kids", "value": 20003},
1178
- ],
1179
- "EITC_c-indexed": [{"year": 2022, "value": False}],
1180
- }
1181
- )
1182
- cmp_policy_objs(pol1, pol2)
1117
+ pol0 = Policy()
1118
+ pol0.set_year(2019)
1119
+ pol2.set_year(2019)
1183
1120
 
1184
- pol0 = Policy()
1185
- pol0.set_year(2019)
1186
- pol2.set_year(2019)
1121
+ assert np.allclose(pol0.EITC_c, pol2.EITC_c)
1187
1122
 
1188
- assert np.allclose(pol0.EITC_c, pol2.EITC_c)
1123
+ pol2.set_state(year=[2020, 2021, 2022, 2023, 2024])
1189
1124
 
1190
- pol2.set_state(year=[2020, 2021, 2022, 2023, 2024])
1125
+ val2020 = np.array([[10000, 10001, 10002, 10003]])
1126
+ val2023 = np.array([[20000, 20001, 20002, 20003]])
1191
1127
 
1192
- val2020 = np.array([[10000, 10001, 10002, 10003]])
1193
- val2023 = np.array([[20000, 20001, 20002, 20003]])
1128
+ exp = np.vstack([
1129
+ val2020,
1130
+ val2020,
1131
+ val2020,
1132
+ val2023,
1133
+ val2023,
1134
+ ]).round(2)
1135
+ np.testing.assert_allclose(pol2.EITC_c, exp)
1194
1136
 
1195
- exp = np.vstack([
1196
- val2020,
1197
- val2020 * (1 + pol2.inflation_rates(year=2020)),
1198
- (
1199
- val2020 * (1 + pol2.inflation_rates(year=2020))
1200
- ).round(2) * (1 + pol2.inflation_rates(year=2021)),
1201
- val2023,
1202
- val2023,
1203
- ]).round(2)
1204
- np.testing.assert_allclose(pol2.EITC_c, exp)
1205
1137
 
1206
- def test_activate_index(self):
1207
- """
1208
- Test changing a non-indexed parameter to an indexed parameter.
1209
- """
1210
- pol1 = Policy()
1211
- pol1.implement_reform({
1212
- "CTC_c": {2022: 2000},
1213
- "CTC_c-indexed": {2022: True}
1214
- })
1215
-
1216
- pol2 = Policy()
1217
- pol2.adjust(
1218
- {
1219
- "CTC_c": [{"year": 2022, "value": 2000}],
1220
- "CTC_c-indexed": [{"year": 2022, "value": True}],
1221
- }
1222
- )
1223
- cmp_policy_objs(pol1, pol2)
1138
+ def test_adj_without_index_2():
1139
+ """
1140
+ Test updating an indexed parameter, making it unindexed,
1141
+ and then adjusting it again.
1142
+ """
1143
+ pol1 = Policy()
1144
+ pol1.implement_reform(
1145
+ {
1146
+ "EITC_c": {
1147
+ 2020: [10000, 10001, 10002, 10003],
1148
+ 2023: [20000, 20001, 20002, 20003],
1149
+ },
1150
+ "EITC_c-indexed": {2022: False},
1151
+ }
1152
+ )
1153
+ pol2 = Policy()
1154
+ pol2.adjust(
1155
+ {
1156
+ "EITC_c": [
1157
+ {"year": 2020, "EIC": "0kids", "value": 10000},
1158
+ {"year": 2020, "EIC": "1kid", "value": 10001},
1159
+ {"year": 2020, "EIC": "2kids", "value": 10002},
1160
+ {"year": 2020, "EIC": "3+kids", "value": 10003},
1161
+ {"year": 2023, "EIC": "0kids", "value": 20000},
1162
+ {"year": 2023, "EIC": "1kid", "value": 20001},
1163
+ {"year": 2023, "EIC": "2kids", "value": 20002},
1164
+ {"year": 2023, "EIC": "3+kids", "value": 20003},
1165
+ ],
1166
+ "EITC_c-indexed": [{"year": 2022, "value": False}],
1167
+ }
1168
+ )
1169
+ cmp_policy_objs(pol1, pol2)
1224
1170
 
1225
- pol0 = Policy()
1226
- pol0.set_year(year=2021)
1227
- pol2.set_state(year=[2021, 2022, 2023])
1228
- exp = np.array([
1229
- pol0.CTC_c[0],
1230
- 2000,
1231
- 2000 * (1 + pol2.inflation_rates(year=2022))
1232
- ]).round(2)
1171
+ pol0 = Policy()
1172
+ pol0.set_year(2019)
1173
+ pol2.set_year(2019)
1233
1174
 
1234
- np.testing.assert_allclose(pol2.CTC_c, exp)
1175
+ assert np.allclose(pol0.EITC_c, pol2.EITC_c)
1235
1176
 
1236
- def test_apply_cpi_offset(self):
1237
- """
1238
- Test applying the parameter_indexing_CPI_offset parameter
1239
- without any other parameters.
1240
- """
1241
- pol1 = Policy()
1242
- pol1.implement_reform(
1243
- {"parameter_indexing_CPI_offset": {2021: -0.001}}
1244
- )
1177
+ pol2.set_state(year=[2020, 2021, 2022, 2023, 2024])
1245
1178
 
1246
- pol2 = Policy()
1247
- pol2.adjust(
1248
- {"parameter_indexing_CPI_offset": [
1249
- {"year": 2021, "value": -0.001}
1250
- ]}
1251
- )
1179
+ val2020 = np.array([[10000, 10001, 10002, 10003]])
1180
+ val2023 = np.array([[20000, 20001, 20002, 20003]])
1252
1181
 
1253
- cmp_policy_objs(pol1, pol2)
1182
+ exp = np.vstack([
1183
+ val2020,
1184
+ val2020 * (1 + pol2.inflation_rates(year=2020)),
1185
+ (
1186
+ val2020 * (1 + pol2.inflation_rates(year=2020))
1187
+ ).round(2) * (1 + pol2.inflation_rates(year=2021)),
1188
+ val2023,
1189
+ val2023,
1190
+ ]).round(2)
1191
+ np.testing.assert_allclose(pol2.EITC_c, exp)
1254
1192
 
1255
- pol0 = Policy()
1256
- pol0.implement_reform({"parameter_indexing_CPI_offset": {2021: 0}})
1257
1193
 
1258
- init_rates = pol0.inflation_rates()
1259
- new_rates = pol2.inflation_rates()
1194
+ def test_activate_index():
1195
+ """
1196
+ Test changing a non-indexed parameter to an indexed parameter.
1197
+ """
1198
+ pol1 = Policy()
1199
+ pol1.implement_reform({
1200
+ "CTC_c": {2022: 2000},
1201
+ "CTC_c-indexed": {2022: True}
1202
+ })
1203
+ pol2 = Policy()
1204
+ pol2.adjust(
1205
+ {
1206
+ "CTC_c": [{"year": 2022, "value": 2000}],
1207
+ "CTC_c-indexed": [{"year": 2022, "value": True}],
1208
+ }
1209
+ )
1210
+ cmp_policy_objs(pol1, pol2)
1260
1211
 
1261
- start_ix = 2021 - pol2.start_year
1212
+ pol0 = Policy()
1213
+ pol0.set_year(year=2021)
1214
+ pol2.set_state(year=[2021, 2022, 2023])
1215
+ exp = np.array([
1216
+ pol0.CTC_c[0],
1217
+ 2000,
1218
+ 2000 * (1 + pol2.inflation_rates(year=2022))
1219
+ ]).round(2)
1262
1220
 
1263
- exp_rates = copy.deepcopy(new_rates)
1264
- exp_rates[start_ix:] -= pol2._parameter_indexing_CPI_offset[start_ix:]
1265
- np.testing.assert_allclose(init_rates, exp_rates)
1221
+ np.testing.assert_allclose(pol2.CTC_c, exp)
1266
1222
 
1267
- # make sure values prior to 2021 were not affected.
1268
- cmp_policy_objs(pol0, pol2, year_range=range(pol2.start_year, 2021))
1269
1223
 
1270
- pol2.set_state(year=[2022, 2023])
1271
- np.testing.assert_equal(
1272
- (pol2.EITC_c[1] / pol2.EITC_c[0] - 1).round(4),
1273
- (pol0.inflation_rates(year=2022) + (-0.001)).round(4),
1274
- )
1224
+ def test_apply_cpi_offset():
1225
+ """
1226
+ Test applying the parameter_indexing_CPI_offset parameter
1227
+ without any other parameters.
1228
+ """
1229
+ pol1 = Policy()
1230
+ pol1.implement_reform(
1231
+ {"parameter_indexing_CPI_offset": {2021: -0.001}}
1232
+ )
1233
+ pol2 = Policy()
1234
+ pol2.adjust(
1235
+ {"parameter_indexing_CPI_offset": [
1236
+ {"year": 2021, "value": -0.001}
1237
+ ]}
1238
+ )
1239
+ cmp_policy_objs(pol1, pol2)
1275
1240
 
1276
- def test_multiple_cpi_swaps(self):
1277
- """
1278
- Test changing a parameter's indexed status multiple times.
1279
- """
1280
- pol1 = Policy()
1281
- pol1.implement_reform(
1282
- {
1283
- "II_em": {2016: 6000, 2018: 7500, 2020: 9000},
1284
- "II_em-indexed": {2016: False, 2018: True},
1285
- }
1286
- )
1241
+ pol0 = Policy()
1242
+ pol0.implement_reform({"parameter_indexing_CPI_offset": {2021: 0}})
1287
1243
 
1288
- pol2 = Policy()
1289
- pol2.adjust(
1290
- {
1291
- "II_em": [
1292
- {"year": 2016, "value": 6000},
1293
- {"year": 2018, "value": 7500},
1294
- {"year": 2020, "value": 9000},
1295
- ],
1296
- "II_em-indexed": [
1297
- {"year": 2016, "value": False},
1298
- {"year": 2018, "value": True},
1299
- ],
1300
- }
1301
- )
1244
+ init_rates = pol0.inflation_rates()
1245
+ new_rates = pol2.inflation_rates()
1302
1246
 
1303
- cmp_policy_objs(pol1, pol2)
1247
+ start_ix = 2021 - pol2.start_year
1304
1248
 
1305
- # check inflation is not applied.
1306
- pol2.set_state(year=[2016, 2017])
1307
- np.testing.assert_equal(
1308
- pol2.II_em[0], pol2.II_em[1]
1309
- )
1249
+ exp_rates = copy.deepcopy(new_rates)
1250
+ exp_rates[start_ix:] -= pol2._parameter_indexing_CPI_offset[start_ix:]
1251
+ np.testing.assert_allclose(init_rates, exp_rates)
1310
1252
 
1311
- # check inflation rate is applied.
1312
- pol2.set_state(year=[2018, 2019])
1313
- np.testing.assert_equal(
1314
- (pol2.II_em[1] / pol2.II_em[0] - 1).round(4),
1315
- pol2.inflation_rates(year=2018),
1316
- )
1253
+ # make sure values prior to 2021 were not affected.
1254
+ cmp_policy_objs(pol0, pol2, year_range=range(pol2.start_year, 2021))
1317
1255
 
1318
- # check inflation rate applied for rest of window.
1319
- window = list(range(2020, pol2.end_year + 1))
1320
- pol2.set_state(year=window)
1321
- np.testing.assert_equal(
1322
- (pol2.II_em[1:] / pol2.II_em[:-1] - 1).round(4),
1323
- [pol2.inflation_rates(year=year) for year in window[:-1]],
1324
- )
1256
+ test_year = Policy.LAST_KNOWN_YEAR
1257
+ pol2.set_state(year=[test_year, test_year + 1])
1258
+ np.testing.assert_equal(
1259
+ (pol2.EITC_c[1] / pol2.EITC_c[0] - 1).round(4),
1260
+ (pol0.inflation_rates(year=test_year) + (-0.001)).round(4),
1261
+ )
1325
1262
 
1326
- def test_multiple_cpi_swaps2(self):
1327
- """
1328
- Test changing the indexed status of multiple parameters multiple
1329
- times.
1330
- """
1331
- pol1 = Policy()
1332
- pol1.implement_reform(
1333
- {
1334
- "II_em": {2016: 6000, 2018: 7500, 2020: 9000},
1335
- "II_em-indexed": {2016: False, 2018: True},
1336
- "SS_Earnings_c": {2016: 300000, 2018: 500000},
1337
- "SS_Earnings_c-indexed": {2017: False, 2019: True},
1338
- "AMT_em-indexed": {2017: False, 2020: True},
1339
- }
1340
- )
1341
1263
 
1342
- pol2 = Policy()
1343
- pol2.adjust(
1344
- {
1345
- "SS_Earnings_c": [
1346
- {"year": 2016, "value": 300000},
1347
- {"year": 2018, "value": 500000},
1348
- ],
1349
- "SS_Earnings_c-indexed": [
1350
- {"year": 2017, "value": False},
1351
- {"year": 2019, "value": True},
1352
- ],
1353
- "AMT_em-indexed": [
1354
- {"year": 2017, "value": False},
1355
- {"year": 2020, "value": True},
1356
- ],
1357
- "II_em": [
1358
- {"year": 2016, "value": 6000},
1359
- {"year": 2018, "value": 7500},
1360
- {"year": 2020, "value": 9000},
1361
- ],
1362
- "II_em-indexed": [
1363
- {"year": 2016, "value": False},
1364
- {"year": 2018, "value": True},
1365
- ],
1366
- }
1367
- )
1264
+ def test_multiple_cpi_swaps():
1265
+ """
1266
+ Test changing a parameter's indexed status multiple times.
1267
+ """
1268
+ pol1 = Policy()
1269
+ pol1.implement_reform(
1270
+ {
1271
+ "II_em": {2016: 6000, 2018: 7500, 2020: 9000},
1272
+ "II_em-indexed": {2016: False, 2018: True},
1273
+ }
1274
+ )
1275
+ pol2 = Policy()
1276
+ pol2.adjust(
1277
+ {
1278
+ "II_em": [
1279
+ {"year": 2016, "value": 6000},
1280
+ {"year": 2018, "value": 7500},
1281
+ {"year": 2020, "value": 9000},
1282
+ ],
1283
+ "II_em-indexed": [
1284
+ {"year": 2016, "value": False},
1285
+ {"year": 2018, "value": True},
1286
+ ],
1287
+ }
1288
+ )
1289
+ cmp_policy_objs(pol1, pol2)
1368
1290
 
1369
- cmp_policy_objs(pol1, pol2)
1291
+ # check inflation is not applied.
1292
+ pol2.set_state(year=[2016, 2017])
1293
+ np.testing.assert_equal(
1294
+ pol2.II_em[0], pol2.II_em[1]
1295
+ )
1370
1296
 
1371
- # Test SS_Earnings_c
1372
- # check inflation is still applied from 2016 to 2017.
1373
- pol2.set_state(year=[2016, 2017])
1374
- np.testing.assert_equal(
1375
- (pol2.SS_Earnings_c[1] / pol2.SS_Earnings_c[0] - 1).round(4),
1376
- pol2.wage_growth_rates(year=2016),
1377
- )
1297
+ # check inflation rate is applied.
1298
+ pol2.set_state(year=[2018, 2019])
1299
+ np.testing.assert_equal(
1300
+ (pol2.II_em[1] / pol2.II_em[0] - 1).round(4),
1301
+ pol2.inflation_rates(year=2018),
1302
+ )
1378
1303
 
1379
- # check inflation rate is not applied after adjustment in 2018.
1380
- pol2.set_state(year=[2018, 2019])
1381
- np.testing.assert_equal(
1382
- pol2.SS_Earnings_c[0], pol2.SS_Earnings_c[1]
1383
- )
1304
+ # check inflation rate applied for rest of window.
1305
+ window = list(range(2020, pol2.end_year + 1))
1306
+ pol2.set_state(year=window)
1307
+ np.testing.assert_equal(
1308
+ (pol2.II_em[1:] / pol2.II_em[:-1] - 1).round(4),
1309
+ [pol2.inflation_rates(year=year) for year in window[:-1]],
1310
+ )
1384
1311
 
1385
- # check inflation rate applied for rest of window.
1386
- window = list(range(2019, pol2.end_year + 1))
1387
- pol2.set_state(year=window)
1388
- np.testing.assert_equal(
1389
- (pol2.SS_Earnings_c[1:] / pol2.SS_Earnings_c[:-1] - 1).round(4),
1390
- [pol2.wage_growth_rates(year=year) for year in window[:-1]],
1391
- )
1392
1312
 
1393
- # Test AMT
1394
- # Check values for 2017 through 2020 are equal.
1395
- pol2.set_state(year=[2017, 2018, 2019, 2020])
1396
- for i in (1, 2, 3):
1397
- np.testing.assert_equal(
1398
- pol2.AMT_em[0], pol2.AMT_em[i]
1399
- )
1400
-
1401
- # check inflation rate applied for rest of window.
1402
- window = list(range(2020, pol2.end_year + 1))
1403
- pol2.set_state(year=window)
1404
- # repeat inflation rates accross matrix so they can be compared to the
1405
- # rates derived from AMT_em, a 5 * N matrix.
1406
- exp_rates = [pol2.inflation_rates(year=year) for year in window[:-1]]
1407
- exp_rates = np.tile([exp_rates], (5, 1)).transpose()
1408
- np.testing.assert_equal(
1409
- (pol2.AMT_em[1:] / pol2.AMT_em[:-1] - 1).round(4),
1410
- exp_rates,
1411
- )
1313
+ def test_multiple_cpi_swaps2():
1314
+ """
1315
+ Test changing the indexed status of multiple parameters multiple times.
1316
+ """
1317
+ pol1 = Policy()
1318
+ pol1.implement_reform(
1319
+ {
1320
+ "II_em": {2016: 6000, 2018: 7500, 2020: 9000},
1321
+ "II_em-indexed": {2016: False, 2018: True},
1322
+ "SS_Earnings_c": {2016: 300000, 2018: 500000},
1323
+ "SS_Earnings_c-indexed": {2017: False, 2019: True},
1324
+ "AMT_em-indexed": {2017: False, 2020: True},
1325
+ }
1326
+ )
1327
+ pol2 = Policy()
1328
+ pol2.adjust(
1329
+ {
1330
+ "SS_Earnings_c": [
1331
+ {"year": 2016, "value": 300000},
1332
+ {"year": 2018, "value": 500000},
1333
+ ],
1334
+ "SS_Earnings_c-indexed": [
1335
+ {"year": 2017, "value": False},
1336
+ {"year": 2019, "value": True},
1337
+ ],
1338
+ "AMT_em-indexed": [
1339
+ {"year": 2017, "value": False},
1340
+ {"year": 2020, "value": True},
1341
+ ],
1342
+ "II_em": [
1343
+ {"year": 2016, "value": 6000},
1344
+ {"year": 2018, "value": 7500},
1345
+ {"year": 2020, "value": 9000},
1346
+ ],
1347
+ "II_em-indexed": [
1348
+ {"year": 2016, "value": False},
1349
+ {"year": 2018, "value": True},
1350
+ ],
1351
+ }
1352
+ )
1353
+ cmp_policy_objs(pol1, pol2)
1354
+
1355
+ # Test SS_Earnings_c
1356
+ # check inflation is still applied from 2016 to 2017.
1357
+ pol2.set_state(year=[2016, 2017])
1358
+ np.testing.assert_equal(
1359
+ (pol2.SS_Earnings_c[1] / pol2.SS_Earnings_c[0] - 1).round(4),
1360
+ pol2.wage_growth_rates(year=2016),
1361
+ )
1412
1362
 
1413
- # Test II_em
1414
- # check inflation is not applied.
1415
- pol2.set_state(year=[2016, 2017])
1416
- np.testing.assert_equal(
1417
- pol2.II_em[0], pol2.II_em[1]
1418
- )
1363
+ # check inflation rate is not applied after adjustment in 2018.
1364
+ pol2.set_state(year=[2018, 2019])
1365
+ np.testing.assert_equal(
1366
+ pol2.SS_Earnings_c[0], pol2.SS_Earnings_c[1]
1367
+ )
1419
1368
 
1420
- # check inflation rate is applied.
1421
- pol2.set_state(year=[2018, 2019])
1422
- np.testing.assert_equal(
1423
- (pol2.II_em[1] / pol2.II_em[0] - 1).round(4),
1424
- pol2.inflation_rates(year=2018),
1425
- )
1369
+ # check inflation rate applied for rest of window.
1370
+ window = list(range(2019, pol2.end_year + 1))
1371
+ pol2.set_state(year=window)
1372
+ np.testing.assert_equal(
1373
+ (pol2.SS_Earnings_c[1:] / pol2.SS_Earnings_c[:-1] - 1).round(4),
1374
+ [pol2.wage_growth_rates(year=year) for year in window[:-1]],
1375
+ )
1426
1376
 
1427
- # check inflation rate applied for rest of window.
1428
- window = list(range(2020, pol2.end_year + 1))
1429
- pol2.set_state(year=window)
1377
+ # Test AMT
1378
+ # Check values for 2017 through 2020 are equal.
1379
+ pol2.set_state(year=[2017, 2018, 2019, 2020])
1380
+ for i in (1, 2, 3):
1430
1381
  np.testing.assert_equal(
1431
- (pol2.II_em[1:] / pol2.II_em[:-1] - 1).round(4),
1432
- [pol2.inflation_rates(year=year) for year in window[:-1]],
1433
- )
1434
-
1435
- def test_adj_CPI_offset_and_index_status(self):
1436
- """
1437
- Test changing parameter_indexing_CPI_offset and another
1438
- parameter simultaneously.
1439
- """
1440
- pol1 = Policy()
1441
- pol1.implement_reform({
1442
- "CTC_c-indexed": {2020: True},
1443
- "parameter_indexing_CPI_offset": {2020: -0.005}},
1444
- )
1445
-
1446
- pol2 = Policy()
1447
- pol2.adjust(
1448
- {
1449
- "parameter_indexing_CPI_offset":
1450
- [{"year": 2020, "value": -0.005}],
1451
- "CTC_c-indexed": [{"year": 2020, "value": True}],
1452
- }
1382
+ pol2.AMT_em[0], pol2.AMT_em[i]
1453
1383
  )
1454
1384
 
1455
- cmp_policy_objs(pol1, pol2)
1456
-
1457
- # Check no difference prior to 2020
1458
- pol0 = Policy()
1459
- pol0.implement_reform({"parameter_indexing_CPI_offset": {2020: 0}})
1460
- cmp_policy_objs(
1461
- pol0,
1462
- pol2,
1463
- year_range=range(pol2.start_year, 2020 + 1),
1464
- exclude=["parameter_indexing_CPI_offset"]
1465
- )
1385
+ # check inflation rate applied for rest of window.
1386
+ window = list(range(2020, pol2.end_year + 1))
1387
+ pol2.set_state(year=window)
1388
+ # repeat inflation rates accross matrix so they can be compared to the
1389
+ # rates derived from AMT_em, a 5 * N matrix.
1390
+ exp_rates = [pol2.inflation_rates(year=year) for year in window[:-1]]
1391
+ exp_rates = np.tile([exp_rates], (5, 1)).transpose()
1392
+ np.testing.assert_equal(
1393
+ (pol2.AMT_em[1:] / pol2.AMT_em[:-1] - 1).round(4),
1394
+ exp_rates,
1395
+ )
1466
1396
 
1467
- pol2.set_state(year=[2021, 2022])
1468
- np.testing.assert_equal(
1469
- (pol2.CTC_c[1] / pol2.CTC_c[0] - 1).round(4),
1470
- round(pol0.inflation_rates(year=2021) + (-0.005), 4),
1471
- )
1397
+ # Test II_em
1398
+ # check inflation is not applied.
1399
+ pol2.set_state(year=[2016, 2017])
1400
+ np.testing.assert_equal(
1401
+ pol2.II_em[0], pol2.II_em[1]
1402
+ )
1472
1403
 
1473
- def test_adj_related_parameters_and_index_status(self):
1474
- """
1475
- Test changing two related parameters simulataneously and
1476
- one of their indexed statuses.
1477
- """
1404
+ # check inflation rate is applied.
1405
+ pol2.set_state(year=[2018, 2019])
1406
+ np.testing.assert_equal(
1407
+ (pol2.II_em[1] / pol2.II_em[0] - 1).round(4),
1408
+ pol2.inflation_rates(year=2018),
1409
+ )
1478
1410
 
1479
- pol = Policy()
1480
- pol.adjust(
1481
- {
1482
- "II_brk7-indexed": [{"year": 2020, "value": True}],
1483
- # Update II_brk5 in 2026 to make reform valid after reset.
1484
- "II_brk5": [{"value": 330000, "MARS": "single", "year": 2026}],
1485
- "II_brk6": [{"value": 316700, "MARS": "single", "year": 2020}],
1486
- "II_brk7": [{"value": 445400, "MARS": "single", "year": 2020}],
1487
- }
1488
- )
1411
+ # check inflation rate applied for rest of window.
1412
+ window = list(range(2020, pol2.end_year + 1))
1413
+ pol2.set_state(year=window)
1414
+ np.testing.assert_equal(
1415
+ (pol2.II_em[1:] / pol2.II_em[:-1] - 1).round(4),
1416
+ [pol2.inflation_rates(year=year) for year in window[:-1]],
1417
+ )
1489
1418
 
1490
- # Check no difference prior to 2020
1491
- pol0 = Policy()
1492
- cmp_policy_objs(
1493
- pol0,
1494
- pol,
1495
- year_range=range(pol.start_year, 2019 + 1),
1496
- )
1497
1419
 
1498
- res = (
1499
- (pol.sel["II_brk6"]["MARS"] == "single")
1500
- & (pol.sel["II_brk6"]["year"] == 2020)
1501
- )
1502
- assert res.isel[0]["value"] == [316700]
1503
- res = (
1504
- (pol.sel["II_brk7"]["MARS"] == "single")
1505
- & (pol.sel["II_brk7"]["year"] == 2020)
1506
- )
1507
- assert res.isel[0]["value"] == [445400]
1420
+ def test_adj_CPI_offset_and_index_status():
1421
+ """
1422
+ Test changing parameter_indexing_CPI_offset and another
1423
+ parameter simultaneously.
1424
+ """
1425
+ pol1 = Policy()
1426
+ pol1.implement_reform({
1427
+ "CTC_c-indexed": {2020: True},
1428
+ "parameter_indexing_CPI_offset": {2020: -0.005}},
1429
+ )
1430
+ pol2 = Policy()
1431
+ pol2.adjust(
1432
+ {
1433
+ "parameter_indexing_CPI_offset":
1434
+ [{"year": 2020, "value": -0.005}],
1435
+ "CTC_c-indexed": [{"year": 2020, "value": True}],
1436
+ }
1437
+ )
1438
+ cmp_policy_objs(pol1, pol2)
1439
+
1440
+ # Check no difference prior to 2020
1441
+ pol0 = Policy()
1442
+ pol0.implement_reform({"parameter_indexing_CPI_offset": {2020: 0}})
1443
+ cmp_policy_objs(
1444
+ pol0,
1445
+ pol2,
1446
+ year_range=range(pol2.start_year, 2020 + 1),
1447
+ exclude=["parameter_indexing_CPI_offset"]
1448
+ )
1508
1449
 
1509
- II_brk7 = pol.to_array("II_brk7", year=[2021, 2022])
1510
- II_brk7_single = II_brk7[:, 0]
1511
- np.testing.assert_equal(
1512
- (II_brk7_single[1] / II_brk7_single[0] - 1).round(4),
1513
- pol.inflation_rates(year=2021),
1514
- )
1450
+ pol2.set_state(year=[2021, 2022])
1451
+ np.testing.assert_equal(
1452
+ (pol2.CTC_c[1] / pol2.CTC_c[0] - 1).round(4),
1453
+ round(pol0.inflation_rates(year=2021) + (-0.005), 4),
1454
+ )
1515
1455
 
1516
- def test_indexed_status_parsing(self):
1517
- pol1 = Policy()
1518
1456
 
1519
- pol1.implement_reform({"EITC_c-indexed": {pol1.start_year: False}})
1457
+ def test_adj_related_parameters_and_index_status():
1458
+ """
1459
+ Test changing two related parameters simulataneously and
1460
+ one of their indexed statuses.
1461
+ """
1462
+ pol = Policy()
1463
+ pol.adjust(
1464
+ {
1465
+ "II_brk7-indexed": [{"year": 2020, "value": True}],
1466
+ # Update II_brk5 in 2026 to make reform valid after reset.
1467
+ "II_brk5": [{"value": 330000, "MARS": "single", "year": 2026}],
1468
+ "II_brk6": [{"value": 316700, "MARS": "single", "year": 2020}],
1469
+ "II_brk7": [{"value": 445400, "MARS": "single", "year": 2020}],
1470
+ }
1471
+ )
1520
1472
 
1521
- pol2 = Policy()
1522
- pol2.adjust({"EITC_c-indexed": False})
1473
+ # Check no difference prior to 2020
1474
+ pol0 = Policy()
1475
+ cmp_policy_objs(
1476
+ pol0,
1477
+ pol,
1478
+ year_range=range(pol.start_year, 2019 + 1),
1479
+ )
1523
1480
 
1524
- cmp_policy_objs(pol1, pol2)
1481
+ res = (
1482
+ (pol.sel["II_brk6"]["MARS"] == "single")
1483
+ & (pol.sel["II_brk6"]["year"] == 2020)
1484
+ )
1485
+ assert res.isel[0]["value"] == [316700]
1486
+ res = (
1487
+ (pol.sel["II_brk7"]["MARS"] == "single")
1488
+ & (pol.sel["II_brk7"]["year"] == 2020)
1489
+ )
1490
+ assert res.isel[0]["value"] == [445400]
1525
1491
 
1526
- with pytest.raises(pt.ValidationError):
1527
- pol2.adjust({"EITC_c-indexed": 123})
1492
+ II_brk7 = pol.to_array("II_brk7", year=[2021, 2022])
1493
+ II_brk7_single = II_brk7[:, 0]
1494
+ np.testing.assert_equal(
1495
+ (II_brk7_single[1] / II_brk7_single[0] - 1).round(4),
1496
+ pol.inflation_rates(year=2021),
1497
+ )
1528
1498
 
1529
- def test_cpi_offset_does_not_affect_wage_indexed_params(self):
1530
- """
1531
- Test adjusting parameter_indexing_CPI_offset does not affect unknown
1532
- values of wage indexed parameters like SS_Earnings_c.
1533
- """
1534
- base_reform = {
1535
- "parameter_indexing_CPI_offset": {2021: -0.001},
1536
- "SS_Earnings_c": {2024: 300000},
1537
- }
1538
1499
 
1539
- pol0 = Policy()
1540
- pol0.implement_reform(base_reform)
1500
+ def test_indexed_status_parsing():
1501
+ """
1502
+ Test parsing.
1503
+ """
1504
+ pol1 = Policy()
1505
+ pol1.implement_reform({"EITC_c-indexed": {pol1.start_year: False}})
1506
+ pol2 = Policy()
1507
+ pol2.adjust({"EITC_c-indexed": False})
1508
+ cmp_policy_objs(pol1, pol2)
1541
1509
 
1542
- pol1 = Policy()
1543
- pol1.implement_reform(base_reform)
1544
- pol1.implement_reform(dict(base_reform, SS_Earnings_c={2025: 500000}))
1510
+ with pytest.raises(pt.ValidationError):
1511
+ pol2.adjust({"EITC_c-indexed": 123})
1545
1512
 
1546
- exp_before_2025 = pol0.to_array(
1547
- "SS_Earnings_c", year=list(range(2021, 2024 + 1))
1548
- )
1549
- act_before_2025 = pol1.to_array(
1550
- "SS_Earnings_c", year=list(range(2021, 2024 + 1))
1551
- )
1552
1513
 
1553
- np.testing.assert_equal(act_before_2025, exp_before_2025)
1514
+ def test_cpi_offset_does_not_affect_wage_indexed_params():
1515
+ """
1516
+ Test adjusting parameter_indexing_CPI_offset does not affect unknown
1517
+ values of wage indexed parameters like SS_Earnings_c.
1518
+ """
1519
+ base_reform = {
1520
+ "parameter_indexing_CPI_offset": {2021: -0.001},
1521
+ "SS_Earnings_c": {2024: 300000},
1522
+ }
1523
+ pol0 = Policy()
1524
+ pol0.implement_reform(base_reform)
1525
+ pol1 = Policy()
1526
+ pol1.implement_reform(base_reform)
1527
+ pol1.implement_reform(dict(base_reform, SS_Earnings_c={2025: 500000}))
1528
+
1529
+ exp_before_2025 = pol0.to_array(
1530
+ "SS_Earnings_c", year=list(range(2021, 2024 + 1))
1531
+ )
1532
+ act_before_2025 = pol1.to_array(
1533
+ "SS_Earnings_c", year=list(range(2021, 2024 + 1))
1534
+ )
1535
+ np.testing.assert_equal(act_before_2025, exp_before_2025)
1554
1536
 
1555
1537
 
1556
1538
  def test_two_sets_of_tax_brackets():