Skip to content

Commit 01cd2a5

Browse files
Add guidance for household calculations
1 parent 4da1a85 commit 01cd2a5

1 file changed

Lines changed: 118 additions & 25 deletions

File tree

src/policyengine_api/api/household.py

Lines changed: 118 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,68 @@
1414

1515

1616
class HouseholdCalculateRequest(BaseModel):
17-
"""Request body for household calculation."""
17+
"""Request body for household calculation.
18+
19+
IMPORTANT: Use flat values for variables, NOT time-period dictionaries.
20+
The year is specified separately via the `year` parameter.
21+
22+
CORRECT: {"employment_income": 70000, "age": 40}
23+
WRONG: {"employment_income": {"2024": 70000}, "age": {"2024": 40}}
24+
25+
Example US request:
26+
{
27+
"tax_benefit_model_name": "policyengine_us",
28+
"people": [{"employment_income": 70000, "age": 40}],
29+
"tax_unit": {"state_code": "CA"},
30+
"household": {"state_fips": 6},
31+
"year": 2024
32+
}
33+
34+
Example UK request:
35+
{
36+
"tax_benefit_model_name": "policyengine_uk",
37+
"people": [{"employment_income": 50000, "age": 30}],
38+
"household": {},
39+
"year": 2026
40+
}
41+
"""
1842

19-
tax_benefit_model_name: Literal["policyengine_uk", "policyengine_us"]
20-
people: list[dict[str, Any]]
21-
benunit: dict[str, Any] = Field(default_factory=dict)
22-
marital_unit: dict[str, Any] = Field(default_factory=dict)
23-
family: dict[str, Any] = Field(default_factory=dict)
24-
spm_unit: dict[str, Any] = Field(default_factory=dict)
25-
tax_unit: dict[str, Any] = Field(default_factory=dict)
26-
household: dict[str, Any] = Field(default_factory=dict)
27-
year: int | None = None
28-
policy_id: UUID | None = None
29-
dynamic_id: UUID | None = None
43+
tax_benefit_model_name: Literal["policyengine_uk", "policyengine_us"] = Field(
44+
description="Which country model to use"
45+
)
46+
people: list[dict[str, Any]] = Field(
47+
description="List of people with flat variable values (e.g. [{'age': 30, 'employment_income': 50000}]). Do NOT use time-period format."
48+
)
49+
benunit: dict[str, Any] = Field(
50+
default_factory=dict, description="UK benefit unit variables (flat values)"
51+
)
52+
marital_unit: dict[str, Any] = Field(
53+
default_factory=dict, description="US marital unit variables (flat values)"
54+
)
55+
family: dict[str, Any] = Field(
56+
default_factory=dict, description="US family variables (flat values)"
57+
)
58+
spm_unit: dict[str, Any] = Field(
59+
default_factory=dict, description="US SPM unit variables (flat values)"
60+
)
61+
tax_unit: dict[str, Any] = Field(
62+
default_factory=dict,
63+
description="US tax unit variables (flat values, e.g. {'state_code': 'CA'})",
64+
)
65+
household: dict[str, Any] = Field(
66+
default_factory=dict,
67+
description="Household variables (flat values, e.g. {'state_fips': 6} for US)",
68+
)
69+
year: int | None = Field(
70+
default=None,
71+
description="Simulation year (default: 2024 for US, 2026 for UK). Specify this instead of embedding years in variable values.",
72+
)
73+
policy_id: UUID | None = Field(
74+
default=None, description="Optional policy reform ID"
75+
)
76+
dynamic_id: UUID | None = Field(
77+
default=None, description="Optional behavioural response ID"
78+
)
3079

3180

3281
class HouseholdCalculateResponse(BaseModel):
@@ -42,19 +91,54 @@ class HouseholdCalculateResponse(BaseModel):
4291

4392

4493
class HouseholdImpactRequest(BaseModel):
45-
"""Request body for household impact comparison."""
94+
"""Request body for household impact comparison.
95+
96+
Same format as HouseholdCalculateRequest - use flat values, NOT time-period dictionaries.
97+
98+
Example:
99+
{
100+
"tax_benefit_model_name": "policyengine_us",
101+
"people": [{"employment_income": 70000, "age": 40}],
102+
"tax_unit": {"state_code": "CA"},
103+
"household": {"state_fips": 6},
104+
"year": 2024,
105+
"policy_id": "uuid-of-reform-policy"
106+
}
107+
"""
46108

47-
tax_benefit_model_name: Literal["policyengine_uk", "policyengine_us"]
48-
people: list[dict[str, Any]]
49-
benunit: dict[str, Any] = Field(default_factory=dict)
50-
marital_unit: dict[str, Any] = Field(default_factory=dict)
51-
family: dict[str, Any] = Field(default_factory=dict)
52-
spm_unit: dict[str, Any] = Field(default_factory=dict)
53-
tax_unit: dict[str, Any] = Field(default_factory=dict)
54-
household: dict[str, Any] = Field(default_factory=dict)
55-
year: int | None = None
56-
policy_id: UUID | None = None # Reform policy (baseline uses no policy)
57-
dynamic_id: UUID | None = None
109+
tax_benefit_model_name: Literal["policyengine_uk", "policyengine_us"] = Field(
110+
description="Which country model to use"
111+
)
112+
people: list[dict[str, Any]] = Field(
113+
description="List of people with flat variable values. Do NOT use time-period format."
114+
)
115+
benunit: dict[str, Any] = Field(
116+
default_factory=dict, description="UK benefit unit variables (flat values)"
117+
)
118+
marital_unit: dict[str, Any] = Field(
119+
default_factory=dict, description="US marital unit variables (flat values)"
120+
)
121+
family: dict[str, Any] = Field(
122+
default_factory=dict, description="US family variables (flat values)"
123+
)
124+
spm_unit: dict[str, Any] = Field(
125+
default_factory=dict, description="US SPM unit variables (flat values)"
126+
)
127+
tax_unit: dict[str, Any] = Field(
128+
default_factory=dict, description="US tax unit variables (flat values)"
129+
)
130+
household: dict[str, Any] = Field(
131+
default_factory=dict, description="Household variables (flat values)"
132+
)
133+
year: int | None = Field(
134+
default=None, description="Simulation year (default: 2024 for US, 2026 for UK)"
135+
)
136+
policy_id: UUID | None = Field(
137+
default=None, description="Reform policy ID to compare against baseline"
138+
)
139+
dynamic_id: UUID | None = Field(
140+
default=None, description="Optional behavioural response ID"
141+
)
58142

59143

60144
class HouseholdImpactResponse(BaseModel):
@@ -148,7 +232,14 @@ def calculate_household(
148232
request: HouseholdCalculateRequest,
149233
session: Session = Depends(get_session),
150234
) -> HouseholdCalculateResponse:
151-
"""Calculate tax and benefit impacts for a household."""
235+
"""Calculate tax and benefit impacts for a household.
236+
237+
Use flat values for all variables - do NOT use time-period format like {"2024": value}.
238+
The simulation year is specified via the `year` parameter.
239+
240+
US example: people=[{"employment_income": 70000, "age": 40}], tax_unit={"state_code": "CA"}, year=2024
241+
UK example: people=[{"employment_income": 50000, "age": 30}], year=2026
242+
"""
152243
if request.tax_benefit_model_name == "policyengine_uk":
153244
from policyengine.tax_benefit_models.uk import uk_latest
154245

@@ -275,6 +366,8 @@ def calculate_household_impact_comparison(
275366
276367
Compares the household under baseline (current law) vs reform (policy_id).
277368
Returns both calculations plus computed differences.
369+
370+
Use flat values for all variables - do NOT use time-period format like {"2024": value}.
278371
"""
279372
# Build baseline request (no policy)
280373
baseline_request = HouseholdCalculateRequest(

0 commit comments

Comments
 (0)