Pylon
Pylon is a static analysis CLI for Python that flags real issues in your code and, on request, explains them and suggests fixes using an LLM.
Pylon mostly utilises Python's included ast module to traverse source code.
Built in collaboration with Soham200613 and GraydenDonaldson
Implemented rules
-
Unused imports: imports that are never referenced. Correctly handles Python's re-export idioms (
from .app import Flask as Flask,__all__ = [...]) so it doesn't flag deliberate public re-exports as dead code. -
Mutable default arguments:
def f(x=[])shares the same object across every call, a classic source of hard-to-trace bugs. Catches both literal syntax ([],{}) and constructor calls (list(),dict(),set()). -
Bare
except:clauses: catching all exceptions, includingKeyboardInterruptandSystemExit, silently swallows bugs. Recognizes and skips the deliberate catch-and-reraise pattern (except: ... raise), rather than flagging every bare except indiscriminately. -
Wildcard imports:
from module import *pollutes the namespace and makes it impossible to tell where a name came from. -
Comparing with
==instead ofisforNone/True/False— non-idiomatic and can misbehave with custom__eq__. Checkast.Comparenodes where one side is anast.Constantwith valueNone/True/Falseand the operator isEq/NotEq. -
Shadowed funcions/methods/class definitions: functions later shadowed without an @overload stub and other exceptions are silently shadowed by python
-
Shadowed builtins: parameters and variable bindings named
list,dict,id,type, etc. hide Python's builtins. Attribute names and ordinary builtin references are not flagged.
Rules yet to be implemented
- Excessive function arguments: functions with too many parameters are hard to maintain and often signal the function is doing too much.
- Unused function arguments: parameters never referenced in the function body, often signaling incomplete refactoring. Same "walk and collect
ast.Nameusages" pattern as unused imports, applied per-function. - Global variable mutation inside functions: using
globalto mutate outer-scope state is a common source of hard-to-trace bugs. Check forast.Globalnodes within functions. - Deeply nested code (high cyclomatic complexity): functions with many nested
if/for/while/tryblocks are hard to read and test. Requires tracking nesting depth/branch count while walking, rather than matching a single node type. - Redefining function in same scope: functions that are later redefined in the same scope silently shadow, hinting to dead code
- Format-string arg count mismatch:
%operator andloggingcalls with a mismatch in the number of format requests and args supplied
LLM layer
Passing --explain sends each finding, along with its surrounding source code, to an LLM for a short, specific judgment on whether it's a genuine issue or a likely false positive. This is deliberately kept separate from the deterministic rule engine: rules encode patterns worth hard-coding that have few special deliberate cases, while the LLM layer handles judgment calls that don't generalize cleanly into a fixed rule. For example, correctly identifying that an unused from __future__ import annotations import is not actually dead code, despite never appearing as a referenced name in its respective file.
Supports multiple providers behind a shared interface — local models via ollama for fast, free iteration, or Anthropic/OpenAI for production-quality explanations:
pylon path/to/file.py --explain --provider ollama # default
pylon path/to/file.py --explain --provider anthropic
pylon path/to/file.py --explain --provider openai
pylon path/to/file.py --explain # will use default ollama qwen2.5:7b-coder
Note that users of OpenAI/Anthropic models should configure their API keys by following the Configuration section above.
Installation, as PyPI package
Plain installation without external provider support ie. Ollama only
pip install pylon-analyzer
To install specific or all providers,
# Just Anthropic
pip install "pylon-analyzer[anthropic]"
# Just OpenAI
pip install "pylon-analyzer[openai]"
# Just Google
pip install "pylon-analyzer[google]"
# Full provider support
pip install "pylon-analyzer[llm-all]"
Installation, from source
git clone https://github.com/Anonymoose725/pylon.git
cd pylon
python3 -m venv .venv
source .venv/bin/activate # for linux/mac, or .venv\Scripts\activate on Windows
pip install -r requirements.txt
Minimal install (Ollama only, no API keys required)
pip install -e ".[ollama]"
Full install with all LLM providers
pip install -e ".[llm-all]"
Or install specific providers
# Just OpenAI
pip install -e ".[openai]"
# Just Anthropic
pip install -e ".[anthropic]"
Configuration: Set Up Environment Variables
After installation, you'll need to configure environment variables for LLM API access:
-
Copy the example file: Rename
.env.exampleto.env.localfirst to review the template, then rename it to.env:cp .env.example .env.local # Review what needs to be set mv .env.local .env # Now you can edit it safely
-
Edit
.env: Add your API keys to the.envfile:nano .env # or use your preferred editor
-
Load environment variables (if your shell doesn't auto-source):
source .env # Linux/mac, or .venv\Scripts\activate.ps1 for Windows
Detailed setup, for contributors
Clone the repo:
git clone https://github.com/Anonymoose725/pylon.git
cd pylon
Create and activate a virtual environment:
python3 -m venv .venv
source .venv/bin/activate
Install dependencies from requirements.txt:
pip install -r requirements.txt
Run the test suite to confirm everything works:
pytest testing/ -v
Optional: Configure LLM API keys by following the Configuration section. The tests will run with Ollama by default (no API keys needed) unless you've installed other providers and set up .env.
Milestones & metrics
Validated against 5 actively maintained production codebases to confirm the tool works at real scale and to catch genuine false-positive patterns before they'd be found by an actual user.
| Repo | Files | Lines | Findings |
|---|---|---|---|
| Flask | 24 | 9,513 | 32 |
| Requests | 19 | 6,394 | 56 |
| Click | 17 | 12,821 | 19 |
| Django | 907 | 165,529 | 198 |
| NumPy | 428 | 260,868 | 764 |
| Total | 1,395 | 455,125 | 1,069 |
- Reduced false-positive unused-import findings by 34% (1,479 → 976) by diagnosing and fixing two Python re-export idioms (
from x import Y as Yand__all__re-exports) that the AST-based detector initially misread as dead code - Correctly identified a genuine bare-except anti-pattern in Flask's core WSGI dispatch logic (
app.py), then refined the rule to distinguish safe catch-and-reraise handlers from true error suppression via AST-level exception analysis - Processes ~365 files/sec (Django) and remains performant on dense, large codebases (~83 files/sec on NumPy's 260K-line source tree due to larger file sizes)
- Every rule is covered by positive and negative test cases (
pytest) — proving each rule catches real issues without false-flagging safe, idiomatic code - Uploaded to PyPI, where now users can 'pip install pylon-analyzer' on any system!
Roadmap
- Implement the roadmap rules listed above!
- Implement a --fat flag that assumes a user is testing on a large number of files/repos, compacting the large list of findings into a more digestible (and collapsible?) format, potentially outside the CLI
- Add a false-positive flagging mechanism to the CLI, so users can mark findings as false positives, with and without having seen an
--explainexplanation first. This is the basis for measuring whether the LLM layer's context genuinely reduces false-positive flags in practice
Metadata
Release files for pylon-analyzer 0.1.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 |
|---|---|---|---|---|
| pylon_analyzer-0.1.1.tar.gz | 18.3 kB | Without provenance | Details for pylon_analyzer-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pylon_analyzer-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for pylon_analyzer-0.1.1-py3-none-any.whl |
Total release size: 38.2 kB
Release files / pylon_analyzer-0.1.1.tar.gz
| Download URL | pylon_analyzer-0.1.1.tar.gz |
|---|---|
| Size | 18.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3321527663f5b867d0391292b630c17c35405647797c91ba1e6aed5491646fbe
|
|
BLAKE2b-256 checksum How to use checksums |
35084ca165e0b23c2de45cbe22d03cf5423856aa9179b64b353b3b93a865c4b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.2
|
Release files / pylon_analyzer-0.1.1-py3-none-any.whl
| Download URL | pylon_analyzer-0.1.1-py3-none-any.whl |
|---|---|
| Size | 19.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5055103056b2c4a59d911d1a0d6495417235d95bf45e2fee4d770338520963d6
|
|
BLAKE2b-256 checksum How to use checksums |
458f11aff3550e4175a150f8854b50b6e03aa2942176934c9add2c641f3cd70e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.2
|
Security for pylon-analyzer 0.1.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.