policyengine 3.1.12__py3-none-any.whl → 3.1.13__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.
- policyengine/__pycache__/__init__.cpython-313.pyc +0 -0
- policyengine/core/parameter.py +47 -3
- policyengine/core/tax_benefit_model_version.py +25 -27
- policyengine/tax_benefit_models/uk/datasets.py +2 -2
- policyengine/tax_benefit_models/uk/model.py +4 -28
- policyengine/tax_benefit_models/us/datasets.py +2 -2
- policyengine/tax_benefit_models/us/model.py +3 -25
- {policyengine-3.1.12.dist-info → policyengine-3.1.13.dist-info}/METADATA +1 -1
- {policyengine-3.1.12.dist-info → policyengine-3.1.13.dist-info}/RECORD +12 -12
- {policyengine-3.1.12.dist-info → policyengine-3.1.13.dist-info}/WHEEL +0 -0
- {policyengine-3.1.12.dist-info → policyengine-3.1.13.dist-info}/licenses/LICENSE +0 -0
- {policyengine-3.1.12.dist-info → policyengine-3.1.13.dist-info}/top_level.txt +0 -0
|
Binary file
|
policyengine/core/parameter.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
2
|
from uuid import uuid4
|
|
3
3
|
|
|
4
|
-
from pydantic import BaseModel, Field
|
|
4
|
+
from pydantic import BaseModel, Field, PrivateAttr
|
|
5
5
|
|
|
6
6
|
from .parameter_value import ParameterValue
|
|
7
7
|
from .tax_benefit_model_version import TaxBenefitModelVersion
|
|
@@ -11,6 +11,8 @@ if TYPE_CHECKING:
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class Parameter(BaseModel):
|
|
14
|
+
model_config = {"arbitrary_types_allowed": True}
|
|
15
|
+
|
|
14
16
|
id: str = Field(default_factory=lambda: str(uuid4()))
|
|
15
17
|
name: str
|
|
16
18
|
label: str | None = None
|
|
@@ -18,4 +20,46 @@ class Parameter(BaseModel):
|
|
|
18
20
|
data_type: type | None = None
|
|
19
21
|
tax_benefit_model_version: TaxBenefitModelVersion
|
|
20
22
|
unit: str | None = None
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
# Lazy loading: store core param ref, build values on demand
|
|
25
|
+
_core_param: Any = PrivateAttr(default=None)
|
|
26
|
+
_parameter_values: list["ParameterValue"] | None = PrivateAttr(
|
|
27
|
+
default=None
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def __init__(self, _core_param: Any = None, **data):
|
|
31
|
+
super().__init__(**data)
|
|
32
|
+
self._core_param = _core_param
|
|
33
|
+
self._parameter_values = None
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def parameter_values(self) -> list["ParameterValue"]:
|
|
37
|
+
"""Lazily build parameter values on first access."""
|
|
38
|
+
if self._parameter_values is None:
|
|
39
|
+
self._parameter_values = []
|
|
40
|
+
if self._core_param is not None:
|
|
41
|
+
from policyengine.utils import parse_safe_date
|
|
42
|
+
|
|
43
|
+
for i in range(len(self._core_param.values_list)):
|
|
44
|
+
param_at_instant = self._core_param.values_list[i]
|
|
45
|
+
if i + 1 < len(self._core_param.values_list):
|
|
46
|
+
next_instant = self._core_param.values_list[i + 1]
|
|
47
|
+
else:
|
|
48
|
+
next_instant = None
|
|
49
|
+
pv = ParameterValue(
|
|
50
|
+
parameter=self,
|
|
51
|
+
start_date=parse_safe_date(
|
|
52
|
+
param_at_instant.instant_str
|
|
53
|
+
),
|
|
54
|
+
end_date=parse_safe_date(next_instant.instant_str)
|
|
55
|
+
if next_instant
|
|
56
|
+
else None,
|
|
57
|
+
value=param_at_instant.value,
|
|
58
|
+
)
|
|
59
|
+
self._parameter_values.append(pv)
|
|
60
|
+
return self._parameter_values
|
|
61
|
+
|
|
62
|
+
@parameter_values.setter
|
|
63
|
+
def parameter_values(self, value: list["ParameterValue"]) -> None:
|
|
64
|
+
"""Allow direct setting of parameter values."""
|
|
65
|
+
self._parameter_values = value
|
|
@@ -14,6 +14,8 @@ if TYPE_CHECKING:
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class TaxBenefitModelVersion(BaseModel):
|
|
17
|
+
model_config = {"arbitrary_types_allowed": True}
|
|
18
|
+
|
|
17
19
|
id: str = Field(default_factory=lambda: str(uuid4()))
|
|
18
20
|
model: TaxBenefitModel
|
|
19
21
|
version: str
|
|
@@ -24,6 +26,14 @@ class TaxBenefitModelVersion(BaseModel):
|
|
|
24
26
|
parameters: list["Parameter"] = Field(default_factory=list)
|
|
25
27
|
parameter_values: list["ParameterValue"] = Field(default_factory=list)
|
|
26
28
|
|
|
29
|
+
# Lookup dicts for O(1) access (excluded from serialization)
|
|
30
|
+
variables_by_name: dict[str, "Variable"] = Field(
|
|
31
|
+
default_factory=dict, exclude=True
|
|
32
|
+
)
|
|
33
|
+
parameters_by_name: dict[str, "Parameter"] = Field(
|
|
34
|
+
default_factory=dict, exclude=True
|
|
35
|
+
)
|
|
36
|
+
|
|
27
37
|
def run(self, simulation: "Simulation") -> "Simulation":
|
|
28
38
|
raise NotImplementedError(
|
|
29
39
|
"The TaxBenefitModel class must define a method to execute simulations."
|
|
@@ -39,40 +49,28 @@ class TaxBenefitModelVersion(BaseModel):
|
|
|
39
49
|
"The TaxBenefitModel class must define a method to load simulations."
|
|
40
50
|
)
|
|
41
51
|
|
|
42
|
-
def
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
name: The parameter name (e.g., "gov.hmrc.income_tax.allowances.personal_allowance.amount")
|
|
52
|
+
def add_parameter(self, param: "Parameter") -> None:
|
|
53
|
+
"""Add a parameter and index it for fast lookup."""
|
|
54
|
+
self.parameters.append(param)
|
|
55
|
+
self.parameters_by_name[param.name] = param
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
def add_variable(self, var: "Variable") -> None:
|
|
58
|
+
"""Add a variable and index it for fast lookup."""
|
|
59
|
+
self.variables.append(var)
|
|
60
|
+
self.variables_by_name[var.name] = var
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if param.name == name:
|
|
56
|
-
return param
|
|
62
|
+
def get_parameter(self, name: str) -> "Parameter":
|
|
63
|
+
"""Get a parameter by name (O(1) lookup)."""
|
|
64
|
+
if name in self.parameters_by_name:
|
|
65
|
+
return self.parameters_by_name[name]
|
|
57
66
|
raise ValueError(
|
|
58
67
|
f"Parameter '{name}' not found in {self.model.id} version {self.version}"
|
|
59
68
|
)
|
|
60
69
|
|
|
61
70
|
def get_variable(self, name: str) -> "Variable":
|
|
62
|
-
"""Get a variable by name.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
name: The variable name (e.g., "income_tax", "household_net_income")
|
|
66
|
-
|
|
67
|
-
Returns:
|
|
68
|
-
Variable: The matching variable
|
|
69
|
-
|
|
70
|
-
Raises:
|
|
71
|
-
ValueError: If variable not found
|
|
72
|
-
"""
|
|
73
|
-
for var in self.variables:
|
|
74
|
-
if var.name == name:
|
|
75
|
-
return var
|
|
71
|
+
"""Get a variable by name (O(1) lookup)."""
|
|
72
|
+
if name in self.variables_by_name:
|
|
73
|
+
return self.variables_by_name[name]
|
|
76
74
|
raise ValueError(
|
|
77
75
|
f"Variable '{name}' not found in {self.model.id} version {self.version}"
|
|
78
76
|
)
|
|
@@ -161,8 +161,8 @@ def create_datasets(
|
|
|
161
161
|
|
|
162
162
|
uk_dataset = PolicyEngineUKDataset(
|
|
163
163
|
id=f"{Path(dataset).stem}_year_{year}",
|
|
164
|
-
name=f"{dataset}-year-{year}",
|
|
165
|
-
description=f"UK Dataset for year {year} based on {dataset}",
|
|
164
|
+
name=f"{Path(dataset).stem}-year-{year}",
|
|
165
|
+
description=f"UK Dataset for year {year} based on {Path(dataset).stem}",
|
|
166
166
|
filepath=f"{data_folder}/{Path(dataset).stem}_year_{year}.h5",
|
|
167
167
|
year=int(year),
|
|
168
168
|
data=UKYearData(
|
|
@@ -118,7 +118,6 @@ class PolicyEngineUKLatest(TaxBenefitModelVersion):
|
|
|
118
118
|
|
|
119
119
|
self.id = f"{self.model.id}@{self.version}"
|
|
120
120
|
|
|
121
|
-
self.variables = []
|
|
122
121
|
for var_obj in system.variables.values():
|
|
123
122
|
variable = Variable(
|
|
124
123
|
id=self.id + "-" + var_obj.name,
|
|
@@ -140,9 +139,8 @@ class PolicyEngineUKLatest(TaxBenefitModelVersion):
|
|
|
140
139
|
var_obj.possible_values._value2member_map_.values(),
|
|
141
140
|
)
|
|
142
141
|
)
|
|
143
|
-
self.
|
|
142
|
+
self.add_variable(variable)
|
|
144
143
|
|
|
145
|
-
self.parameters = []
|
|
146
144
|
from policyengine_core.parameters import Parameter as CoreParameter
|
|
147
145
|
|
|
148
146
|
for param_node in system.parameters.get_descendants():
|
|
@@ -153,33 +151,11 @@ class PolicyEngineUKLatest(TaxBenefitModelVersion):
|
|
|
153
151
|
label=param_node.metadata.get("label", param_node.name),
|
|
154
152
|
tax_benefit_model_version=self,
|
|
155
153
|
description=param_node.description,
|
|
156
|
-
data_type=type(
|
|
157
|
-
param_node(2025)
|
|
158
|
-
), # Example year to infer type
|
|
154
|
+
data_type=type(param_node(2025)),
|
|
159
155
|
unit=param_node.metadata.get("unit"),
|
|
156
|
+
_core_param=param_node, # Store for lazy value loading
|
|
160
157
|
)
|
|
161
|
-
self.
|
|
162
|
-
|
|
163
|
-
for i in range(len(param_node.values_list)):
|
|
164
|
-
param_at_instant = param_node.values_list[i]
|
|
165
|
-
if i + 1 < len(param_node.values_list):
|
|
166
|
-
next_instant = param_node.values_list[i + 1]
|
|
167
|
-
else:
|
|
168
|
-
next_instant = None
|
|
169
|
-
parameter_value = ParameterValue(
|
|
170
|
-
parameter=parameter,
|
|
171
|
-
start_date=parse_safe_date(
|
|
172
|
-
param_at_instant.instant_str
|
|
173
|
-
),
|
|
174
|
-
end_date=parse_safe_date(next_instant.instant_str)
|
|
175
|
-
if next_instant
|
|
176
|
-
else None,
|
|
177
|
-
value=param_at_instant.value,
|
|
178
|
-
)
|
|
179
|
-
self.parameter_values.append(parameter_value)
|
|
180
|
-
self.get_parameter(parameter.name).parameter_values.append(
|
|
181
|
-
parameter_value
|
|
182
|
-
)
|
|
158
|
+
self.add_parameter(parameter)
|
|
183
159
|
|
|
184
160
|
def run(self, simulation: "Simulation") -> "Simulation":
|
|
185
161
|
from policyengine_uk import Microsimulation
|
|
@@ -266,8 +266,8 @@ def create_datasets(
|
|
|
266
266
|
|
|
267
267
|
us_dataset = PolicyEngineUSDataset(
|
|
268
268
|
id=f"{Path(dataset).stem}_year_{year}",
|
|
269
|
-
name=f"{dataset}-year-{year}",
|
|
270
|
-
description=f"US Dataset for year {year} based on {dataset}",
|
|
269
|
+
name=f"{Path(dataset).stem}-year-{year}",
|
|
270
|
+
description=f"US Dataset for year {year} based on {Path(dataset).stem}",
|
|
271
271
|
filepath=f"{data_folder}/{Path(dataset).stem}_year_{year}.h5",
|
|
272
272
|
year=int(year),
|
|
273
273
|
data=USYearData(
|
|
@@ -111,7 +111,6 @@ class PolicyEngineUSLatest(TaxBenefitModelVersion):
|
|
|
111
111
|
|
|
112
112
|
self.id = f"{self.model.id}@{self.version}"
|
|
113
113
|
|
|
114
|
-
self.variables = []
|
|
115
114
|
for var_obj in system.variables.values():
|
|
116
115
|
variable = Variable(
|
|
117
116
|
id=self.id + "-" + var_obj.name,
|
|
@@ -133,9 +132,8 @@ class PolicyEngineUSLatest(TaxBenefitModelVersion):
|
|
|
133
132
|
var_obj.possible_values._value2member_map_.values(),
|
|
134
133
|
)
|
|
135
134
|
)
|
|
136
|
-
self.
|
|
135
|
+
self.add_variable(variable)
|
|
137
136
|
|
|
138
|
-
self.parameters = []
|
|
139
137
|
from policyengine_core.parameters import Parameter as CoreParameter
|
|
140
138
|
|
|
141
139
|
for param_node in system.parameters.get_descendants():
|
|
@@ -147,29 +145,9 @@ class PolicyEngineUSLatest(TaxBenefitModelVersion):
|
|
|
147
145
|
description=param_node.description,
|
|
148
146
|
data_type=type(param_node(2025)),
|
|
149
147
|
unit=param_node.metadata.get("unit"),
|
|
148
|
+
_core_param=param_node, # Store for lazy value loading
|
|
150
149
|
)
|
|
151
|
-
self.
|
|
152
|
-
|
|
153
|
-
for i in range(len(param_node.values_list)):
|
|
154
|
-
param_at_instant = param_node.values_list[i]
|
|
155
|
-
if i + 1 < len(param_node.values_list):
|
|
156
|
-
next_instant = param_node.values_list[i + 1]
|
|
157
|
-
else:
|
|
158
|
-
next_instant = None
|
|
159
|
-
parameter_value = ParameterValue(
|
|
160
|
-
parameter=parameter,
|
|
161
|
-
start_date=parse_safe_date(
|
|
162
|
-
param_at_instant.instant_str
|
|
163
|
-
),
|
|
164
|
-
end_date=parse_safe_date(next_instant.instant_str)
|
|
165
|
-
if next_instant
|
|
166
|
-
else None,
|
|
167
|
-
value=param_at_instant.value,
|
|
168
|
-
)
|
|
169
|
-
self.parameter_values.append(parameter_value)
|
|
170
|
-
self.get_parameter(parameter.name).parameter_values.append(
|
|
171
|
-
parameter_value
|
|
172
|
-
)
|
|
150
|
+
self.add_parameter(parameter)
|
|
173
151
|
|
|
174
152
|
def run(self, simulation: "Simulation") -> "Simulation":
|
|
175
153
|
from policyengine_us import Microsimulation
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
policyengine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
policyengine/__pycache__/__init__.cpython-313.pyc,sha256=
|
|
2
|
+
policyengine/__pycache__/__init__.cpython-313.pyc,sha256=uVHsGqNxZlQfIUi3c2mJIGYwZoh7v_hBZty19_E2l2g,175
|
|
3
3
|
policyengine/core/__init__.py,sha256=KBVhkqzkvjWLDDwk96vquQKL63ZFuLen5AzBOBnO9pg,912
|
|
4
4
|
policyengine/core/cache.py,sha256=DcVVFaCt7k9PmqwlhXoNDMtJ8sF4neYP1uRqWik5QYg,1812
|
|
5
5
|
policyengine/core/dataset.py,sha256=iJr9-J6w11uMRYy3EEJO9Gveku1m71AA1yzeo-0SiCs,16094
|
|
6
6
|
policyengine/core/dataset_version.py,sha256=6KeFCRGQto_Yyl4QY4Vo2JFythjaXrNAOHQiwRGESyM,378
|
|
7
7
|
policyengine/core/dynamic.py,sha256=ng9BjDzxdwjJ0e7zoqXFmq33E1SRbaaPYfW7pjRSSzI,1641
|
|
8
8
|
policyengine/core/output.py,sha256=cCW4vbzkLdQaT_nJTyDJBl7Hubm7nZeRuR7aVG1dKvg,643
|
|
9
|
-
policyengine/core/parameter.py,sha256=
|
|
9
|
+
policyengine/core/parameter.py,sha256=MMhx5bN-9jn6n2sRxJf_ow-j-ze8IehCF4r_VrpfR94,2407
|
|
10
10
|
policyengine/core/parameter_value.py,sha256=ZRBZWFYtaY9TqdgjrCymzOZNmuKOBZsrWBET24DIJ_Q,434
|
|
11
11
|
policyengine/core/policy.py,sha256=ExMrUDMvNk_uuOL0cSm0UCzDyGka0t_yk6x4U0Kp6Ww,1635
|
|
12
12
|
policyengine/core/simulation.py,sha256=h6QbFt3uEvyfRXRVbSFBlrOd6Ze03OeZkwX9oElmO2M,1406
|
|
13
13
|
policyengine/core/tax_benefit_model.py,sha256=2Yc1RlQrUG7djDMZbJOQH4Ns86_lOnLeISCGR4-9zMo,176
|
|
14
|
-
policyengine/core/tax_benefit_model_version.py,sha256=
|
|
14
|
+
policyengine/core/tax_benefit_model_version.py,sha256=csHeZasdvCyyRTlBIr1gtuJstye3pftQAsoI8mpRHa4,3012
|
|
15
15
|
policyengine/core/variable.py,sha256=AjSImORlRkh05xhYxyeT6GFMOfViRzYg0qRQAIj-mxo,350
|
|
16
16
|
policyengine/outputs/__init__.py,sha256=IJUmLP0Og41VrwiqhJF-a9-3fIb4nlXpS7uFuVCINIs,515
|
|
17
17
|
policyengine/outputs/aggregate.py,sha256=exI-U04OF5kVf2BBYV6sf8VldIWnT_IzxgkBs5wtnCw,4846
|
|
@@ -21,20 +21,20 @@ policyengine/tax_benefit_models/uk.py,sha256=HzAG_dORmsj1NJ9pd9WrqwgZPe9DUDrZ1wV
|
|
|
21
21
|
policyengine/tax_benefit_models/us.py,sha256=G51dAmHo8NJLb2mnbne6iO5eNaatCGUd_2unvawwF84,946
|
|
22
22
|
policyengine/tax_benefit_models/uk/__init__.py,sha256=AiA74iED5FEryvUCMfVZi6pYDYuTfQcj9B01h8J5xFA,1105
|
|
23
23
|
policyengine/tax_benefit_models/uk/analysis.py,sha256=O4eYJYF7tsgiuLuiWMU0OXq7ss6U8-vzlg6nC2U8sgU,3175
|
|
24
|
-
policyengine/tax_benefit_models/uk/datasets.py,sha256=
|
|
25
|
-
policyengine/tax_benefit_models/uk/model.py,sha256=
|
|
24
|
+
policyengine/tax_benefit_models/uk/datasets.py,sha256=OtBGQPI-P2jnLfurw1MiFDo3LRi5xye0uI3XM9J-9rY,9021
|
|
25
|
+
policyengine/tax_benefit_models/uk/model.py,sha256=7eqCNW9bjCM-6BN2Dp8soUAEjZBP_0QmMC2OtDPCiXw,8694
|
|
26
26
|
policyengine/tax_benefit_models/uk/outputs.py,sha256=2mYLwQW4QNvrOHtHfm_ACqE9gbmuLxvcCyldRU46s0o,3543
|
|
27
27
|
policyengine/tax_benefit_models/us/__init__.py,sha256=zP-UUQqOc9g0ymyHkweJdi4RVXQDKSR6SUxavUKvV0s,1101
|
|
28
28
|
policyengine/tax_benefit_models/us/analysis.py,sha256=Xf-DT0QjVySs0QG_koCwgvOeWI_scLtv3S3SP8u8ZWc,3253
|
|
29
|
-
policyengine/tax_benefit_models/us/datasets.py,sha256=
|
|
30
|
-
policyengine/tax_benefit_models/us/model.py,sha256=
|
|
29
|
+
policyengine/tax_benefit_models/us/datasets.py,sha256=Jfw8cYHBTjokiJJ1WBQtNcHEDd7BJuQ4A4wD6dN7Znk,14735
|
|
30
|
+
policyengine/tax_benefit_models/us/model.py,sha256=eNlot8yMZkNwPiYfrWpDJkxRAwTBYLGWL-VC4Pss4JI,15579
|
|
31
31
|
policyengine/tax_benefit_models/us/outputs.py,sha256=GT8Eur8DfB9cPQRbSljEl9RpKSNHW80Fq_CBXCybvIU,3519
|
|
32
32
|
policyengine/utils/__init__.py,sha256=1X-VYAWLyB9A0YRHwsGWrqQHns1WfeZ7ISC6DMU5myM,140
|
|
33
33
|
policyengine/utils/dates.py,sha256=HnAqyl8S8EOYp8ibsnMTmECYoDWCSqwL-7A2_qKgxSc,1510
|
|
34
34
|
policyengine/utils/parametric_reforms.py,sha256=4P3U39-4pYTU4BN6JjgmVLUkCkBhRfZJ6UIWTlsjyQE,1155
|
|
35
35
|
policyengine/utils/plotting.py,sha256=ZAzTWz38vIaW0c3Nt4Un1kfrNoXLyHCDd1pEJIlsRg4,5335
|
|
36
|
-
policyengine-3.1.
|
|
37
|
-
policyengine-3.1.
|
|
38
|
-
policyengine-3.1.
|
|
39
|
-
policyengine-3.1.
|
|
40
|
-
policyengine-3.1.
|
|
36
|
+
policyengine-3.1.13.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
37
|
+
policyengine-3.1.13.dist-info/METADATA,sha256=35l_TCb-BLgwO2Gbdpnl5up_-LMcqSowLieYrjTrjpw,45919
|
|
38
|
+
policyengine-3.1.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
39
|
+
policyengine-3.1.13.dist-info/top_level.txt,sha256=_23UPobfkneHQkpJ0e0OmDJfhCUfoXj_F2sTckCGOH4,13
|
|
40
|
+
policyengine-3.1.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|