SigReview
Deterministic code review for data science, ML and GenAI projects. One install, one command, one report.
pip install sigreview
sigreview scan -f ./my_project # a local folder
sigreview scan -r https://github.com/org/repo # a Git repo link (GitHub, GitLab, Azure DevOps, Bitbucket)
SigReview reads every .py, .ipynb and Databricks notebook in the project, runs its own 90
data science rules plus six proven tools, and writes four files into a scan_result folder:
sigreview_report.html: the report for peoplesigreview_findings.json: the same findings for machines (CI, the review agent)sigreview_findings.sarif: for inline findings on GitHub and Azure DevOps pull requestssigreview_summary.md: a short summary to post as a PR comment
Nothing in your project is executed. SigReview only reads code.
Test files (test_*.py, *_test.py, conftest.py, test/ and tests/ folders) are not checked by the data
science rules or the type checker: tests break rules on purpose.
Commands
| Command | What it does |
|---|---|
sigreview scan -f "folder" |
Scan a local folder. Reports go to folder/scan_result/ |
sigreview scan -r "repo link" |
Clone a repo, scan it, delete the copy. Reports go to ./scan_result/ |
sigreview baseline -f "folder" |
Record today's findings as known, so later scans show only new ones |
sigreview doctor |
Check that every wrapped tool and Git are installed, with versions |
sigreview rules [ID] |
List every rule, or show one in full: sigreview rules DS001 |
sigreview --version |
Show the version |
Options for scan:
| Option | What it does |
|---|---|
-b, --branch NAME |
With -r: the branch to scan. Default: the repo's default branch |
-d, --diff BRANCH |
Only show findings in files changed since that branch, e.g. --diff main |
--fail-on LEVEL |
high (default), medium, low or none: the lowest severity that fails the scan |
--baseline FILE |
Baseline file to use. Default: .sigreview-baseline.json in the project, if present |
-o, --output FOLDER |
Write the reports somewhere other than scan_result/ |
scan exits with 1 when a finding reaches the --fail-on level, so it can gate CI, and 2 on usage errors.
| Severity | Meaning |
|---|---|
| High | Proven problem. Fix before merging. |
| Medium | Likely bug or risky pattern. Someone should look. |
| Low | Cleanup and readability. |
Scanning a repo link
-r works with GitHub, Azure DevOps, Bitbucket and GitLab (and any other Git host), with
https://... or git@... links:
sigreview scan -r https://github.com/org/churn-model
sigreview scan -r git@github.com:org/churn-model.git --branch feature/new-features
sigreview scan -r https://dev.azure.com/org/project/_git/routing
sigreview scan -r https://bitbucket.org/team/forecast
Login. Public repos need nothing. For private repos:
- Your own Git login is used by default: whatever already works for
git cloneon your machine (saved HTTPS login, Git Credential Manager, or your SSH key forgit@links). - A token, for CI or a machine without a saved login: set
SIGREVIEW_GIT_TOKEN. It is used instead of your own login when set. SIGREVIEW_GIT_USERonly if your host needs a specific username with the token. The defaults work for GitHub, Azure DevOps, Bitbucket and GitLab tokens.
| Host | Token to create | Access it needs |
|---|---|---|
| GitHub | Fine-grained personal access token | Contents: Read-only, on the repos to scan |
| Azure DevOps | Personal access token (PAT) | Code: Read |
| Bitbucket | Repository access token, or API token | Repositories: Read |
| GitLab | Personal or project access token | read_repository |
export SIGREVIEW_GIT_TOKEN=... # Windows PowerShell: $env:SIGREVIEW_GIT_TOKEN="..."
sigreview scan -r https://dev.azure.com/org/project/_git/routing
Inside a CI pipeline the platform's own token is picked up automatically: GITHUB_TOKEN,
SYSTEM_ACCESSTOKEN (Azure Pipelines), BITBUCKET_TOKEN or CI_JOB_TOKEN (GitLab).
The token is never accepted on the command line (it would end up in your shell history), is passed to Git without being written to disk, and is masked in every message.
Reviewing pull requests
sigreview scan -f . --diff main # only files changed since main
sigreview scan -f . --diff origin/main --fail-on medium
Old projects. Run sigreview baseline -f . once and commit .sigreview-baseline.json.
Every later scan hides those known findings and shows only new ones. Run it again whenever
you want to accept the current state.
What it checks
Data science rules (SigReview's own, run sigreview rules for the full list)
| Area | Rules |
|---|---|
| Machine learning | DS001-DS015: leakage before the split (sklearn and pandas), fitting on test data, target left in features, target-based features, resampling before the split, early stopping on the test set, the same entity in train and test, separate encoding of train and test, unscaled features for KNN/SVM, missing seeds, PyTorch zero_grad / eval() / unsafe torch.load |
| Evaluation | EV001-EV004: probability metrics on hard labels, swapped metric arguments, model chosen on the test set, scoring on training data only |
| Time series | TS001-TS007: shuffled splits, windows that include the current target, centred windows, backward fill, future values as features, no gap for multi-step forecasts, scoring on the tail of the fitted series |
| Deep learning | DL001-DL007: softmax before a logits loss, loss tensors accumulated, wrong step order, softmax without dim, unshuffled training loader, model.forward(), fine-tuning evaluated on its training data |
| DataFrames | DF001-DF014: chained assignment, results thrown away, iterrows() writes, pandas 2.0 removals, merge without validate=, concat in a loop, inplace=True assigned, index misalignment, .loc[i] after filtering, pandas 3 string and datetime changes, ignored conversion errors, ambiguous dates, NaN turned into "nan" |
| Spark | SP001-SP008: collect() / toPandas() without limit(), withColumn in a loop, == None, UDFs without a return type, static partition overwrite, actions in a loop, monotonically_increasing_id as row number, single-partition writes |
| Notebooks | NB001-NB008: names used before the cell that defines them, out-of-order runs, !pip install, saved errors, large outputs, data tables and secrets saved in outputs, %run |
| GenAI and LLM apps | LLM001-LLM019: model output run as code, SQL or HTML, agents with shell or code tools, remote code from model hubs, unsafe pickles, user text in the system prompt, whole DataFrames in prompts, unguarded JSON parsing, no output limit, no timeout or unbounded retries, one call per row, unpinned model versions, mixed embedding models, unbounded chat history, removed SDK APIs, prompts in logs, right padding for generation, chunks longer than the embedding model |
| Project | PR001-PR008: no dependency file, unpinned versions, no tests, large data files or secret files committed, hardcoded absolute paths, training window tied to today's date, models saved without library versions |
Wrapped tools (installed with SigReview)
| Tool | Checks |
|---|---|
| Ruff | Likely bugs, risky security patterns, unused imports and variables, functions with a complexity above 30 |
| Pyrefly | Type errors: wrong arguments, missing attributes |
| Vulture | Functions and classes nothing calls, unreachable code |
| deptry | Imports missing from the dependency file, unused dependencies |
| pip-audit | Known vulnerabilities in pinned packages (needs internet) |
| detect-secrets | API keys, tokens and passwords in files |
Style nits do not get one finding per line. Each kind is reported once for the whole project,
with a count and the files most affected: formatting, docstrings and legacy-random.
Databricks. Notebooks exported to Git as .py files (they start with
# Databricks notebook source) are read as notebooks: the notebook rules run, and every
finding shows its cell number.
Silencing a finding
On the line itself:
df = pd.read_csv("/Users/anna/data.csv") # sigreview: ignore[PR006]
For the whole project, in pyproject.toml:
[tool.sigreview]
ignore = ["PR003", "docstrings"] # rule IDs to switch off
exclude = ["legacy/", "*_old.py"] # paths to skip
Use in CI
Ready-made setups are in the ci/ folder: copy the one for your platform.
GitLab (ci/gitlab-ci.yml): scans the files changed in each merge request
and keeps the reports as job artifacts.
Azure Pipelines (ci/azure-pipelines.yml), GitHub Actions
(ci/github-actions.yml) and Bitbucket
(ci/bitbucket-pipelines.yml) work the same way.
Any CI, in two lines:
pip install sigreview
sigreview scan -f . --diff origin/main --fail-on high
pre-commit, with sigreview installed in your environment:
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: sigreview
name: sigreview
entry: sigreview scan -f . --diff main
language: system
pass_filenames: false
always_run: true
stages: [pre-push]
Add scan_result/ to .gitignore in projects you scan.
Colour and symbols switch off automatically in CI logs, pipes and when NO_COLOR is set.
Development
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest
sigreview scan -f tests/fixtures/sample_project
Try it on the sample project, then open tests/fixtures/sample_project/scan_result/sigreview_report.html
in a browser. The sample has one or more examples of most rules.
Colours live in src/sigreview/theme.py: SIGMOID_RED for the terminal, REPORT_COLOURS for the report.
The report embeds the Red Hat Text and Red Hat Mono fonts (SIL Open Font License, see
src/sigreview/report/templates/fonts/OFL.txt), so it looks the same offline and on every machine.
Adding a rule: write a function with the @rule(...) decorator in the right file under
src/sigreview/rules/, then add tests/fixtures/rules/<ID>_bad.py and <ID>_good.py.
The tests check that every rule fires on its bad file and stays silent on its good one.
Author: Subhabrat Biswal
Metadata
Release files for sigreview 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sigreview-1.0.1.tar.gz | 172.4 kB | Without provenance | Details for sigreview-1.0.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| sigreview-1.0.1-py3-none-any.whl | Python 3 | none | any | Details for sigreview-1.0.1-py3-none-any.whl |
Total release size: 345.0 kB
Release files / sigreview-1.0.1.tar.gz
| Download URL | sigreview-1.0.1.tar.gz |
|---|---|
| Size | 172.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4bd2e62600a2793144c800fc4414d4e931f3beab17f730e7d511186563d4ffd4
|
|
BLAKE2b-256 checksum How to use checksums |
08e13d4c1c0123b405cea1703c07cbfc10d96008165b40569ecc6a436f72dd23
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.2
|
Release files / sigreview-1.0.1-py3-none-any.whl
| Download URL | sigreview-1.0.1-py3-none-any.whl |
|---|---|
| Size | 172.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b9a33ac546ed87f64bff53e33e518759b9900a1563f6cb4232f04548ae44204e
|
|
BLAKE2b-256 checksum How to use checksums |
63ebd2c5214e269921b3030277aa07d52e1880bef7bcba877cdfae064d3fd167
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.2
|
Security for sigreview 1.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.