tools/type-checking/README.md
This directory contains the infrastructure for running PEP-484 type checking on Redpanda's Python test suite (ducktape) using pyright.
The type checking system provides:
type-check.pyThe main type checking orchestration script. Provides multiple commands:
check - Run type checking on files and report errorspromotion-check - Identify files that can be promoted to stricter type checking levelsfruit - Show files with fewest errors at each target level (low-hanging fruit for type checking improvements)ci - Run both check and promotion-check and decorates the results (used in CI)type-check-strictness.jsonConfiguration file that maps Python files to their current type checking strictness level. Files not listed default to strict level.
Strictness levels (from most to least strict):
strict - Full type checking (default for unlisted files)standard - Standard type checkingbasic - Basic type checkingoff - Minimal checking (syntax, imports, etc.)skip - No type checking at allDockerfileMulti-stage Docker image for running type checking in a consistent environment. Installs Python dependencies and pyright.
type-check.shShell script that builds the Docker image and runs type checking inside a container.
requirements.txtPython dependencies for type checking (primarily pyright).
There is a type-check task which is a very thin wrapper around the scripts: this is probably the most convenient way to call it as it works
anywhere in the repository. Call it with arguments for the script after --, like so:
task rp:type-check -- --help
You can also call the script as tools/type-checking/type-check.sh --help. This is essentially the same as the task invocation above. This runs the underlying python script inside a docker container, so it should "just work".
Locally you should also able to run the .py script directly, like tools/type-checking/type-check.py --help if you have run local_venv.sh.
These examples all the task invocation method but work with any of the methods above.
# Run type checking on all files
task rp:type-check -- check
# Check for files ready to be promoted to stricter levels
task rp:type-check -- promotion-check
# Find low-hanging fruit - files with fewest errors at each target level
task rp:type-check -- fruit
# Show top 25 fruit candidates
task rp:type-check -- fruit --top 25
# Show detailed error information with verbose output
task rp:type-check -- fruit --verbose 2
# Automatically promote eligible files
task rp:type-check -- promotion-check --update
# Run CI checks (both check and promotion-check)
task rp:type-check -- ci
# Check specific files
task rp:type-check -- check --input-files "rptest/tests/my_test.py"
# Force all files to be checked at a specific level
task rp:type-check -- check --force-level strict
In order to have type checking useful immediately, without needing to fix 1000s of existing type errors, the system uses a progressive approach to type checking adoption:
strict type checking--update flagWhen adding type hints to improve a file:
tools/type-checking/type-check.py promotion-check --updatetype-check-strictness.jsonThe fruit command helps identify files that are closest to being promotable to stricter type checking levels by showing files with the fewest errors at each target level:
# Show top 10 files with fewest errors per target level
task rp:type-check -- fruit
# Show top 20 files with fewest errors per target level
task rp:type-check -- fruit --top 20
# Show detailed error information with verbose output
task rp:type-check -- fruit --verbose 2
This is useful for:
The command groups files by their potential promotion target (off→basic, basic→standard, etc.) and sorts them by error count, making it easy to find files that are closest to passing at the next strictness level.
You may be here because CI failed with a "promotion check" error. This means that the strictness level for some files are set too low, i.e., your change has improved the state of the Python code base and as a reward you can promote some files to higher strictness levels. Pat yourself on the back, then use the following command to automatically update the strictness file:
# Automatically update the configuration
task rp:type-check -- promotion-check --update
# Commit the updated type-check-strictness.json
git add tools/type-checking/type-check-strictness.json
git commit -m "chore: update type checking strictness"
--tests-root PATH - Path to tests directory (auto-detected by default)--config PATH - Path to pyrightconfig.json--input-files GLOB - Glob pattern for files to check (default: rptest/**/*.py)--force-level LEVEL - Override strictness levels and check all files at specified level--no-venv - Don't use virtual environment when running pyright--verbose [LEVEL] - Enable verbose output (0=off, 1=verbose, 2=very verbose)--update - Update type-check-strictness.json in-place (for promotion-check)--top N - Number of files to show per target level in fruit command (default: 10)The type checking runs automatically on pull requests via GitHub Actions (.github/workflows/python-type-check.yml). The CI:
Dockerfiletype-check.py ci which executes both type checking and promotion detectionThis check tries to be as fast as possible, and usually runs in about 3 minutes if the docker image build is fully cached (usually the case), or a few minutes more if not.
The system is designed around Microsoft's pyright type checker with these key features:
.venv if available for consistent Python environmentThe type-check.py script is modular and can be extended with new commands by:
CMDS listCOMMAND_DOCTypeCheck class with the command name (with hyphens converted to underscores)The script follows the pattern where each command method returns True for success, False for failure, or None for success (which is treated as True).