flake8-stepdown
A flake8 plugin that enforces top-down (newspaper-style) function ordering in Python modules.
This is inspired by Robert C. Martin's "Clean Code" stepdown rule: High-level logic first, details later. When reading a module, callers should appear before callees, so you can read the code from top to bottom like a newspaper article.
Violation codes
| Code | Meaning |
|---|---|
| TDP001 | Function is defined in the wrong order (should appear after another function) |
Installation
pip install flake8-stepdown
The plugin registers itself with flake8 automatically. Verify it's installed:
flake8 --version
You should see flake8-stepdown in the list of installed plugins.
Usage
As a flake8 plugin
Just run flake8 as usual, the plugin will report TDP001 violations:
flake8 your_module.py
Standalone CLI
The package also provides a stepdown command with three subcommands:
# Report violations
stepdown check your_module.py
# Show a unified diff of the proposed reordering
stepdown diff your_module.py
# Rewrite files in place
stepdown fix your_module.py
Use -v / --verbose to show mutual recursion info on stderr.
Development
Prerequisites
- UV (Python package manager)
Setup
uv sync
Linting
./lint.sh
Testing
uv run pytest
Tests are organized by pipeline stage (test_parser.py, test_graph.py, test_rewriter.py, etc.). The rewriter uses snapshot testing: tests/fixtures/ contains input Python files exercising various scenarios (bottom-up ordering, mutual recursion, decorators, etc.), and tests/snapshots/ contains the expected output after rewriting. The test suite asserts correctness against snapshots, idempotency, and syntax validity.
Robustness testing
A separate script tests the plugin against real-world Python projects (click, httpx, rich, attrs, typer, pendulum, pydantic-settings) to detect crashes and code corruption:
bash tests/robustness/run_robustness.sh
For each project, the script:
- Clones the repo and installs it alongside flake8-stepdown
- Runs
stepdown checkand verifies it doesn't crash - Runs the project's test suite (baseline)
- Runs
stepdown fixand validates the rewritten code compiles - Re-runs the test suite and checks for regressions
See tests/robustness/projects.json to configure the list of target projects.
Pre-commit hooks
Pre-commit hooks are installed automatically. To run manually:
uv run pre-commit run --all-files
CI
GitHub Actions runs linting, type checking, and tests on every push to main and on pull requests.
Publishing to PyPI
This project uses trusted publishing via GitHub Actions.
To publish a new version:
- Bump the version with
uv version --bump patch(orminor/major) - Update
__version__inflake8_stepdown/__init__.pyto match - Create a GitHub release with a tag matching the version (e.g.,
v0.1.0) - The publish workflow will automatically build and upload to PyPI
First-time setup: Configure a trusted publisher on PyPI under your project's settings (Publishing tab). Use
publish.ymlas the workflow name andpublishas the environment name.
Contributing
See CONTRIBUTING.md for code style, conventions, and development workflow.
Metadata
Release files for flake8-stepdown 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| flake8_stepdown-0.1.2.tar.gz | 67.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| flake8_stepdown-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 87.8 kB
Release files / flake8_stepdown-0.1.2.tar.gz
| Download URL | flake8_stepdown-0.1.2.tar.gz |
|---|---|
| Size | 67.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0fe5675c2a091e1d0ba0188d0d6a367fe277551aa55aafa12988991d14f46f81
|
|
BLAKE2b-256 checksum How to use checksums |
19ef88a4750045bd2b67bfadc9e8a4d145919aa5e120fb27b879f74f65b0106a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.
Transparency logRelease files / flake8_stepdown-0.1.2-py3-none-any.whl
| Download URL | flake8_stepdown-0.1.2-py3-none-any.whl |
|---|---|
| Size | 20.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f466ecfdd89558e8f2b2a72da8509f0e60026c8c19b7c6952168051aa40eeb3c
|
|
BLAKE2b-256 checksum How to use checksums |
58f1f93ee584f5516c3b275d968cfdb4d0c81b4ffb51c442980a8bc82e38e638
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.
Transparency log