econeval 0.3.1__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.
econeval-0.3.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 EconEval Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,373 @@
1
+ Metadata-Version: 2.4
2
+ Name: econeval
3
+ Version: 0.3.1
4
+ Summary: CI/CD checks for economic, policy, and statistical models
5
+ Author: EconEval Contributors
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: pydantic>=2.0
11
+ Requires-Dist: numexpr>=2.14
12
+ Provides-Extra: dev
13
+ Requires-Dist: pre-commit>=3.7; extra == "dev"
14
+ Requires-Dist: pytest>=8.0; extra == "dev"
15
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
16
+ Requires-Dist: ruff>=0.5.0; extra == "dev"
17
+ Provides-Extra: stats
18
+ Requires-Dist: statsmodels>=0.14; extra == "stats"
19
+ Dynamic: license-file
20
+
21
+ # EconEval
22
+
23
+ <p align="left">
24
+ <img src="assets/logo.svg" alt="EconEval logo" width="120" />
25
+ </p>
26
+
27
+ [![PyPI version](https://img.shields.io/pypi/v/econeval.svg)](https://pypi.org/project/econeval/)
28
+ [![CI](https://github.com/Farukhsb/econeval/actions/workflows/ci.yml/badge.svg)](https://github.com/Farukhsb/econeval/actions/workflows/ci.yml)
29
+ [![Python 3.10-3.11](https://img.shields.io/badge/python-3.10%20%7C%203.11-blue.svg)](https://www.python.org/)
30
+ [![Version](https://img.shields.io/badge/version-v0.3.1-blue.svg)](https://github.com/Farukhsb/econeval/releases/tag/v0.3.1)
31
+
32
+ EconEval is a small open-source framework for checking economic and policy models in CI.
33
+
34
+ It is built for the kind of code that can look fine at the syntax level and still be wrong in practice. A model can run, pass unit tests, and still break an economic rule, drift off course after a data change, or produce results that no longer make sense under stress. EconEval is meant to catch those problems early, before they reach a report, dashboard, or paper.
35
+
36
+ Latest release: [`v0.3.1`](https://github.com/Farukhsb/econeval/releases/tag/v0.3.1)
37
+
38
+ ## What It Does
39
+
40
+ EconEval currently does three things:
41
+
42
+ - loads a model check config
43
+ - runs invariant tests against a Python object
44
+ - writes JSON, JUnit, Markdown, or HTML reports that CI can keep or fail on
45
+
46
+ The config layer is validated with Pydantic, and invariant evaluation can route to `numexpr` for vectorized math or a restricted logical evaluator for model-state checks.
47
+
48
+ That gives you a practical starting point for:
49
+
50
+ - checking that important economic rules still hold
51
+ - making model assumptions explicit in code
52
+ - failing pull requests when a change breaks a rule you care about
53
+
54
+ ## Who Should Use This
55
+
56
+ EconEval is a fit for people who need model checks that are closer to policy and economics than generic unit tests.
57
+
58
+ It is especially useful when the people reviewing a model are not just software engineers, but also domain stakeholders who care about whether the model still makes sense economically.
59
+
60
+ - academic economists validating research code and replication projects
61
+ - policy analysts checking that a model still respects program rules and constraints
62
+ - quantitative consultants delivering models to clients with auditability requirements
63
+ - teams working on forecasting, scenario analysis, or simulation pipelines
64
+ - researchers who want a lightweight validation layer before a model is published or deployed
65
+ - applied data scientists building models that need economics-aware guardrails
66
+ - analysts who want CI checks they can explain in a report or appendix
67
+
68
+ ## Why It Exists
69
+
70
+ Traditional software tests are useful, but they do not tell you whether a model still behaves like a valid model.
71
+
72
+ For example, a change might:
73
+
74
+ - flip the sign of an elasticity
75
+ - violate a market-clearing condition
76
+ - break a policy constraint
77
+ - quietly change the meaning of a downstream output
78
+
79
+ EconEval gives you a place to encode those rules and run them automatically.
80
+
81
+ ## Current MVP
82
+
83
+ The first usable version of EconEval does three things well:
84
+
85
+ 1. read a simple YAML config
86
+ 2. evaluate invariant expressions against a model object
87
+ 3. return a clear pass or fail result that GitHub Actions can use
88
+
89
+ That is enough to support a real workflow without pretending to solve every validation problem at once.
90
+
91
+ ## Example Config
92
+
93
+ ```yaml
94
+ project: demo-model
95
+ version: 1
96
+
97
+ invariants:
98
+ - name: elasticity_must_be_negative
99
+ expression: model.elasticity < 0
100
+ - name: supply_must_be_non_negative
101
+ expression: model.supply >= 0
102
+
103
+ stress_tests:
104
+ - name: stagflation_shock
105
+ dataset: data/stagflation.csv
106
+ metric: mape
107
+ threshold: 0.15
108
+
109
+ - name: macro_stagflation
110
+ kind: synthetic
111
+ metric: invariants
112
+ manipulations:
113
+ - variable: input_data.unemployment_rate
114
+ action: add
115
+ value: 0.04
116
+ - variable: input_data.energy_costs
117
+ action: multiply
118
+ value: 1.5
119
+ invariants:
120
+ - name: slowdown_flag
121
+ expression: model.predicted_gdp_growth < 0.01
122
+
123
+ fairness:
124
+ enabled: true
125
+ metrics:
126
+ - demographic_parity_difference
127
+ - disparate_impact_ratio
128
+ - gini
129
+ - atkinson
130
+ - equal_opportunity_difference
131
+ - equalized_odds_difference
132
+ ```
133
+
134
+ ## How It Fits Together
135
+
136
+ ```text
137
+ model repo
138
+ -> econeval.yml
139
+ -> load config
140
+ -> run invariant checks
141
+ -> collect results
142
+ -> fail or pass CI
143
+ ```
144
+
145
+ ## Project Layout
146
+
147
+ ```text
148
+ econeval/
149
+ .github/
150
+ workflows/
151
+ ci.yml
152
+ action.yml
153
+ examples/
154
+ basic_model/
155
+ model.py
156
+ econeval.yml
157
+ drift_model/
158
+ model.py
159
+ econeval.yml
160
+ fairness_model/
161
+ README.md
162
+ model.py
163
+ econeval.yml
164
+ broken_model/
165
+ model.py
166
+ econeval.yml
167
+ policy_model/
168
+ model.py
169
+ econeval.yml
170
+ advanced_model/
171
+ model.py
172
+ econeval.yml
173
+ src/
174
+ econeval/
175
+ __init__.py
176
+ cli.py
177
+ config.py
178
+ invariants.py
179
+ scenarios.py
180
+ reporting.py
181
+ tests/
182
+ test_config.py
183
+ test_invariants.py
184
+ ```
185
+
186
+ ## Install
187
+
188
+ For development from a checkout:
189
+
190
+ ```bash
191
+ git clone https://github.com/Farukhsb/econeval.git
192
+ cd econeval
193
+ pip install -e .[dev]
194
+ ```
195
+
196
+ `pytest` and `ruff` are included in the `dev` extra. If you only want the CLI, install the package without the extra.
197
+
198
+ EconEval parses its YAML-like config format with its own loader, so you do not need `PyYAML` for the current release.
199
+
200
+ Once the package is published to PyPI, the normal install path will be:
201
+
202
+ ```bash
203
+ pip install econeval
204
+ ```
205
+
206
+ If you want the published package state, start from the `v0.3.1` release tag or the GitHub release page.
207
+
208
+ ## How To Use It
209
+
210
+ Create a config file that lists the checks you want to enforce, then point EconEval at a Python model class.
211
+
212
+ Command line example:
213
+
214
+ ```bash
215
+ econeval --config examples/basic_model/econeval.yml --model examples/basic_model/model.py --class DemoModel --report econeval-report.json
216
+ ```
217
+
218
+ If you prefer module execution, `python -m econeval` works the same way.
219
+
220
+ To write a text report instead:
221
+
222
+ ```bash
223
+ econeval --config examples/advanced_model/econeval.yml --model examples/advanced_model/model.py --class AdvancedModel --report econeval-report.md --format markdown
224
+ econeval --config examples/advanced_model/econeval.yml --model examples/advanced_model/model.py --class AdvancedModel --report econeval-report.html --format html
225
+ ```
226
+
227
+ ## GitHub Action
228
+
229
+ The repository also exposes a composite GitHub Action so workflows can run EconEval in one step.
230
+
231
+ ```yaml
232
+ - uses: Farukhsb/econeval@v1
233
+ with:
234
+ config: examples/basic_model/econeval.yml
235
+ model: examples/basic_model/model.py
236
+ class: DemoModel
237
+ report: econeval-report.json
238
+ python-version: "3.11"
239
+ ```
240
+
241
+ The action installs the package from the action source, sets up Python, and runs the CLI with the inputs you provide.
242
+
243
+ ## Fairness Checks
244
+
245
+ Fairness checks expect a tabular dataset with:
246
+
247
+ - a group column, defaulting to `group`
248
+ - one or more feature columns that are passed to `predict(features)`
249
+ - an `actual` column when you use label-based metrics such as `equal_opportunity_difference` or `equalized_odds_difference`
250
+
251
+ The example in [examples/fairness_model/README.md](examples/fairness_model/README.md) shows the full data format.
252
+
253
+ The built-in thresholds are:
254
+
255
+ - `demographic_parity_difference`: pass at `<= 0.2`
256
+ - `disparate_impact_ratio`: pass at `>= 0.8`
257
+ - `equal_opportunity_difference`: pass at `<= 0.2`
258
+ - `equalized_odds_difference`: pass at `<= 0.2`
259
+ - `gini`: pass at `<= 0.3`
260
+ - `atkinson`: pass at `<= 0.2`
261
+
262
+ Fairness results also include a `severity` field:
263
+
264
+ - `pass` for checks within the threshold
265
+ - `warn` for borderline misses that should not fail CI
266
+ - `fail` for clear misses or execution errors
267
+
268
+ To run the full advanced example with synthetic shocks, drift checks, fairness metrics, and scan checks:
269
+
270
+ ```bash
271
+ econeval --config examples/advanced_model/econeval.yml --model examples/advanced_model/model.py --class AdvancedModel --report artifacts/advanced-report.md --format markdown
272
+ ```
273
+
274
+ What the current runner expects:
275
+
276
+ - a model file that defines a class you can import by name
277
+ - a `predict(features)` method for stress tests, drift checks, and fairness checks
278
+ - CSV datasets with an `actual` column for stress tests
279
+ - CSV datasets with the feature or group columns required by the check
280
+
281
+ If your runtime looks different, use a thin adapter. EconEval now normalizes
282
+ common shapes like callable models, `solve()`-style solver wrappers, and
283
+ PyMC-style posterior predictive samplers so you can bridge external engines
284
+ without rewriting the check pipeline.
285
+
286
+ Example invariant rule:
287
+
288
+ ```yaml
289
+ - name: elasticity_must_be_negative
290
+ expression: model.elasticity < 0
291
+ ```
292
+
293
+ If the expression returns `False`, the invariant fails.
294
+
295
+ The JSON report includes the project name, a summary count, and the result of each invariant, economic check, stress test, drift check, economic drift check, and fairness check.
296
+
297
+ ## Expression Engine
298
+
299
+ EconEval uses a restricted AST-based expression engine for invariants.
300
+
301
+ That keeps the syntax simple for users while avoiding raw `eval()`. It is still a security-sensitive surface, so the allowed syntax is intentionally narrow:
302
+
303
+ - comparisons, boolean logic, simple arithmetic, and attribute access on the model object
304
+
305
+ It explicitly rejects function calls, subscripts, comprehensions, lambdas, dictionaries, sets, and private attributes such as `__class__`.
306
+
307
+ If you need a broader or more standardized expression engine later, the most likely replacement options are `asteval` or `numexpr`, depending on whether you need general Python-like rules or numeric-only expressions.
308
+
309
+ ## Examples
310
+
311
+ - `examples/basic_model` shows the happy path with invariants, stress tests, drift checks, and fairness checks.
312
+ - `examples/broken_model` shows a model and dataset that fail the checks.
313
+ - `examples/drift_model` focuses on drift validation, including trend drift over time.
314
+ - `examples/fairness_model` focuses on fairness checks and a simple stress test.
315
+ - `examples/policy_model` is a minimal policy-focused fairness example.
316
+ - `examples/advanced_model` shows accounting identities, monotonicity, convergence, grid sweeps, and synthetic shocks.
317
+ - `examples/advanced_model` also shows synthetic manipulations, economic drift checks, and GitHub-friendly report output.
318
+ - `examples/advanced_model` now includes a native scan check for monotonicity and elasticity-style responses.
319
+ - `examples/demo_notebook.ipynb` is a short walkthrough you can open in Jupyter or VS Code.
320
+ - The repository examples are intended to double as a lightweight demo workflow.
321
+
322
+ ## Roadmap
323
+
324
+ Planned or likely next steps for the project:
325
+
326
+ - expand stress testing with parameter shocks and Monte Carlo runs
327
+ - deepen drift detection over time with rolling windows and alerting
328
+ - add fairness and equity checks for policy-relevant models
329
+ - add deeper interop with tools like `pandas`, `statsmodels`, `PyMC`, `GAMS`, and Julia
330
+ - fairness and drift checks already accept pandas-like row data through `to_dict(orient="records")`
331
+ - install `econeval[stats]` if you want the optional `statsmodels`-based drift helper
332
+ - use `--format dashboard` for a richer HTML overview with filtering and collapsible drill-downs
333
+
334
+ ## Release Flow
335
+
336
+ Publishing a GitHub Release triggers the release workflow in [`.github/workflows/release.yml`](.github/workflows/release.yml).
337
+
338
+ That workflow:
339
+
340
+ - installs the package
341
+ - runs the test suite
342
+ - runs EconEval against the example model
343
+ - uploads a release report artifact
344
+
345
+ ## Next Step
346
+
347
+ The next useful additions are:
348
+
349
+ - a richer report viewer
350
+ - more scenario types
351
+
352
+ ## Release Checklist
353
+
354
+ When you are ready to publish a new version:
355
+
356
+ 1. run the test suite locally
357
+ 2. update the package version if needed
358
+ 3. tag the release, for example `v0.3.1`
359
+ 4. publish the GitHub Release so the release workflow runs
360
+ 5. confirm the release artifact uploaded from Actions
361
+ 6. confirm the wheel and sdist were published to PyPI
362
+
363
+ To publish to PyPI through GitHub Actions, enable PyPI trusted publishing for this
364
+ repository and then publish the GitHub Release. The release workflow will build the
365
+ distribution and upload it automatically.
366
+
367
+ ## Changelog
368
+
369
+ See [CHANGELOG.md](CHANGELOG.md) for version-by-version changes.
370
+
371
+ ## License
372
+
373
+ MIT