Skip to main content

assert-python-definition-is-used

Assert that every public Python definition in a tree is named somewhere else.

Why

A function whose last caller is deleted does not disappear. Its tests still pass, the coverage gate over its module stays green, and static analysis keeps reading it, so the tree grows a layer of code that is maintained and never called. Nothing in a normal toolchain reports it: coverage measures whether lines run, not whether anything wants them, and a module held at 100% by its own tests manufactures exactly the evidence that makes it look used.

This tool asks the other question. For every public top-level def and class in the trees you point it at, it asks whether anything else names it, and reports the ones nothing does.

Installation

pip install assert-python-definition-is-used

Usage

# Every definition in lib/python must be named somewhere in the repo
assert-python-definition-is-used lib/python \
  --search-in lib/python --search-in scripts \
  --search-in src --search-in test

# The same, but a module's own tests no longer count as a caller
assert-python-definition-is-used lib/python \
  --search-in lib/python --search-in scripts \
  --search-in src --search-in test \
  --dont-search-in 'test/lib/python/test_{package}'

Those two runs are the pair worth having. The first is a cheap outer bound that catches a definition whose tests were deleted along with its caller. The second is the one that finds code kept alive only by the tests written for it, which is what a coverage gate hides.

Options

Option Effect
--search-in PATH A tree to search for uses. Repeatable.
--dont-search-in TEMPLATE Template left out of the search.
--count-defining-file Count a use in the defining file.
--exclude PATTERNS Comma-separated globs to leave out of both trees.
--quiet Print nothing; report through the exit code.
--count Print only how many findings there were.
--verbose Print the trees read, each file scanned, and a summary.
--fail-fast Stop at the first finding.
--warn-only Always exit 0.

Exit codes

Code Meaning
0 Nothing unused
1 Something unused
2 A tree was missing, unreadable, or would not parse

What counts as a use

A use is the definition's name written as a whole word in any file the searched trees reach. That is deliberately blunt, and it has two consequences worth knowing before you read the output.

By default a name written elsewhere in its own defining file does not count. A docstring example, an __all__ entry and a call from a sibling that is itself dead all look the same as a live caller, so crediting them hides real findings. Pass --count-defining-file for the looser rule. When the stricter rule reports a definition that a live sibling in the same file genuinely calls, the finding is that the definition is public and should not be: rename it with a leading underscore, which takes it out of scope.

Matching on a bare name also means a definition reads as used when any other file happens to contain that word, including a file that defines its own unrelated function of the same name. The count is a lower bound rather than an exact figure.

Only top-level def and class statements are read. A method and a nested function are reached through the name of the thing that holds them, so neither is something this tool can speak about. Names starting with an underscore are skipped.

Packages and their own tests

The usual thing to leave out is a package's own tests, and --dont-search-in takes a path template rather than a fixed layout, because the convention differs between repositories. The {package} field is the first directory below the definition tree:

lib/python/aws_clients/__init__.py  ->  package is "aws_clients"

So --dont-search-in 'test/lib/python/test_{package}' leaves out test/lib/python/test_aws_clients/, and --dont-search-in 'test/lib/python/{package}' leaves out test/lib/python/aws_clients/.

A file sitting directly in the definition tree belongs to no package and so has no directory of its own to leave out. Uses of its definitions count wherever they appear.

--dont-search-in is not --exclude. An excluded file is dropped from the run altogether, so its own definitions go unchecked too. A file left out of the search is still read for the definitions it holds; it just does not get a vote on whether anything else is used.

GitHub Actions

- name: Assert every definition is used outside its own tests
  uses: 10U-Labs/assert-python-definition-is-used@latest
  with:
    dont-search-in: test/lib/python/test_{package}
    search-in: lib/python scripts src test
    trees: lib/python
    verbose: true

License

Apache-2.0

Download files

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

Source Distribution

Built Distribution

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

File details

Details for the file assert_python_definition_is_used-20260823033619.tar.gz.

File metadata

File hashes

Hashes for assert_python_definition_is_used-20260823033619.tar.gz
Algorithm Hash digest
SHA256 e0dd7f5b2b2811e77558ddd05b4ae9c6ceb3221ef9c4583fa5d4ab3afe567eac
MD5 4f34c5028522c3335233dc10733be5ba
BLAKE2b-256 d64fa37b4757aa3e625ecdb81562ba33670c8f30fcb7cc0df7a0840d44015411

See more details on using hashes here.

Provenance

The following attestation bundles were made for assert_python_definition_is_used-20260823033619.tar.gz:

Publisher: release.yml on 10U-Labs/assert-python-definition-is-used

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

File details

Details for the file assert_python_definition_is_used-20260823033619-py3-none-any.whl.

File metadata

File hashes

Hashes for assert_python_definition_is_used-20260823033619-py3-none-any.whl
Algorithm Hash digest
SHA256 84f771cd504a94bc76bcb8af42a1720fdb49e617d5db4c28ac484bd68d9e9867
MD5 dfcce0202b66052ad1c53a96124d4acc
BLAKE2b-256 47a415af59901f6c3c2f0b020421944635070ec2b9379f2c5fc97c1736709264

See more details on using hashes here.

Provenance

The following attestation bundles were made for assert_python_definition_is_used-20260823033619-py3-none-any.whl:

Publisher: release.yml on 10U-Labs/assert-python-definition-is-used

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

Release history Release notifications | RSS feed

20260830060121

2 files

20260830020719

2 files

20260829003946

2 files

20260829003639

2 files

20260829001340

2 files

20260828112619

2 files

20260828104252

2 files

20260823122013

2 files

This release

20260823033619 This release

2 files

20260823031322

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