policyengine 3.1.12__tar.gz → 3.1.14__tar.gz
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-3.1.12 → policyengine-3.1.14}/CHANGELOG.md +14 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/PKG-INFO +1 -1
- {policyengine-3.1.12 → policyengine-3.1.14}/changelog.yaml +10 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/pyproject.toml +1 -1
- policyengine-3.1.14/src/policyengine/__pycache__/__init__.cpython-313.pyc +0 -0
- policyengine-3.1.14/src/policyengine/core/parameter.py +65 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/tax_benefit_model_version.py +25 -27
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/datasets.py +4 -4
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/model.py +4 -28
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/datasets.py +4 -4
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/model.py +4 -25
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine.egg-info/PKG-INFO +1 -1
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine.egg-info/SOURCES.txt +2 -1
- policyengine-3.1.14/tests/test_models.py +68 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/uv.lock +3 -1
- policyengine-3.1.12/src/policyengine/__pycache__/__init__.cpython-313.pyc +0 -0
- policyengine-3.1.12/src/policyengine/core/parameter.py +0 -21
- {policyengine-3.1.12 → policyengine-3.1.14}/.claude/policyengine-guide.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.claude/quick-reference.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/CONTRIBUTING.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/changelog_template.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/fetch_version.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/get-changelog-diff.sh +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/has-functional-changes.sh +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/is-version-number-acceptable.sh +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/publish-git-tag.sh +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/workflows/code_changes.yaml +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/workflows/docs.yml +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/workflows/pr_code_changes.yaml +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/workflows/pr_docs_changes.yaml +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.github/workflows/versioning.yaml +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/.gitignore +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/CLAUDE.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/LICENSE +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/Makefile +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/README.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/changelog_entry.yaml +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/docs/.gitignore +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/docs/core-concepts.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/docs/country-models-uk.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/docs/country-models-us.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/docs/dev.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/docs/index.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/docs/myst.yml +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/docs/visualisation.md +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/examples/employment_income_variation_uk.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/examples/employment_income_variation_us.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/examples/income_bands_uk.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/examples/income_distribution_us.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/examples/policy_change_uk.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/examples/speedtest_us_simulation.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/setup.cfg +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/__init__.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/__init__.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/cache.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/dataset.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/dataset_version.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/dynamic.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/output.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/parameter_value.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/policy.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/simulation.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/tax_benefit_model.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/variable.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/outputs/__init__.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/outputs/aggregate.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/outputs/change_aggregate.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/outputs/decile_impact.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/__init__.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/analysis.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/outputs.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/__init__.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/analysis.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/outputs.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/utils/__init__.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/utils/dates.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/utils/parametric_reforms.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/utils/plotting.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine.egg-info/dependency_links.txt +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine.egg-info/requires.txt +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine.egg-info/top_level.txt +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/tests/test_aggregate.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/tests/test_cache.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/tests/test_change_aggregate.py +0 -0
- {policyengine-3.1.12 → policyengine-3.1.14}/tests/test_entity_mapping.py +0 -0
|
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.1.14] - 2025-12-10 21:59:24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Improvements to loading taxbenefitsystems.
|
|
13
|
+
|
|
14
|
+
## [3.1.13] - 2025-12-10 19:29:28
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Naming improvements.
|
|
19
|
+
|
|
8
20
|
## [3.1.12] - 2025-12-10 14:43:52
|
|
9
21
|
|
|
10
22
|
### Fixed
|
|
@@ -269,6 +281,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
269
281
|
|
|
270
282
|
|
|
271
283
|
|
|
284
|
+
[3.1.14]: https://github.com/PolicyEngine/policyengine.py/compare/3.1.13...3.1.14
|
|
285
|
+
[3.1.13]: https://github.com/PolicyEngine/policyengine.py/compare/3.1.12...3.1.13
|
|
272
286
|
[3.1.12]: https://github.com/PolicyEngine/policyengine.py/compare/3.1.11...3.1.12
|
|
273
287
|
[3.1.11]: https://github.com/PolicyEngine/policyengine.py/compare/3.1.10...3.1.11
|
|
274
288
|
[3.1.10]: https://github.com/PolicyEngine/policyengine.py/compare/3.1.9...3.1.10
|
|
@@ -220,3 +220,13 @@
|
|
|
220
220
|
fixed:
|
|
221
221
|
- Bug where all datasets would be the last year.
|
|
222
222
|
date: 2025-12-10 14:43:52
|
|
223
|
+
- bump: patch
|
|
224
|
+
changes:
|
|
225
|
+
fixed:
|
|
226
|
+
- Naming improvements.
|
|
227
|
+
date: 2025-12-10 19:29:28
|
|
228
|
+
- bump: patch
|
|
229
|
+
changes:
|
|
230
|
+
fixed:
|
|
231
|
+
- Improvements to loading taxbenefitsystems.
|
|
232
|
+
date: 2025-12-10 21:59:24
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, PrivateAttr
|
|
5
|
+
|
|
6
|
+
from .parameter_value import ParameterValue
|
|
7
|
+
from .tax_benefit_model_version import TaxBenefitModelVersion
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from .parameter_value import ParameterValue
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Parameter(BaseModel):
|
|
14
|
+
model_config = {"arbitrary_types_allowed": True}
|
|
15
|
+
|
|
16
|
+
id: str = Field(default_factory=lambda: str(uuid4()))
|
|
17
|
+
name: str
|
|
18
|
+
label: str | None = None
|
|
19
|
+
description: str | None = None
|
|
20
|
+
data_type: type | None = None
|
|
21
|
+
tax_benefit_model_version: TaxBenefitModelVersion
|
|
22
|
+
unit: str | None = None
|
|
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
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/core/tax_benefit_model_version.py
RENAMED
|
@@ -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
|
)
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/datasets.py
RENAMED
|
@@ -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(
|
|
@@ -196,8 +196,8 @@ def load_datasets(
|
|
|
196
196
|
for year in years:
|
|
197
197
|
filepath = f"{data_folder}/{Path(dataset).stem}_year_{year}.h5"
|
|
198
198
|
uk_dataset = PolicyEngineUKDataset(
|
|
199
|
-
name=f"{dataset}-year-{year}",
|
|
200
|
-
description=f"UK Dataset for year {year} based on {dataset}",
|
|
199
|
+
name=f"{Path(dataset).stem}-year-{year}",
|
|
200
|
+
description=f"UK Dataset for year {year} based on {Path(dataset).stem}",
|
|
201
201
|
filepath=filepath,
|
|
202
202
|
year=int(year),
|
|
203
203
|
)
|
|
@@ -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
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/datasets.py
RENAMED
|
@@ -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(
|
|
@@ -317,8 +317,8 @@ def load_datasets(
|
|
|
317
317
|
for year in years:
|
|
318
318
|
filepath = f"{data_folder}/{Path(dataset).stem}_year_{year}.h5"
|
|
319
319
|
us_dataset = PolicyEngineUSDataset(
|
|
320
|
-
name=f"{dataset}-year-{year}",
|
|
321
|
-
description=f"US Dataset for year {year} based on {dataset}",
|
|
320
|
+
name=f"{Path(dataset).stem}-year-{year}",
|
|
321
|
+
description=f"US Dataset for year {year} based on {Path(dataset).stem}",
|
|
322
322
|
filepath=filepath,
|
|
323
323
|
year=year,
|
|
324
324
|
)
|
|
@@ -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():
|
|
@@ -143,33 +141,14 @@ class PolicyEngineUSLatest(TaxBenefitModelVersion):
|
|
|
143
141
|
parameter = Parameter(
|
|
144
142
|
id=self.id + "-" + param_node.name,
|
|
145
143
|
name=param_node.name,
|
|
144
|
+
label=param_node.metadata.get("label"),
|
|
146
145
|
tax_benefit_model_version=self,
|
|
147
146
|
description=param_node.description,
|
|
148
147
|
data_type=type(param_node(2025)),
|
|
149
148
|
unit=param_node.metadata.get("unit"),
|
|
149
|
+
_core_param=param_node, # Store for lazy value loading
|
|
150
150
|
)
|
|
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
|
-
)
|
|
151
|
+
self.add_parameter(parameter)
|
|
173
152
|
|
|
174
153
|
def run(self, simulation: "Simulation") -> "Simulation":
|
|
175
154
|
from policyengine_us import Microsimulation
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Tests for UK and US tax-benefit model versions."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from policyengine.tax_benefit_models.uk import uk_latest
|
|
6
|
+
from policyengine.tax_benefit_models.us import us_latest
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestUKModel:
|
|
10
|
+
"""Tests for PolicyEngine UK model."""
|
|
11
|
+
|
|
12
|
+
def test_has_hundreds_of_parameters(self):
|
|
13
|
+
"""UK model should have hundreds of parameters."""
|
|
14
|
+
assert len(uk_latest.parameters) >= 100
|
|
15
|
+
|
|
16
|
+
def test_has_hundreds_of_variables(self):
|
|
17
|
+
"""UK model should have hundreds of variables."""
|
|
18
|
+
assert len(uk_latest.variables) >= 100
|
|
19
|
+
|
|
20
|
+
def test_parameters_have_values(self):
|
|
21
|
+
"""Each parameter should have at least one parameter value."""
|
|
22
|
+
total_values = 0
|
|
23
|
+
for param in uk_latest.parameters[:100]: # Check first 100 for speed
|
|
24
|
+
values = param.parameter_values
|
|
25
|
+
assert len(values) >= 1, f"Parameter {param.name} has no values"
|
|
26
|
+
total_values += len(values)
|
|
27
|
+
|
|
28
|
+
# Should have many parameter values in total
|
|
29
|
+
assert total_values >= 100
|
|
30
|
+
|
|
31
|
+
def test_parameter_values_have_required_fields(self):
|
|
32
|
+
"""Parameter values should have start_date and value."""
|
|
33
|
+
for param in uk_latest.parameters[:50]:
|
|
34
|
+
for pv in param.parameter_values:
|
|
35
|
+
assert pv.start_date is not None
|
|
36
|
+
assert pv.value is not None
|
|
37
|
+
assert pv.parameter is param
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TestUSModel:
|
|
41
|
+
"""Tests for PolicyEngine US model."""
|
|
42
|
+
|
|
43
|
+
def test_has_hundreds_of_parameters(self):
|
|
44
|
+
"""US model should have hundreds of parameters."""
|
|
45
|
+
assert len(us_latest.parameters) >= 100
|
|
46
|
+
|
|
47
|
+
def test_has_hundreds_of_variables(self):
|
|
48
|
+
"""US model should have hundreds of variables."""
|
|
49
|
+
assert len(us_latest.variables) >= 100
|
|
50
|
+
|
|
51
|
+
def test_parameters_have_values(self):
|
|
52
|
+
"""Each parameter should have at least one parameter value."""
|
|
53
|
+
total_values = 0
|
|
54
|
+
for param in us_latest.parameters[:100]: # Check first 100 for speed
|
|
55
|
+
values = param.parameter_values
|
|
56
|
+
assert len(values) >= 1, f"Parameter {param.name} has no values"
|
|
57
|
+
total_values += len(values)
|
|
58
|
+
|
|
59
|
+
# Should have many parameter values in total
|
|
60
|
+
assert total_values >= 100
|
|
61
|
+
|
|
62
|
+
def test_parameter_values_have_required_fields(self):
|
|
63
|
+
"""Parameter values should have start_date and value."""
|
|
64
|
+
for param in us_latest.parameters[:50]:
|
|
65
|
+
for pv in param.parameter_values:
|
|
66
|
+
assert pv.start_date is not None
|
|
67
|
+
assert pv.value is not None
|
|
68
|
+
assert pv.parameter is param
|
|
@@ -1080,12 +1080,13 @@ wheels = [
|
|
|
1080
1080
|
|
|
1081
1081
|
[[package]]
|
|
1082
1082
|
name = "policyengine"
|
|
1083
|
-
version = "3.1.
|
|
1083
|
+
version = "3.1.12"
|
|
1084
1084
|
source = { editable = "." }
|
|
1085
1085
|
dependencies = [
|
|
1086
1086
|
{ name = "microdf-python" },
|
|
1087
1087
|
{ name = "pandas" },
|
|
1088
1088
|
{ name = "plotly" },
|
|
1089
|
+
{ name = "psutil" },
|
|
1089
1090
|
{ name = "pydantic" },
|
|
1090
1091
|
{ name = "requests" },
|
|
1091
1092
|
]
|
|
@@ -1133,6 +1134,7 @@ requires-dist = [
|
|
|
1133
1134
|
{ name = "policyengine-uk", marker = "extra == 'uk'", specifier = ">=2.51.0" },
|
|
1134
1135
|
{ name = "policyengine-us", marker = "extra == 'dev'", specifier = ">=1.213.1" },
|
|
1135
1136
|
{ name = "policyengine-us", marker = "extra == 'us'", specifier = ">=1.213.1" },
|
|
1137
|
+
{ name = "psutil", specifier = ">=5.9.0" },
|
|
1136
1138
|
{ name = "pydantic", specifier = ">=2.0.0" },
|
|
1137
1139
|
{ name = "pytest", marker = "extra == 'dev'" },
|
|
1138
1140
|
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.26.0" },
|
|
Binary file
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
2
|
-
from uuid import uuid4
|
|
3
|
-
|
|
4
|
-
from pydantic import BaseModel, Field
|
|
5
|
-
|
|
6
|
-
from .parameter_value import ParameterValue
|
|
7
|
-
from .tax_benefit_model_version import TaxBenefitModelVersion
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from .parameter_value import ParameterValue
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Parameter(BaseModel):
|
|
14
|
-
id: str = Field(default_factory=lambda: str(uuid4()))
|
|
15
|
-
name: str
|
|
16
|
-
label: str | None = None
|
|
17
|
-
description: str | None = None
|
|
18
|
-
data_type: type | None = None
|
|
19
|
-
tax_benefit_model_version: TaxBenefitModelVersion
|
|
20
|
-
unit: str | None = None
|
|
21
|
-
parameter_values: list["ParameterValue"] = Field(default_factory=list)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/__init__.py
RENAMED
|
File without changes
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/analysis.py
RENAMED
|
File without changes
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/uk/outputs.py
RENAMED
|
File without changes
|
|
File without changes
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/__init__.py
RENAMED
|
File without changes
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/analysis.py
RENAMED
|
File without changes
|
{policyengine-3.1.12 → policyengine-3.1.14}/src/policyengine/tax_benefit_models/us/outputs.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|