Skip to content

Commit 8bfa539

Browse files
Extract compute_income_change and add exact value test
Pulls the 3-line formula into a named function so it can be tested directly with exact value assertions, not just bucket assignment. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 227f342 commit 8bfa539

2 files changed

Lines changed: 23 additions & 6 deletions

File tree

policyengine_api/endpoints/economy/compare.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,14 @@ def poverty_impact(baseline: dict, reform: dict) -> dict:
310310
)
311311

312312

313+
def compute_income_change(baseline_values, reform_values):
314+
"""Percentage income change with a floor of 1 on the baseline
315+
to avoid division by zero for zero/negative incomes."""
316+
absolute_change = reform_values - baseline_values
317+
capped_baseline = np.maximum(baseline_values, 1)
318+
return absolute_change / capped_baseline
319+
320+
313321
def intra_decile_impact(baseline: dict, reform: dict) -> dict:
314322
baseline_income = MicroSeries(
315323
baseline["household_net_income"], weights=baseline["household_weight"]
@@ -321,9 +329,9 @@ def intra_decile_impact(baseline: dict, reform: dict) -> dict:
321329
baseline["household_count_people"], weights=baseline_income.weights
322330
)
323331
decile = MicroSeries(baseline["household_income_decile"]).values
324-
absolute_change = (reform_income - baseline_income).values
325-
capped_baseline_income = np.maximum(baseline_income.values, 1)
326-
income_change = absolute_change / capped_baseline_income
332+
income_change = compute_income_change(
333+
baseline_income.values, reform_income.values
334+
)
327335

328336
# Within each decile, calculate the percentage of people who:
329337
# 1. Gained more than 5% of their income
@@ -378,9 +386,9 @@ def intra_wealth_decile_impact(baseline: dict, reform: dict) -> dict:
378386
baseline["household_count_people"], weights=baseline_income.weights
379387
)
380388
decile = MicroSeries(baseline["household_wealth_decile"]).values
381-
absolute_change = (reform_income - baseline_income).values
382-
capped_baseline_income = np.maximum(baseline_income.values, 1)
383-
income_change = absolute_change / capped_baseline_income
389+
income_change = compute_income_change(
390+
baseline_income.values, reform_income.values
391+
)
384392

385393
# Within each decile, calculate the percentage of people who:
386394
# 1. Gained more than 5% of their income

tests/unit/endpoints/economy/test_compare.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
UKLocalAuthorityBreakdown,
1212
uk_constituency_breakdown,
1313
uk_local_authority_breakdown,
14+
compute_income_change,
1415
intra_decile_impact,
1516
intra_wealth_decile_impact,
1617
)
@@ -752,6 +753,14 @@ def _make_economy(
752753
}
753754

754755

756+
class TestComputeIncomeChange:
757+
"""Direct unit tests for the income change formula."""
758+
759+
def test__income_change_formula_exact(self):
760+
result = compute_income_change(np.array([1000.0]), np.array([1040.0]))
761+
assert result[0] == pytest.approx(0.04)
762+
763+
755764
class TestIntraDecileImpact:
756765
"""Tests for the intra_decile_impact function — verifying correct
757766
percentage change calculation and bucket assignment."""

0 commit comments

Comments
 (0)