Skip to main content

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.3.0 released. 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 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. v0.3 adds schema_version on JSON/baseline output, published JSON Schema under docs/schema/, per-rule [tool.chokkin.severity] overrides, and stabilized SARIF rule metadata. The §17 CHK002 false-positive gate passed after Phase 1.5 (make oss-metrics ARGS=--gate), v0.2 validation is recorded (docs/dev/v0.2-release-validation.md), and v0.1.0 / v0.2.0 / v0.3.0 have 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.3.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

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 and how reachability was judged. CHK002 explain includes top-level modules and reachable/unreachable import evidence; --trace prints a positive path for reachable files and a negative trace (reason, entry roots, incoming import chain) for unreachable files. 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

# Per-rule severity overrides (off / info / warning / error)
[tool.chokkin.severity]
CHK001 = "off"
CHK006 = "info"
CHK002 = "error"

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:

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

Baseline and --reporter json output include schema_version: "1". v0.2 baseline files without that field remain readable. Published JSON Schema files live under docs/schema/; migration notes are in docs/dev/schema-migration-notes.md.

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

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.3.0.tar.gz (432.3 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.3.0-py3-none-win_amd64.whl (2.5 MB view details)

Uploaded Python 3Windows x86-64

chokkin-0.3.0-py3-none-musllinux_1_2_x86_64.whl (2.7 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

chokkin-0.3.0-py3-none-musllinux_1_2_aarch64.whl (2.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

chokkin-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

chokkin-0.3.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.5 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

chokkin-0.3.0-py3-none-macosx_11_0_arm64.whl (2.4 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

chokkin-0.3.0-py3-none-macosx_10_12_x86_64.whl (2.6 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

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

File metadata

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

File hashes

Hashes for chokkin-0.3.0.tar.gz
Algorithm Hash digest
SHA256 acb0984879795eaf5f5a7257e9c463c2ff8814774003eb41a928d86a4092f530
MD5 79e56fb3f1c9ec7897f3076c7078d34f
BLAKE2b-256 d36911ee4ce218f962d2e3a5fd7076bfb34736630a4082a713debfbe9c949572

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.3.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.3.0-py3-none-win_amd64.whl.

File metadata

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

File hashes

Hashes for chokkin-0.3.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 6ec172b96f975caf6ff0afe4cf95c6a88ac2138f8bfb444bbc4bc3067ab34750
MD5 3aeaf7f49d0cc8570a97bdf04471729f
BLAKE2b-256 492acca729bbe81c386cfc4ce70c1938a28c03bd6328f5af90987a7003d14463

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.3.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.3.0-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for chokkin-0.3.0-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 ea6c4fa4a6c065f142be62ee7ff8a9ecf58929a3b333a64135a23ed1bce0736a
MD5 7493ce086e42193d6c7073b9cb8b9702
BLAKE2b-256 63213adfe31a159e2e4f2e64baf883d7aab426451834ce6c943f71e715818142

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.3.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.3.0-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for chokkin-0.3.0-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 b378bc2b372e27a44762d3676ecc8dabf92e9f8a34d8c9616496dc3af3a93835
MD5 09a18fc1b0b7d98fcd543f1c5843562b
BLAKE2b-256 b5a2e02137464b4ae361899b87c21e309310db307eeee523239a1c83d072af6d

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.3.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.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chokkin-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4501f6a45f74488b83ebca03ffeabef7f15b5c24a6883608c223e05286d76959
MD5 a1a624adc96b7304a83c2c9026a10a92
BLAKE2b-256 27cd14a2ad198b037bc4eb2a357945a4a9a594e7969c7fbad090a989b6e8482e

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.3.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.3.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chokkin-0.3.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 8488cc94cc62671e49b0f6af44c1c44e135d4f220558b5450895e99df23de7f3
MD5 7fbe025465798abcc4619c28fe3c4424
BLAKE2b-256 8e231e53414907d44394dd0b7a5b668a18da100271c7d180fd5d11c9bee474a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.3.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.3.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chokkin-0.3.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fcb3de7634ae562d3961b1481079d2dcef66924aca2ddf92b74047edfb36bf29
MD5 dd826d399423c8936663be777bc53b12
BLAKE2b-256 1be2969a9592653654f17714379c214bfdac596196e5742d8c20c25b70f80904

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.3.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.3.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for chokkin-0.3.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 b8109f31f70e5a7a27997fcd4493561fefca54b5490486879a4cad1262ff3ae7
MD5 bf739422c6c02436018813fee6a4fb78
BLAKE2b-256 8e84a6828e6f64bb733a8d0f2f11017e4706f0c408895ca4ed7842d9a5001ca1

See more details on using hashes here.

Provenance

The following attestation bundles were made for chokkin-0.3.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