Skip to main content

PragyaLint 🔍

A static dead-code analyzer for Python. PragyaLint builds a module graph from your entry points, traces what's actually reachable, and reports unused files, exports, functions, imports, and circular imports — so you can keep your codebase lean.

Inspired by OptiPrune (a dead-code analyzer for TypeScript/JavaScript) — PragyaLint brings the same concept to Python.


Features

Area What is included
Project analysis Entry discovery, module graph, reachability, import-cycle reporting
Python .py files and packages, __init__.py, relative imports, dynamic imports
Dead code Unreachable modules/files, unused public exports, unused functions/classes, unused imports, unused assignments
Confidence levels Every finding is rated high, medium, or low so you know how much to trust it
Output Human-readable terminal output, JSON reports, and SARIF for CI/code-scanning workflows
CI-ready --fail-on <confidence> gates your pipeline on dead-code findings
Configuration pragyalint.toml, pragyalint.json, or [tool.pragyalint] in pyproject.toml
Opt-in fixes --fix actually removes dead code — confidence-gated with --dry-run
Zero dependencies Uses only the Python standard library — no pip install deps, no parser to ship

Installation

pip install pragyalint
# or
pipx install pragyalint
# or
pip install --user pragyalint

Requires Python 3.11+.

Quick start

Run an analysis from the project root:

pragyalint

Specify entry points and output formats:

pragyalint --entry src/main.py
pragyalint --json
pragyalint --sarif > pragyalint.sarif

Commands

Command Purpose
pragyalint Analyze the project (default command)
pragyalint --json Print the structured report as JSON
pragyalint --sarif Print SARIF output for CI
pragyalint --help Print command and option help
pragyalint --version Print the version

Analyze flags

Flag Description Default
-r, --root-dir <path> Root directory of the project current directory
-e, --entry <module...> Entry-point modules, globs, or file paths auto-detect
-i, --ignore <patterns...> Glob patterns to ignore []
-x, --extensions <exts...> File extensions to analyze .py
--include <paths...> Only analyze files under these paths []
--rules <rules...> Restrict analysis to specific rules all
--no-report-unused-exports Disable unused-export reporting enabled
--no-conventional-entries Exclude conventional entries (main.py, app.py, ...) included
--include-entry-exports Report unused exports in entry files disabled
--ignore-tests Ignore test files and directories disabled
--cycles Report circular import cycles disabled
--fail-on <confidence> Exit non-zero at/above this confidence
--json JSON output
--sarif SARIF output
--no-color Disable ANSI colors
-v, --verbose Print internal graph state
--fix <targets...> Apply fixes: files, imports, exports
--confidence <level> Minimum fix confidence: high, medium+, low+, all high
--dry-run Log planned fixes without changing files
--force Allow a fix considered unsafe (e.g. __all__-listed exports)

Rules / finding types

Rule Confidence What it finds
unused_file high Modules unreachable from any entry point
unused_import high Imports never used in their module
unused_export medium Public names never imported anywhere
unused_local medium/low Functions/classes/variables defined but never used
cycle low Circular import cycles

Confidence

Every finding carries a confidence level:

  • high — structurally certain (module unreachable, import unused)
  • medium — strongly implied (export/definition not referenced)
  • low — heuristic (constant assignments, cycles)

Use --fail-on to make your CI fail on a given threshold, e.g.:

pragyalint --fail-on high

This exits with a non-zero code when any high-confidence finding exists — perfect for blocking PRs that introduce dead code.

Fixes

Like OptiPrune, PragyaLint's fixer is explicit, not implicit. Analysis only reports; use --fix to actually remove dead code. Always start with a dry run, inspect the output, then drop --dry-run.

# Preview what would change (does NOT modify files)
pragyalint --fix --dry-run

# Actually remove dead code
pragyalint --fix

# Remove dead code and functions with lower-risk edits too
pragyalint --fix exports --confidence medium+
Target What it does
files Delete unreachable modules (never deletes entries or __init__.py)
imports Remove unused imports; trims unused names from multi-name imports
exports Remove unused function/class/variable definitions (respects __all__)

Fixes are confidence-gated:

  • --confidence high (default) — only high-confidence removals.
  • --confidence medium+ — also remove unused exports/definitions.
  • --force — allow an edit otherwise considered unsafe (e.g. removing a name listed in __all__).

Always commit before fixing. Removing code can have ripple effects. Run --dry-run first and re-run after fixing.

Configuration

PragyaLint loads configuration from the first file it finds (starting at the root directory):

  1. pragyalint.toml
  2. pragyalint.json
  3. [tool.pragyalint] section of pyproject.toml
# pragyalint.toml
entry = ["src"]
ignore = ["migrations/", "generated/"]
extensions = [".py"]
detect_cycles = true
fail_on = "medium"

Or inside your pyproject.toml:

[tool.pragyalint]
ignore = ["tests/"]
report_unused_exports = false

Why Python for analyzing Python?

PragyaLint is written in pure Python and relies on the standard-library ast module. That gives you:

  • A complete, battle-tested Python parser with zero external dependencies
  • Correct handling of every modern Python syntax construct
  • Simple distribution via PyPI / pipx
  • No parser to build or maintain

Development

git clone https://github.com/example/pragyalint
cd pragyalint
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest

License

GPL-3.0-or-later

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pragyalint-0.1.1.tar.gz (104.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pragyalint-0.1.1-py3-none-any.whl (40.6 kB view details)

Uploaded Python 3

File details

Details for the file pragyalint-0.1.1.tar.gz.

File metadata

  • Download URL: pragyalint-0.1.1.tar.gz
  • Upload date:
  • Size: 104.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pragyalint-0.1.1.tar.gz
Algorithm Hash digest
SHA256 fd395e00aacdb6c07c2ea33fc5143430e2025aeec85b0a53c2d959de8775a7c4
MD5 5600f5fadc03f034d2bec215fa5374d8
BLAKE2b-256 c39bbd7ea3a80bd2e0bc0cd2e5f7bb816edfb40d35efaacccd5b7d6f7059aa29

See more details on using hashes here.

File details

Details for the file pragyalint-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pragyalint-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 40.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pragyalint-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a2ab55031ed3192a523a00aac0cf156f1f4ae539eb4b32a9f546ce684a541ca4
MD5 00336ef73e1ecc4c2fe6dbade0549e06
BLAKE2b-256 997fe09edb2d622ec959297aa665eb2c730e7059275118169ee77f140d82679c

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

This release

0.1.1 This release

2 files

0.1.0

2 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