policyengine-uk 2.53.0__py3-none-any.whl → 2.54.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of policyengine-uk might be problematic. Click here for more details.

@@ -2,3 +2,4 @@ from policyengine_uk.data.dataset_schema import (
2
2
  UKMultiYearDataset,
3
3
  UKSingleYearDataset,
4
4
  )
5
+ from .filter_dataset import filter_dataset
@@ -0,0 +1,52 @@
1
+ import typing
2
+
3
+ if typing.TYPE_CHECKING:
4
+ from policyengine_uk import Microsimulation
5
+ from policyengine_uk.data import UKSingleYearDataset
6
+
7
+
8
+ def filter_dataset(
9
+ sim: "Microsimulation", household_id: int, year: int = 2026
10
+ ) -> "UKSingleYearDataset":
11
+ from policyengine_uk import Microsimulation
12
+ from policyengine_uk.data import UKSingleYearDataset
13
+
14
+ """
15
+ Extract a single household from a simulation dataset.
16
+
17
+ This function creates a new dataset containing only the specified household
18
+ and the associated benefit units and people within that household.
19
+
20
+ Parameters
21
+ ----------
22
+ sim : Microsimulation
23
+ The microsimulation object containing the dataset.
24
+ household_id : int
25
+ The ID of the household to extract.
26
+ year : int, default 2026
27
+ The dataset year to filter.
28
+
29
+ Returns
30
+ -------
31
+ UKSingleYearDataset
32
+ A new dataset containing only data for the specified household.
33
+ """
34
+ dataset: UKSingleYearDataset = sim.dataset[year]
35
+ new_dataset = dataset.copy()
36
+ new_dataset.person = new_dataset.person[
37
+ new_dataset.person.person_household_id == household_id
38
+ ]
39
+ new_dataset.household = new_dataset.household[
40
+ new_dataset.household.household_id == household_id
41
+ ]
42
+ benunits = new_dataset.person.person_benunit_id.unique()
43
+ new_dataset.benunit = new_dataset.benunit[
44
+ new_dataset.benunit.benunit_id.isin(benunits)
45
+ ]
46
+
47
+ return UKSingleYearDataset(
48
+ person=new_dataset.person,
49
+ household=new_dataset.household,
50
+ benunit=new_dataset.benunit,
51
+ fiscal_year=year,
52
+ )
@@ -28,7 +28,7 @@ from .participation import (
28
28
 
29
29
 
30
30
  def calculate_excluded_from_labour_supply_responses(
31
- sim: Simulation, count_adults: int = 1
31
+ sim: Simulation, count_adults: int = 2
32
32
  ):
33
33
  """Calculate which individuals are excluded from labour supply responses.
34
34
 
@@ -58,7 +58,7 @@ def calculate_excluded_from_labour_supply_responses(
58
58
  | (adult_index == 0)
59
59
  | (adult_index >= count_adults + 1)
60
60
  )
61
- return excluded
61
+ return excluded.values
62
62
 
63
63
 
64
64
  class FTEImpacts(BaseModel):
@@ -97,10 +97,10 @@ class LabourSupplyResponseData(BaseModel):
97
97
 
98
98
  def apply_labour_supply_responses(
99
99
  sim: Simulation,
100
- target_variable: str = "household_net_income",
100
+ target_variable: str = "hbai_household_net_income",
101
101
  input_variable: str = "employment_income",
102
102
  year: int = 2025,
103
- count_adults: int = 1,
103
+ count_adults: int = 2,
104
104
  delta: float = 1_000,
105
105
  ) -> pd.DataFrame:
106
106
  """Apply labour supply responses to simulation and return the response vector.
@@ -132,8 +132,9 @@ def apply_labour_supply_responses(
132
132
  )
133
133
  reform_income = sim.calculate(target_variable, year, map_to="person")
134
134
 
135
- baseline_income = baseline_income.values
136
- reform_income = reform_income.values
135
+ baseline_income = baseline_income
136
+ reform_income = reform_income
137
+ baseline_income = pd.Series(baseline_income, index=reform_income.index)
137
138
 
138
139
  # Calculate relative changes
139
140
  income_rel_change = np.where(
@@ -154,7 +155,9 @@ def apply_labour_supply_responses(
154
155
  )
155
156
 
156
157
  # Apply extensive margin responses (participation model)
157
- participation_responses = apply_participation_responses(sim=sim, year=year)
158
+ participation_responses = (
159
+ None # = apply_participation_responses(sim=sim, year=year)
160
+ )
158
161
 
159
162
  # Add FTE impacts to the response data
160
163
  fte_impacts = FTEImpacts(
@@ -194,10 +197,10 @@ def apply_labour_supply_responses(
194
197
 
195
198
  def apply_progression_responses(
196
199
  sim: Simulation,
197
- target_variable: str = "household_net_income",
200
+ target_variable: str = "hbai_household_net_income",
198
201
  input_variable: str = "employment_income",
199
202
  year: int = 2025,
200
- count_adults: int = 1,
203
+ count_adults: int = 2,
201
204
  delta: float = 1_000,
202
205
  pre_calculated_income_rel_change: np.ndarray = None,
203
206
  ) -> pd.DataFrame:
@@ -230,6 +233,7 @@ def apply_progression_responses(
230
233
  derivative_changes = derivative_changes.rename(
231
234
  columns={col: f"deriv_{col}" for col in derivative_changes.columns}
232
235
  )
236
+ derivative_changes["person_id"] = sim.calculate("person_id", year).values
233
237
 
234
238
  # Add in actual implied wages
235
239
  gross_wage = sim.calculate("employment_income", year) / sim.calculate(
@@ -259,20 +263,13 @@ def apply_progression_responses(
259
263
 
260
264
  # Calculate changes in income levels (drives income effects)
261
265
  if pre_calculated_income_rel_change is not None:
262
- # Use pre-calculated values
263
266
  n_people = len(sim.calculate("person_id", year))
264
267
  income_changes = pd.DataFrame(
265
268
  {
266
- "baseline": np.zeros(
267
- n_people
268
- ), # Not needed for behavioral response
269
- "scenario": np.zeros(
270
- n_people
271
- ), # Not needed for behavioral response
269
+ "baseline": np.zeros(n_people),
270
+ "scenario": np.zeros(n_people),
272
271
  "rel_change": pre_calculated_income_rel_change,
273
- "abs_change": np.zeros(
274
- n_people
275
- ), # Not needed for behavioral response
272
+ "abs_change": np.zeros(n_people),
276
273
  }
277
274
  )
278
275
  else:
@@ -336,11 +333,10 @@ def apply_progression_responses(
336
333
  response = response_df["total_response"].values
337
334
 
338
335
  # Apply the labour supply response to the simulation
339
- # NOTE: Don't reset calculations as this breaks UC and other benefit calculations
340
- # Instead, just update the employment income with the behavioral response
336
+ sim.reset_calculations()
341
337
  sim.set_input(input_variable, year, employment_income + response)
342
338
 
343
- weight = sim.calculate("household_weight", year, map_to="person")
339
+ weight = sim.calculate("household_weight", year, map_to="person").values
344
340
 
345
341
  result = MicroDataFrame(df, weights=weight)
346
342
 
@@ -14,7 +14,7 @@ from policyengine_uk import Simulation
14
14
 
15
15
  def calculate_derivative(
16
16
  sim: Simulation,
17
- target_variable: str = "household_net_income",
17
+ target_variable: str = "hbai_household_net_income",
18
18
  input_variable: str = "employment_income",
19
19
  year: int = 2025,
20
20
  count_adults: int = 2,
@@ -38,7 +38,7 @@ def calculate_derivative(
38
38
  Array of marginal rates clipped between 0 and 1
39
39
  """
40
40
  # Get baseline values for input variable and identify adults
41
- input_variable_values = sim.calculate(input_variable, year)
41
+ input_variable_values = sim.calculate(input_variable, year).copy()
42
42
  adult_index = sim.calculate("adult_index")
43
43
  entity_key = sim.tax_benefit_system.variables[input_variable].entity.key
44
44
 
@@ -67,13 +67,17 @@ def calculate_derivative(
67
67
  ~pd.Series(adult_index).isin(range(1, count_adults + 1))
68
68
  ] = np.nan
69
69
 
70
+ # Reset simulation to original state
71
+ sim.reset_calculations()
72
+ sim.set_input(input_variable, year, input_variable_values)
73
+
70
74
  # Clip to ensure rates are between 0 and 1 (0% to 100% retention)
71
- return rel_marginal_wages.clip(0, 1)
75
+ return rel_marginal_wages.round(4)
72
76
 
73
77
 
74
78
  def calculate_relative_income_change(
75
79
  sim: Simulation,
76
- target_variable: str = "household_net_income",
80
+ target_variable: str = "hbai_household_net_income",
77
81
  year: int = 2025,
78
82
  ) -> pd.DataFrame:
79
83
  """Calculate relative change in income between baseline and scenario.
@@ -96,6 +100,9 @@ def calculate_relative_income_change(
96
100
  reformed_target_values = sim.calculate(
97
101
  target_variable, year, map_to="person"
98
102
  )
103
+ original_target_values = pd.Series(
104
+ original_target_values, index=reformed_target_values.index
105
+ )
99
106
 
100
107
  # Calculate relative change, handling division by zero
101
108
  rel_change = (
@@ -118,10 +125,10 @@ def calculate_relative_income_change(
118
125
 
119
126
  def calculate_derivative_change(
120
127
  sim: Simulation,
121
- target_variable: str = "household_net_income",
128
+ target_variable: str = "hbai_household_net_income",
122
129
  input_variable: str = "employment_income",
123
130
  year: int = 2025,
124
- count_adults: int = 1,
131
+ count_adults: int = 2,
125
132
  delta: float = 1_000,
126
133
  ) -> pd.DataFrame:
127
134
  """Calculate change in marginal rates between baseline and scenario.
@@ -159,6 +166,7 @@ def calculate_derivative_change(
159
166
  count_adults=count_adults,
160
167
  delta=delta,
161
168
  )
169
+ original_deriv = pd.Series(original_deriv, index=reformed_deriv.index)
162
170
 
163
171
  # Calculate relative and absolute changes in marginal rates
164
172
  rel_change = reformed_deriv / original_deriv - 1
@@ -8,7 +8,9 @@ def add_universal_credit_reform(sim: Microsimulation):
8
8
  sim.tax_benefit_system.parameters.gov.dwp.universal_credit.rebalancing
9
9
  )
10
10
 
11
- uc_seed = np.random.random(len(sim.calculate("benunit_id")))
11
+ generator = np.random.default_rng(43)
12
+
13
+ uc_seed = generator.random(len(sim.calculate("benunit_id")))
12
14
  p_uc_post_2026_status = {
13
15
  2025: 0,
14
16
  2026: 0.11,
@@ -104,8 +104,6 @@ class Simulation(CoreSimulation):
104
104
  else:
105
105
  raise ValueError(f"Unsupported dataset type: {dataset.__class__}")
106
106
 
107
- self.input_variables = self.get_known_variables()
108
-
109
107
  # Universal Credit reform (July 2025). Needs closer integration in the baseline,
110
108
  # but adding here for ease of toggling on/off via the 'active' parameter.
111
109
  from policyengine_uk.scenarios import universal_credit_july_2025_reform
@@ -119,6 +117,8 @@ class Simulation(CoreSimulation):
119
117
  self.move_values("capital_gains", "capital_gains_before_response")
120
118
  self.move_values("employment_income", "employment_income_before_lsr")
121
119
 
120
+ self.input_variables = self.get_known_variables()
121
+
122
122
  if scenario is not None:
123
123
  self.baseline = Simulation(
124
124
  scenario=None,
@@ -1,10 +1,10 @@
1
1
  reforms:
2
2
  - name: Raise basic rate by 1pp
3
- expected_impact: 8.0
3
+ expected_impact: 8.1
4
4
  parameters:
5
5
  gov.hmrc.income_tax.rates.uk[0].rate: 0.21
6
6
  - name: Raise higher rate by 1pp
7
- expected_impact: 5.0
7
+ expected_impact: 4.9
8
8
  parameters:
9
9
  gov.hmrc.income_tax.rates.uk[1].rate: 0.42
10
10
  - name: Raise personal allowance by ~800GBP/year
@@ -12,22 +12,22 @@ reforms:
12
12
  parameters:
13
13
  gov.hmrc.income_tax.allowances.personal_allowance.amount: 13000
14
14
  - name: Raise child benefit by 25GBP/week per additional child
15
- expected_impact: -1.5
15
+ expected_impact: -1.3
16
16
  parameters:
17
17
  gov.hmrc.child_benefit.amount.additional: 25
18
18
  - name: Reduce Universal Credit taper rate to 20%
19
- expected_impact: -36.5
19
+ expected_impact: -36.0
20
20
  parameters:
21
21
  gov.dwp.universal_credit.means_test.reduction_rate: 0.2
22
22
  - name: Raise Class 1 main employee NICs rate to 10%
23
- expected_impact: 12.4
23
+ expected_impact: 12.5
24
24
  parameters:
25
25
  gov.hmrc.national_insurance.class_1.rates.employee.main: 0.1
26
26
  - name: Raise VAT standard rate by 2pp
27
- expected_impact: 21.2
27
+ expected_impact: 19.1
28
28
  parameters:
29
29
  gov.hmrc.vat.standard_rate: 0.22
30
30
  - name: Raise additional rate by 3pp
31
- expected_impact: 5.4
31
+ expected_impact: 4.5
32
32
  parameters:
33
33
  gov.hmrc.income_tax.rates.uk[2].rate: 0.48
@@ -4,67 +4,16 @@ from policyengine_uk.model_api import *
4
4
  class is_benefit_cap_exempt(Variable):
5
5
  value_type = bool
6
6
  entity = BenUnit
7
- label = "Whether exempt from the benefits cap"
7
+ label = (
8
+ "Whether exempt from the benefits cap because of health or disability"
9
+ )
8
10
  definition_period = YEAR
9
11
  reference = "https://www.gov.uk/benefit-cap/when-youre-not-affected"
10
12
 
11
13
  def formula(benunit, period, parameters):
12
- # Check if anyone in benefit unit is over state pension age
13
- person = benunit.members
14
- over_pension_age = person("is_SP_age", period)
15
- has_pensioner = benunit.any(over_pension_age)
16
-
17
- # UC-specific exemptions
18
- # Limited capability for work and work-related activity
19
- has_lcwra = benunit.any(
20
- person("uc_limited_capability_for_WRA", period)
21
- )
22
-
23
- # Carer element in UC indicates caring for someone with disability
24
- gets_uc_carer_element = benunit("uc_carer_element", period) > 0
25
-
26
- # Earnings exemption for UC (£846/month = £10,152/year)
27
- # Note: Only check earned income, not UC amount itself to avoid circular dependency
28
- uc_earned = benunit("uc_earned_income", period)
29
- earnings_threshold = 10_152
30
- meets_earnings_test = uc_earned >= earnings_threshold
31
-
32
- # Disability and carer benefits that exempt from cap
33
- QUAL_PERSONAL_BENEFITS = [
34
- "attendance_allowance",
35
- "carers_allowance",
36
- "dla", # Disability Living Allowance (includes components)
37
- "pip_dl", # PIP daily living component
38
- "pip_m", # PIP mobility component
39
- "iidb", # Industrial injuries disability benefit
40
- ]
41
-
42
- # ESA and Working Tax Credit
43
- QUAL_BENUNIT_BENEFITS = [
44
- "esa_income", # Income-based ESA
45
- "working_tax_credit", # If getting WTC, likely working enough
46
- ]
47
-
48
- qualifying_personal_benefits = add(
49
- benunit, period, QUAL_PERSONAL_BENEFITS
50
- )
51
- qualifying_benunit_benefits = add(
52
- benunit, period, QUAL_BENUNIT_BENEFITS
53
- )
54
-
55
- # Check for Armed Forces Compensation Scheme payments
56
- afcs = benunit("afcs", period) > 0
57
-
58
- # ESA contribution-based with support component
59
- esa_support_component = benunit("esa_contrib", period) > 0
60
-
61
- return (
62
- has_pensioner
63
- | has_lcwra
64
- | gets_uc_carer_element
65
- | meets_earnings_test
66
- | (qualifying_personal_benefits > 0)
67
- | (qualifying_benunit_benefits > 0)
68
- | afcs
69
- | esa_support_component
14
+ exempt_health = benunit(
15
+ "is_benefit_cap_exempt_health_disability", period
70
16
  )
17
+ exempt_other = benunit("is_benefit_cap_exempt_other", period)
18
+ exempt_earnings = benunit("is_benefit_cap_exempt_earnings", period)
19
+ return exempt_health | exempt_earnings | exempt_other
@@ -0,0 +1,66 @@
1
+ from policyengine_uk.model_api import *
2
+
3
+
4
+ class is_benefit_cap_exempt_earnings(Variable):
5
+ value_type = bool
6
+ entity = BenUnit
7
+ label = "Whether exempt from the benefits cap for non-health/disability reasons"
8
+ definition_period = YEAR
9
+ reference = "https://www.gov.uk/benefit-cap/when-youre-not-affected"
10
+
11
+ def formula(benunit, period, parameters):
12
+ # Check if anyone in benefit unit is over state pension age
13
+ person = benunit.members
14
+ over_pension_age = person("is_SP_age", period)
15
+ has_pensioner = benunit.any(over_pension_age)
16
+
17
+ # UC-specific exemptions
18
+ # Limited capability for work and work-related activity
19
+ has_lcwra = benunit.any(
20
+ person("uc_limited_capability_for_WRA", period)
21
+ )
22
+
23
+ # Carer element in UC indicates caring for someone with disability
24
+ gets_uc_carer_element = benunit("uc_carer_element", period) > 0
25
+
26
+ # Earnings exemption for UC (£846/month = £10,152/year)
27
+ # Note: Only check earned income, not UC amount itself to avoid circular dependency
28
+ uc_earned = benunit.sum(
29
+ benunit.members("employment_income", period)
30
+ + benunit.members("self_employment_income", period)
31
+ - benunit.members("income_tax", period)
32
+ - benunit.members("national_insurance", period)
33
+ )
34
+ earnings_threshold = 10_152
35
+ meets_earnings_test = uc_earned >= earnings_threshold
36
+
37
+ # Disability and carer benefits that exempt from cap
38
+ QUAL_PERSONAL_BENEFITS = [
39
+ "attendance_allowance",
40
+ "carers_allowance",
41
+ "dla", # Disability Living Allowance (includes components)
42
+ "pip_dl", # PIP daily living component
43
+ "pip_m", # PIP mobility component
44
+ "iidb", # Industrial injuries disability benefit
45
+ ]
46
+
47
+ # ESA and Working Tax Credit
48
+ QUAL_BENUNIT_BENEFITS = [
49
+ "esa_income", # Income-based ESA
50
+ "working_tax_credit", # If getting WTC, likely working enough
51
+ ]
52
+
53
+ qualifying_personal_benefits = add(
54
+ benunit, period, QUAL_PERSONAL_BENEFITS
55
+ )
56
+ qualifying_benunit_benefits = add(
57
+ benunit, period, QUAL_BENUNIT_BENEFITS
58
+ )
59
+
60
+ # Check for Armed Forces Compensation Scheme payments
61
+ afcs = benunit("afcs", period) > 0
62
+
63
+ # ESA contribution-based with support component
64
+ esa_support_component = benunit("esa_contrib", period) > 0
65
+
66
+ return meets_earnings_test
@@ -0,0 +1,75 @@
1
+ from policyengine_uk.model_api import *
2
+
3
+
4
+ class is_benefit_cap_exempt_health_disability(Variable):
5
+ value_type = bool
6
+ entity = BenUnit
7
+ label = (
8
+ "Whether exempt from the benefits cap because of health or disability"
9
+ )
10
+ definition_period = YEAR
11
+ reference = "https://www.gov.uk/benefit-cap/when-youre-not-affected"
12
+
13
+ def formula(benunit, period, parameters):
14
+ # Check if anyone in benefit unit is over state pension age
15
+ person = benunit.members
16
+ over_pension_age = person("is_SP_age", period)
17
+ has_pensioner = benunit.any(over_pension_age)
18
+
19
+ # UC-specific exemptions
20
+ # Limited capability for work and work-related activity
21
+ has_lcwra = benunit.any(
22
+ person("uc_limited_capability_for_WRA", period)
23
+ )
24
+
25
+ # Carer element in UC indicates caring for someone with disability
26
+ gets_uc_carer_element = benunit("uc_carer_element", period) > 0
27
+
28
+ # Earnings exemption for UC (£846/month = £10,152/year)
29
+ # Note: Only check earned income, not UC amount itself to avoid circular dependency
30
+ uc_earned = benunit.sum(
31
+ benunit.members("employment_income", period)
32
+ + benunit.members("self_employment_income", period)
33
+ - benunit.members("income_tax", period)
34
+ - benunit.members("national_insurance", period)
35
+ )
36
+ earnings_threshold = 10_152
37
+ meets_earnings_test = uc_earned >= earnings_threshold
38
+
39
+ # Disability and carer benefits that exempt from cap
40
+ QUAL_PERSONAL_BENEFITS = [
41
+ "attendance_allowance",
42
+ "carers_allowance",
43
+ "dla", # Disability Living Allowance (includes components)
44
+ "pip_dl", # PIP daily living component
45
+ "pip_m", # PIP mobility component
46
+ "iidb", # Industrial injuries disability benefit
47
+ ]
48
+
49
+ # ESA and Working Tax Credit
50
+ QUAL_BENUNIT_BENEFITS = [
51
+ "esa_income", # Income-based ESA
52
+ "working_tax_credit", # If getting WTC, likely working enough
53
+ ]
54
+
55
+ qualifying_personal_benefits = add(
56
+ benunit, period, QUAL_PERSONAL_BENEFITS
57
+ )
58
+ qualifying_benunit_benefits = add(
59
+ benunit, period, QUAL_BENUNIT_BENEFITS
60
+ )
61
+
62
+ # Check for Armed Forces Compensation Scheme payments
63
+ afcs = benunit("afcs", period) > 0
64
+
65
+ # ESA contribution-based with support component
66
+ esa_support_component = benunit("esa_contrib", period) > 0
67
+
68
+ return (
69
+ has_lcwra
70
+ | gets_uc_carer_element
71
+ | (qualifying_personal_benefits > 0)
72
+ | (qualifying_benunit_benefits > 0)
73
+ | afcs
74
+ | esa_support_component
75
+ )
@@ -0,0 +1,66 @@
1
+ from policyengine_uk.model_api import *
2
+
3
+
4
+ class is_benefit_cap_exempt_other(Variable):
5
+ value_type = bool
6
+ entity = BenUnit
7
+ label = "Whether exempt from the benefits cap for non-health/disability reasons"
8
+ definition_period = YEAR
9
+ reference = "https://www.gov.uk/benefit-cap/when-youre-not-affected"
10
+
11
+ def formula(benunit, period, parameters):
12
+ # Check if anyone in benefit unit is over state pension age
13
+ person = benunit.members
14
+ over_pension_age = person("is_SP_age", period)
15
+ has_pensioner = benunit.any(over_pension_age)
16
+
17
+ # UC-specific exemptions
18
+ # Limited capability for work and work-related activity
19
+ has_lcwra = benunit.any(
20
+ person("uc_limited_capability_for_WRA", period)
21
+ )
22
+
23
+ # Carer element in UC indicates caring for someone with disability
24
+ gets_uc_carer_element = benunit("uc_carer_element", period) > 0
25
+
26
+ # Earnings exemption for UC (£846/month = £10,152/year)
27
+ # Note: Only check earned income, not UC amount itself to avoid circular dependency
28
+ uc_earned = benunit.sum(
29
+ benunit.members("employment_income", period)
30
+ + benunit.members("self_employment_income", period)
31
+ - benunit.members("income_tax", period)
32
+ - benunit.members("national_insurance", period)
33
+ )
34
+ earnings_threshold = 10_152
35
+ meets_earnings_test = uc_earned >= earnings_threshold
36
+
37
+ # Disability and carer benefits that exempt from cap
38
+ QUAL_PERSONAL_BENEFITS = [
39
+ "attendance_allowance",
40
+ "carers_allowance",
41
+ "dla", # Disability Living Allowance (includes components)
42
+ "pip_dl", # PIP daily living component
43
+ "pip_m", # PIP mobility component
44
+ "iidb", # Industrial injuries disability benefit
45
+ ]
46
+
47
+ # ESA and Working Tax Credit
48
+ QUAL_BENUNIT_BENEFITS = [
49
+ "esa_income", # Income-based ESA
50
+ "working_tax_credit", # If getting WTC, likely working enough
51
+ ]
52
+
53
+ qualifying_personal_benefits = add(
54
+ benunit, period, QUAL_PERSONAL_BENEFITS
55
+ )
56
+ qualifying_benunit_benefits = add(
57
+ benunit, period, QUAL_BENUNIT_BENEFITS
58
+ )
59
+
60
+ # Check for Armed Forces Compensation Scheme payments
61
+ afcs = benunit("afcs", period) > 0
62
+
63
+ # ESA contribution-based with support component
64
+ esa_support_component = benunit("esa_contrib", period) > 0
65
+
66
+ return has_pensioner | afcs | esa_support_component
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: policyengine-uk
3
- Version: 2.53.0
3
+ Version: 2.54.1
4
4
  Summary: PolicyEngine tax and benefit system for the UK.
5
5
  Project-URL: Homepage, https://github.com/PolicyEngine/policyengine-uk
6
6
  Project-URL: Repository, https://github.com/PolicyEngine/policyengine-uk
@@ -3,16 +3,17 @@ policyengine_uk/entities.py,sha256=9yUbkUWQr3WydNE-gHhUudG97HGyXIZY3dkgQ6Z3t9A,1
3
3
  policyengine_uk/microsimulation.py,sha256=WskrrDrLGfDYwS1CzFk5rJkQSQlTknLkxFufStKRpxc,3379
4
4
  policyengine_uk/model_api.py,sha256=KdwJCL2HkXVxDpL6fCsCnQ9Sub6Kqp7Hyxlis3MNIx4,241
5
5
  policyengine_uk/modelled_policies.yaml,sha256=TLhvmkuI9ip-Fjq63n66RzDErCkN8K4BzY6XLxLMtFg,463
6
- policyengine_uk/simulation.py,sha256=n8LwAjabGHQLLg6bSWiotcJzrr49wDcvzaq1eOZSbqA,21265
6
+ policyengine_uk/simulation.py,sha256=YR8mxP6D5wSQGdCo2nLO0Jq6isNv5U83ddusVMnoOZk,21265
7
7
  policyengine_uk/system.py,sha256=Z-ax_ImUq5k4tycuThczTxQNW5iTE6ikBJIBQdKfIzU,91
8
8
  policyengine_uk/tax_benefit_system.py,sha256=CjX1lERyOm_vlgHQcQO92HZtJiwItLH-MxJveJqk6iM,5165
9
- policyengine_uk/data/__init__.py,sha256=J0bZ3WnvPzZ4qfVLYcwOc4lziMUMdbcMqJ3xwjoekbM,101
9
+ policyengine_uk/data/__init__.py,sha256=fF3Qhm01PCx26pbG_WRKddacNzbgbuEoayV_xMETDgc,144
10
10
  policyengine_uk/data/dataset_schema.py,sha256=781beGVnPWJhw2FzcG6he-LtmgxtwS1h6keAz7TPoXI,10036
11
11
  policyengine_uk/data/economic_assumptions.py,sha256=U3wyBs4zVI5-bcMB-GivELC1qG-895l5NPds3cuWb90,6239
12
+ policyengine_uk/data/filter_dataset.py,sha256=DtIixUMRnY-g-acXZIxaZ5217NYYVAMxVgs1Wa3rya0,1622
12
13
  policyengine_uk/data/uprating_indices.yaml,sha256=kQtfeGWyqge4dbJhs0iF4kTMqovuegill_Zfs8orJi4,2394
13
- policyengine_uk/dynamics/labour_supply.py,sha256=PlmYTGo6G-bZoazB2slpD35F2Wq5dIGlUJOzjc1dnSw,12283
14
+ policyengine_uk/dynamics/labour_supply.py,sha256=MQnlp2OfD2RboqBOxKoLHzVKfZjP04j6Oif1Jswp1-w,12074
14
15
  policyengine_uk/dynamics/participation.py,sha256=g5xUqg-Nj2lQny9GrUfI2D_swLx0-9k-486NXtcWwbM,23238
15
- policyengine_uk/dynamics/progression.py,sha256=4Wl3ZE-bYxNTMVGeOGFh22lYtHGPCarrhp8JzuLQs7I,13738
16
+ policyengine_uk/dynamics/progression.py,sha256=Mym2IxkcL20gKPZXk0JmT6quo0A9XU5_SbpShpa_PxE,14080
16
17
  policyengine_uk/parameters/gov/README.md,sha256=bHUep1_2pLHD3Or8SwjStOWXDIbW9OuYxOd4ml8IXcM,13
17
18
  policyengine_uk/parameters/gov/benefit_uprating_cpi.yaml,sha256=2zOSdJeUhDZYYsKE2vLkcK-UbKNoOSVwfac0QIAp02g,250
18
19
  policyengine_uk/parameters/gov/contrib/README.md,sha256=b282dmUFAmj7cXSfiMLyE81q5Y0Gnehy-6atLus-ESs,70
@@ -539,13 +540,13 @@ policyengine_uk/scenarios/__init__.py,sha256=OP_05x7RS8qUuwEN6tqoTGwrpk8vYLxCSav
539
540
  policyengine_uk/scenarios/pip_reform.py,sha256=fv6-HCuRxhzt-XEYv9yLJTEliAWu3EGx6duADSBO4n8,687
540
541
  policyengine_uk/scenarios/reindex_benefit_cap.py,sha256=dPUOsTkgYZNRN15e_ax5hg5ObHngk5tizz7FYStkGaE,1070
541
542
  policyengine_uk/scenarios/repeal_two_child_limit.py,sha256=vZndQVFNCe7v7k4v-PgneOCPld-YTnCmlveRbX_1czk,250
542
- policyengine_uk/scenarios/uc_reform.py,sha256=WPYKGBY_V7A0pQPxDM0lOYTR9GoLrF-iEm_8aXg5fXU,1840
543
+ policyengine_uk/scenarios/uc_reform.py,sha256=xfgNRVR5S_UMKmd3Zivrc717DvJX4hVqf2gTUlocGQA,1883
543
544
  policyengine_uk/tests/test_behavioral_responses.py,sha256=xuKOyuki6nLMrS-XArRqs8nU-o538eyMG2eAB1WDHHY,8191
544
545
  policyengine_uk/tests/test_parameter_metadata.py,sha256=_2w2dSokAf5Jskye_KIL8eh80N7yIrUszlmqnZtwQws,450
545
546
  policyengine_uk/tests/behavioral_responses/test_labor_supply_responses.yaml,sha256=xR8cy0XjcG8xTL_ufgEl1BHNWhXefVnA2va7X3v6FBk,5783
546
547
  policyengine_uk/tests/code_health/test_variables.py,sha256=9Y-KpmzhyRGy9eEqocK9z91NXHX5QIF3mDMNGvegb7Q,1398
547
548
  policyengine_uk/tests/microsimulation/README.md,sha256=1toB1Z06ynlUielTrsAaeo9Vb-c3ZrB3tbbR4E1xUGk,3924
548
- policyengine_uk/tests/microsimulation/reforms_config.yaml,sha256=M4A8PIdTfxGxGF7iSk8lKqriqR9HrV6VtyPGzS2BkrM,1086
549
+ policyengine_uk/tests/microsimulation/reforms_config.yaml,sha256=-XQjsQfb3GGs-qwdAP7OVT_OG2g3zHyDbHcw82p5UX8,1086
549
550
  policyengine_uk/tests/microsimulation/test_reform_impacts.py,sha256=xM3M2pclEhA9JIFpnuiPMy1fEBFOKcSzroRPk73FPls,2635
550
551
  policyengine_uk/tests/microsimulation/test_validity.py,sha256=_mHgrNu-hKzVd9V2GSg_yPQgJctxRzdQM7lM2bUvqNY,636
551
552
  policyengine_uk/tests/microsimulation/update_reform_impacts.py,sha256=4m5EpPu4SXTE3qOPkx3eIZnlaOzprfm6GmMCXETZuLk,6890
@@ -846,7 +847,10 @@ policyengine_uk/variables/gov/dwp/is_CTC_child_limit_exempt.py,sha256=_kSBwtMuTL
846
847
  policyengine_uk/variables/gov/dwp/is_CTC_eligible.py,sha256=eDWw_fj_dAvE8zZ4XStvxUd06D_D9goDMqvnL1ILTvo,565
847
848
  policyengine_uk/variables/gov/dwp/is_SP_age.py,sha256=yiDWUA5FicwN4PSXVQ9CDXwONj96LFtlsGoT22kYH8s,364
848
849
  policyengine_uk/variables/gov/dwp/is_WTC_eligible.py,sha256=Oc0ZyQYK09U4PQv00HZtVhXMxh5MQGs3s4M-VjJvv_g,2020
849
- policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt.py,sha256=jtaAEjRjhesm6UpauO6Th1FteO-Dkt5g7u7qlrdf1hs,2548
850
+ policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt.py,sha256=Q1_t-Hxg18LX39wTB-Sjc3ItDXRHh3FTHqY8_R64CPg,685
851
+ policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py,sha256=CK64_j_Cq7-aF8sCDUXRUf7mAJiodjlyeF3BdFG4Zvk,2547
852
+ policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_health_disability.py,sha256=4PeVQHBrtbtUlCVOJX5tmxhqKdmAwqtPJY91wPqtaIQ,2772
853
+ policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_other.py,sha256=5nfrcIMwAV3Q67yMOpFMP4Bjyus9y4AKQr5Uh_G363M,2569
850
854
  policyengine_uk/variables/gov/dwp/is_child_for_CTC.py,sha256=p1vdgGohyqRWy-0nppBa5McUr3alDPIwWZl9vC_NDWk,336
851
855
  policyengine_uk/variables/gov/dwp/jsa.py,sha256=2m9V-fwcawZzpOLC6TyWEl-Odze9E6vLH5E2h26kBQA,254
852
856
  policyengine_uk/variables/gov/dwp/jsa_contrib.py,sha256=6rdONNAAl2OYAmGfLxx2RNo2g0OyMzCn5Fd-S7GHizQ,234
@@ -1387,7 +1391,7 @@ policyengine_uk/variables/misc/spi_imputed.py,sha256=iPVlBF_TisM0rtKvO-3-PQ2UYCe
1387
1391
  policyengine_uk/variables/misc/uc_migrated.py,sha256=zFNcUJaO8gwmbL1iY9GKgUt3G6J9yrCraqBV_5dCvlM,306
1388
1392
  policyengine_uk/variables/misc/categories/lower_middle_or_higher.py,sha256=C54tHYz2DmOyvQYCC1bF8RJwRZinhAq_e3aYC-9F5fM,157
1389
1393
  policyengine_uk/variables/misc/categories/lower_or_higher.py,sha256=81NIbLLabRr9NwjpUZDuV8IV8_mqmp5NM-CZvt55TwE,129
1390
- policyengine_uk-2.53.0.dist-info/METADATA,sha256=-kXsAiFqG1qpcQFlhI7kakfoHjCZNNZA-9zENg0zoUY,3995
1391
- policyengine_uk-2.53.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
1392
- policyengine_uk-2.53.0.dist-info/licenses/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
1393
- policyengine_uk-2.53.0.dist-info/RECORD,,
1394
+ policyengine_uk-2.54.1.dist-info/METADATA,sha256=1kOpL7EC6aBugy0R27XQ2QpqSzowUF_40vBNSp-sh3c,3995
1395
+ policyengine_uk-2.54.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
1396
+ policyengine_uk-2.54.1.dist-info/licenses/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
1397
+ policyengine_uk-2.54.1.dist-info/RECORD,,