Skip to main content

Find unused files, dependencies, and public symbols in Python projects

Project description

chokkin

日本語

Find unused files, dependencies, and public symbols in Python projects.

chokkin is a reachability analyzer for whole Python projects — a Knip-like experience for Python. It builds a project-wide graph from your manifests, source code, and tool configs, then reports what nothing reaches: run uvx chokkin with zero configuration, and tighten things up with precise settings and CI integration as you go.

[!NOTE] Status: v0.2 development. chokkin runs the full analysis pipeline (steps 1–13) by default: unused files, dependencies, and symbols with built-in reporters (default, compact, json, markdown, github, sarif), plus --explain, --trace, --fix, and baseline filtering. Use --probe for steps 1–4 summary only; it now reports resolved workspace member counts, and resolver tags member-owned imports while treating cross-member imports as first-party. Strict mode enforces member-local dependency declarations, and reporters expose member ids on workspace findings. The §17 CHK002 false-positive gate passed after Phase 1.5 (make oss-metrics ARGS=--gate), Rust 1.93 v0.2 validation measurements are recorded (docs/dev/v0.2-release-validation.md), and v0.1.0 has been released.

Why chokkin?

Existing tools each cover one slice of the problem:

Ruff     : per-file, syntax-level linting
Vulture  : Python AST-based dead code detection
deptry   : consistency between dependency manifests and imports
chokkin    : unused files, dependencies, and public symbols from the whole project graph

chokkin is not a style/lint tool. It answers a different question: starting from your entry points, what can actually be reached — and what is just sitting there? It reads pyproject.toml (including Poetry/PDM/Hatch dependency sections), requirements files, uv lockfiles, and framework/tool configs (Django, FastAPI, pytest, tox, nox, pre-commit, GitHub Actions, …) to build that picture.

Quick start

uvx chokkin

No configuration needed. On first run, chokkin discovers your manifests (pyproject.toml, setup.cfg, setup.py, requirements*.txt, uv.lock), infers your layout (src/flat, tests, scripts, docs), infers entry points, builds the import graph, and reconciles it against your declared dependencies:

chokkin 0.2.0

Project: acme-api
Config : pyproject.toml
Mode   : auto, production=false

Unused dependencies  3
  boto3          pyproject.toml:18  declared in [project.dependencies], no reachable import found
  rich           pyproject.toml:25  only used by scripts/dev.py; move to dependency-groups.dev
  python-dotenv  pyproject.toml:29  no import/config/binary usage found

Missing dependencies  1
  yaml -> PyYAML  src/acme/config.py:3  imported but not declared

Unused files  2
  src/acme/legacy.py        no path from any entry point
  src/acme/old_handlers.py  no path from any entry point

Unused exports  4
  src/acme/utils.py:12  function legacy_slugify
  src/acme/auth.py:44   class OldTokenBackend

Summary: 10 issues

What it checks

Code Issue Description Default severity
CHK001 unused_file Python file not reachable from any entry point warning
CHK002 unused_dependency declared in a manifest, but no import/config/binary usage found error
CHK003 missing_dependency imported, but not declared directly in any manifest error
CHK004 transitive_dependency imported directly, but only available via another dependency error
CHK005 misplaced_dependency runtime code uses a dev-group dependency, or a test-only dep is in main warning
CHK006 unused_export public symbol not referenced from outside its module warning
CHK007 unused_reexport re-export (e.g. in __init__.py) not referenced internally library: info / app: warning
CHK008 unlisted_binary CLI used by tox/nox/pre-commit/CI without a declared dependency warning
CHK009 duplicate_dependency declared in multiple of main/dev/optional warning
CHK010 unresolved_import import that resolves to neither first-party, third-party, nor stdlib warning

Because any module top-level name is importable in Python, unused_export starts out as a preview rule (info-level in library mode) rather than a hard error.

CLI

uvx chokkin
uvx chokkin --production
uvx chokkin --strict
uvx chokkin --no-exit-code
uvx chokkin --include CHK002,CHK003
uvx chokkin --exclude CHK006
uvx chokkin --reporter json
uvx chokkin --reporter markdown
uvx chokkin --reporter github
uvx chokkin --reporter sarif
uvx chokkin --confidence likely
uvx chokkin --fix
uvx chokkin --fix --dry-run
uvx chokkin --fix --allow-remove-files
uvx chokkin --fix --add-missing
uvx chokkin --baseline chokkin-baseline.json
uvx chokkin --baseline chokkin-baseline.json --update-baseline
uvx chokkin --no-cache
uvx chokkin --explain CHK002:boto3
uvx chokkin --trace src/acme/legacy.py
uvx chokkin --probe              # steps 1–4 summary only
uvx chokkin --init                # v0.2

Key flags:

  • --production — drop dev/test/docs/lint/type contexts and judge reachability from runtime context only. Dev-only files and dependencies are no longer reported, and "unused in production" becomes strict.
  • --strict — direct imports of transitive dependencies always error, workspace members must declare their own dependencies, unused environment-marker dependencies error, and maybe-confidence issues are shown.
  • --no-exit-code — exit 0 even when issues are found (config/CLI errors still exit 2, internal errors 3). Useful during adoption and for GitHub Actions summaries.
  • --fix — apply conservative fixes for certain dependency findings; add --allow-remove-files to also remove certain unreachable files. --add-missing adds Certain CHK003 findings to non-Poetry [project].dependencies when the distribution is unambiguous; workspace findings are inserted into the member pyproject.toml when that member manifest was inventoried. Unsupported cases are reported as skipped fixes with details on stderr.
  • --baseline PATH / --update-baseline — freeze current issues in a baseline file and suppress matching issues on later runs so CI fails only on new findings.
  • --no-cache — disable Phase 2 cache reads/writes. Parse, manifest/config scan, and module-index cache units are enabled by default under the project root and are conservative: corrupt or stale entries are treated as misses.
  • --reporter github / --reporter sarif — emit GitHub Actions annotations or a SARIF 2.1.0 subset for code scanning.
  • --probe — include resolved and inventoried workspace member counts when uv or chokkin workspaces are detected.
  • --explain / --trace — show why an issue was reported / why a file is considered reachable. These are the intended path for investigating and reporting false positives.

Exit codes are fixed for CI:

0: no reportable issues
1: issues found
2: CLI/config error
3: internal error

Configuration

Zero config is the default. When you need precision, configure [tool.chokkin] in pyproject.toml (standalone chokkin.toml / .chokkin.toml are also accepted). chokkin --init appends a starter [tool.chokkin] reflecting what auto-discovery found.

[tool.chokkin]
entry = [
  "src/acme/__main__.py",
  "src/acme/asgi.py:application",
  "manage.py",
]
project = [
  "src/**/*.py",
  "tests/**/*.py",
  "scripts/**/*.py",
]
mode = "auto"             # auto | app | library
production = false
target_version = "py311"  # Python version of the analyzed project
respect_gitignore = true
confidence = "likely"     # certain | likely | maybe
exclude = [
  ".venv/**",
  "build/**",
  "dist/**",
  "**/__pycache__/**",
]

[tool.chokkin.dependencies]
dev_groups = ["dev", "test", "tests", "lint", "docs"]
runtime_groups = ["server", "worker"]
type_groups = ["types", "typing", "mypy"]

# distribution name -> import name(s), for cases the bundled map doesn't cover
[tool.chokkin.package_module_map]
"PyYAML" = ["yaml"]
"Pillow" = ["PIL"]

# CLI name -> distribution name, used by CHK008/CHK002 binary-usage checks
[tool.chokkin.binary_map]
"sphinx-build" = "Sphinx"

[tool.chokkin.plugins]
pytest = true
django = true
fastapi = true

Modes

mode = "auto" picks one of:

  • app mode — there's a clear entry (console_scripts, manage.py, asgi.py, wsgi.py, app.py). Unused files are reported aggressively.
  • library mode — a [project] name with a package and no clear entry. Public modules may be imported by external users, so unused files/exports are reported at low confidence (or as info). For serious unused-file detection in a library, declare entry explicitly.
  • workspace mode — multiple pyproject.toml files or tool.uv.workspace.members. Each member is analyzed separately (per-member [tool.chokkin.workspaces.<name>] config is supported), sharing the workspace lockfile.

Dependency contexts

Dependencies and files are both assigned contexts (runtime / dev / test / docs / lint / type / optional extras). That's what powers CHK005: import pytest in tests/ with pytest in your dev group is fine; the same import in src/ is a misplaced dependency. TYPE_CHECKING-only imports are type-context, and try: import orjson / except ImportError is treated as optional rather than missing.

Plugins

Frameworks reference modules through strings and decorators, which pure import analysis can't see. Plugins close that gap by adding entry files, string/module references, and binary usage:

  • v0.1: pytest, django, fastapi/uvicorn
  • v0.2+: tox/nox/pre-commit/GitHub Actions binary usage detection, static Flask/Celery route/task references, conventional Sphinx/MkDocs/Alembic config entries, and .ipynb code-cell parsing.

For example, the Django plugin treats INSTALLED_APPS / MIDDLEWARE / ROOT_URLCONF strings as module references and migrations/** as framework-used; the FastAPI plugin treats @router.get-decorated handlers as externally used.

Suppressing issues

Inline and file-level ignores:

from legacy import old_api  # chokkin: ignore[CHK003]

# chokkin: file-ignore[CHK006]   (at the top of a file)

Config ignores, keyed by rule code (globs over distribution names, paths, or path:symbol):

[tool.chokkin.ignore]
CHK001 = ["src/acme/generated/**/*.py"]
CHK002 = ["boto3", "google-cloud-*"]
CHK006 = ["src/acme/public_api.py:*"]

For large existing projects, a baseline freezes current issues so CI only fails on new ones (v0.2):

uvx chokkin --baseline chokkin-baseline.json --update-baseline
uvx chokkin --baseline chokkin-baseline.json

CI adoption

For an existing project, generate and review the baseline once:

uvx chokkin --baseline chokkin-baseline.json --update-baseline
git add chokkin-baseline.json

Then wire the baseline into pull request checks. This job emits GitHub annotations, writes SARIF for code scanning, and fails only for findings not already present in the baseline:

name: chokkin

on:
  pull_request:

permissions:
  contents: read
  security-events: write

jobs:
  chokkin:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v5
      - name: Annotations
        run: uvx chokkin --baseline chokkin-baseline.json --reporter github
      - name: SARIF
        if: always()
        run: uvx chokkin --baseline chokkin-baseline.json --reporter sarif > chokkin.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: chokkin.sarif

Installation

chokkin is a single Rust binary shipped inside a Python wheel (prebuilt for Linux/macOS/Windows), so all of these work without a Rust toolchain:

uvx chokkin        # run without installing
pipx run chokkin
pip install chokkin

chokkin never executes your project's code — analysis is fully static. It also doesn't require your project's virtualenv: if .venv exists it is read for dist-info metadata (METADATA, top_level.txt, RECORD, entry_points.txt), otherwise manifests, lockfiles, and bundled maps are used.

Contributing

See CONTRIBUTING.md. The full design specification (analysis engine, import resolution strategy, roadmap) is in docs/dev/spec.ja.md (Japanese).

License

MIT

Project details


Download files

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

Source Distribution

chokkin-0.2.0.tar.gz (400.2 kB view details)

Uploaded Source

Built Distributions

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

chokkin-0.2.0-py3-none-win_amd64.whl (2.6 MB view details)

Uploaded Python 3Windows x86-64

chokkin-0.2.0-py3-none-musllinux_1_2_x86_64.whl (2.8 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

chokkin-0.2.0-py3-none-musllinux_1_2_aarch64.whl (2.6 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

chokkin-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

chokkin-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

chokkin-0.2.0-py3-none-macosx_11_0_arm64.whl (2.5 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

chokkin-0.2.0-py3-none-macosx_10_12_x86_64.whl (2.7 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file chokkin-0.2.0.tar.gz.

File metadata

  • Download URL: chokkin-0.2.0.tar.gz
  • Upload date:
  • Size: 400.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chokkin-0.2.0.tar.gz
Algorithm Hash digest
SHA256 0aa719e623d100cd991e1c62549e69d5360565c94deff9e9e516c72cd80f3380
MD5 60d1781134b76bb386289e5b1cdf7748
BLAKE2b-256 85b601e14d17a399086ae50d81e9de7d2a0b134e6bcdce5602fb2adc984d8f20

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.2.0.tar.gz:

Publisher: release.yml on watany-dev/chokkin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chokkin-0.2.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: chokkin-0.2.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.6 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chokkin-0.2.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 6caa5a75c07906f377ec8c66959b769f9fc94a763975035980d6e3bb03da67be
MD5 f51866b1fc84bfd24b797555db0f7b3b
BLAKE2b-256 b1f1a360e3d5a96b0e1ce864988c221c7786fa1715ac501f383dba9ed04c44ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.2.0-py3-none-win_amd64.whl:

Publisher: release.yml on watany-dev/chokkin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chokkin-0.2.0-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for chokkin-0.2.0-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 cd40ce320c7310b35d6661c46e850bf2a63577848c93e73a82711eabd44b56d8
MD5 e9395cb0ba176547c20ab83eb4053044
BLAKE2b-256 a5cff17515824258c352f27ab6b82aa8ab0c6b09e8203d42afa582f0bc1ee5a3

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.2.0-py3-none-musllinux_1_2_x86_64.whl:

Publisher: release.yml on watany-dev/chokkin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chokkin-0.2.0-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for chokkin-0.2.0-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 e70bd58786fbaeb44a802090855b3538e34c9833c38463afe29f5f5c3b3de13e
MD5 9875a01bf3de8dcd7d8cd20a5f8cba75
BLAKE2b-256 59bfcf351b495c5c2553a5fb504a59155f5e4a58ceef8ff77be2dc4b374cf0ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.2.0-py3-none-musllinux_1_2_aarch64.whl:

Publisher: release.yml on watany-dev/chokkin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chokkin-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chokkin-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 3e76d5fa5c888986f5cb2e063fba514c0a2bf829abb97df7c734bb0cef12ee33
MD5 67a880f5e810a404cf93a8945b891892
BLAKE2b-256 7c18b9acaba417ce56593d1421267ef3b737b129721e7457861fdcf83e958113

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on watany-dev/chokkin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chokkin-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chokkin-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 880d5d912e862678913282c2124d9629edb218b2f6df26edc4e2ae6d46f3c845
MD5 dba043dab58713b765898b8718e7c711
BLAKE2b-256 5c041324660798048b4f9577b27bf9190dcd988e7b168739ad21619b77b73b76

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on watany-dev/chokkin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chokkin-0.2.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chokkin-0.2.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 70ca9bf416488e87d8759289d3aa6d08cf8bcca6c2885064938531abb3439285
MD5 c4e29dd4b7e1a86800cddbf39a2eb6bc
BLAKE2b-256 a14308176df4702389fe37cad72541de828fb178361ba78bc4a045a2a01b0be9

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.2.0-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on watany-dev/chokkin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chokkin-0.2.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for chokkin-0.2.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 de3a4222df231622265a3e2521b5770ee58be8b5edb76a6c3be39858d7964887
MD5 13c37ff034179fa5a725d0c8e834347c
BLAKE2b-256 fc43dc0a1a8397dbef4c4e6acc2c869ff4595b5bc94b6a43f8bff4bbc472a5b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.2.0-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on watany-dev/chokkin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page