policyengine 3.0.0__py3-none-any.whl → 3.1.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.
- policyengine/__pycache__/__init__.cpython-313.pyc +0 -0
- policyengine/core/__init__.py +22 -0
- policyengine/core/dataset.py +260 -0
- policyengine/core/dataset_version.py +16 -0
- policyengine/core/dynamic.py +43 -0
- policyengine/core/output.py +26 -0
- policyengine/{models → core}/parameter.py +4 -2
- policyengine/{models → core}/parameter_value.py +1 -1
- policyengine/core/policy.py +43 -0
- policyengine/{models → core}/simulation.py +10 -14
- policyengine/core/tax_benefit_model.py +11 -0
- policyengine/core/tax_benefit_model_version.py +34 -0
- policyengine/core/variable.py +15 -0
- policyengine/outputs/__init__.py +21 -0
- policyengine/outputs/aggregate.py +124 -0
- policyengine/outputs/change_aggregate.py +184 -0
- policyengine/outputs/decile_impact.py +140 -0
- policyengine/tax_benefit_models/uk/__init__.py +26 -0
- policyengine/tax_benefit_models/uk/analysis.py +97 -0
- policyengine/tax_benefit_models/uk/datasets.py +176 -0
- policyengine/tax_benefit_models/uk/model.py +268 -0
- policyengine/tax_benefit_models/uk/outputs.py +108 -0
- policyengine/tax_benefit_models/uk.py +33 -0
- policyengine/tax_benefit_models/us/__init__.py +36 -0
- policyengine/tax_benefit_models/us/analysis.py +99 -0
- policyengine/tax_benefit_models/us/datasets.py +307 -0
- policyengine/tax_benefit_models/us/model.py +447 -0
- policyengine/tax_benefit_models/us/outputs.py +108 -0
- policyengine/tax_benefit_models/us.py +32 -0
- policyengine/utils/__init__.py +3 -0
- policyengine/utils/dates.py +40 -0
- policyengine/utils/parametric_reforms.py +39 -0
- policyengine/utils/plotting.py +179 -0
- {policyengine-3.0.0.dist-info → policyengine-3.1.1.dist-info}/METADATA +185 -20
- policyengine-3.1.1.dist-info/RECORD +39 -0
- policyengine/database/__init__.py +0 -56
- policyengine/database/aggregate.py +0 -33
- policyengine/database/baseline_parameter_value_table.py +0 -66
- policyengine/database/baseline_variable_table.py +0 -40
- policyengine/database/database.py +0 -251
- policyengine/database/dataset_table.py +0 -41
- policyengine/database/dynamic_table.py +0 -34
- policyengine/database/link.py +0 -82
- policyengine/database/model_table.py +0 -27
- policyengine/database/model_version_table.py +0 -28
- policyengine/database/parameter_table.py +0 -31
- policyengine/database/parameter_value_table.py +0 -62
- policyengine/database/policy_table.py +0 -34
- policyengine/database/report_element_table.py +0 -48
- policyengine/database/report_table.py +0 -24
- policyengine/database/simulation_table.py +0 -50
- policyengine/database/user_table.py +0 -28
- policyengine/database/versioned_dataset_table.py +0 -28
- policyengine/models/__init__.py +0 -30
- policyengine/models/aggregate.py +0 -92
- policyengine/models/baseline_parameter_value.py +0 -14
- policyengine/models/baseline_variable.py +0 -12
- policyengine/models/dataset.py +0 -18
- policyengine/models/dynamic.py +0 -15
- policyengine/models/model.py +0 -124
- policyengine/models/model_version.py +0 -14
- policyengine/models/policy.py +0 -17
- policyengine/models/policyengine_uk.py +0 -114
- policyengine/models/policyengine_us.py +0 -115
- policyengine/models/report.py +0 -10
- policyengine/models/report_element.py +0 -36
- policyengine/models/user.py +0 -14
- policyengine/models/versioned_dataset.py +0 -12
- policyengine/utils/charts.py +0 -286
- policyengine/utils/compress.py +0 -20
- policyengine/utils/datasets.py +0 -71
- policyengine-3.0.0.dist-info/RECORD +0 -47
- policyengine-3.0.0.dist-info/entry_points.txt +0 -2
- {policyengine-3.0.0.dist-info → policyengine-3.1.1.dist-info}/WHEEL +0 -0
- {policyengine-3.0.0.dist-info → policyengine-3.1.1.dist-info}/licenses/LICENSE +0 -0
- {policyengine-3.0.0.dist-info → policyengine-3.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Plotting utilities for PolicyEngine visualisations."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import plotly.graph_objects as go
|
|
5
|
+
|
|
6
|
+
# PolicyEngine brand colours
|
|
7
|
+
COLORS = {
|
|
8
|
+
"primary": "#319795", # Teal
|
|
9
|
+
"primary_light": "#E6FFFA",
|
|
10
|
+
"primary_dark": "#1D4044",
|
|
11
|
+
"success": "#22C55E", # Green (positive changes)
|
|
12
|
+
"warning": "#FEC601", # Yellow (cautions)
|
|
13
|
+
"error": "#EF4444", # Red (negative changes)
|
|
14
|
+
"info": "#1890FF", # Blue (neutral info)
|
|
15
|
+
"gray_light": "#F2F4F7",
|
|
16
|
+
"gray": "#667085",
|
|
17
|
+
"gray_dark": "#101828",
|
|
18
|
+
"blue_secondary": "#026AA2",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Typography
|
|
22
|
+
FONT_FAMILY = (
|
|
23
|
+
"Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
|
|
24
|
+
)
|
|
25
|
+
FONT_SIZE_LABEL = 12
|
|
26
|
+
FONT_SIZE_DEFAULT = 14
|
|
27
|
+
FONT_SIZE_TITLE = 16
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def format_fig(
|
|
31
|
+
fig: go.Figure,
|
|
32
|
+
title: str | None = None,
|
|
33
|
+
xaxis_title: str | None = None,
|
|
34
|
+
yaxis_title: str | None = None,
|
|
35
|
+
show_legend: bool = True,
|
|
36
|
+
height: int | None = None,
|
|
37
|
+
width: int | None = None,
|
|
38
|
+
) -> go.Figure:
|
|
39
|
+
"""Apply PolicyEngine visual style to a plotly figure.
|
|
40
|
+
|
|
41
|
+
Applies professional, clean styling following PolicyEngine design principles:
|
|
42
|
+
- Data-driven clarity prioritising immediate understanding
|
|
43
|
+
- Professional brand colours (teal primary, semantic colours)
|
|
44
|
+
- Clean typography with Inter font family
|
|
45
|
+
- Minimal visual clutter
|
|
46
|
+
- Appropriate spacing and margins
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
fig: Plotly figure to format
|
|
50
|
+
title: Optional title to set/override
|
|
51
|
+
xaxis_title: Optional x-axis title to set/override
|
|
52
|
+
yaxis_title: Optional y-axis title to set/override
|
|
53
|
+
show_legend: Whether to show the legend (default: True)
|
|
54
|
+
height: Optional height in pixels
|
|
55
|
+
width: Optional width in pixels
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Formatted plotly figure (same object, modified in place)
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
>>> import plotly.graph_objects as go
|
|
62
|
+
>>> from policyengine.utils import format_fig
|
|
63
|
+
>>> fig = go.Figure(data=go.Scatter(x=[1, 2, 3], y=[4, 5, 6]))
|
|
64
|
+
>>> format_fig(fig, title="Example chart", xaxis_title="X", yaxis_title="Y")
|
|
65
|
+
"""
|
|
66
|
+
# Build layout updates
|
|
67
|
+
layout_updates = {
|
|
68
|
+
"font": {
|
|
69
|
+
"family": FONT_FAMILY,
|
|
70
|
+
"size": FONT_SIZE_DEFAULT,
|
|
71
|
+
"color": COLORS["gray_dark"],
|
|
72
|
+
},
|
|
73
|
+
"plot_bgcolor": "#FAFAFA",
|
|
74
|
+
"paper_bgcolor": "white",
|
|
75
|
+
"margin": {"l": 100, "r": 60, "t": 100, "b": 80},
|
|
76
|
+
"showlegend": show_legend,
|
|
77
|
+
"xaxis": {
|
|
78
|
+
"title": {
|
|
79
|
+
"font": {
|
|
80
|
+
"size": FONT_SIZE_DEFAULT,
|
|
81
|
+
"family": FONT_FAMILY,
|
|
82
|
+
"color": COLORS["gray_dark"],
|
|
83
|
+
},
|
|
84
|
+
"standoff": 20,
|
|
85
|
+
},
|
|
86
|
+
"tickfont": {
|
|
87
|
+
"size": FONT_SIZE_LABEL,
|
|
88
|
+
"family": FONT_FAMILY,
|
|
89
|
+
"color": COLORS["gray"],
|
|
90
|
+
},
|
|
91
|
+
"showgrid": False,
|
|
92
|
+
"showline": True,
|
|
93
|
+
"linewidth": 2,
|
|
94
|
+
"linecolor": COLORS["gray_light"],
|
|
95
|
+
"zeroline": False,
|
|
96
|
+
"ticks": "outside",
|
|
97
|
+
"tickwidth": 1,
|
|
98
|
+
"tickcolor": COLORS["gray_light"],
|
|
99
|
+
},
|
|
100
|
+
"yaxis": {
|
|
101
|
+
"title": {
|
|
102
|
+
"font": {
|
|
103
|
+
"size": FONT_SIZE_DEFAULT,
|
|
104
|
+
"family": FONT_FAMILY,
|
|
105
|
+
"color": COLORS["gray_dark"],
|
|
106
|
+
},
|
|
107
|
+
"standoff": 20,
|
|
108
|
+
},
|
|
109
|
+
"tickfont": {
|
|
110
|
+
"size": FONT_SIZE_LABEL,
|
|
111
|
+
"family": FONT_FAMILY,
|
|
112
|
+
"color": COLORS["gray"],
|
|
113
|
+
},
|
|
114
|
+
"showgrid": True,
|
|
115
|
+
"gridwidth": 1,
|
|
116
|
+
"gridcolor": "#E5E7EB",
|
|
117
|
+
"showline": False,
|
|
118
|
+
"zeroline": False,
|
|
119
|
+
},
|
|
120
|
+
"legend": {
|
|
121
|
+
"bgcolor": "white",
|
|
122
|
+
"bordercolor": COLORS["gray_light"],
|
|
123
|
+
"borderwidth": 1,
|
|
124
|
+
"font": {"size": FONT_SIZE_LABEL, "family": FONT_FAMILY},
|
|
125
|
+
"orientation": "v",
|
|
126
|
+
"yanchor": "top",
|
|
127
|
+
"y": 0.99,
|
|
128
|
+
"xanchor": "right",
|
|
129
|
+
"x": 0.99,
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Add optional parameters
|
|
134
|
+
if title is not None:
|
|
135
|
+
layout_updates["title"] = {
|
|
136
|
+
"text": title,
|
|
137
|
+
"font": {
|
|
138
|
+
"size": 18,
|
|
139
|
+
"family": FONT_FAMILY,
|
|
140
|
+
"color": COLORS["gray_dark"],
|
|
141
|
+
"weight": 600,
|
|
142
|
+
},
|
|
143
|
+
"x": 0,
|
|
144
|
+
"xanchor": "left",
|
|
145
|
+
"y": 0.98,
|
|
146
|
+
"yanchor": "top",
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if xaxis_title is not None:
|
|
150
|
+
layout_updates["xaxis"]["title"]["text"] = xaxis_title
|
|
151
|
+
|
|
152
|
+
if yaxis_title is not None:
|
|
153
|
+
layout_updates["yaxis"]["title"]["text"] = yaxis_title
|
|
154
|
+
|
|
155
|
+
if height is not None:
|
|
156
|
+
layout_updates["height"] = height
|
|
157
|
+
|
|
158
|
+
if width is not None:
|
|
159
|
+
layout_updates["width"] = width
|
|
160
|
+
|
|
161
|
+
# Apply layout
|
|
162
|
+
fig.update_layout(**layout_updates)
|
|
163
|
+
|
|
164
|
+
# Update all traces to have cleaner styling
|
|
165
|
+
fig.update_traces(
|
|
166
|
+
marker=dict(size=8, line=dict(width=0)),
|
|
167
|
+
line=dict(width=3),
|
|
168
|
+
selector=dict(mode="markers+lines"),
|
|
169
|
+
)
|
|
170
|
+
fig.update_traces(
|
|
171
|
+
marker=dict(size=8, line=dict(width=0)),
|
|
172
|
+
selector=dict(mode="markers"),
|
|
173
|
+
)
|
|
174
|
+
fig.update_traces(
|
|
175
|
+
line=dict(width=3),
|
|
176
|
+
selector=dict(mode="lines"),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return fig
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: policyengine
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.1.1
|
|
4
4
|
Summary: A package to conduct policy analysis using PolicyEngine tax-benefit models.
|
|
5
5
|
Author-email: PolicyEngine <hello@policyengine.org>
|
|
6
6
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
@@ -668,20 +668,11 @@ License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
|
668
668
|
Requires-Python: >=3.13
|
|
669
669
|
Description-Content-Type: text/markdown
|
|
670
670
|
License-File: LICENSE
|
|
671
|
-
Requires-Dist: sqlalchemy>=2.0.0
|
|
672
|
-
Requires-Dist: sqlmodel>=0.0.21
|
|
673
|
-
Requires-Dist: alembic>=1.13.0
|
|
674
|
-
Requires-Dist: psycopg2-binary>=2.9.0
|
|
675
|
-
Requires-Dist: pymysql>=1.1.0
|
|
676
|
-
Requires-Dist: google-cloud-storage>=2.10.0
|
|
677
|
-
Requires-Dist: getpass4
|
|
678
671
|
Requires-Dist: pydantic>=2.0.0
|
|
679
672
|
Requires-Dist: pandas>=2.0.0
|
|
680
|
-
Requires-Dist: rich>=13.0.0
|
|
681
|
-
Requires-Dist: ipywidgets>=8.0.0
|
|
682
673
|
Requires-Dist: microdf_python
|
|
683
|
-
Requires-Dist:
|
|
684
|
-
Requires-Dist:
|
|
674
|
+
Requires-Dist: plotly>=5.0.0
|
|
675
|
+
Requires-Dist: requests>=2.31.0
|
|
685
676
|
Provides-Extra: uk
|
|
686
677
|
Requires-Dist: policyengine_core>=3.10; extra == "uk"
|
|
687
678
|
Requires-Dist: policyengine-uk>=2.51.0; extra == "uk"
|
|
@@ -706,13 +697,187 @@ Dynamic: license-file
|
|
|
706
697
|
|
|
707
698
|
# PolicyEngine.py
|
|
708
699
|
|
|
709
|
-
|
|
700
|
+
A Python package for tax-benefit microsimulation analysis. Run policy simulations, analyse distributional impacts, and visualise results across the UK and US.
|
|
710
701
|
|
|
711
|
-
|
|
712
|
-
- Policies and dynamic: `docs/02_policies_dynamic.ipynb`
|
|
713
|
-
- Datasets: `docs/03_datasets.ipynb`
|
|
714
|
-
- Simulations: `docs/04_simulations.ipynb`
|
|
715
|
-
- Output data items: `docs/05_output_data_items.ipynb`
|
|
716
|
-
- Reports and users: `docs/06_reports_users.ipynb`
|
|
702
|
+
## Quick start
|
|
717
703
|
|
|
718
|
-
|
|
704
|
+
```python
|
|
705
|
+
from policyengine.core import Simulation
|
|
706
|
+
from policyengine.tax_benefit_models.uk import PolicyEngineUKDataset, uk_latest
|
|
707
|
+
from policyengine.outputs.aggregate import Aggregate, AggregateType
|
|
708
|
+
|
|
709
|
+
# Load representative microdata
|
|
710
|
+
dataset = PolicyEngineUKDataset(
|
|
711
|
+
name="FRS 2023-24",
|
|
712
|
+
filepath="./data/frs_2023_24_year_2026.h5",
|
|
713
|
+
year=2026,
|
|
714
|
+
)
|
|
715
|
+
|
|
716
|
+
# Run simulation
|
|
717
|
+
simulation = Simulation(
|
|
718
|
+
dataset=dataset,
|
|
719
|
+
tax_benefit_model_version=uk_latest,
|
|
720
|
+
)
|
|
721
|
+
simulation.run()
|
|
722
|
+
|
|
723
|
+
# Calculate total universal credit spending
|
|
724
|
+
agg = Aggregate(
|
|
725
|
+
simulation=simulation,
|
|
726
|
+
variable="universal_credit",
|
|
727
|
+
aggregate_type=AggregateType.SUM,
|
|
728
|
+
entity="benunit",
|
|
729
|
+
)
|
|
730
|
+
agg.run()
|
|
731
|
+
print(f"Total UC spending: £{agg.result / 1e9:.1f}bn")
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
## Documentation
|
|
735
|
+
|
|
736
|
+
**Core concepts:**
|
|
737
|
+
- [Core concepts](docs/core-concepts.md): Architecture, datasets, simulations, outputs
|
|
738
|
+
- [UK tax-benefit model](docs/country-models-uk.md): Entities, parameters, examples
|
|
739
|
+
- [US tax-benefit model](docs/country-models-us.md): Entities, parameters, examples
|
|
740
|
+
|
|
741
|
+
**Examples:**
|
|
742
|
+
- `examples/income_distribution_us.py`: Analyse benefit distribution by decile
|
|
743
|
+
- `examples/employment_income_variation_uk.py`: Model employment income phase-outs
|
|
744
|
+
- `examples/policy_change_uk.py`: Analyse policy reform impacts
|
|
745
|
+
|
|
746
|
+
## Installation
|
|
747
|
+
|
|
748
|
+
```bash
|
|
749
|
+
pip install policyengine
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
## Features
|
|
753
|
+
|
|
754
|
+
- **Multi-country support**: UK and US tax-benefit systems
|
|
755
|
+
- **Representative microdata**: Load FRS, CPS, or create custom scenarios
|
|
756
|
+
- **Policy reforms**: Parametric reforms with date-bound parameter values
|
|
757
|
+
- **Distributional analysis**: Aggregate statistics by income decile, demographics
|
|
758
|
+
- **Entity mapping**: Automatic mapping between person, household, tax unit levels
|
|
759
|
+
- **Visualisation**: PolicyEngine-branded charts with Plotly
|
|
760
|
+
|
|
761
|
+
## Key concepts
|
|
762
|
+
|
|
763
|
+
### Datasets
|
|
764
|
+
|
|
765
|
+
Datasets contain microdata at entity level (person, household, tax unit). Load representative data or create custom scenarios:
|
|
766
|
+
|
|
767
|
+
```python
|
|
768
|
+
from policyengine.tax_benefit_models.uk import PolicyEngineUKDataset
|
|
769
|
+
|
|
770
|
+
dataset = PolicyEngineUKDataset(
|
|
771
|
+
name="Representative data",
|
|
772
|
+
filepath="./data/frs_2023_24_year_2026.h5",
|
|
773
|
+
year=2026,
|
|
774
|
+
)
|
|
775
|
+
dataset.load()
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
### Simulations
|
|
779
|
+
|
|
780
|
+
Simulations apply tax-benefit models to datasets:
|
|
781
|
+
|
|
782
|
+
```python
|
|
783
|
+
from policyengine.core import Simulation
|
|
784
|
+
from policyengine.tax_benefit_models.uk import uk_latest
|
|
785
|
+
|
|
786
|
+
simulation = Simulation(
|
|
787
|
+
dataset=dataset,
|
|
788
|
+
tax_benefit_model_version=uk_latest,
|
|
789
|
+
)
|
|
790
|
+
simulation.run()
|
|
791
|
+
|
|
792
|
+
# Access calculated variables
|
|
793
|
+
output = simulation.output_dataset.data
|
|
794
|
+
print(output.household[["household_net_income", "household_benefits"]])
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### Outputs
|
|
798
|
+
|
|
799
|
+
Extract insights with aggregate statistics:
|
|
800
|
+
|
|
801
|
+
```python
|
|
802
|
+
from policyengine.outputs.aggregate import Aggregate, AggregateType
|
|
803
|
+
|
|
804
|
+
# Mean income in top decile
|
|
805
|
+
agg = Aggregate(
|
|
806
|
+
simulation=simulation,
|
|
807
|
+
variable="household_net_income",
|
|
808
|
+
aggregate_type=AggregateType.MEAN,
|
|
809
|
+
filter_variable="household_net_income",
|
|
810
|
+
quantile=10,
|
|
811
|
+
quantile_eq=10,
|
|
812
|
+
)
|
|
813
|
+
agg.run()
|
|
814
|
+
print(f"Top decile mean income: £{agg.result:,.0f}")
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
### Policy reforms
|
|
818
|
+
|
|
819
|
+
Apply parametric reforms:
|
|
820
|
+
|
|
821
|
+
```python
|
|
822
|
+
from policyengine.core import Policy, Parameter, ParameterValue
|
|
823
|
+
import datetime
|
|
824
|
+
|
|
825
|
+
parameter = Parameter(
|
|
826
|
+
name="gov.hmrc.income_tax.allowances.personal_allowance.amount",
|
|
827
|
+
tax_benefit_model_version=uk_latest,
|
|
828
|
+
data_type=float,
|
|
829
|
+
)
|
|
830
|
+
|
|
831
|
+
policy = Policy(
|
|
832
|
+
name="Increase personal allowance",
|
|
833
|
+
parameter_values=[
|
|
834
|
+
ParameterValue(
|
|
835
|
+
parameter=parameter,
|
|
836
|
+
start_date=datetime.date(2026, 1, 1),
|
|
837
|
+
end_date=datetime.date(2026, 12, 31),
|
|
838
|
+
value=15000,
|
|
839
|
+
)
|
|
840
|
+
],
|
|
841
|
+
)
|
|
842
|
+
|
|
843
|
+
# Run reform simulation
|
|
844
|
+
reform_sim = Simulation(
|
|
845
|
+
dataset=dataset,
|
|
846
|
+
tax_benefit_model_version=uk_latest,
|
|
847
|
+
policy=policy,
|
|
848
|
+
)
|
|
849
|
+
reform_sim.run()
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
## Country models
|
|
853
|
+
|
|
854
|
+
### UK
|
|
855
|
+
|
|
856
|
+
Three entity levels:
|
|
857
|
+
- **Person**: Individual with income and demographics
|
|
858
|
+
- **Benunit**: Benefit unit (single person or couple with children)
|
|
859
|
+
- **Household**: Residence unit
|
|
860
|
+
|
|
861
|
+
Key benefits: Universal Credit, Child Benefit, Pension Credit
|
|
862
|
+
Key taxes: Income tax, National Insurance
|
|
863
|
+
|
|
864
|
+
### US
|
|
865
|
+
|
|
866
|
+
Six entity levels:
|
|
867
|
+
- **Person**: Individual
|
|
868
|
+
- **Tax unit**: Federal tax filing unit
|
|
869
|
+
- **SPM unit**: Supplemental Poverty Measure unit
|
|
870
|
+
- **Family**: Census family definition
|
|
871
|
+
- **Marital unit**: Married couple or single person
|
|
872
|
+
- **Household**: Residence unit
|
|
873
|
+
|
|
874
|
+
Key benefits: SNAP, TANF, EITC, CTC, SSI, Social Security
|
|
875
|
+
Key taxes: Federal income tax, payroll tax
|
|
876
|
+
|
|
877
|
+
## Contributing
|
|
878
|
+
|
|
879
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
|
|
880
|
+
|
|
881
|
+
## License
|
|
882
|
+
|
|
883
|
+
AGPL-3.0
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
policyengine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
policyengine/__pycache__/__init__.cpython-313.pyc,sha256=dmkhqYKcUjDPvirOFgf1L-P-aV3l7JIWK6zZZ6J45LU,175
|
|
3
|
+
policyengine/core/__init__.py,sha256=3vabkWXYNNmQmN4Vy1yx2kKk6RKVSsdjtToQ8s8gzUg,870
|
|
4
|
+
policyengine/core/dataset.py,sha256=jGjnoyEQ6VcTiCs8Hr6PT22l59CRhK1oUT5RPaz7mC0,9256
|
|
5
|
+
policyengine/core/dataset_version.py,sha256=6KeFCRGQto_Yyl4QY4Vo2JFythjaXrNAOHQiwRGESyM,378
|
|
6
|
+
policyengine/core/dynamic.py,sha256=40RO3N6hmUT6-3tpJy0wSOC-9ITdFSS5LRiqPmi79f0,1605
|
|
7
|
+
policyengine/core/output.py,sha256=cCW4vbzkLdQaT_nJTyDJBl7Hubm7nZeRuR7aVG1dKvg,643
|
|
8
|
+
policyengine/core/parameter.py,sha256=PLDaepytqB7FVSfYQ541vnkVuMDLamFBeHtz2TmQrOE,378
|
|
9
|
+
policyengine/core/parameter_value.py,sha256=b0ts1kbWcwjPSYnZm2rlCylmTLPJRLxDL8z3RmxM5OI,377
|
|
10
|
+
policyengine/core/policy.py,sha256=xorVf03bcjB-3mBEmwj2YMqF1-6Xzps74SquzqtS0lo,1599
|
|
11
|
+
policyengine/core/simulation.py,sha256=x9dU_nKEIgCZa11cxB-VdRNt9DZjjSML7n7M8_3STv8,941
|
|
12
|
+
policyengine/core/tax_benefit_model.py,sha256=2Yc1RlQrUG7djDMZbJOQH4Ns86_lOnLeISCGR4-9zMo,176
|
|
13
|
+
policyengine/core/tax_benefit_model_version.py,sha256=AJHFRaSEzR2_0FVkBBb40ID3FAaFFrFLnhSXRYYbtWs,1291
|
|
14
|
+
policyengine/core/variable.py,sha256=AjSImORlRkh05xhYxyeT6GFMOfViRzYg0qRQAIj-mxo,350
|
|
15
|
+
policyengine/outputs/__init__.py,sha256=IJUmLP0Og41VrwiqhJF-a9-3fIb4nlXpS7uFuVCINIs,515
|
|
16
|
+
policyengine/outputs/aggregate.py,sha256=exI-U04OF5kVf2BBYV6sf8VldIWnT_IzxgkBs5wtnCw,4846
|
|
17
|
+
policyengine/outputs/change_aggregate.py,sha256=tK4K87YlByKikqFaB7OHyh1SqAuGtUnLL7cSF_EhrOs,7373
|
|
18
|
+
policyengine/outputs/decile_impact.py,sha256=jclhbj5U-xX8D-myy0SuWeJFVfQTqJDCh7qBXugak5U,4811
|
|
19
|
+
policyengine/tax_benefit_models/uk.py,sha256=MCeJGQCTwUzBYdz0ru7IgT8Mgv-vJMqqVwFrntGWWTE,734
|
|
20
|
+
policyengine/tax_benefit_models/us.py,sha256=d6rdhW2awoUvk5Ldp9mHAUiHqlnSfEQR318PkIXS_9c,794
|
|
21
|
+
policyengine/tax_benefit_models/uk/__init__.py,sha256=1L1HBbOTflRefjOcU5vgEYkn6wLWOt_uG9G_PF089S0,732
|
|
22
|
+
policyengine/tax_benefit_models/uk/analysis.py,sha256=O4eYJYF7tsgiuLuiWMU0OXq7ss6U8-vzlg6nC2U8sgU,3175
|
|
23
|
+
policyengine/tax_benefit_models/uk/datasets.py,sha256=LvbHemfhMU1kk9sZU5eAPrix8EmTl07p9fYkwbSasIE,6542
|
|
24
|
+
policyengine/tax_benefit_models/uk/model.py,sha256=5GGhscQEX1-YBgkUt4kd2RyFfVIBEd7IihaSP3ia7hg,9247
|
|
25
|
+
policyengine/tax_benefit_models/uk/outputs.py,sha256=2mYLwQW4QNvrOHtHfm_ACqE9gbmuLxvcCyldRU46s0o,3543
|
|
26
|
+
policyengine/tax_benefit_models/us/__init__.py,sha256=ClBkFwRa_nFQ3YU003uxBKiMG3pktaUb8jRvhzfR0vE,968
|
|
27
|
+
policyengine/tax_benefit_models/us/analysis.py,sha256=Xf-DT0QjVySs0QG_koCwgvOeWI_scLtv3S3SP8u8ZWc,3253
|
|
28
|
+
policyengine/tax_benefit_models/us/datasets.py,sha256=sQ0YsTsmqpaM-j7w6Cea1lKUzjMV3UPqH5Bc3hH71cI,12718
|
|
29
|
+
policyengine/tax_benefit_models/us/model.py,sha256=SNQ3_pVLJDF41gRzU4NZ1yZUq8nLMPSHWwb-qGaTae0,16021
|
|
30
|
+
policyengine/tax_benefit_models/us/outputs.py,sha256=GT8Eur8DfB9cPQRbSljEl9RpKSNHW80Fq_CBXCybvIU,3519
|
|
31
|
+
policyengine/utils/__init__.py,sha256=1X-VYAWLyB9A0YRHwsGWrqQHns1WfeZ7ISC6DMU5myM,140
|
|
32
|
+
policyengine/utils/dates.py,sha256=HnAqyl8S8EOYp8ibsnMTmECYoDWCSqwL-7A2_qKgxSc,1510
|
|
33
|
+
policyengine/utils/parametric_reforms.py,sha256=4P3U39-4pYTU4BN6JjgmVLUkCkBhRfZJ6UIWTlsjyQE,1155
|
|
34
|
+
policyengine/utils/plotting.py,sha256=JbMPwD7SCQqp_qbjYrXixT5zS0eG734n0Sg4JkD9nDc,5336
|
|
35
|
+
policyengine-3.1.1.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
36
|
+
policyengine-3.1.1.dist-info/METADATA,sha256=JuCAmXnSyBcTeeqyBm54GYmsYrrOPg8zGhWHdYoleT4,45889
|
|
37
|
+
policyengine-3.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
38
|
+
policyengine-3.1.1.dist-info/top_level.txt,sha256=_23UPobfkneHQkpJ0e0OmDJfhCUfoXj_F2sTckCGOH4,13
|
|
39
|
+
policyengine-3.1.1.dist-info/RECORD,,
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
from .baseline_parameter_value_table import (
|
|
2
|
-
BaselineParameterValueTable,
|
|
3
|
-
baseline_parameter_value_table_link,
|
|
4
|
-
)
|
|
5
|
-
from .baseline_variable_table import (
|
|
6
|
-
BaselineVariableTable,
|
|
7
|
-
baseline_variable_table_link,
|
|
8
|
-
)
|
|
9
|
-
from .database import Database
|
|
10
|
-
from .dataset_table import DatasetTable, dataset_table_link
|
|
11
|
-
from .dynamic_table import DynamicTable, dynamic_table_link
|
|
12
|
-
from .link import TableLink
|
|
13
|
-
|
|
14
|
-
# Import all table classes and links
|
|
15
|
-
from .model_table import ModelTable, model_table_link
|
|
16
|
-
from .model_version_table import ModelVersionTable, model_version_table_link
|
|
17
|
-
from .parameter_table import ParameterTable, parameter_table_link
|
|
18
|
-
from .parameter_value_table import (
|
|
19
|
-
ParameterValueTable,
|
|
20
|
-
parameter_value_table_link,
|
|
21
|
-
)
|
|
22
|
-
from .policy_table import PolicyTable, policy_table_link
|
|
23
|
-
from .simulation_table import SimulationTable, simulation_table_link
|
|
24
|
-
from .versioned_dataset_table import (
|
|
25
|
-
VersionedDatasetTable,
|
|
26
|
-
versioned_dataset_table_link,
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
__all__ = [
|
|
30
|
-
"Database",
|
|
31
|
-
"TableLink",
|
|
32
|
-
# Tables
|
|
33
|
-
"ModelTable",
|
|
34
|
-
"ModelVersionTable",
|
|
35
|
-
"DatasetTable",
|
|
36
|
-
"VersionedDatasetTable",
|
|
37
|
-
"PolicyTable",
|
|
38
|
-
"DynamicTable",
|
|
39
|
-
"ParameterTable",
|
|
40
|
-
"ParameterValueTable",
|
|
41
|
-
"BaselineParameterValueTable",
|
|
42
|
-
"BaselineVariableTable",
|
|
43
|
-
"SimulationTable",
|
|
44
|
-
# Links
|
|
45
|
-
"model_table_link",
|
|
46
|
-
"model_version_table_link",
|
|
47
|
-
"dataset_table_link",
|
|
48
|
-
"versioned_dataset_table_link",
|
|
49
|
-
"policy_table_link",
|
|
50
|
-
"dynamic_table_link",
|
|
51
|
-
"parameter_table_link",
|
|
52
|
-
"parameter_value_table_link",
|
|
53
|
-
"baseline_parameter_value_table_link",
|
|
54
|
-
"baseline_variable_table_link",
|
|
55
|
-
"simulation_table_link",
|
|
56
|
-
]
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
from uuid import uuid4
|
|
2
|
-
|
|
3
|
-
from sqlmodel import Field, SQLModel
|
|
4
|
-
|
|
5
|
-
from policyengine.database.link import TableLink
|
|
6
|
-
from policyengine.models.aggregate import Aggregate
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class AggregateTable(SQLModel, table=True):
|
|
10
|
-
__tablename__ = "aggregates"
|
|
11
|
-
|
|
12
|
-
id: str = Field(default_factory=lambda: str(uuid4()), primary_key=True)
|
|
13
|
-
simulation_id: str = Field(
|
|
14
|
-
foreign_key="simulations.id", ondelete="CASCADE"
|
|
15
|
-
)
|
|
16
|
-
entity: str
|
|
17
|
-
variable_name: str
|
|
18
|
-
year: int | None = None
|
|
19
|
-
filter_variable_name: str | None = None
|
|
20
|
-
filter_variable_value: str | None = None
|
|
21
|
-
filter_variable_leq: float | None = None
|
|
22
|
-
filter_variable_geq: float | None = None
|
|
23
|
-
aggregate_function: str
|
|
24
|
-
value: float | None = None
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
aggregate_table_link = TableLink(
|
|
28
|
-
model_cls=Aggregate,
|
|
29
|
-
table_cls=AggregateTable,
|
|
30
|
-
model_to_table_custom_transforms=dict(
|
|
31
|
-
simulation_id=lambda a: a.simulation.id,
|
|
32
|
-
),
|
|
33
|
-
)
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import Any
|
|
3
|
-
from uuid import uuid4
|
|
4
|
-
|
|
5
|
-
from sqlmodel import JSON, Column, Field, SQLModel
|
|
6
|
-
|
|
7
|
-
from policyengine.models import BaselineParameterValue
|
|
8
|
-
|
|
9
|
-
from .link import TableLink
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class BaselineParameterValueTable(SQLModel, table=True):
|
|
13
|
-
__tablename__ = "baseline_parameter_values"
|
|
14
|
-
__table_args__ = ({"extend_existing": True},)
|
|
15
|
-
|
|
16
|
-
id: str = Field(default_factory=lambda: str(uuid4()), primary_key=True)
|
|
17
|
-
parameter_id: str = Field(nullable=False) # Part of composite foreign key
|
|
18
|
-
model_id: str = Field(nullable=False) # Part of composite foreign key
|
|
19
|
-
model_version_id: str = Field(
|
|
20
|
-
foreign_key="model_versions.id", ondelete="CASCADE"
|
|
21
|
-
)
|
|
22
|
-
value: Any | None = Field(
|
|
23
|
-
default=None, sa_column=Column(JSON)
|
|
24
|
-
) # JSON field for any type
|
|
25
|
-
start_date: datetime = Field(nullable=False)
|
|
26
|
-
end_date: datetime | None = Field(default=None)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def transform_value_to_table(bpv):
|
|
30
|
-
"""Transform value for storage, handling special float values."""
|
|
31
|
-
import math
|
|
32
|
-
|
|
33
|
-
value = bpv.value
|
|
34
|
-
if isinstance(value, float):
|
|
35
|
-
if math.isinf(value):
|
|
36
|
-
return "Infinity" if value > 0 else "-Infinity"
|
|
37
|
-
elif math.isnan(value):
|
|
38
|
-
return "NaN"
|
|
39
|
-
return value
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def transform_value_from_table(table_row):
|
|
43
|
-
"""Transform value from storage, converting special strings back to floats."""
|
|
44
|
-
value = table_row.value
|
|
45
|
-
if value == "Infinity":
|
|
46
|
-
return float("inf")
|
|
47
|
-
elif value == "-Infinity":
|
|
48
|
-
return float("-inf")
|
|
49
|
-
elif value == "NaN":
|
|
50
|
-
return float("nan")
|
|
51
|
-
return value
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
baseline_parameter_value_table_link = TableLink(
|
|
55
|
-
model_cls=BaselineParameterValue,
|
|
56
|
-
table_cls=BaselineParameterValueTable,
|
|
57
|
-
model_to_table_custom_transforms=dict(
|
|
58
|
-
parameter_id=lambda bpv: bpv.parameter.id,
|
|
59
|
-
model_id=lambda bpv: bpv.parameter.model.id, # Add model_id from parameter
|
|
60
|
-
model_version_id=lambda bpv: bpv.model_version.id,
|
|
61
|
-
value=transform_value_to_table,
|
|
62
|
-
),
|
|
63
|
-
table_to_model_custom_transforms=dict(
|
|
64
|
-
value=transform_value_from_table,
|
|
65
|
-
),
|
|
66
|
-
)
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
from sqlmodel import Field, SQLModel
|
|
2
|
-
|
|
3
|
-
from policyengine.models import BaselineVariable
|
|
4
|
-
from policyengine.utils.compress import compress_data, decompress_data
|
|
5
|
-
|
|
6
|
-
from .link import TableLink
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class BaselineVariableTable(SQLModel, table=True):
|
|
10
|
-
__tablename__ = "baseline_variables"
|
|
11
|
-
__table_args__ = ({"extend_existing": True},)
|
|
12
|
-
|
|
13
|
-
id: str = Field(primary_key=True) # Variable name
|
|
14
|
-
model_id: str = Field(
|
|
15
|
-
primary_key=True, foreign_key="models.id"
|
|
16
|
-
) # Part of composite key
|
|
17
|
-
model_version_id: str = Field(
|
|
18
|
-
foreign_key="model_versions.id", ondelete="CASCADE"
|
|
19
|
-
)
|
|
20
|
-
entity: str = Field(nullable=False)
|
|
21
|
-
label: str | None = Field(default=None)
|
|
22
|
-
description: str | None = Field(default=None)
|
|
23
|
-
data_type: bytes | None = Field(default=None) # Pickled type
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
baseline_variable_table_link = TableLink(
|
|
27
|
-
model_cls=BaselineVariable,
|
|
28
|
-
table_cls=BaselineVariableTable,
|
|
29
|
-
primary_key=("id", "model_id"), # Composite primary key
|
|
30
|
-
model_to_table_custom_transforms=dict(
|
|
31
|
-
model_id=lambda bv: bv.model_version.model.id, # Add model_id from model_version
|
|
32
|
-
model_version_id=lambda bv: bv.model_version.id,
|
|
33
|
-
data_type=lambda bv: compress_data(bv.data_type)
|
|
34
|
-
if bv.data_type
|
|
35
|
-
else None,
|
|
36
|
-
),
|
|
37
|
-
table_to_model_custom_transforms=dict(
|
|
38
|
-
data_type=lambda dt: decompress_data(dt) if dt else None,
|
|
39
|
-
),
|
|
40
|
-
)
|