Skip to content

Commit f4a38b0

Browse files
committed
Remove uprating metadata from formula variables
1 parent f106e8e commit f4a38b0

19 files changed

Lines changed: 115 additions & 21 deletions
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove redundant uprating metadata and class-level aggregation metadata from variables that already define their computation explicitly.

policyengine_us/data/economic_assumptions.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,38 @@
1212
# is updated with new projection years, datasets will automatically
1313
# extend to match — no hardcoded year constant to maintain.
1414
CPI_U_PARAM_PATH = "gov.bls.cpi.cpi_u"
15+
DEFAULT_MICRODATA_UPRATING = (
16+
"calibration.gov.cbo.income_by_source.adjusted_gross_income"
17+
)
18+
19+
MICRODATA_UPRATING_OVERRIDES = {
20+
"american_opportunity_credit": DEFAULT_MICRODATA_UPRATING,
21+
"cdcc_relevant_expenses": DEFAULT_MICRODATA_UPRATING,
22+
"employment_income": "calibration.gov.irs.soi.employment_income",
23+
"employment_income_last_year": "calibration.gov.irs.soi.employment_income",
24+
"energy_efficient_home_improvement_credit": DEFAULT_MICRODATA_UPRATING,
25+
"foreign_tax_credit": DEFAULT_MICRODATA_UPRATING,
26+
"interest_deduction": DEFAULT_MICRODATA_UPRATING,
27+
"long_term_capital_gains": "calibration.gov.irs.soi.long_term_capital_gains",
28+
"misc_deduction": DEFAULT_MICRODATA_UPRATING,
29+
"person_weight": "calibration.gov.census.populations.total",
30+
"pre_tax_contributions": DEFAULT_MICRODATA_UPRATING,
31+
"rent": "gov.bls.cpi.cpi_u",
32+
"savers_credit": DEFAULT_MICRODATA_UPRATING,
33+
"self_employment_income": "calibration.gov.irs.soi.self_employment_income",
34+
"self_employed_health_insurance_ald": DEFAULT_MICRODATA_UPRATING,
35+
"self_employed_pension_contribution_ald": DEFAULT_MICRODATA_UPRATING,
36+
"social_security": "calibration.gov.irs.soi.social_security",
37+
"spm_unit_weight": "calibration.gov.census.populations.total",
38+
"spm_unit_spm_threshold": DEFAULT_MICRODATA_UPRATING,
39+
"state_and_local_sales_or_income_tax": DEFAULT_MICRODATA_UPRATING,
40+
"sstb_self_employment_income": "calibration.gov.irs.soi.self_employment_income",
41+
"taxable_pension_income": "calibration.gov.irs.soi.taxable_pension_income",
42+
"taxable_unemployment_compensation": DEFAULT_MICRODATA_UPRATING,
43+
"tax_unit_weight": "calibration.gov.census.populations.total",
44+
"tax_exempt_pension_income": DEFAULT_MICRODATA_UPRATING,
45+
"total_self_employment_income": "calibration.gov.irs.soi.self_employment_income",
46+
}
1547

1648

1749
def get_parameter_last_year(parameter) -> int:
@@ -100,11 +132,10 @@ def _apply_uprating(dataset: USMultiYearDataset, system=None) -> USMultiYearData
100132
def _apply_single_year_uprating(current, previous, system):
101133
"""Apply multiplicative uprating from previous year to current year.
102134
103-
For each variable column in each entity DataFrame, looks up the
104-
variable's uprating parameter path in ``system.variables``. If the
105-
variable has an uprating parameter, computes the growth factor as
106-
``param(current_year) / param(previous_year)`` and multiplies the
107-
column by that factor.
135+
For each variable column in each entity DataFrame, looks up its
136+
dataset-extension uprating parameter path. Formula and adds/subtracts
137+
variables cannot use Core variable-level uprating, so their dataset-only
138+
upraters live in ``MICRODATA_UPRATING_OVERRIDES`` instead.
108139
109140
Variables without an uprating parameter (or whose uprating parameter
110141
evaluates to 0 for the previous year) are left unchanged — they were
@@ -122,7 +153,9 @@ def _apply_single_year_uprating(current, previous, system):
122153
if col not in system.variables:
123154
continue
124155
var = system.variables[col]
125-
uprating_path = getattr(var, "uprating", None)
156+
uprating_path = MICRODATA_UPRATING_OVERRIDES.get(col) or getattr(
157+
var, "uprating", None
158+
)
126159
if uprating_path is None:
127160
continue
128161

policyengine_us/tests/microsimulation/data/test_extend_single_year_dataset.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,30 @@ def test_given_variable_without_uprating_then_values_unchanged(
125125
# Then — age has no uprating, should be unchanged
126126
np.testing.assert_array_equal(current.person["age"].values, AGE_BASE)
127127

128+
def test_given_computed_variable_with_microdata_override_then_values_scaled(
129+
self, base_dataset
130+
):
131+
# Given
132+
current = base_dataset.copy()
133+
current.time_period = str(BASE_YEAR + 1)
134+
previous = base_dataset
135+
variables = {
136+
"employment_income": MockVariable("employment_income", uprating=None)
137+
}
138+
system = MockSystem(
139+
variables=variables,
140+
parameters=build_mock_parameters(
141+
{EMPLOYMENT_INCOME_UPRATING: EMPLOYMENT_INCOME_PARAM_VALUES}
142+
),
143+
)
144+
145+
# When
146+
_apply_single_year_uprating(current, previous, system)
147+
148+
# Then
149+
expected = EMPLOYMENT_INCOME_BASE * EMPLOYMENT_INCOME_GROWTH_FACTOR_2024_TO_2025
150+
np.testing.assert_allclose(current.person["employment_income"].values, expected)
151+
128152
def test_given_household_variable_with_uprating_then_values_scaled(
129153
self, base_dataset, mock_system
130154
):

policyengine_us/tests/test_system_import.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,49 @@ def test_package_import_does_not_raise():
3636
import policyengine_us
3737

3838
importlib.reload(policyengine_us)
39+
40+
41+
def test_variables_use_at_most_one_computation_mode():
42+
"""Variables should choose exactly one computation mode after all
43+
system-level mutations, including default uprating assignment.
44+
"""
45+
from policyengine_us.system import CountryTaxBenefitSystem
46+
47+
system = CountryTaxBenefitSystem()
48+
conflicts = []
49+
for name, variable in system.variables.items():
50+
modes = []
51+
if variable.formulas:
52+
modes.append("formula")
53+
if variable.adds is not None or variable.subtracts is not None:
54+
modes.append("adds/subtracts")
55+
if variable.uprating is not None:
56+
modes.append("uprating")
57+
if len(modes) > 1:
58+
conflicts.append(f"{name}: {', '.join(modes)}")
59+
60+
assert conflicts == []
61+
62+
63+
def test_computed_default_uprated_variables_have_microdata_overrides():
64+
"""Default uprating can only be assigned to input variables at runtime.
65+
Computed columns that previously received the default uprater keep that
66+
behavior through microdata-only overrides.
67+
"""
68+
from policyengine_us.data.economic_assumptions import MICRODATA_UPRATING_OVERRIDES
69+
from policyengine_us.system import CountryTaxBenefitSystem
70+
from policyengine_us.tools.default_uprating import INPUT_VARIABLES
71+
72+
system = CountryTaxBenefitSystem()
73+
missing_overrides = []
74+
for name in INPUT_VARIABLES:
75+
variable = system.variables.get(name)
76+
if variable is None:
77+
continue
78+
if (
79+
not variable.is_input_variable()
80+
and name not in MICRODATA_UPRATING_OVERRIDES
81+
):
82+
missing_overrides.append(name)
83+
84+
assert missing_overrides == []

policyengine_us/tools/default_uprating.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@
9898

9999
def add_default_uprating(system):
100100
for variable in system.variables.values():
101-
if (variable.name in INPUT_VARIABLES) and (variable.uprating is None):
101+
if (
102+
(variable.name in INPUT_VARIABLES)
103+
and (variable.uprating is None)
104+
and variable.is_input_variable()
105+
):
102106
variable.uprating = (
103107
"calibration.gov.cbo.income_by_source.adjusted_gross_income"
104108
)

policyengine_us/variables/gov/ssa/ss/social_security.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,3 @@ class social_security(Variable):
1212
"social_security_" + i
1313
for i in ["dependents", "disability", "retirement", "survivors"]
1414
]
15-
uprating = "calibration.gov.irs.soi.social_security"

policyengine_us/variables/gov/states/tax/income/state_itemized_deductions.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ class state_itemized_deductions(Variable):
77
label = "State itemized deductions"
88
unit = USD
99
definition_period = YEAR
10-
adds = "gov.states.household.state_itemized_deductions"
1110

1211
def formula(tax_unit, period, parameters):
1312
# States that adopt the federal itemized deductions

policyengine_us/variables/gov/states/tax/income/taxsim_state_agi.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ class taxsim_state_agi(Variable):
77
label = "State adjusted gross income"
88
unit = USD
99
definition_period = YEAR
10-
adds = "gov.states.household.state_agis"
1110

1211
def formula(tax_unit, period, parameters):
1312
# States that adopt the federal AGI

policyengine_us/variables/household/demographic/weights/person_weight.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ class person_weight(Variable):
66
entity = Person
77
label = "Person weight"
88
definition_period = YEAR
9-
uprating = "calibration.gov.census.populations.total"
109

1110
def formula(person, period, parameters):
1211
return person.household("household_weight", period)

policyengine_us/variables/household/demographic/weights/spm_unit_weight.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ class spm_unit_weight(Variable):
66
entity = SPMUnit
77
label = "SPM unit weight"
88
definition_period = YEAR
9-
uprating = "calibration.gov.census.populations.total"
109

1110
def formula(spm_unit, period, parameters):
1211
# Use household weights if not provided

0 commit comments

Comments
 (0)