Skip to content
Open
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/853.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Rename `labor` to `labour` in LSR parameter and variable paths, labels, and descriptions to use British English spelling. The two consumed paths (`gov.simulation.labor_supply_responses.income_elasticity` and `.substitution_elasticity`) remain available as deprecation aliases for one release so downstream consumers — particularly the legacy `policyengine-app` PolicyRightSidebar — keep working until they migrate.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Deprecation aliases mirroring the renamed `labour_supply_responses` parameters
under the legacy `labor_supply_responses` path.

`policyengine-app` (legacy) hard-codes
`gov.simulation.labor_supply_responses.{income_elasticity,substitution_elasticity}`
in PolicyRightSidebar.jsx. Without this alias the LSR sliders break the
moment a deployed app rebuilds against this version of policyengine-uk.
The companion app PR (PolicyEngine/policyengine-app#2829) migrates to the
new path; remove this alias once that ships.
"""

from policyengine_core.parameters import Parameter, ParameterNode


_ALIASED_PARAMETERS = ("income_elasticity", "substitution_elasticity")


def add_lsr_deprecation_aliases(parameters: ParameterNode) -> ParameterNode:
simulation = parameters.gov.simulation
canonical = simulation.labour_supply_responses

legacy_node = ParameterNode(
name="gov.simulation.labor_supply_responses",
data={},
)

for child_name in _ALIASED_PARAMETERS:
canonical_child: Parameter = getattr(canonical, child_name)
legacy_child = canonical_child.clone()
legacy_child.name = f"gov.simulation.labor_supply_responses.{child_name}"
legacy_node.add_child(child_name, legacy_child)

simulation.add_child("labor_supply_responses", legacy_node)
return parameters
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
description: Percent change in labour supply given a 1% change in disposable income. This applies only to employment income.
values:
2020-01-01: 0
metadata:
unit: /1
label: Income elasticity of labour supply
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
description: Use the OBR's progression elasticities for the labor supply responses.
description: Use the OBR's progression elasticities for the labour supply responses.
values:
2000-01-01: 0
metadata:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
description: Percent change in labour supply given a 1% change in the effective marginal wage. This applies only to employment income.
values:
2020-01-01: 0
metadata:
unit: /1
label: Substitution elasticity of labour supply
4 changes: 4 additions & 0 deletions policyengine_uk/tax_benefit_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
from policyengine_uk.parameters.gov.economic_assumptions.lag_cpi import (
add_lagged_cpi,
)
from policyengine_uk.parameters.gov.simulation.labour_supply_responses.aliases import (
add_lsr_deprecation_aliases,
)
from policyengine_uk.utils.parameters import (
backdate_parameters,
convert_to_fiscal_year_parameters,
Expand Down Expand Up @@ -93,6 +96,7 @@ def process_parameters(self) -> None:
self.parameters = add_lagged_cpi(self.parameters)
self.parameters = add_triple_lock(self.parameters)
self.parameters = create_economic_assumption_indices(self.parameters)
self.parameters = add_lsr_deprecation_aliases(self.parameters)

# Create baseline parameters for reform comparisons
self.parameters.add_child("baseline", self.parameters.clone())
Expand Down
6 changes: 3 additions & 3 deletions policyengine_uk/tests/test_behavioral_responses.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Tests for behavioral labor supply responses.
Tests for behavioral labour supply responses.

This test module validates that the behavioral response system works correctly
and that all the critical fixes are functioning:
Expand Down Expand Up @@ -29,15 +29,15 @@

# Load YAML test cases
yaml_file = (
Path(__file__).parent / "behavioral_responses" / "test_labor_supply_responses.yaml"
Path(__file__).parent / "behavioral_responses" / "test_labour_supply_responses.yaml"
)
with open(yaml_file, "r") as f:
yaml_content = f.read()
test_cases = yaml.safe_load(yaml_content)


class TestBehavioralResponses:
"""Test behavioral labor supply responses functionality"""
"""Test behavioral labour supply responses functionality"""

def test_yaml_file_structure(self):
"""Test that YAML file loads correctly and has expected structure"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
from policyengine_uk.dynamics.progression import (
calculate_employment_income_change,
)
from policyengine_uk.variables.gov.simulation.labor_supply_response.income_elasticity_lsr import (
from policyengine_uk.variables.gov.simulation.labour_supply_response.income_elasticity_lsr import (
income_elasticity_lsr,
)
from policyengine_uk.variables.gov.simulation.labor_supply_response.substitution_elasticity_lsr import (
from policyengine_uk.variables.gov.simulation.labour_supply_response.substitution_elasticity_lsr import (
substitution_elasticity_lsr,
)

Expand All @@ -26,7 +26,7 @@ class FakeParameters:
def __init__(self, income_elasticity=0.1, substitution_elasticity=0.2):
self.gov = SimpleNamespace(
simulation=SimpleNamespace(
labor_supply_responses=SimpleNamespace(
labour_supply_responses=SimpleNamespace(
income_elasticity=income_elasticity,
substitution_elasticity=substitution_elasticity,
)
Expand Down Expand Up @@ -67,7 +67,7 @@ def test_substitution_elasticity_lsr_clips_negative_earnings():
assert np.allclose(result, np.array([0.0, 0.0, 40.0]))


def test_progression_labor_supply_response_clips_negative_earnings():
def test_progression_labour_supply_response_clips_negative_earnings():
result = calculate_employment_income_change(
employment_income=np.array([-1_000.0, 0.0, 1_000.0]),
derivative_changes=pd.DataFrame({"wage_rel_change": [0.1, 0.1, 0.1]}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
class employment_income_behavioral_response(Variable):
value_type = float
entity = Person
label = "income-related labor supply change"
label = "income-related labour supply change"
unit = GBP
definition_period = YEAR

def formula(person, period, parameters):
lsr = parameters(period).gov.simulation.labor_supply_responses
lsr = parameters(period).gov.simulation.labour_supply_responses
simulation = person.simulation
if simulation.baseline is None:
return 0 # No reform, no impact
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
class income_elasticity_lsr(Variable):
value_type = float
entity = Person
label = "income elasticity of labor supply response"
label = "income elasticity of labour supply response"
unit = GBP
definition_period = YEAR
requires_computation_after = "employment_income_behavioral_response"

def formula(person, period, parameters):
lsr = parameters(period).gov.simulation.labor_supply_responses
lsr = parameters(period).gov.simulation.labour_supply_responses
employment_income = max_(person("employment_income_before_lsr", period), 0)
income_change = person("relative_income_change", period)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def formula(person, period, parameters):
net_income = measurement_person.household("household_net_income", period)
income_change_bound = parameters(
period
).gov.simulation.labor_supply_responses.bounds.income_change
).gov.simulation.labour_supply_responses.bounds.income_change
# _c suffix for "clipped"
baseline_net_income_c = np.clip(baseline_net_income, 1, None)
net_income_c = np.clip(net_income, 1, None)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ def formula(person, period, parameters):
relative_change = (wage_rate_c - baseline_wage_c) / baseline_wage_c
wage_change_bound = parameters(
period
).gov.simulation.labor_supply_responses.bounds.effective_wage_rate_change
).gov.simulation.labour_supply_responses.bounds.effective_wage_rate_change
return np.clip(relative_change, -wage_change_bound, wage_change_bound)
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
class substitution_elasticity_lsr(Variable):
value_type = float
entity = Person
label = "substitution elasticity of labor supply response"
label = "substitution elasticity of labour supply response"
unit = GBP
definition_period = YEAR
requires_computation_after = "employment_income_behavioral_response"

def formula(person, period, parameters):
lsr = parameters(period).gov.simulation.labor_supply_responses
lsr = parameters(period).gov.simulation.labour_supply_responses
employment_income = max_(person("employment_income_before_lsr", period), 0)
wage_change = person("relative_wage_change", period)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class employment_income_before_lsr(Variable):
value_type = float
entity = Person
label = "employment income before labor supply responses"
label = "employment income before labour supply responses"
unit = GBP
definition_period = YEAR
uprating = "gov.economic_assumptions.indices.obr.average_earnings"
Loading