Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/remove-household-options.removed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove `household_options` from the `/{country}/metadata` response, added in 5.22.0. No client read it, and household and society-wide calculations will offer the same years, from `economy_options.time_period`.
2 changes: 1 addition & 1 deletion docs/generated/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Every rule that governs `policyengine-api` is listed here with how it is enforce

### Ratcheted (existing violations still tolerated)

- `api.dependencies.declared-and-used`: 16 remaining in `rules/baselines/deptry.txt`
- `api.dependencies.declared-and-used`: 15 remaining in `rules/baselines/deptry.txt`
- `api.quality.suppressions-explained`: 29 remaining in `rules/baselines/suppressions.txt`
- `api.quality.tests-assert`: 21 remaining in `rules/baselines/tests-without-checks.txt`
- `api.v2.connectors-no-cross-calls`: 7 remaining in `rules/baselines/import-linter-api-v2-connectors-independent.txt`
Expand Down
37 changes: 1 addition & 36 deletions policyengine_api/country.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,10 @@
)
from policyengine_api.data.uk_regions import uk_areas
from policyengine_api.economy_years import uk_economy_years
from policyengine_api.household_years import us_household_years
from policyengine_api.services.household_calculation_service import CalculationResult
from policyengine_api.spm import (
SPM_INPUT_ERROR_CODES,
calculation_spm_receipt,
certified_spm_forecast_years,
normalize_spm_selection,
spm_error_detail,
spm_metadata,
Expand Down Expand Up @@ -171,15 +169,13 @@ def parameter_names(self) -> frozenset[str]:

def build_metadata(self) -> None:
"""Build the JSON-safe metadata document served by the metadata endpoints."""
economy_options = self.build_microsimulation_options()
self.metadata = self._json_safe(
{
"variables": self.build_variables(),
"parameters": self.build_parameters(),
"entities": self.build_entities(),
"variableModules": self.tax_benefit_system.variable_module_metadata,
"economy_options": economy_options,
"household_options": self.build_household_options(economy_options),
"economy_options": self.build_microsimulation_options(),
"current_law_id": get_current_law_policy_id(self.country_id),
"basicInputs": self.tax_benefit_system.basic_inputs,
"modelled_policies": self.tax_benefit_system.modelled_policies,
Expand Down Expand Up @@ -319,37 +315,6 @@ def build_microsimulation_options(self) -> dict:
options["datasets"] = datasets
return options

def build_household_options(self, economy_options: dict) -> dict:
"""Build the years offered for household calculations.

Each year has the shape of an ``economy_options`` year. The US years
are the certified SPM forecast's years up to the last CPI-U year
(``us_household_years``), or the society-wide years when the bundle
has no certified SPM forecast. The UK years follow the rule for the
UK society-wide years (``uk_economy_years``). Any other country
offers its society-wide years.
"""
parameters = self.tax_benefit_system.parameters
years = None
if self.country_id == "uk":
years = uk_economy_years(parameters)
elif self.country_id == "us":
forecast_years = certified_spm_forecast_years()
if forecast_years is None:
logger.warning(
"The bundle has no certified SPM forecast; the US household "
"years are the US society-wide years"
)
else:
years = us_household_years(parameters, forecast_years)
if years is None:
return {
"time_period": [
dict(period) for period in economy_options.get("time_period", [])
]
}
return {"time_period": [{"name": year, "label": str(year)} for year in years]}

def build_variables(self) -> dict:
"""Describe every variable by name; enum variables list their values."""
variables = self.tax_benefit_system.variables
Expand Down
39 changes: 0 additions & 39 deletions policyengine_api/household_years.py

This file was deleted.

19 changes: 0 additions & 19 deletions policyengine_api/spm.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,25 +739,6 @@ def spm_metadata(country_id: str) -> dict:
}


def certified_spm_forecast_years() -> tuple[int, ...] | None:
"""Return the years the bundle's certified US SPM forecast covers.

The US model refuses an SPM calculation in any other year
(``SPM_YEAR_UNAVAILABLE``). Return None in the cases in which
``spm_metadata`` reports SPM as unavailable: the bundle certifies no
forecast, or the certified one cannot be loaded. The forecast file is read
once per process and shared with ``spm_metadata``.
"""
try:
defaults = normalize_spm_selection("us", None)
except SPMValidationError:
return None
if defaults is None:
return None
forecast = _selected_forecast(defaults["forecast_content_sha256"])
return tuple(int(year) for year in forecast.years)


def calculation_spm_receipt(simulation: Simulation) -> dict:
"""Reduce a country's existing receipt; never request calculations here."""
if not hasattr(simulation, "spm_config"):
Expand Down
1 change: 0 additions & 1 deletion rules/baselines/deptry.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ DEP003 jsonschema
DEP003 numpy
DEP003 policyengine_core
DEP003 policyengine_uk
DEP003 policyengine_us
DEP003 spm_calculator
DEP003 starlette
2 changes: 1 addition & 1 deletion rules/registry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1807,7 +1807,7 @@ job = "quality-guards"
invocation = "run_quality_guards.py"
[rule.baseline]
file = "rules/baselines/deptry.txt"
count = 16
count = 15
[rule.proof]
bad_fixture = "rules/fixtures/api.dependencies.declared-and-used/rejected"
good_fixture = "rules/fixtures/api.dependencies.declared-and-used/accepted"
Expand Down
147 changes: 0 additions & 147 deletions tests/unit/test_household_options.py

This file was deleted.

33 changes: 0 additions & 33 deletions tests/unit/test_spm_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,39 +237,6 @@ def test_metadata_exposes_typed_defaults_only_when_available():
assert result["settings_schema"] == spm.SPMSelection.model_json_schema()


@pytest.mark.usefixtures("certified_bundle")
def test_certified_forecast_years_are_the_artifacts_years():
assert spm.certified_spm_forecast_years() == (2022, 2035)


@pytest.mark.parametrize("model_supports_spm", [False, True])
def test_certified_forecast_years_are_none_without_a_certified_forecast(
monkeypatch, model_supports_spm
):
"""No certified forecast means no years, whether or not the model has SPM."""
monkeypatch.setattr(spm, "_current_bundle", lambda: deepcopy(LEGACY_BUNDLE))
monkeypatch.setattr(spm, "simulation_supports_spm", lambda _: model_supports_spm)

def must_not_load(_expected):
msg = "No certified forecast should be loaded"
raise AssertionError(msg)

monkeypatch.setattr(spm, "_selected_forecast", must_not_load)
assert spm.certified_spm_forecast_years() is None


@pytest.mark.usefixtures("certified_bundle")
def test_certified_forecast_years_are_none_when_the_forecast_cannot_load(
monkeypatch,
):
def mismatched_artifact(_expected):
msg = "Forecast content SHA256 mismatch"
raise ValueError(msg)

monkeypatch.setattr(spm, "_selected_forecast", mismatched_artifact)
assert spm.certified_spm_forecast_years() is None


@pytest.mark.usefixtures("certified_bundle")
def test_selected_area_must_exist_in_artifact():
with pytest.raises(spm.SPMValidationError) as caught:
Expand Down
Loading