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.0.tar.gz (59.7 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.0-py3-none-any.whl (40.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pragyalint-0.1.0.tar.gz
  • Upload date:
  • Size: 59.7 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.0.tar.gz
Algorithm Hash digest
SHA256 2a790fc60f86173299819afa093137e402e566b13652e04bf1d1784294ea5e2e
MD5 e04fe5a3eba5a0801e55e717839e5b26
BLAKE2b-256 1edeb7f290ba02f0c8d3113ffc2d743dc4f74295702bcdb8c55990ecae8dd8b5

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pragyalint-0.1.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 226c037e527ab94f7b6625323095c641849abfee3346ed1f7ecc3614d4062744
MD5 e963477c120989d4fa71c1d4a5d2d439
BLAKE2b-256 5ed24f2ede997e9ea617fe6ab37af24bd3644607d1bc584ccc05a7d760954373

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

0.1.1

2 files

This release

0.1.0 This release

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