flake8 review
Flake8 7.3.0 runs PyFlakes, pycodestyle, and McCabe checks behind one command, then merges their file and line reports. It finds undefined names, unused imports, style violations, and optionally excessive branch complexity. Plugins add more rule codes through Python entry points. Flake8 does not rewrite files or check types. Version 7.3.0 updates its bundled checker ranges, understands Python t-string syntax, and documents the F824 and F542 findings.
Flake8 7.3.0 installed in 0.4 seconds and used 1 MB in our sandbox, with 0 audit findings and a working 0.09-second import. Keep it where plugin behavior and existing ignores are part of the repository contract; compare Ruff first for a new codebase that wants fixes and pyproject.toml support.
We installed it
| Install | ✓ · 0.4s | 4 packages on disk · 1 MB |
| Import | ✓ | import flake8 in 0.09s · pure Python · requires Python >=3.9 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does flake8 install cleanly?
Yes. In a fresh container with an empty cache, pip install flake8 finished in 0.4s, leaving 4 packages and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does flake8 need to run?
Python >=3.9, and nothing compiled: it is pure Python. In our run import flake8 succeeded in 0.09s.
flake8 or ruff: which should you use?
ruff: Use it for fast linting, automatic fixes, formatting, and pyproject.toml configuration. Flake8 7.3.0 installed in 0.4 seconds and used 1 MB in our sandbox, with 0 audit findings and a working 0.09-second import.
When should you not use flake8?
A new project wants lint fixes, formatting, and pyproject.toml settings from one tool; Flake8 edits nothing and reads INI-style configuration
Use it if
- An existing repository has a reviewed set of Flake8 plugins, ignores, and stable rule codes in CI
- A required Flake8 extension has no equivalent in the linter you would otherwise choose
- Checks must run under Python 3.9 as well as newer interpreters
- Your team deliberately keeps lint reporting separate from formatting and static type analysis
- A new project wants lint fixes, formatting, and pyproject.toml settings from one tool; Flake8 edits nothing and reads INI-style configuration
- No Flake8-only plugin is required; Ruff covers many PyFlakes and pycodestyle rules while adding fixes and a formatter
- Your dependency solver already struggles with plugin pins; Flake8 7.3.0 caps pycodestyle below 2.15, PyFlakes below 3.5, and McCabe below 0.8
- Developers install tools ad hoc; every installed Flake8 plugin can change the active checks, so environments that differ can disagree on the same commit
- You need annotation and cross-module type checking; PyFlakes catches some name errors but does not replace mypy or Pyright
Setup reality
Our Flake8 7.3.0 install took 0.4 seconds in a clean Python 3.12 container. Four packages occupied 1 MB, pip-audit found 0 known vulnerabilities, and import flake8 returned in 0.09 seconds. It is pure Python with 3 direct dependencies, supports Python 3.9 or newer, uses the MIT license, and does not include py.typed metadata.
Running flake8 with no path checks the current directory. Settings belong in .flake8, setup.cfg, or tox.ini; Flake8 does not read pyproject.toml. The default line length is 79. Use extend-ignore or extend-select to add to existing defaults because plain ignore and select replace the relevant lists. Repositories formatted by Black need an explicit decision about E203, W503, and line length.
Plugins are separate Python packages discovered through entry points. Installing 1 plugin can add rule families without changing the project config. Pin every plugin in CI or pre-commit, inspect flake8 --version to see what loaded, and use --require-plugins when a missing checker must fail the job. Overlapping Flake8 and plugin dependency ranges are a common reason upgrades cannot move together.
Flake8 only reports findings and sets an exit code. A targeted # noqa: CODE suppresses one rule on one line; a bare noqa hides everything there. Per-file ignores are better for package exports, generated files, or tests with known exceptions. Version 7.3.0 changes parser and checker inputs even if your INI file stays untouched, so run the full repository before updating the pinned CI version.
Patterns
Check the project or named directories lint-paths
flake8
flake8 src/ tests/
flake8 --count src/A run with no findings exits 0. Any reported violation normally produces exit code 1, which is what CI should use.
Store repository policy in .flake8 configure-rules
# .flake8
[flake8]
max-line-length = 88
extend-ignore = E203
extend-exclude = .venv,build,migrations
max-complexity = 10
per-file-ignores =
__init__.py:F401Flake8 7.3.0 does not read pyproject.toml. extend-ignore retains default exclusions, while ignore replaces them.
Resolve Black rule conflicts pair-black
# .flake8
[flake8]
max-line-length = 88
extend-ignore = E203,W503Black and pycodestyle make different choices for slice spacing and breaks around binary operators. E501 still needs a separate team decision.
Suppress only the intended code suppress-line
import os # noqa: F401
from package import * # noqa: F403
# suppress the whole generated file:
# flake8: noqaA bare inline noqa also hides rules added later. Naming F401 or another code limits the exception's future scope.
Select or extend rule families choose-codes
flake8 --select=E9,F63,F7,F82 .
flake8 --extend-select=C901 .
flake8 --extend-ignore=E501,W291 .
flake8 --disable-noqa .select replaces the configured selection. extend-select adds codes, while disable-noqa reveals findings currently hidden in source.
Apply exceptions by path ignore-files
# .flake8
[flake8]
per-file-ignores =
package/__init__.py:F401,F403
tests/**:S101
generated/**:E501Patterns match the paths Flake8 receives. Running from below the repository root can change those paths and miss an expected rule.
Install plugins inside pre-commit pin-pre-commit
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pycqa/flake8
rev: 7.3.0
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear==24.12.12Pre-commit builds an isolated environment. A plugin absent from additional_dependencies will not contribute any checks there.
Fail when a plugin is missing require-extensions
flake8 --version
flake8 --require-plugins=flake8-bugbear,flake8-comprehensions .Installed plugins activate automatically. --require-plugins turns a smaller-than-expected rule set into an explicit error.
Turn on McCabe's C901 check limit-complexity
flake8 --max-complexity=10 src/
# src/handler.py:88:1: C901 'process' is too complex (17)McCabe is installed with Flake8, but C901 stays inactive until max-complexity receives a number.
Shape output for CI format-output
flake8 --count --statistics --show-source .
flake8 --format='%(path)s:%(row)d:%(col)d: %(code)s %(text)s' .Avoid --exit-zero in an enforcement job because it deliberately returns success even when the report contains violations.
Check editor input on standard input lint-stdin
flake8 - --stdin-display-name=src/app.py < src/app.pyThe display name keeps useful paths in diagnostics and allows per-file ignores to match the virtual input.
Find inherited settings and plugins trace-config
flake8 --bug-report
flake8 -vv src/app.py
flake8 --isolated src/app.pyVerbose mode prints configuration discovery. --isolated skips config files, which helps separate a code error from inherited settings.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| ruff | PyPI | Use it for fast linting, automatic fixes, formatting, and pyproject.toml configuration |
| pylint | PyPI | Use it for inference-heavy checks when extra runtime and configuration are acceptable |
| pycodestyle | PyPI | Use it when PEP 8 style reports are enough and PyFlakes or plugin loading would be excess |
More cli & tooling guides
commander · chalk · typescript · esbuild · yargs · click · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

