pycheck-neuron 1.0.0__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.
- pycheck/__init__.py +10 -0
- pycheck/__main__.py +3 -0
- pycheck/analyzer.py +198 -0
- pycheck/cli.py +191 -0
- pycheck/flow.py +265 -0
- pycheck/rules.py +938 -0
- pycheck_neuron-1.0.0.dist-info/METADATA +296 -0
- pycheck_neuron-1.0.0.dist-info/RECORD +12 -0
- pycheck_neuron-1.0.0.dist-info/WHEEL +5 -0
- pycheck_neuron-1.0.0.dist-info/entry_points.txt +2 -0
- pycheck_neuron-1.0.0.dist-info/licenses/LICENSE +21 -0
- pycheck_neuron-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pycheck-neuron
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: 32-rule static AST analyzer catching temporal lookahead bias, causal confusion, and uncertainty bugs in Python ML code. Zero dependencies.
|
|
5
|
+
Author: NEURON Team
|
|
6
|
+
Author-email: Fayo Ibrahim <fayo@neuron-lab.org>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/neuronlabs-ai/pycheck
|
|
9
|
+
Project-URL: Documentation, https://github.com/neuronlabs-ai/pycheck#readme
|
|
10
|
+
Project-URL: Repository, https://github.com/neuronlabs-ai/pycheck
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/neuronlabs-ai/pycheck/issues
|
|
12
|
+
Keywords: machine-learning,data-leakage,temporal-bias,lookahead-bias,backtesting,quantitative-finance,algorithmic-trading,linter,static-analysis,causal-inference,time-series,pandas,sklearn,scikit-learn,uncertainty,neuron,ml-safety,data-science,feature-engineering
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
22
|
+
Classifier: Topic :: Software Development :: Testing
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
25
|
+
Classifier: Intended Audience :: Science/Research
|
|
26
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
27
|
+
Classifier: Intended Audience :: Developers
|
|
28
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
29
|
+
Classifier: Environment :: Console
|
|
30
|
+
Requires-Python: >=3.7
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
35
|
+
Requires-Dist: build; extra == "dev"
|
|
36
|
+
Requires-Dist: twine; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# PyCheck — ML Safety Analyzer
|
|
40
|
+
|
|
41
|
+
**30 rules. Zero dependencies. Catches the bugs that cost millions.**
|
|
42
|
+
|
|
43
|
+
PyCheck is a static AST analyzer that detects **temporal lookahead bias**, **causal confusion**, and **unguarded uncertainty** in Python ML and trading scripts — before you run a single line of code.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install pycheck-neuron
|
|
47
|
+
pycheck my_strategy.py
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## The Problem It Solves
|
|
53
|
+
|
|
54
|
+
These bugs are invisible to Python, pytest, and your IDE. They only show up in production — often after you've already lost money or shipped a flawed model.
|
|
55
|
+
|
|
56
|
+
**Lookahead bias** — the single most expensive silent bug in quantitative ML:
|
|
57
|
+
```python
|
|
58
|
+
# This looks fine. Python won't complain. Your backtest will show 94% accuracy.
|
|
59
|
+
# In production, you lose everything — because this uses data from the future.
|
|
60
|
+
df['target'] = df['close'].shift(-1) # ERROR[T001]: future data access
|
|
61
|
+
X_scaled = scaler.fit_transform(X) # ERROR[T010]: test set leaks into training
|
|
62
|
+
cv = KFold(n_splits=5, shuffle=True) # ERROR[T012]: shuffles time — leaks future
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
PyCheck catches all three before execution:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
=================================================================
|
|
69
|
+
PyCheck — NEURON ML Safety Analyzer
|
|
70
|
+
Scanning: strategy.py
|
|
71
|
+
Rules: 30 active
|
|
72
|
+
=================================================================
|
|
73
|
+
|
|
74
|
+
ERROR[T001]: .shift(-1) accesses data 1 rows INTO THE FUTURE
|
|
75
|
+
--> strategy.py:4:14
|
|
76
|
+
4 | df['target'] = df['close'].shift(-1)
|
|
77
|
+
^^^^^^^^^^^
|
|
78
|
+
help: Use .shift(1) to access past data instead
|
|
79
|
+
|
|
80
|
+
ERROR[T010]: .fit_transform() on full dataset leaks test statistics into training
|
|
81
|
+
--> strategy.py:8:11
|
|
82
|
+
8 | X_scaled = scaler.fit_transform(X)
|
|
83
|
+
^^^^^^^^^^^
|
|
84
|
+
help: Use .fit(X_train).transform(X_train), then .transform(X_test) separately
|
|
85
|
+
|
|
86
|
+
ERROR[T012]: KFold() shuffles time-series data across folds, leaking future into training
|
|
87
|
+
--> strategy.py:11:5
|
|
88
|
+
11 | cv = KFold(n_splits=5, shuffle=True)
|
|
89
|
+
^^^^^^^^^^^
|
|
90
|
+
help: Use TimeSeriesSplit() for temporal cross-validation
|
|
91
|
+
|
|
92
|
+
-----------------------------------------------------------------
|
|
93
|
+
Summary: 3 error(s), 0 warning(s)
|
|
94
|
+
These 3 error(s) would be COMPILE-TIME ERRORS in NEURON
|
|
95
|
+
Python detected: 0 of these issues at runtime
|
|
96
|
+
-----------------------------------------------------------------
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## What It Catches
|
|
102
|
+
|
|
103
|
+
### Temporal Leak Rules (17 rules — `T001`–`T017`)
|
|
104
|
+
|
|
105
|
+
| Rule | What It Catches | Severity |
|
|
106
|
+
|------|----------------|----------|
|
|
107
|
+
| `T001` | `.shift(-1)` — accessing future data | **Error** |
|
|
108
|
+
| `T002` | `train_test_split()` on time-series data | **Error** |
|
|
109
|
+
| `T003` | `.rolling()` computed before the train/test split | Warning |
|
|
110
|
+
| `T004` | `.expanding()` computed before split | Warning |
|
|
111
|
+
| `T005` | `.pct_change(-1)` — future percent returns | **Error** |
|
|
112
|
+
| `T006` | `iloc[i + 1]` inside a loop — future index access | **Error** |
|
|
113
|
+
| `T007` | `.bfill()` — backward fill uses future to fill past | **Error** |
|
|
114
|
+
| `T008` | `.interpolate(method='cubic')` — non-causal interpolation | Warning |
|
|
115
|
+
| `T009` | `.rolling(center=True)` — centered window leaks future | **Error** |
|
|
116
|
+
| `T010` | `.fit_transform()` on full dataset — test leaks into train | **Error** |
|
|
117
|
+
| `T011` | `StandardScaler` / `MinMaxScaler` fitted before split | **Error** |
|
|
118
|
+
| `T012` | `KFold` instead of `TimeSeriesSplit` | **Error** |
|
|
119
|
+
| `T013` | `.resample()` on full dataset before split | Warning |
|
|
120
|
+
| `T014` | `.diff(-5)` — future difference computation | **Error** |
|
|
121
|
+
| `T015` | Negative `.shift()` inside `groupby().transform()` | **Error** |
|
|
122
|
+
| `T016` | `pd.merge_asof()` with `direction='nearest'` or `'forward'` | **Error** |
|
|
123
|
+
| `T017` | Target laundering & un-split target encoding (`regime_success_rate`) | **Error** |
|
|
124
|
+
|
|
125
|
+
### Causal Confusion Rules (7 rules — `C001`–`C007`)
|
|
126
|
+
|
|
127
|
+
| Rule | What It Catches | Severity |
|
|
128
|
+
|------|----------------|----------|
|
|
129
|
+
| `C001` | `.corr()` used as a basis for trading or treatment decisions | Warning |
|
|
130
|
+
| `C002` | Target column included as a feature | **Error** |
|
|
131
|
+
| `C003` | Post-treatment variable included in features | Warning |
|
|
132
|
+
| `C004` | Filtering by outcome variable — survivorship bias | **Error** |
|
|
133
|
+
| `C005` | `.dropna()` removing non-random rows — selection bias | Warning |
|
|
134
|
+
| `C006` | p-value threshold without multiple comparison correction | Warning |
|
|
135
|
+
| `C007` | `.corrwith()` used for causal feature selection | Warning |
|
|
136
|
+
|
|
137
|
+
### Uncertainty Rules (6 rules — `U001`–`U006`)
|
|
138
|
+
|
|
139
|
+
| Rule | What It Catches | Severity |
|
|
140
|
+
|------|----------------|----------|
|
|
141
|
+
| `U001` | `.predict()` without confidence or probability scores | Warning |
|
|
142
|
+
| `U002` | Hardcoded decision threshold (e.g. `if pred > 0.5`) | Warning |
|
|
143
|
+
| `U003` | `.predict_proba()` without calibration check | Info |
|
|
144
|
+
| `U004` | Single model without ensemble or uncertainty estimate | Info |
|
|
145
|
+
| `U005` | `.score()` evaluated on training data only | **Error** |
|
|
146
|
+
| `U006` | `.predict()` inside a production loop without guard | **Error** |
|
|
147
|
+
|
|
148
|
+
### Data Quality Rules (2 rules)
|
|
149
|
+
|
|
150
|
+
| Rule | What It Catches | Severity |
|
|
151
|
+
|------|----------------|----------|
|
|
152
|
+
| `D002` | `except: pass` — silently swallowed pipeline errors | Warning |
|
|
153
|
+
| `D003` | Magic numbers in data operations | Info |
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Taint Flow Analysis
|
|
158
|
+
|
|
159
|
+
Beyond pattern matching, PyCheck traces how future-contaminated data **flows through your codebase**:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
future_ret = df['close'].shift(-1) # Tainted source
|
|
163
|
+
signal = future_ret - df['close'] # Taint propagates
|
|
164
|
+
model.fit(X, signal) # ERROR: tainted label reaches .fit() sink
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The taint engine follows assignments across three levels of variable indirection.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## CLI Usage
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
pycheck script.py # Errors + warnings (default)
|
|
175
|
+
pycheck script.py --info # Include info-level diagnostics
|
|
176
|
+
pycheck script.py --quiet # Errors only
|
|
177
|
+
pycheck script.py --json # JSON output — pipe into CI/CD
|
|
178
|
+
pycheck --list # List all 30 rules
|
|
179
|
+
pycheck --help
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### JSON Output (CI/CD Integration)
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
pycheck strategy.py --json | jq '.[] | select(.severity == "error")'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Returns structured output for automated pipelines:
|
|
189
|
+
```json
|
|
190
|
+
[
|
|
191
|
+
{
|
|
192
|
+
"line": 22,
|
|
193
|
+
"col": 14,
|
|
194
|
+
"severity": "error",
|
|
195
|
+
"code": "T001",
|
|
196
|
+
"message": ".shift(-5) accesses data 5 rows INTO THE FUTURE",
|
|
197
|
+
"help": "Use .shift(5) to access past data instead"
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Exit Codes
|
|
203
|
+
|
|
204
|
+
- `0` — No errors found
|
|
205
|
+
- `1` — One or more errors found
|
|
206
|
+
|
|
207
|
+
Clean integration with `make`, `pre-commit`, GitHub Actions, and GitLab CI.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Enterprise CI/CD & GitLab Integration
|
|
212
|
+
|
|
213
|
+
PyCheck natively exports into the **GitLab Code Quality** report format (`gl-codequality.json`), enabling quantitative teams, hedge funds, and enterprise banks to guard against lookahead bias directly in their Merge Requests.
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Output GitLab Code Quality JSON directly to stdout
|
|
217
|
+
pycheck . --gitlab
|
|
218
|
+
|
|
219
|
+
# Or write report artifact while printing directory summary in CI job trace
|
|
220
|
+
pycheck . --gitlab --output gl-codequality.json
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Turnkey `.gitlab-ci.yml`
|
|
224
|
+
|
|
225
|
+
Add this job to your repository to automatically block any Merge Request containing lookahead leaks:
|
|
226
|
+
|
|
227
|
+
```yaml
|
|
228
|
+
pycheck:
|
|
229
|
+
stage: test
|
|
230
|
+
image: python:3.11-slim
|
|
231
|
+
before_script:
|
|
232
|
+
- pip install pycheck-neuron
|
|
233
|
+
script:
|
|
234
|
+
- pycheck . --gitlab --output gl-codequality.json
|
|
235
|
+
artifacts:
|
|
236
|
+
reports:
|
|
237
|
+
codequality: gl-codequality.json
|
|
238
|
+
rules:
|
|
239
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
240
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
241
|
+
allow_failure: false
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
GitLab will automatically annotate the Merge Request diff with red warnings on every line where temporal data leaks or unguarded point predictions are introduced.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Real-World Examples
|
|
249
|
+
|
|
250
|
+
The `examples/` directory contains recreations of actual ML disasters:
|
|
251
|
+
|
|
252
|
+
| File | What It Demonstrates |
|
|
253
|
+
|------|---------------------|
|
|
254
|
+
| `zillow_ibuying.py` | 11 bugs replicating the structural failures behind the $881M Zillow Offers write-down |
|
|
255
|
+
| `yfinance_strategy.py` | The classic quant blog tutorial: `shift(-5)` + `fit_transform` before split |
|
|
256
|
+
| `sentdex_tutorial.py` | A widely-shared ML tutorial with silent time-series cross-validation errors |
|
|
257
|
+
| `leaky_pipeline.py` | A complete end-to-end pipeline showing taint propagation across 4 variables |
|
|
258
|
+
| `clean_pipeline.py` | The correct version — 0 errors, 0 warnings |
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## VS Code Extension
|
|
263
|
+
|
|
264
|
+
The `pycheck-vscode` extension gives you **real-time red/yellow squiggles** as you write:
|
|
265
|
+
|
|
266
|
+
- Inline error markers on every flagged line
|
|
267
|
+
- Hover tooltips with rule description and fix suggestion
|
|
268
|
+
- Status bar showing live error/warning count
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Beyond Python: the NEURON Language
|
|
273
|
+
|
|
274
|
+
PyCheck catches these bugs **after you write them**.
|
|
275
|
+
|
|
276
|
+
[NEURON](https://github.com/neuronlabs-ai/neuron-lang) prevents them **before the program compiles** — by encoding time horizons, causal modes, and uncertainty directly into the type system:
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
# In NEURON, this is a compile-time error — not a runtime surprise:
|
|
280
|
+
fn strategy(prices: Temporal[Tensor, 0]) -> Tensor:
|
|
281
|
+
let future = prices.shift(-1)
|
|
282
|
+
# error[TemporalLeak]: shift(-1) produces offset +1 > 0
|
|
283
|
+
# Lookahead bias detected at compile time.
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
For 100% compile-time temporal proofs, type-checked do-calculus, and native ahead-of-time compilation, see the [NEURON language](https://github.com/neuronlabs-ai/neuron-lang).
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
MIT — free for any use.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
*PyCheck is built on the [NEURON](https://github.com/neuronlabs-ai/neuron-lang) type theory for temporal, causal, and uncertainty safety in ML programs.*
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
pycheck/__init__.py,sha256=DnfQ_9-EPxDtGgLLwYwSbAPRHC-mVvEdAlk76kd_sEs,311
|
|
2
|
+
pycheck/__main__.py,sha256=I0O-cpkys0wMWsoczRo4DsQvj8azMc2rMkfaBkEuQT4,93
|
|
3
|
+
pycheck/analyzer.py,sha256=BKuLGgM8hGXr9A4H0V_RA-fHZ8I4h8VdR-7esGCiXVg,7318
|
|
4
|
+
pycheck/cli.py,sha256=2e6vC4Hf8hgT_l0_WVtU_jXErKZhxx6csS3_gtXkcb4,7871
|
|
5
|
+
pycheck/flow.py,sha256=KJqpFXJLGFkvilqDlk0OnAZXuO5N5N9mgLbc1t_tXow,12866
|
|
6
|
+
pycheck/rules.py,sha256=5RcOH9HRfC0LTi6x-AUtOh6D59yegT47zSABtQPHx4w,41950
|
|
7
|
+
pycheck_neuron-1.0.0.dist-info/licenses/LICENSE,sha256=bEHvMGANsTvIx-xTv8l6Ukv_9IOlaBCYeRuL0CKQPcs,1089
|
|
8
|
+
pycheck_neuron-1.0.0.dist-info/METADATA,sha256=CmgtgVcN_CZd7afbbmLPQ-XdaRYvGBtqZ1tJbeFsDv4,11854
|
|
9
|
+
pycheck_neuron-1.0.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
10
|
+
pycheck_neuron-1.0.0.dist-info/entry_points.txt,sha256=K1DMmBZoTtvHNo0CFlth0EnWQvIh1t9ZcbfT0e5YfxM,45
|
|
11
|
+
pycheck_neuron-1.0.0.dist-info/top_level.txt,sha256=0iSa2bhZWXFaKObpl3Fh5v_kib5WXyxrHwfxdlxgwC4,8
|
|
12
|
+
pycheck_neuron-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NEURON Team
|
|
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 @@
|
|
|
1
|
+
pycheck
|