Skip to main content

PyCheck — ML Safety Analyzer

32 rules. Zero dependencies. Catches the bugs that cost millions.

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.

pip install pycheck-neuron
pycheck my_strategy.py

The Problem It Solves

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.

Lookahead bias — the single most expensive silent bug in quantitative ML:

# This looks fine. Python won't complain. Your backtest will show 94% accuracy.
# In production, you lose everything — because this uses data from the future.
df['target'] = df['close'].shift(-1)   # ERROR[T001]: future data access
X_scaled = scaler.fit_transform(X)     # ERROR[T010]: test set leaks into training
cv = KFold(n_splits=5, shuffle=True)   # ERROR[T012]: shuffles time — leaks future

PyCheck catches all three before execution:

=================================================================
  PyCheck — NEURON ML Safety Analyzer
  Scanning: strategy.py
  Rules: 32 active + Data Flow & Provenance Engine
=================================================================

  ERROR[T001]: .shift(-1) accesses data 1 rows INTO THE FUTURE
  --> strategy.py:4:14
     4 |  df['target'] = df['close'].shift(-1)
                       ^^^^^^^^^^^
       help: Use .shift(1) to access past data instead

  ERROR[T010]: .fit_transform() on full dataset leaks test statistics into training
  --> strategy.py:8:11
     8 |  X_scaled = scaler.fit_transform(X)
                  ^^^^^^^^^^^
       help: Use .fit(X_train).transform(X_train), then .transform(X_test) separately

  ERROR[T012]: KFold() shuffles time-series data across folds, leaking future into training
  --> strategy.py:11:5
    11 |  cv = KFold(n_splits=5, shuffle=True)
              ^^^^^^^^^^^
       help: Use TimeSeriesSplit() for temporal cross-validation

-----------------------------------------------------------------
  Summary: 3 error(s), 0 warning(s)
  These 3 error(s) would be COMPILE-TIME ERRORS in NEURON
  Python detected: 0 of these issues at runtime
-----------------------------------------------------------------

What It Catches

Temporal Leak Rules (17 rules — T001–T017)

Rule What It Catches Severity
T001 .shift(-1) — accessing future data Error
T002 train_test_split() on time-series data Error
T003 .rolling() computed before the train/test split Warning
T004 .expanding() computed before split Warning
T005 .pct_change(-1) — future percent returns Error
T006 iloc[i + 1] inside a loop — future index access Error
T007 .bfill() — backward fill uses future to fill past Error
T008 .interpolate(method='cubic') — non-causal interpolation Warning
T009 .rolling(center=True) — centered window leaks future Error
T010 .fit_transform() on full dataset — test leaks into train Error
T011 StandardScaler / MinMaxScaler fitted before split Error
T012 KFold instead of TimeSeriesSplit Error
T013 .resample() on full dataset before split Warning
T014 .diff(-5) — future difference computation Error
T015 Negative .shift() inside groupby().transform() Error
T016 pd.merge_asof() with direction='nearest' or 'forward' Error
T017 Target laundering & un-split target encoding (regime_success_rate) Error

Causal Confusion Rules (7 rules — C001–C007)

Rule What It Catches Severity
C001 .corr() used as a basis for trading or treatment decisions Warning
C002 Target column included as a feature Error
C003 Post-treatment variable included in features Warning
C004 Filtering by outcome variable — survivorship bias Error
C005 .dropna() removing non-random rows — selection bias Warning
C006 p-value threshold without multiple comparison correction Warning
C007 .corrwith() used for causal feature selection Warning

Uncertainty Rules (6 rules — U001–U006)

Rule What It Catches Severity
U001 .predict() without confidence or probability scores Warning
U002 Hardcoded decision threshold (e.g. if pred > 0.5) Warning
U003 .predict_proba() without calibration check Info
U004 Single model without ensemble or uncertainty estimate Info
U005 .score() evaluated on training data only Error
U006 .predict() inside a production loop without guard Error

Data Quality Rules (2 rules)

Rule What It Catches Severity
D002 except: pass — silently swallowed pipeline errors Warning
D003 Magic numbers in data operations Info

Data Flow & Provenance Tracking Engine

Beyond syntactic pattern matching, PyCheck includes a two-pass AST data flow engine that traces data lineage across reassignments, aliases, joins, and helper functions:

1. Future Taint Propagation (F001)

Traces future-leaked signals across multi-level variable indirection:

future_ret = df['close'].shift(-1)        # Future taint source
signal     = future_ret - df['close']     # Taint propagates through arithmetic
model.fit(X, signal)                      # ERROR[F001]: tainted data reaches .fit() sink

2. Partition Provenance & Contamination (F002)

Identifies training partitions, test partitions, and cross-fold leakage:

# Naming conventions alone are insufficient when variables get reassigned:
X_train = pd.concat([X_train, X_test])    # Tainted with test fold data
scaler.fit_transform(X_train)             # ERROR[F002]: test partition data in training sink

PyCheck follows:

  • Concatenation & Merges: pd.concat, np.concatenate, .append(), .merge(), .join().
  • Aliases: X_eval = X_test followed by combination or fitting.
  • Inter-Procedural Helper Functions: Functions returning expressions derived from test partition arguments.

CLI Usage

pycheck script.py              # Errors + warnings (default)
pycheck script.py --info       # Include info-level diagnostics
pycheck script.py --quiet      # Errors only
pycheck script.py --json       # JSON output — pipe into CI/CD
pycheck --list                 # List all 32 rules
pycheck --help

JSON Output (CI/CD Integration)

pycheck strategy.py --json | jq '.[] | select(.severity == "error")'

Returns structured output for automated pipelines:

[
  {
    "line": 22,
    "col": 14,
    "severity": "error",
    "code": "T001",
    "message": ".shift(-5) accesses data 5 rows INTO THE FUTURE",
    "help": "Use .shift(5) to access past data instead"
  }
]

Exit Codes

  • 0 — No errors found
  • 1 — One or more errors found

Clean integration with make, pre-commit, GitHub Actions, and GitLab CI.


Enterprise CI/CD & GitLab Integration

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.

# Output GitLab Code Quality JSON directly to stdout
pycheck . --gitlab

# Or write report artifact while printing directory summary in CI job trace
pycheck . --gitlab --output gl-codequality.json

Turnkey .gitlab-ci.yml

Add this job to your repository to automatically block any Merge Request containing lookahead leaks:

pycheck:
  stage: test
  image: python:3.11-slim
  before_script:
    - pip install pycheck-neuron
  script:
    - pycheck . --gitlab --output gl-codequality.json
  artifacts:
    reports:
      codequality: gl-codequality.json
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  allow_failure: false

GitLab will automatically annotate the Merge Request diff with red warnings on every line where temporal data leaks or unguarded point predictions are introduced.


Real-World Examples

The examples/ directory contains recreations of actual ML disasters:

File What It Demonstrates
zillow_ibuying.py 11 bugs replicating the structural failures behind the $881M Zillow Offers write-down
yfinance_strategy.py The classic quant blog tutorial: shift(-5) + fit_transform before split
sentdex_tutorial.py A widely-shared ML tutorial with silent time-series cross-validation errors
leaky_pipeline.py A complete end-to-end pipeline showing taint propagation across 4 variables
clean_pipeline.py The correct version — 0 errors, 0 warnings

VS Code Extension

The pycheck-vscode extension gives you real-time red/yellow squiggles as you write:

  • Inline error markers on every flagged line
  • Hover tooltips with rule description and fix suggestion
  • Status bar showing live error/warning count


PyCheck Cloud & Enterprise SaaS

For institutional hedge funds, algorithmic trading desks, and enterprise ML engineering teams, PyCheck Cloud provides continuous compliance and automated gatekeeping:

  • Automated PR / MR Gatekeeping: GitHub App & GitLab integration that automatically blocks pull requests containing temporal leaks, lookahead joins, or cross-fold contamination before they reach production.
  • Proof-of-Causality Audit Certificates: Cryptographically verifiable backtest audit reports (PDF & JSON) certifying that quantitative strategies and feature pipelines are provably free of temporal lookahead bias for LP allocators and risk committees.
  • Firm-Wide Policy Engine: Author proprietary firm-specific invariants, restrict internal data feed schemas, and monitor leak incident trends across 50+ quant researchers.
  • Air-Gapped & On-Prem Deployment: Private VPC and on-premise Kubernetes support for proprietary trading strategies that cannot leave your internal network.

See the Enterprise CI/CD Integration section or visit https://github.com/neuronlabs-ai/pycheck to learn more or request institutional access.


PyCheck & NEURON: Working Hand-in-Hand

PyCheck and the NEURON Programming Language represent a dual-defense ecosystem against algorithmic failures:

System Role Mechanism Guarantee
PyCheck The Diagnostic Layer for existing Python code 2-pass AST data flow & provenance static analysis Flags known leakage patterns & contamination in seconds
NEURON The Permanent Cure for future algorithmic systems Type-theoretic stochastic filtration proofs ($\mathcal{F}_t$) 100% mathematical compile-time proof; zero runtime overhead

The Migration Pathway

  1. Audit Today with PyCheck: Run pycheck across existing Python/Pandas/PyTorch repositories to identify lookahead leaks and target laundering.
  2. Transpile with py2nr: Use the automated transpiler to convert validated feature pipelines into typed NEURON modules.
  3. Deploy with 100% Compile-Time Safety:
# In NEURON, lookahead bias is a compile-time type error — not a runtime surprise:
fn strategy(prices: Temporal[Tensor, 0]) -> Tensor:
  let future = prices.shift(1)  # NEURON uses causal algebraic offsets (+1 is future)
  # error[TemporalLeak]: operation requires filtration F_{t+1}, but context is F_t (offset 0)
  # Lookahead bias rejected at compile time before execution.

Explore the language: https://github.com/neuronlabs-ai/neuron-lang


License

MIT — free for any use.


PyCheck is built on the NEURON type theory for temporal, causal, and uncertainty safety in ML programs.

Metadata

Release files for pycheck-neuron 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pycheck-neuron 1.0.2
File Size Uploaded
pycheck_neuron-1.0.2.tar.gz 42.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pycheck-neuron 1.0.2
File Interpreter ABI Platform
pycheck_neuron-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 75.8 kB

Release files / pycheck_neuron-1.0.2.tar.gz

Download URL pycheck_neuron-1.0.2.tar.gz
Size 42.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8f5ceb1675db1c78db0e9400694d3af3e2384a7376b8bf2fc66fca2c23b81eae
BLAKE2b-256 checksum
How to use checksums
7c1d77b4552711d94903ffda6c35966cd6bb66641b7665b8e98879e45c48d251
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / pycheck_neuron-1.0.2-py3-none-any.whl

Download URL pycheck_neuron-1.0.2-py3-none-any.whl
Size 33.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a9e79e685900ef9f98848c65c7ef54c2995a21f0ac4f008c3fe4e4a85c88425a
BLAKE2b-256 checksum
How to use checksums
8ddaf399e78187c3708a1efaa0657e3edfafbbe2431e88c1e94e1962545abe02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page