From 32cc184d5d50fd648554a032c80974ffb0107e41 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Apr 2026 23:31:45 -0400 Subject: [PATCH 1/2] Add PLA and ADG SLC targets --- changelog.d/pla-adg-targets.added.md | 1 + .../targets/build_loss_matrix.py | 13 +- .../targets/compute/__init__.py | 4 +- policyengine_uk_data/targets/compute/other.py | 15 +- policyengine_uk_data/targets/sources/slc.py | 178 +++++++++++++++++- .../tests/test_student_loan_targets.py | 125 +++++++++++- pyproject.toml | 2 +- uv.lock | 10 +- 8 files changed, 320 insertions(+), 28 deletions(-) create mode 100644 changelog.d/pla-adg-targets.added.md diff --git a/changelog.d/pla-adg-targets.added.md b/changelog.d/pla-adg-targets.added.md new file mode 100644 index 000000000..7d0d3bc20 --- /dev/null +++ b/changelog.d/pla-adg-targets.added.md @@ -0,0 +1 @@ +Add SLC calibration targets for Parents' Learning Allowance and Adult Dependants' Grant. diff --git a/policyengine_uk_data/targets/build_loss_matrix.py b/policyengine_uk_data/targets/build_loss_matrix.py index 77c135994..ed18e676f 100644 --- a/policyengine_uk_data/targets/build_loss_matrix.py +++ b/policyengine_uk_data/targets/build_loss_matrix.py @@ -31,8 +31,8 @@ compute_housing, compute_income_band, compute_land_value, - compute_maintenance_loan, compute_regional_land_value, + compute_person_support, compute_obr_council_tax, compute_pip_claimants, compute_regional_age, @@ -321,8 +321,15 @@ def _compute_column(target: Target, ctx: _SimContext, year: int) -> np.ndarray | # Student loan plan borrower counts (SLC) if name.startswith("slc/student_loan_repayment/"): return compute_student_loan_repayment(target, ctx) - if name in ("slc/maintenance_loan_recipients", "slc/maintenance_loan_spend"): - return compute_maintenance_loan(target, ctx) + if name in ( + "slc/maintenance_loan_recipients", + "slc/maintenance_loan_spend", + "slc/parents_learning_allowance_recipients", + "slc/parents_learning_allowance_spend", + "slc/adult_dependants_grant_recipients", + "slc/adult_dependants_grant_spend", + ): + return compute_person_support(target, ctx) if name.startswith("slc/plan_") and "above_threshold" in name: return compute_student_loan_plan(target, ctx) if name.startswith("slc/plan_") and "liable" in name: diff --git a/policyengine_uk_data/targets/compute/__init__.py b/policyengine_uk_data/targets/compute/__init__.py index 4457e2202..9ab23cd0e 100644 --- a/policyengine_uk_data/targets/compute/__init__.py +++ b/policyengine_uk_data/targets/compute/__init__.py @@ -34,9 +34,9 @@ compute_ss_ni_relief, ) from policyengine_uk_data.targets.compute.other import ( - compute_maintenance_loan, compute_housing, compute_land_value, + compute_person_support, compute_regional_land_value, compute_savings_interest, compute_scottish_child_payment, @@ -54,10 +54,10 @@ "compute_household_type", "compute_housing", "compute_land_value", - "compute_maintenance_loan", "compute_regional_land_value", "compute_income_band", "compute_obr_council_tax", + "compute_person_support", "compute_pip_claimants", "compute_regional_age", "compute_savings_interest", diff --git a/policyengine_uk_data/targets/compute/other.py b/policyengine_uk_data/targets/compute/other.py index 9a6146862..4ff852a20 100644 --- a/policyengine_uk_data/targets/compute/other.py +++ b/policyengine_uk_data/targets/compute/other.py @@ -1,6 +1,7 @@ """Miscellaneous compute functions (vehicles, housing, savings, SCP, student loans).""" import numpy as np +from policyengine_uk_data.targets.schema import Unit _STUDENT_LOAN_COUNTRIES = { "england": "ENGLAND", @@ -128,11 +129,11 @@ def compute_student_loan_repayment(target, ctx) -> np.ndarray: return ctx.household_from_person(repayments * mask) -def compute_maintenance_loan(target, ctx) -> np.ndarray: - """Compute maintenance-loan recipient-count and spend targets.""" - maintenance_loan = ctx.pe_person("maintenance_loan") - if target.name == "slc/maintenance_loan_recipients": - return ctx.household_from_person((maintenance_loan > 0).astype(float)) - if target.name == "slc/maintenance_loan_spend": - return ctx.household_from_person(maintenance_loan) +def compute_person_support(target, ctx) -> np.ndarray: + """Compute recipient-count and spend targets for person-level support variables.""" + values = ctx.pe_person(target.variable) + if target.is_count or target.unit == Unit.COUNT: + return ctx.household_from_person((values > 0).astype(float)) + if target.unit == Unit.GBP: + return ctx.household_from_person(values) return None diff --git a/policyengine_uk_data/targets/sources/slc.py b/policyengine_uk_data/targets/sources/slc.py index c458eaf7c..13694285e 100644 --- a/policyengine_uk_data/targets/sources/slc.py +++ b/policyengine_uk_data/targets/sources/slc.py @@ -2,11 +2,13 @@ Borrower counts for England only: Plan 2 and Plan 5. -Two target types are exposed: +Three target families are exposed: - `above_threshold`: borrowers liable to repay and earning above threshold - `liable`: all borrowers liable to repay, including below-threshold holders - `maintenance_loan`: full-time undergraduate England maintenance-loan recipient counts and total amount paid +- `parents_learning_allowance` and `adult_dependants_grant`: full-time + undergraduate England grant recipient counts and amounts awarded Source: Explore Education Statistics — Student loan forecasts for England, Table 6a: Forecast number of student borrowers liable to repay and number @@ -18,6 +20,11 @@ England 2025, Table 3A: Maintenance Loans paid to full-time undergraduate students. Academic year 20XX/YY maps to calendar year 20XX+1. +Parents' Learning Allowance and Adult Dependants' Grant targets come from +Student support for higher education in England 2025, Table 4C (i): +Other targeted support awarded to full-time applicants. Academic year +20XX/YY maps to calendar year 20XX+1. + Data permalink: https://explore-education-statistics.service.gov.uk/data-tables/permalink/6ff75517-7124-487c-cb4e-08de6eccf22d """ @@ -37,7 +44,7 @@ f"https://explore-education-statistics.service.gov.uk" f"/data-tables/permalink/{_PERMALINK_ID}" ) -_MAINTENANCE_LOAN_URL = ( +_STUDENT_SUPPORT_URL = ( "https://assets.publishing.service.gov.uk/media/" "691d9e662c6b98ecdbc5003f/slcsp052025.xlsx" ) @@ -109,6 +116,68 @@ 2025: 8_591_659_718, }, } +_TARGETED_SUPPORT_TESTING_DATA = { + "adult_dependants_grant": { + "recipients": { + 2014: 13_836, + 2015: 14_420, + 2016: 13_877, + 2017: 14_222, + 2018: 15_410, + 2019: 16_336, + 2020: 19_603, + 2021: 22_453, + 2022: 23_699, + 2023: 20_226, + 2024: 17_960, + 2025: 18_611, + }, + "amount_paid": { + 2014: 33_050_091, + 2015: 34_538_762, + 2016: 34_065_350, + 2017: 34_884_056, + 2018: 38_145_981, + 2019: 41_154_737, + 2020: 48_060_995, + 2021: 56_104_466, + 2022: 60_506_271, + 2023: 54_638_997, + 2024: 51_719_576, + 2025: 55_364_917, + }, + }, + "parents_learning_allowance": { + "recipients": { + 2014: 49_219, + 2015: 49_409, + 2016: 47_414, + 2017: 47_772, + 2018: 52_568, + 2019: 57_408, + 2020: 66_407, + 2021: 76_740, + 2022: 82_911, + 2023: 89_283, + 2024: 95_287, + 2025: 99_645, + }, + "amount_paid": { + 2014: 70_524_886, + 2015: 71_710_128, + 2016: 70_799_276, + 2017: 70_955_697, + 2018: 80_020_029, + 2019: 90_006_145, + 2020: 106_581_771, + 2021: 126_314_502, + 2022: 139_380_387, + 2023: 153_266_251, + 2024: 168_349_637, + 2025: 181_421_659, + }, + }, +} def get_snapshot_data() -> dict: @@ -128,6 +197,16 @@ def get_maintenance_loan_snapshot_data() -> dict: } +def get_targeted_support_snapshot_data() -> dict: + """Return the checked-in targeted-support snapshot.""" + return { + product: { + key: values.copy() for key, values in product_data.items() + } + for product, product_data in _TARGETED_SUPPORT_TESTING_DATA.items() + } + + @lru_cache(maxsize=1) def _fetch_slc_data() -> dict: """Fetch and parse SLC Table 6a data from Explore Education Statistics. @@ -232,7 +311,7 @@ def _fetch_maintenance_loan_data() -> dict: if os.environ.get("TESTING", "0") == "1": return get_maintenance_loan_snapshot_data() - df = pd.read_excel(_MAINTENANCE_LOAN_URL, sheet_name="Table 3A", header=None) + df = pd.read_excel(_STUDENT_SUPPORT_URL, sheet_name="Table 3A", header=None) count_header_row = _find_row(df, "Number of students paid (000s) [27]") count_year_row = count_header_row + 1 @@ -266,10 +345,65 @@ def _fetch_maintenance_loan_data() -> dict: } +def _series_from_row( + df: pd.DataFrame, year_row: int, value_row: int, multiplier: int +) -> dict: + year_columns = {} + for column, value in df.iloc[year_row].items(): + if isinstance(value, str) and re.fullmatch(r"\d{4}/\d{2}", value): + year_columns[column] = int(value[:4]) + 1 + + if not year_columns: + raise ValueError("Could not find year columns") + + values = {} + for column, year in year_columns.items(): + raw_value = df.iloc[value_row, column] + if pd.notna(raw_value) and raw_value not in (".", "-", ":"): + values[year] = int(round(float(raw_value) * multiplier)) + return values + + +@lru_cache(maxsize=1) +def _fetch_targeted_support_data() -> dict: + """Fetch Adult Dependants' Grant and Parents' Learning Allowance targets.""" + if os.environ.get("TESTING", "0") == "1": + return get_targeted_support_snapshot_data() + + df = pd.read_excel(_STUDENT_SUPPORT_URL, sheet_name="Table 4C (i)(ii)", header=None) + + count_year_row = _find_row(df, "2013/14") + amount_year_row = _find_row(df, "2013/14", start=count_year_row + 1) + adg_count_row = _find_row(df, "Adult Dependents Grant", start=count_year_row) + pla_count_row = _find_row(df, "Parents Learning Allowance", start=count_year_row) + adg_amount_row = _find_row(df, "Adult Dependents Grant", start=amount_year_row) + pla_amount_row = _find_row(df, "Parents Learning Allowance", start=amount_year_row) + + return { + "adult_dependants_grant": { + "recipients": _series_from_row( + df, count_year_row, adg_count_row, multiplier=1_000 + ), + "amount_paid": _series_from_row( + df, amount_year_row, adg_amount_row, multiplier=1_000_000 + ), + }, + "parents_learning_allowance": { + "recipients": _series_from_row( + df, count_year_row, pla_count_row, multiplier=1_000 + ), + "amount_paid": _series_from_row( + df, amount_year_row, pla_amount_row, multiplier=1_000_000 + ), + }, + } + + def get_targets() -> list[Target]: """Generate SLC calibration targets by fetching live data.""" slc_data = _fetch_slc_data() maintenance_loan_data = _fetch_maintenance_loan_data() + targeted_support_data = _fetch_targeted_support_data() targets = [] @@ -299,7 +433,7 @@ def get_targets() -> list[Target]: unit=Unit.COUNT, is_count=True, values=maintenance_loan_data["recipients"], - reference_url=_MAINTENANCE_LOAN_URL, + reference_url=_STUDENT_SUPPORT_URL, ), Target( name="slc/maintenance_loan_spend", @@ -307,7 +441,41 @@ def get_targets() -> list[Target]: source="slc", unit=Unit.GBP, values=maintenance_loan_data["amount_paid"], - reference_url=_MAINTENANCE_LOAN_URL, + reference_url=_STUDENT_SUPPORT_URL, + ), + Target( + name="slc/parents_learning_allowance_recipients", + variable="parents_learning_allowance", + source="slc", + unit=Unit.COUNT, + is_count=True, + values=targeted_support_data["parents_learning_allowance"]["recipients"], + reference_url=_STUDENT_SUPPORT_URL, + ), + Target( + name="slc/parents_learning_allowance_spend", + variable="parents_learning_allowance", + source="slc", + unit=Unit.GBP, + values=targeted_support_data["parents_learning_allowance"]["amount_paid"], + reference_url=_STUDENT_SUPPORT_URL, + ), + Target( + name="slc/adult_dependants_grant_recipients", + variable="adult_dependants_grant", + source="slc", + unit=Unit.COUNT, + is_count=True, + values=targeted_support_data["adult_dependants_grant"]["recipients"], + reference_url=_STUDENT_SUPPORT_URL, + ), + Target( + name="slc/adult_dependants_grant_spend", + variable="adult_dependants_grant", + source="slc", + unit=Unit.GBP, + values=targeted_support_data["adult_dependants_grant"]["amount_paid"], + reference_url=_STUDENT_SUPPORT_URL, ), ] ) diff --git a/policyengine_uk_data/tests/test_student_loan_targets.py b/policyengine_uk_data/tests/test_student_loan_targets.py index d942f7e00..65a57958b 100644 --- a/policyengine_uk_data/tests/test_student_loan_targets.py +++ b/policyengine_uk_data/tests/test_student_loan_targets.py @@ -20,14 +20,20 @@ def test_slc_targets_registered(): assert "slc/student_loan_repayment/england/plan_2" in targets assert "slc/maintenance_loan_recipients" in targets assert "slc/maintenance_loan_spend" in targets + assert "slc/parents_learning_allowance_recipients" in targets + assert "slc/parents_learning_allowance_spend" in targets + assert "slc/adult_dependants_grant_recipients" in targets + assert "slc/adult_dependants_grant_spend" in targets def test_policyengine_uk_release_exposes_maintenance_loan_variable(): - """The lockfile should point at a policyengine-uk release with maintenance loans.""" + """The lockfile should point at a release with the student-support variables.""" from policyengine_uk import CountryTaxBenefitSystem system = CountryTaxBenefitSystem() assert "maintenance_loan" in system.variables + assert "parents_learning_allowance" in system.variables + assert "adult_dependants_grant" in system.variables def test_slc_snapshot_values_match_higher_education_total_rows(): @@ -117,6 +123,18 @@ def test_slc_maintenance_loan_targets_match_official_2025_values(): assert targets["slc/maintenance_loan_spend"].values[2025] == 8_591_659_718 +def test_slc_targeted_support_targets_match_official_2025_values(): + """PLA and ADG targets should match Table 4C(i) for 2024/25.""" + from policyengine_uk_data.targets.registry import get_all_targets + + targets = {t.name: t for t in get_all_targets()} + + assert targets["slc/parents_learning_allowance_recipients"].values[2025] == 99_645 + assert targets["slc/parents_learning_allowance_spend"].values[2025] == 181_421_659 + assert targets["slc/adult_dependants_grant_recipients"].values[2025] == 18_611 + assert targets["slc/adult_dependants_grant_spend"].values[2025] == 55_364_917 + + def test_slc_maintenance_loan_snapshot_matches_known_series_points(): """Snapshot should preserve the published maintenance-loan time series.""" from policyengine_uk_data.targets.sources import slc @@ -129,6 +147,18 @@ def test_slc_maintenance_loan_snapshot_matches_known_series_points(): assert data["amount_paid"][2025] == 8_591_659_718 +def test_slc_targeted_support_snapshot_matches_known_series_points(): + """Snapshot should preserve the published PLA and ADG series.""" + from policyengine_uk_data.targets.sources import slc + + data = slc.get_targeted_support_snapshot_data() + + assert data["adult_dependants_grant"]["recipients"][2014] == 13_836 + assert data["adult_dependants_grant"]["amount_paid"][2025] == 55_364_917 + assert data["parents_learning_allowance"]["recipients"][2021] == 76_740 + assert data["parents_learning_allowance"]["amount_paid"][2025] == 181_421_659 + + def test_slc_testing_mode_uses_snapshot_without_network(monkeypatch): """Dataset-build CI should not depend on a live SLC endpoint.""" from policyengine_uk_data.targets.sources import slc @@ -163,6 +193,22 @@ def fail_excel(*args, **kwargs): slc._fetch_maintenance_loan_data.cache_clear() +def test_slc_targeted_support_testing_mode_uses_snapshot_without_network(monkeypatch): + """Targeted-support SLC data should also avoid network in TESTING mode.""" + from policyengine_uk_data.targets.sources import slc + + slc._fetch_targeted_support_data.cache_clear() + monkeypatch.setenv("TESTING", "1") + + def fail_excel(*args, **kwargs): + raise AssertionError("network should not be used in TESTING mode") + + monkeypatch.setattr(slc.pd, "read_excel", fail_excel) + + assert slc._fetch_targeted_support_data() == slc.get_targeted_support_snapshot_data() + slc._fetch_targeted_support_data.cache_clear() + + def test_slc_parser_uses_higher_education_total_rows(monkeypatch): """Parser should read HE-total rows, not the first matching above-threshold row.""" from policyengine_uk_data.targets.sources import slc @@ -305,6 +351,45 @@ def test_slc_maintenance_loan_parser_uses_grand_total_rows(monkeypatch): slc._fetch_maintenance_loan_data.cache_clear() +def test_slc_targeted_support_parser_uses_table_4c_rows(monkeypatch): + """Targeted-support parser should read the published Table 4C rows.""" + from policyengine_uk_data.targets.sources import slc + + table = np.full((24, 15), np.nan, dtype=object) + table[7, 3] = "2013/14" + table[7, 14] = "2024/25" + table[9, 1] = "Adult Dependents Grant" + table[9, 3] = 13.836 + table[9, 14] = 18.611 + table[10, 1] = "Parents Learning Allowance" + table[10, 3] = 49.219 + table[10, 14] = 99.645 + table[17, 3] = "2013/14" + table[17, 14] = "2024/25" + table[19, 1] = "Adult Dependents Grant" + table[19, 3] = 33.05009068 + table[19, 14] = 55.36491681 + table[20, 1] = "Parents Learning Allowance" + table[20, 3] = 70.52488619 + table[20, 14] = 181.42165932 + + slc._fetch_targeted_support_data.cache_clear() + monkeypatch.delenv("TESTING", raising=False) + monkeypatch.setattr( + slc.pd, + "read_excel", + lambda *args, **kwargs: __import__("pandas").DataFrame(table), + ) + + data = slc._fetch_targeted_support_data() + assert data["adult_dependants_grant"]["recipients"][2014] == 13_836 + assert data["adult_dependants_grant"]["amount_paid"][2025] == 55_364_917 + assert data["parents_learning_allowance"]["recipients"][2025] == 99_645 + assert data["parents_learning_allowance"]["amount_paid"][2014] == 70_524_886 + + slc._fetch_targeted_support_data.cache_clear() + + def test_student_loan_target_compute_distinguishes_liable_from_repaying(): """Above-threshold counts should require repayments, while liable counts should not.""" from policyengine_uk_data.targets.compute.other import ( @@ -349,16 +434,19 @@ def household_from_person(values): assert liable.tolist() == [1.0, 1.0, 0.0, 0.0] -def test_maintenance_loan_target_compute_handles_count_and_spend(): - """Maintenance-loan targets should bind through the shared compute path.""" +def test_person_support_target_compute_handles_count_and_spend(): + """Person-level support targets should bind through the shared compute path.""" from policyengine_uk_data.targets.build_loss_matrix import _compute_column from policyengine_uk_data.targets.schema import GeographicLevel, Target, Unit class DummyCtx: @staticmethod def pe_person(variable): - assert variable == "maintenance_loan" - return np.array([0.0, 5_000.0, 7_500.0]) + values = { + "maintenance_loan": np.array([0.0, 5_000.0, 7_500.0]), + "parents_learning_allowance": np.array([0.0, 2_024.0, 2_024.0]), + } + return values[variable] @staticmethod def household_from_person(values): @@ -388,9 +476,36 @@ def household_from_person(values): DummyCtx(), 2025, ) + pla_recipients = _compute_column( + Target( + name="slc/parents_learning_allowance_recipients", + variable="parents_learning_allowance", + source="slc", + unit=Unit.COUNT, + geographic_level=GeographicLevel.NATIONAL, + values={2025: 99_645}, + is_count=True, + ), + DummyCtx(), + 2025, + ) + pla_spend = _compute_column( + Target( + name="slc/parents_learning_allowance_spend", + variable="parents_learning_allowance", + source="slc", + unit=Unit.GBP, + geographic_level=GeographicLevel.NATIONAL, + values={2025: 181_421_659}, + ), + DummyCtx(), + 2025, + ) assert recipients.tolist() == [0.0, 1.0, 1.0] assert spend.tolist() == [0.0, 5_000.0, 7_500.0] + assert pla_recipients.tolist() == [0.0, 1.0, 1.0] + assert pla_spend.tolist() == [0.0, 2_024.0, 2_024.0] def test_student_loan_repayment_target_compute_filters_country_and_plan(): diff --git a/pyproject.toml b/pyproject.toml index 66ad0025f..cc4d7865a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ dependencies = [ "policyengine", "google-cloud-storage", "google-auth", - "policyengine-uk>=2.81.0", + "policyengine-uk>=2.85.0", "microcalibrate>=0.18.0", "microimpute>=1.0.1", "ruff>=0.9.0", diff --git a/uv.lock b/uv.lock index 00f492817..71455baf8 100644 --- a/uv.lock +++ b/uv.lock @@ -1351,7 +1351,7 @@ wheels = [ [[package]] name = "policyengine-uk" -version = "2.81.0" +version = "2.85.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "microdf-python" }, @@ -1359,14 +1359,14 @@ dependencies = [ { name = "pydantic" }, { name = "tables" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/bf/631ff06a5cbac23c340e227b4f8531a6cfbc63a4f82857b82a06db0d1575/policyengine_uk-2.81.0.tar.gz", hash = "sha256:1630e8e2d5b2c529ce25e9d4d148efc98bac52a10216c1b7896e4a64d902b539", size = 1142766, upload-time = "2026-04-14T01:05:20.949Z" } +sdist = { url = "https://files.pythonhosted.org/packages/23/3d/ad2c4f0f702c9027f9b0b90db0226c3c03cc2f30a2a360e6be0de3babd46/policyengine_uk-2.85.0.tar.gz", hash = "sha256:8619045b2005dd80ffbe5f1ab29acd4151cb149de7b307ae4167df8d10cc7338", size = 1155602, upload-time = "2026-04-15T03:21:30.941Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/86/24e36797ad31d8777d3f221933ead3bf35bc0dba8a74f64446fb32fb56db/policyengine_uk-2.81.0-py3-none-any.whl", hash = "sha256:9d03f4242e3df736d99d8ea3a58fb8977da24dd41bfe451377d6dfbe6f623f80", size = 1788129, upload-time = "2026-04-14T01:05:19.077Z" }, + { url = "https://files.pythonhosted.org/packages/68/7f/45b29a916a67a77d045407a1e9d0c73bde2b6afe005bbe286d2c107afa9f/policyengine_uk-2.85.0-py3-none-any.whl", hash = "sha256:9c76893051529d45c2cbae49a1f8c46e81aae8464bb00b56a06b2ef56fc2c3b4", size = 1836001, upload-time = "2026-04-15T03:21:29.241Z" }, ] [[package]] name = "policyengine-uk-data" -version = "1.48.0" +version = "1.49.0" source = { editable = "." } dependencies = [ { name = "google-auth" }, @@ -1421,7 +1421,7 @@ requires-dist = [ { name = "pandas" }, { name = "policyengine" }, { name = "policyengine-core", specifier = ">=3.19.4" }, - { name = "policyengine-uk", specifier = ">=2.81.0" }, + { name = "policyengine-uk", specifier = ">=2.85.0" }, { name = "pydantic", specifier = ">=2.0" }, { name = "pytest", marker = "extra == 'dev'" }, { name = "pyyaml" }, From 1759d72a840bc18d2969f06de606c1b0934d13ae Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 14 Apr 2026 23:33:29 -0400 Subject: [PATCH 2/2] Format PLA and ADG target files --- policyengine_uk_data/targets/sources/slc.py | 12 +++++++----- .../tests/test_student_loan_targets.py | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/policyengine_uk_data/targets/sources/slc.py b/policyengine_uk_data/targets/sources/slc.py index 13694285e..f4723d06a 100644 --- a/policyengine_uk_data/targets/sources/slc.py +++ b/policyengine_uk_data/targets/sources/slc.py @@ -200,9 +200,7 @@ def get_maintenance_loan_snapshot_data() -> dict: def get_targeted_support_snapshot_data() -> dict: """Return the checked-in targeted-support snapshot.""" return { - product: { - key: values.copy() for key, values in product_data.items() - } + product: {key: values.copy() for key, values in product_data.items()} for product, product_data in _TARGETED_SUPPORT_TESTING_DATA.items() } @@ -449,7 +447,9 @@ def get_targets() -> list[Target]: source="slc", unit=Unit.COUNT, is_count=True, - values=targeted_support_data["parents_learning_allowance"]["recipients"], + values=targeted_support_data["parents_learning_allowance"][ + "recipients" + ], reference_url=_STUDENT_SUPPORT_URL, ), Target( @@ -457,7 +457,9 @@ def get_targets() -> list[Target]: variable="parents_learning_allowance", source="slc", unit=Unit.GBP, - values=targeted_support_data["parents_learning_allowance"]["amount_paid"], + values=targeted_support_data["parents_learning_allowance"][ + "amount_paid" + ], reference_url=_STUDENT_SUPPORT_URL, ), Target( diff --git a/policyengine_uk_data/tests/test_student_loan_targets.py b/policyengine_uk_data/tests/test_student_loan_targets.py index 65a57958b..86eadef02 100644 --- a/policyengine_uk_data/tests/test_student_loan_targets.py +++ b/policyengine_uk_data/tests/test_student_loan_targets.py @@ -205,7 +205,9 @@ def fail_excel(*args, **kwargs): monkeypatch.setattr(slc.pd, "read_excel", fail_excel) - assert slc._fetch_targeted_support_data() == slc.get_targeted_support_snapshot_data() + assert ( + slc._fetch_targeted_support_data() == slc.get_targeted_support_snapshot_data() + ) slc._fetch_targeted_support_data.cache_clear()