Skip to main content

PyFixer

The auto-fix button for Python.

Upload a broken file. Get a fixed file. That's it.

Upload → Scan → Fix → Verify → Contracts → Done

What It Does

PyFixer finds and fixes Python problems automatically.

Problem Fix
Security holes Replaces eval, exec, hardcoded passwords, weak crypto
Unused imports Removes them
Wrong types Adds type annotations
Bad style Formats code, fixes line length
Missing docs Adds docstrings
Old Python Modernizes to current syntax
Bare excepts Changes to specific exceptions
Print statements Converts to logging
Mutable defaults Fixes def foo(x=[])
Builtin shadowing Fixes list = x
Type comparison Fixes type(x)==type(y)
Performance Fixes O(n²) loops, string concat
Weak random Replaces random with secrets
Weak hash Replaces MD5 with SHA256
Logic bugs Behavioral tests catch wrong operators, crash-on-empty, stubs

17+ types of issues. One click to fix.


How It Works (v0.3)

1. Upload .py file
   ↓
2. Scan with ruff + bandit + mypy + custom/semantic checks
   ↓
3. Generate a behavioral test for EVERY function (coverage guarantee)
   ↓
4. AI proposes a fix (13 specialist workers)
      - clean functions are never sent to the LLM
   ↓
5. Post-processing layer applies guaranteed fixes
      - hardcoded secrets are scrubbed from the output
   ↓
6. CONTRACT GATE: probe original vs fixed behavior
      - untouched functions must return identical results
      - perf/logging-only fixes must be value-identical
      - violations -> corrective retry -> verbatim splice
   ↓
7. Verify: syntax check + ruff + mypy + findings count
   ↓
8. You approve or reject
   ↓
9. Done. File is fixed.

Features

13 Specialist Workers

Each worker is an expert in one thing:

Worker What It Fixes
Syntax Surgeon Syntax errors, indentation
Security Guard SQL injection, hardcoded passwords, weak crypto
Type Tamer Missing type annotations, wrong types
Style Formatter Line length, imports, formatting
Code Cleaner Dead code, unused variables
Docstring Writer Missing docstrings, D101-D107
Annotation Expert Missing annotations, ANN001-ANN204
Modernizer Old Python syntax, PTH/SIM/RET
Performance Optimizer O(n²) loops, string concatenation
Logger print() → logging conversion
Error Handler Bare excepts, broad exceptions
Generalist Complex issues, multiple codes
MyPy Fixer Type ignore comments, mypy-specific

BYOK (Bring Your Own Key)

You bring your own API key. We never store it.

Provider Key prefix Model
Google Gemini AQ. gemini-3.7-flash
DeepSeek sk- (probed) deepseek-chat
OpenRouter sk-or- deepseek/deepseek-v4-flash
OpenAI sk- gpt-4o-mini

Server-side key pool (optional)

Tired of pasting a key into the UI? Configure keys on the server and every client can fix without one:

# Option A: environment variable (comma or newline separated)
export PYFIXER_KEYS="AQ.Ab8RN6...,AQ.Ab8RN7..."

# Option B: key file, one key per line
$EDITOR data/gemini.keys   # gitignored — never commit this file

Keys rotate automatically (N keys = N × 15 requests/min). The pool is only used when a request carries no X-Api-Key header / body key; client keys always take priority and are never stored, logged, or written to disk. GET /api/server-keys reports { "available": true } without exposing them.

LLM control

Every model call goes through a task profile (temperature / token budget / JSON-mode) so behaviour is tunable in one place — PROFILES in pyfixer/byok.py:

Profile Used for Temperature Max tokens
fix code fixes 0.0 4096
fix_escalate contract-violation retries 0.0 4096
testgen behavioral test generation 0.0 3072
classify finding classification 0.0 512 + JSON mode
probe cheap probes 0.0 256

Model resolution order: per-call override → PYFIXER_MODEL env var → provider default. The classifier requests provider-side JSON mode (Gemini response_mime_type, OpenAI-compatible response_format).

Verify & Rollback

  • Verify: Proves the fix works (syntax + ruff + mypy + findings)
  • Rollback: Undo if you don't like it

Pattern Learning

PyFixer remembers what works. The more you use it, the better it gets.


Quickstart

# Clone
git clone <your-repo>
cd pyfixer

# Setup
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

# Run
.venv/bin/uvicorn pyfixer.main:app --host 127.0.0.1 --port 8501

Open http://127.0.0.1:8501

Note: python-multipart is required (pulled in by requirements.txt) so the upload endpoints that use Form(...) work. ruff and bandit must be installed and on PATH (the scanner shells out to python -m ruff / python -m bandit). mypy is optional — only used when you enable the mypy scanner.


CLI

Fix files straight from the terminal — same pipeline, same gates, no server:

# module form (works from a checkout)
python -m pyfixer fix app.py

# after `pip install -e .` you also get the console script
pyfixer scan app.py            # findings only, no AI call   (exit 1 if any)
pyfixer fix app.py             # writes app.fixed.py next to it
pyfixer fix app.py --apply     # overwrite in place
pyfixer fix app.py --diff      # print the patch, write nothing
pyfixer fix src/               # every .py under a folder (summary at end)
pyfixer fix app.py --format json       # machine-readable output
pyfixer fix app.py --worker security   # force a specialist
pyfixer fix app.py --llm              # + LLM fixes (needs API key)
pyfixer fix app.py --llm --fast       # fewer model calls, same gates
pyfixer fix app.py --aggressive       # + mechanical ruff upgrades (no key)
pyfixer fix app.py --check            # preview only, write nothing
pyfixer workers                # list all specialists

# key: --key beats $PYFIXER_KEYS beats data/gemini.keys (rotating pool)

# LLM-gated flags: --comprehensive and --reference work ONLY with --llm;
# --verify needs --llm (pytest gate) or --llm-targeted (mypy gate).
# Without them the CLI exits 2 instead of silently ignoring the flag.

Deterministic Fixes (no API key needed)

Deterministic mode (the default — no API key needed) applies 50+ pattern-based fixes instantly:

Code Fix
C408 dict(name="test"){'name': 'test'}
C416 [x for x in y]list(y)
E711 x == Nonex is None
E712 x == Truex
E722 except:except Exception:
F401 Remove unused imports
F841 Remove unused variables
LOGIC005/009 Fix inverted comparison signs
LOGIC010 Fix insertion sort off-by-one
LOGIC014 def f(x=[])def f(x=None)
LOGIC015 type(x) == intisinstance(x, int)
LOGIC016 for i in range(n)for _ in range(n)
PLR1714 x==1 or x==2x in (1, 2)
RET505 Remove unnecessary else after return
SIM102 if x: if y:if x and y:
SIM105 try: passcontextlib.suppress()
SIM115 open()with open()
SIM116 if k in d: return d[k]d.get(k)
SIM118 x in d.keys()x in d
SIM210 True if x else Falsebool(x)
SIM212 if x: return True else: return Falsereturn x
UP030 "{}".format(x)f"{x}"

Example:

# Quick fix without API key (deterministic is the default)
pyfixer fix buggy.py

# See what would change
pyfixer fix buggy.py --diff

# Apply in place
pyfixer fix buggy.py --apply

Exit codes: 0 OK · 1 findings survived the fix · 2 usage/no key.


API

Method Endpoint Description
GET /healthz Health check
POST /api/uploads Upload + auto-scan
GET /api/uploads List all files
GET /api/uploads/{id} Get file details
POST /api/uploads/{id}/fix Propose AI fix
POST /api/uploads/{id}/verify Verify fix works
POST /api/uploads/{id}/rollback Undo fix
GET /api/fixes/{id}/approve Approve fix
GET /api/fixes/{id}/reject Reject fix
GET /api/uploads/{id}/report Download report
GET /api/workers List all workers
GET /api/audit Audit trail

Scanner

PyFixer uses multiple scanners:

  • ruff — Fast Python linter (16 rule sets)
  • bandit — Security scanner
  • mypy — Type checker
  • AST detector — 16 LOGIC codes + 10 STYLE codes + 5+ ALGO/PERF codes
  • Custom checks — 8 additional checks:
    • ERR001: Missing error handling
    • ERR002: Broad exception catching
    • LOG001: print() instead of logging
    • PERF001: Inefficient string concatenation
    • MUT001: Mutable default arguments
    • SHADOW001: Builtin name shadowing
    • TYPE001: type() comparison instead of isinstance()

Total: 50+ types of issues detected.


Testing

PYTHONPATH=. .venv/bin/pytest tests/ -v

862 tests passing (incl. 9 opt-in corpus parity suites).

Regression benchmarks (LLM-in-the-loop)

benchmarks/ contains bug files with human-verified correct.py references and check.py auto-checkers. The harness runs each through the REAL fix pipeline and scores it — including clean canary functions that must keep identical behavior (contract-regression guard).

# all cases (uses server key pool or PYFIXER_BENCH_KEY)
.venv/bin/python benchmarks/run_bench.py

# one case
.venv/bin/python benchmarks/run_bench.py --only logic_signs

Cases: algorithms, strings, mixed, security_basics, crash_edges, logic_signs, perf_logging. A manual GitHub Actions workflow (.github/workflows/regression.yml) runs them on demand with a PYFIXER_KEYS secret.

Corpus regression (downstream suite parity)

tests/test_corpus_regression.py runs nine real projects' test suites against both the pristine checkout and the deterministic rewrite, asserting identical pass/fail signatures — the harness that caught the RET505 click corruption, the ERR003 logging-import breakage, and the F401 # noqa side-effect import deletion. Opt-in via PYFIXER_CORPUS_DIR:

bash scripts/provision_corpus.sh /path/to/pyfixer-corpus   # checkouts + venvs
PYFIXER_CORPUS_DIR=/path/to/pyfixer-corpus PYTHONPATH=. pytest tests/test_corpus_regression.py -m corpus -q

Repos: click, httpie, requests, rich, flask, fastapi, attrs (2022-era), httpx 1.0b0 (2025-era), pandas 2.2.3. Pandas is special: its compiled _libs can't be PYTHONPATH-shadowed, so it runs as a dedicated two-venv parity test (venv-pandas vs venv-pandas-fixed, both on numpy==1.26.4). A manual + weekly workflow (.github/workflows/corpus.yml) runs the same in CI.

tests/test_semantic_rules.py locks the semantic tier (SEM003/SEM004/SEM006) with a detector mutation oracle plus differential-execution coverage of the SEM004 fixer; tests/test_mock_llm_contract.py locks the SEM003 detector -> per-function-LLM wiring with a stubbed model (no network).

Code quality

# Lint + auto-format
.venv/bin/ruff check pyfixer
.venv/bin/ruff format pyfixer

# Static type checking
.venv/bin/mypy pyfixer

A GitHub Actions workflow (.github/workflows/ci.yml) runs ruff check, ruff format --check, mypy, and the full pytest suite on every push and pull request, so regressions are caught before merge.


Tech Stack

  • Backend: FastAPI + SQLite + Python
  • Scanner: ruff + bandit + mypy + custom AST checks
  • AI: OpenAI, OpenRouter, Google, DeepSeek (BYOK)
  • Testing: pytest + coverage

Tier Semantics

PyFixer promotes fixes through four tier levels. The goal is honest tier assignment — a function's tier reflects the evidence that validates its rewrite.

Tier When it's assigned Promotion path
UNVERIFIED Default for any fixed function that has no oracle (no func_test). LOGIC‑only fixes (ast‑detector findings) always land here, regardless of verify_mode. After the real project suite passes (--verify in cli.py), tiers are promoted by _promote_tiers_to_verified in cli.py:1168/1276.
AI_VERIFIED A generated func_test exists and the rewrite passes _valid_fix. The rewrite was validated against the AI‑generated test. Same real‑suite promotion; this is the interim tier after propose.
VERIFIED Earned only after the real project suite (--verify) runs successfully via _promote_tiers_to_verified. No automatic path mint VERIFIED at propose time. Manual / CI gate after suite runs.
RETRIEVED Deterministic fixes that match an existing reference (e.g. RETRIEVED from known‑good repo). Stays RETRIEVED; no further promotion.

Honesty invariant: verify_mode=True does not mint VERIFIED. It only means the user passed --verify; a real suite still needs to run afterwards. Promotion to VERIFIED belongs to the real‑suite gate in cli.py, never propose().


License

Copyright (c) 2026 Aziz. All rights reserved.


Author

Aziz — Built PyFixer to fix Python code automatically.

Release files for pyfixer-ai 0.4.0

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

Source distribution (sdist)

Source distribution for pyfixer-ai 0.4.0
File Size Uploaded
pyfixer_ai-0.4.0.tar.gz 487.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyfixer-ai 0.4.0
File Interpreter ABI Platform
pyfixer_ai-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 861.8 kB

Release files / pyfixer_ai-0.4.0.tar.gz

Download URL pyfixer_ai-0.4.0.tar.gz
Size 487.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e93923a96166ec073f46b96c0a0f32a62b1a3e411f91923c113ca5a24117ae81
BLAKE2b-256 checksum
How to use checksums
0406b8698795917e3d39f9082cad8803064d2bc12ab936cee846d7fca259251f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release files / pyfixer_ai-0.4.0-py3-none-any.whl

Download URL pyfixer_ai-0.4.0-py3-none-any.whl
Size 374.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8051e5de59085e31d6259d4fa6e5014d2e3226b5d3690f8e5e1d24323c3e180f
BLAKE2b-256 checksum
How to use checksums
64c333bd5c5f8a69c7c726adc2c566cfd9b2172ac3239c824abb14d22677bcc8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

This release

0.4.0 This release

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