policyengine 3.1.14__py3-none-any.whl → 3.1.16__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.
@@ -1,25 +1,195 @@
1
1
  """General utility functions for UK policy reform analysis."""
2
2
 
3
+ import tempfile
4
+ from pathlib import Path
5
+ from typing import Any
6
+
3
7
  import pandas as pd
4
- from pydantic import BaseModel
8
+ from microdf import MicroDataFrame
9
+ from pydantic import BaseModel, Field, create_model
5
10
 
6
11
  from policyengine.core import OutputCollection, Simulation
12
+ from policyengine.core.policy import Policy
7
13
  from policyengine.outputs.decile_impact import (
8
14
  DecileImpact,
9
15
  calculate_decile_impacts,
10
16
  )
17
+ from policyengine.outputs.inequality import (
18
+ Inequality,
19
+ calculate_uk_inequality,
20
+ )
21
+ from policyengine.outputs.poverty import (
22
+ Poverty,
23
+ calculate_uk_poverty_rates,
24
+ )
11
25
 
26
+ from .datasets import PolicyEngineUKDataset, UKYearData
27
+ from .model import uk_latest
12
28
  from .outputs import ProgrammeStatistics
13
29
 
14
30
 
31
+ def _create_entity_output_model(
32
+ entity: str, variables: list[str]
33
+ ) -> type[BaseModel]:
34
+ """Create a dynamic Pydantic model for entity output variables."""
35
+ fields = {var: (float, ...) for var in variables}
36
+ return create_model(f"{entity.title()}Output", **fields)
37
+
38
+
39
+ # Create output models dynamically from uk_latest.entity_variables
40
+ PersonOutput = _create_entity_output_model(
41
+ "person", uk_latest.entity_variables["person"]
42
+ )
43
+ BenunitOutput = _create_entity_output_model(
44
+ "benunit", uk_latest.entity_variables["benunit"]
45
+ )
46
+ HouseholdEntityOutput = _create_entity_output_model(
47
+ "household", uk_latest.entity_variables["household"]
48
+ )
49
+
50
+
51
+ class UKHouseholdOutput(BaseModel):
52
+ """Output from a UK household calculation with all entity data."""
53
+
54
+ person: list[dict[str, Any]]
55
+ benunit: list[dict[str, Any]]
56
+ household: dict[str, Any]
57
+
58
+
59
+ class UKHouseholdInput(BaseModel):
60
+ """Input for a UK household calculation."""
61
+
62
+ people: list[dict[str, Any]]
63
+ benunit: dict[str, Any] = Field(default_factory=dict)
64
+ household: dict[str, Any] = Field(default_factory=dict)
65
+ year: int = 2026
66
+
67
+
68
+ def calculate_household_impact(
69
+ household_input: UKHouseholdInput,
70
+ policy: Policy | None = None,
71
+ ) -> UKHouseholdOutput:
72
+ """Calculate tax and benefit impacts for a single UK household."""
73
+ n_people = len(household_input.people)
74
+
75
+ # Build person data with defaults
76
+ person_data = {
77
+ "person_id": list(range(n_people)),
78
+ "person_benunit_id": [0] * n_people,
79
+ "person_household_id": [0] * n_people,
80
+ "person_weight": [1.0] * n_people,
81
+ }
82
+ # Add user-provided person fields
83
+ for i, person in enumerate(household_input.people):
84
+ for key, value in person.items():
85
+ if key not in person_data:
86
+ person_data[key] = [
87
+ 0.0
88
+ ] * n_people # Default to 0 for numeric fields
89
+ person_data[key][i] = value
90
+
91
+ # Build benunit data with defaults
92
+ benunit_data = {
93
+ "benunit_id": [0],
94
+ "benunit_weight": [1.0],
95
+ }
96
+ for key, value in household_input.benunit.items():
97
+ benunit_data[key] = [value]
98
+
99
+ # Build household data with defaults (required for uprating)
100
+ household_data = {
101
+ "household_id": [0],
102
+ "household_weight": [1.0],
103
+ "region": ["LONDON"],
104
+ "tenure_type": ["RENT_PRIVATELY"],
105
+ "council_tax": [0.0],
106
+ "rent": [0.0],
107
+ }
108
+ for key, value in household_input.household.items():
109
+ household_data[key] = [value]
110
+
111
+ # Create MicroDataFrames
112
+ person_df = MicroDataFrame(
113
+ pd.DataFrame(person_data), weights="person_weight"
114
+ )
115
+ benunit_df = MicroDataFrame(
116
+ pd.DataFrame(benunit_data), weights="benunit_weight"
117
+ )
118
+ household_df = MicroDataFrame(
119
+ pd.DataFrame(household_data), weights="household_weight"
120
+ )
121
+
122
+ # Create temporary dataset
123
+ tmpdir = tempfile.mkdtemp()
124
+ filepath = str(Path(tmpdir) / "household_impact.h5")
125
+
126
+ dataset = PolicyEngineUKDataset(
127
+ name="Household impact calculation",
128
+ description="Single household for impact calculation",
129
+ filepath=filepath,
130
+ year=household_input.year,
131
+ data=UKYearData(
132
+ person=person_df,
133
+ benunit=benunit_df,
134
+ household=household_df,
135
+ ),
136
+ )
137
+
138
+ # Run simulation
139
+ simulation = Simulation(
140
+ dataset=dataset,
141
+ tax_benefit_model_version=uk_latest,
142
+ policy=policy,
143
+ )
144
+ simulation.run()
145
+
146
+ # Extract all output variables defined in entity_variables
147
+ output_data = simulation.output_dataset.data
148
+
149
+ def safe_convert(value):
150
+ """Convert value to float if numeric, otherwise return as string."""
151
+ try:
152
+ return float(value)
153
+ except (ValueError, TypeError):
154
+ return str(value)
155
+
156
+ person_outputs = []
157
+ for i in range(n_people):
158
+ person_dict = {}
159
+ for var in uk_latest.entity_variables["person"]:
160
+ person_dict[var] = safe_convert(output_data.person[var].iloc[i])
161
+ person_outputs.append(person_dict)
162
+
163
+ benunit_outputs = []
164
+ for i in range(len(output_data.benunit)):
165
+ benunit_dict = {}
166
+ for var in uk_latest.entity_variables["benunit"]:
167
+ benunit_dict[var] = safe_convert(output_data.benunit[var].iloc[i])
168
+ benunit_outputs.append(benunit_dict)
169
+
170
+ household_dict = {}
171
+ for var in uk_latest.entity_variables["household"]:
172
+ household_dict[var] = safe_convert(output_data.household[var].iloc[0])
173
+
174
+ return UKHouseholdOutput(
175
+ person=person_outputs,
176
+ benunit=benunit_outputs,
177
+ household=household_dict,
178
+ )
179
+
180
+
15
181
  class PolicyReformAnalysis(BaseModel):
16
182
  """Complete policy reform analysis result."""
17
183
 
18
184
  decile_impacts: OutputCollection[DecileImpact]
19
185
  programme_statistics: OutputCollection[ProgrammeStatistics]
186
+ baseline_poverty: OutputCollection[Poverty]
187
+ reform_poverty: OutputCollection[Poverty]
188
+ baseline_inequality: Inequality
189
+ reform_inequality: Inequality
20
190
 
21
191
 
22
- def general_policy_reform_analysis(
192
+ def economic_impact_analysis(
23
193
  baseline_simulation: Simulation,
24
194
  reform_simulation: Simulation,
25
195
  ) -> PolicyReformAnalysis:
@@ -28,10 +198,23 @@ def general_policy_reform_analysis(
28
198
  Returns:
29
199
  PolicyReformAnalysis containing decile impacts and programme statistics
30
200
  """
201
+ baseline_simulation.ensure()
202
+ reform_simulation.ensure()
203
+
204
+ assert len(baseline_simulation.dataset.data.household) > 100, (
205
+ "Baseline simulation must have more than 100 households"
206
+ )
207
+ assert len(reform_simulation.dataset.data.household) > 100, (
208
+ "Reform simulation must have more than 100 households"
209
+ )
210
+
31
211
  # Decile impact
32
212
  decile_impacts = calculate_decile_impacts(
33
- baseline_simulation=baseline_simulation,
34
- reform_simulation=reform_simulation,
213
+ dataset=baseline_simulation.dataset,
214
+ tax_benefit_model_version=baseline_simulation.tax_benefit_model_version,
215
+ baseline_policy=baseline_simulation.policy,
216
+ reform_policy=reform_simulation.policy,
217
+ dynamic=baseline_simulation.dynamic,
35
218
  )
36
219
 
37
220
  # Major programmes to analyse
@@ -91,7 +274,19 @@ def general_policy_reform_analysis(
91
274
  outputs=programme_statistics, dataframe=programme_df
92
275
  )
93
276
 
277
+ # Calculate poverty rates for both simulations
278
+ baseline_poverty = calculate_uk_poverty_rates(baseline_simulation)
279
+ reform_poverty = calculate_uk_poverty_rates(reform_simulation)
280
+
281
+ # Calculate inequality for both simulations
282
+ baseline_inequality = calculate_uk_inequality(baseline_simulation)
283
+ reform_inequality = calculate_uk_inequality(reform_simulation)
284
+
94
285
  return PolicyReformAnalysis(
95
286
  decile_impacts=decile_impacts,
96
287
  programme_statistics=programme_collection,
288
+ baseline_poverty=baseline_poverty,
289
+ reform_poverty=reform_poverty,
290
+ baseline_inequality=baseline_inequality,
291
+ reform_inequality=reform_inequality,
97
292
  )
@@ -9,12 +9,14 @@ from microdf import MicroDataFrame
9
9
 
10
10
  from policyengine.core import (
11
11
  Parameter,
12
- ParameterValue,
13
12
  TaxBenefitModel,
14
13
  TaxBenefitModelVersion,
15
14
  Variable,
16
15
  )
17
- from policyengine.utils import parse_safe_date
16
+ from policyengine.utils.parameter_labels import (
17
+ build_scale_lookup,
18
+ generate_label_for_parameter,
19
+ )
18
20
 
19
21
  from .datasets import PolicyEngineUKDataset, UKYearData
20
22
 
@@ -108,6 +110,11 @@ class PolicyEngineUKLatest(TaxBenefitModelVersion):
108
110
  "rent",
109
111
  "council_tax",
110
112
  "tenure_type",
113
+ # Poverty measures
114
+ "in_poverty_bhc",
115
+ "in_poverty_ahc",
116
+ "in_relative_poverty_bhc",
117
+ "in_relative_poverty_ahc",
111
118
  ],
112
119
  }
113
120
 
@@ -143,17 +150,21 @@ class PolicyEngineUKLatest(TaxBenefitModelVersion):
143
150
 
144
151
  from policyengine_core.parameters import Parameter as CoreParameter
145
152
 
153
+ scale_lookup = build_scale_lookup(system)
154
+
146
155
  for param_node in system.parameters.get_descendants():
147
156
  if isinstance(param_node, CoreParameter):
148
157
  parameter = Parameter(
149
158
  id=self.id + "-" + param_node.name,
150
159
  name=param_node.name,
151
- label=param_node.metadata.get("label", param_node.name),
160
+ label=generate_label_for_parameter(
161
+ param_node, system, scale_lookup
162
+ ),
152
163
  tax_benefit_model_version=self,
153
164
  description=param_node.description,
154
165
  data_type=type(param_node(2025)),
155
166
  unit=param_node.metadata.get("unit"),
156
- _core_param=param_node, # Store for lazy value loading
167
+ _core_param=param_node,
157
168
  )
158
169
  self.add_parameter(parameter)
159
170
 
@@ -5,7 +5,12 @@ from importlib.util import find_spec
5
5
  if find_spec("policyengine_us") is not None:
6
6
  from policyengine.core import Dataset
7
7
 
8
- from .analysis import general_policy_reform_analysis
8
+ from .analysis import (
9
+ USHouseholdInput,
10
+ USHouseholdOutput,
11
+ calculate_household_impact,
12
+ economic_impact_analysis,
13
+ )
9
14
  from .datasets import (
10
15
  PolicyEngineUSDataset,
11
16
  USYearData,
@@ -37,7 +42,10 @@ if find_spec("policyengine_us") is not None:
37
42
  "PolicyEngineUSLatest",
38
43
  "us_model",
39
44
  "us_latest",
40
- "general_policy_reform_analysis",
45
+ "economic_impact_analysis",
46
+ "calculate_household_impact",
47
+ "USHouseholdInput",
48
+ "USHouseholdOutput",
41
49
  "ProgramStatistics",
42
50
  ]
43
51
  else:
@@ -1,25 +1,213 @@
1
1
  """General utility functions for US policy reform analysis."""
2
2
 
3
+ import tempfile
4
+ from pathlib import Path
5
+ from typing import Any
6
+
3
7
  import pandas as pd
4
- from pydantic import BaseModel
8
+ from microdf import MicroDataFrame
9
+ from pydantic import BaseModel, Field
5
10
 
6
11
  from policyengine.core import OutputCollection, Simulation
12
+ from policyengine.core.policy import Policy
7
13
  from policyengine.outputs.decile_impact import (
8
14
  DecileImpact,
9
15
  calculate_decile_impacts,
10
16
  )
17
+ from policyengine.outputs.inequality import (
18
+ Inequality,
19
+ calculate_us_inequality,
20
+ )
21
+ from policyengine.outputs.poverty import (
22
+ Poverty,
23
+ calculate_us_poverty_rates,
24
+ )
11
25
 
26
+ from .datasets import PolicyEngineUSDataset, USYearData
27
+ from .model import us_latest
12
28
  from .outputs import ProgramStatistics
13
29
 
14
30
 
31
+ class USHouseholdOutput(BaseModel):
32
+ """Output from a US household calculation with all entity data."""
33
+
34
+ person: list[dict[str, Any]]
35
+ marital_unit: list[dict[str, Any]]
36
+ family: list[dict[str, Any]]
37
+ spm_unit: list[dict[str, Any]]
38
+ tax_unit: list[dict[str, Any]]
39
+ household: dict[str, Any]
40
+
41
+
42
+ class USHouseholdInput(BaseModel):
43
+ """Input for a US household calculation."""
44
+
45
+ people: list[dict[str, Any]]
46
+ marital_unit: dict[str, Any] = Field(default_factory=dict)
47
+ family: dict[str, Any] = Field(default_factory=dict)
48
+ spm_unit: dict[str, Any] = Field(default_factory=dict)
49
+ tax_unit: dict[str, Any] = Field(default_factory=dict)
50
+ household: dict[str, Any] = Field(default_factory=dict)
51
+ year: int = 2024
52
+
53
+
54
+ def calculate_household_impact(
55
+ household_input: USHouseholdInput,
56
+ policy: Policy | None = None,
57
+ ) -> USHouseholdOutput:
58
+ """Calculate tax and benefit impacts for a single US household."""
59
+ n_people = len(household_input.people)
60
+
61
+ # Build person data with defaults
62
+ person_data = {
63
+ "person_id": list(range(n_people)),
64
+ "person_household_id": [0] * n_people,
65
+ "person_marital_unit_id": [0] * n_people,
66
+ "person_family_id": [0] * n_people,
67
+ "person_spm_unit_id": [0] * n_people,
68
+ "person_tax_unit_id": [0] * n_people,
69
+ "person_weight": [1.0] * n_people,
70
+ }
71
+ # Add user-provided person fields
72
+ for i, person in enumerate(household_input.people):
73
+ for key, value in person.items():
74
+ if key not in person_data:
75
+ person_data[key] = [
76
+ 0.0
77
+ ] * n_people # Default to 0 for numeric fields
78
+ person_data[key][i] = value
79
+
80
+ # Build entity data with defaults
81
+ household_data = {
82
+ "household_id": [0],
83
+ "household_weight": [1.0],
84
+ }
85
+ for key, value in household_input.household.items():
86
+ household_data[key] = [value]
87
+
88
+ marital_unit_data = {
89
+ "marital_unit_id": [0],
90
+ "marital_unit_weight": [1.0],
91
+ }
92
+ for key, value in household_input.marital_unit.items():
93
+ marital_unit_data[key] = [value]
94
+
95
+ family_data = {
96
+ "family_id": [0],
97
+ "family_weight": [1.0],
98
+ }
99
+ for key, value in household_input.family.items():
100
+ family_data[key] = [value]
101
+
102
+ spm_unit_data = {
103
+ "spm_unit_id": [0],
104
+ "spm_unit_weight": [1.0],
105
+ }
106
+ for key, value in household_input.spm_unit.items():
107
+ spm_unit_data[key] = [value]
108
+
109
+ tax_unit_data = {
110
+ "tax_unit_id": [0],
111
+ "tax_unit_weight": [1.0],
112
+ }
113
+ for key, value in household_input.tax_unit.items():
114
+ tax_unit_data[key] = [value]
115
+
116
+ # Create MicroDataFrames
117
+ person_df = MicroDataFrame(
118
+ pd.DataFrame(person_data), weights="person_weight"
119
+ )
120
+ household_df = MicroDataFrame(
121
+ pd.DataFrame(household_data), weights="household_weight"
122
+ )
123
+ marital_unit_df = MicroDataFrame(
124
+ pd.DataFrame(marital_unit_data), weights="marital_unit_weight"
125
+ )
126
+ family_df = MicroDataFrame(
127
+ pd.DataFrame(family_data), weights="family_weight"
128
+ )
129
+ spm_unit_df = MicroDataFrame(
130
+ pd.DataFrame(spm_unit_data), weights="spm_unit_weight"
131
+ )
132
+ tax_unit_df = MicroDataFrame(
133
+ pd.DataFrame(tax_unit_data), weights="tax_unit_weight"
134
+ )
135
+
136
+ # Create temporary dataset
137
+ tmpdir = tempfile.mkdtemp()
138
+ filepath = str(Path(tmpdir) / "household_impact.h5")
139
+
140
+ dataset = PolicyEngineUSDataset(
141
+ name="Household impact calculation",
142
+ description="Single household for impact calculation",
143
+ filepath=filepath,
144
+ year=household_input.year,
145
+ data=USYearData(
146
+ person=person_df,
147
+ household=household_df,
148
+ marital_unit=marital_unit_df,
149
+ family=family_df,
150
+ spm_unit=spm_unit_df,
151
+ tax_unit=tax_unit_df,
152
+ ),
153
+ )
154
+
155
+ # Run simulation
156
+ simulation = Simulation(
157
+ dataset=dataset,
158
+ tax_benefit_model_version=us_latest,
159
+ policy=policy,
160
+ )
161
+ simulation.run()
162
+
163
+ # Extract all output variables defined in entity_variables
164
+ output_data = simulation.output_dataset.data
165
+
166
+ def safe_convert(value):
167
+ """Convert value to float if numeric, otherwise return as string."""
168
+ try:
169
+ return float(value)
170
+ except (ValueError, TypeError):
171
+ return str(value)
172
+
173
+ def extract_entity_outputs(
174
+ entity_name: str, entity_data, n_rows: int
175
+ ) -> list[dict[str, Any]]:
176
+ outputs = []
177
+ for i in range(n_rows):
178
+ row_dict = {}
179
+ for var in us_latest.entity_variables[entity_name]:
180
+ row_dict[var] = safe_convert(entity_data[var].iloc[i])
181
+ outputs.append(row_dict)
182
+ return outputs
183
+
184
+ return USHouseholdOutput(
185
+ person=extract_entity_outputs("person", output_data.person, n_people),
186
+ marital_unit=extract_entity_outputs(
187
+ "marital_unit", output_data.marital_unit, 1
188
+ ),
189
+ family=extract_entity_outputs("family", output_data.family, 1),
190
+ spm_unit=extract_entity_outputs("spm_unit", output_data.spm_unit, 1),
191
+ tax_unit=extract_entity_outputs("tax_unit", output_data.tax_unit, 1),
192
+ household={
193
+ var: safe_convert(output_data.household[var].iloc[0])
194
+ for var in us_latest.entity_variables["household"]
195
+ },
196
+ )
197
+
198
+
15
199
  class PolicyReformAnalysis(BaseModel):
16
200
  """Complete policy reform analysis result."""
17
201
 
18
202
  decile_impacts: OutputCollection[DecileImpact]
19
203
  program_statistics: OutputCollection[ProgramStatistics]
204
+ baseline_poverty: OutputCollection[Poverty]
205
+ reform_poverty: OutputCollection[Poverty]
206
+ baseline_inequality: Inequality
207
+ reform_inequality: Inequality
20
208
 
21
209
 
22
- def general_policy_reform_analysis(
210
+ def economic_impact_analysis(
23
211
  baseline_simulation: Simulation,
24
212
  reform_simulation: Simulation,
25
213
  ) -> PolicyReformAnalysis:
@@ -28,10 +216,23 @@ def general_policy_reform_analysis(
28
216
  Returns:
29
217
  PolicyReformAnalysis containing decile impacts and program statistics
30
218
  """
219
+ baseline_simulation.ensure()
220
+ reform_simulation.ensure()
221
+
222
+ assert len(baseline_simulation.dataset.data.household) > 100, (
223
+ "Baseline simulation must have more than 100 households"
224
+ )
225
+ assert len(reform_simulation.dataset.data.household) > 100, (
226
+ "Reform simulation must have more than 100 households"
227
+ )
228
+
31
229
  # Decile impact (using household_net_income for US)
32
230
  decile_impacts = calculate_decile_impacts(
33
- baseline_simulation=baseline_simulation,
34
- reform_simulation=reform_simulation,
231
+ dataset=baseline_simulation.dataset,
232
+ tax_benefit_model_version=baseline_simulation.tax_benefit_model_version,
233
+ baseline_policy=baseline_simulation.policy,
234
+ reform_policy=reform_simulation.policy,
235
+ dynamic=baseline_simulation.dynamic,
35
236
  income_variable="household_net_income",
36
237
  )
37
238
 
@@ -94,6 +295,19 @@ def general_policy_reform_analysis(
94
295
  outputs=program_statistics, dataframe=program_df
95
296
  )
96
297
 
298
+ # Calculate poverty rates for both simulations
299
+ baseline_poverty = calculate_us_poverty_rates(baseline_simulation)
300
+ reform_poverty = calculate_us_poverty_rates(reform_simulation)
301
+
302
+ # Calculate inequality for both simulations
303
+ baseline_inequality = calculate_us_inequality(baseline_simulation)
304
+ reform_inequality = calculate_us_inequality(reform_simulation)
305
+
97
306
  return PolicyReformAnalysis(
98
- decile_impacts=decile_impacts, program_statistics=program_collection
307
+ decile_impacts=decile_impacts,
308
+ program_statistics=program_collection,
309
+ baseline_poverty=baseline_poverty,
310
+ reform_poverty=reform_poverty,
311
+ baseline_inequality=baseline_inequality,
312
+ reform_inequality=reform_inequality,
99
313
  )
@@ -9,12 +9,14 @@ from microdf import MicroDataFrame
9
9
 
10
10
  from policyengine.core import (
11
11
  Parameter,
12
- ParameterValue,
13
12
  TaxBenefitModel,
14
13
  TaxBenefitModelVersion,
15
14
  Variable,
16
15
  )
17
- from policyengine.utils import parse_safe_date
16
+ from policyengine.utils.parameter_labels import (
17
+ build_scale_lookup,
18
+ generate_label_for_parameter,
19
+ )
18
20
 
19
21
  from .datasets import PolicyEngineUSDataset, USYearData
20
22
 
@@ -57,6 +59,8 @@ class PolicyEngineUSLatest(TaxBenefitModelVersion):
57
59
  "person_weight",
58
60
  # Demographics
59
61
  "age",
62
+ "is_child",
63
+ "is_adult",
60
64
  # Income
61
65
  "employment_income",
62
66
  # Benefits
@@ -79,6 +83,9 @@ class PolicyEngineUSLatest(TaxBenefitModelVersion):
79
83
  "snap",
80
84
  "tanf",
81
85
  "spm_unit_net_income",
86
+ # Poverty measures
87
+ "spm_unit_is_in_spm_poverty",
88
+ "spm_unit_is_in_deep_spm_poverty",
82
89
  ],
83
90
  "tax_unit": [
84
91
  "tax_unit_id",
@@ -136,17 +143,21 @@ class PolicyEngineUSLatest(TaxBenefitModelVersion):
136
143
 
137
144
  from policyengine_core.parameters import Parameter as CoreParameter
138
145
 
146
+ scale_lookup = build_scale_lookup(system)
147
+
139
148
  for param_node in system.parameters.get_descendants():
140
149
  if isinstance(param_node, CoreParameter):
141
150
  parameter = Parameter(
142
151
  id=self.id + "-" + param_node.name,
143
152
  name=param_node.name,
144
- label=param_node.metadata.get("label"),
153
+ label=generate_label_for_parameter(
154
+ param_node, system, scale_lookup
155
+ ),
145
156
  tax_benefit_model_version=self,
146
157
  description=param_node.description,
147
158
  data_type=type(param_node(2025)),
148
159
  unit=param_node.metadata.get("unit"),
149
- _core_param=param_node, # Store for lazy value loading
160
+ _core_param=param_node,
150
161
  )
151
162
  self.add_parameter(parameter)
152
163
 
@@ -1,3 +1,7 @@
1
1
  from .dates import parse_safe_date as parse_safe_date
2
+ from .parameter_labels import build_scale_lookup as build_scale_lookup
3
+ from .parameter_labels import (
4
+ generate_label_for_parameter as generate_label_for_parameter,
5
+ )
2
6
  from .plotting import COLORS as COLORS
3
7
  from .plotting import format_fig as format_fig