I needed a way to catch Python bugs before they reached production. Manual code review helped, but I kept missing the same class of errors. I wanted something that would flag unused imports, malformed strings, and PEP8 violations automatically every time I saved a file. That is when I started using Flake8.

This article covers what Flake8 is, how to install it, and how to interpret its error messages. By the end, you will know how to configure Flake8 for your projects and integrate it into a code quality workflow.

TLDR

  • Flake8 combines PEP8, PyFlakes, and McCabe into a single linting tool
  • Install with pip and run flake8 filename.py from the command line
  • Error codes like E225, F811, W503 tell you exactly what to fix
  • Configure ignores and per-project settings in setup.cfg or pyproject.toml
  • Integrate Flake8 into VS Code or PyCharm for real-time feedback

What is Flake8?

Flake8 is a Python linting tool that checks code for style violations and potential errors. It wraps three separate tools under one interface: PEP8 (style), PyFlakes (syntax and unused imports), and McCabe (code complexity). Running Flake8 on a Python file produces a list of errors with line numbers and short codes that describe each issue. The tool is installed via pip and runs entirely from the command line, making it easy to add to any project.

Installing and Running Flake8

Flake8 installs like any other Python package. Open a terminal and run the pip command.

Verify the installation by checking the version.

On Windows, if the flake8 command is not recognized after installation, add the Python Scripts directory to your system PATH. The path is usually in your user profile under AppData\Roaming\Python\PythonXX\Scripts.

Create a Python file with a few intentional issues and run Flake8 against it. The tool reads the file, analyzes it against PEP8 rules and PyFlakes checks, then prints any violations it finds.


def factorial(n):
    result=1
    for i in range(1, n+1):
        result *= i
    return result

num = int(input("Enter a number: "))
print("Factorial is:", factorial(num))


example.py:2:1: E225 missing whitespace around operator
example.py:3:1: F811 redefinition of unused 'n'
example.py:1:1: D100 missing docstring in public module

Each line of output follows the format filename:line:column: code message. The letter prefix tells you which tool generated the error: E codes come from PEP8, F codes from PyFlakes, and D codes from the docstring checker. To check an entire directory rather than one file, run flake8 . which recursively scans all Python files in the current directory and subdirectories.

Understanding Flake8 Error Codes

Flake8 categorizes errors by a three-character code. The first letter indicates the tool, and the remaining digits identify the specific rule. Knowing what each code means makes it faster to decide whether to fix the issue or suppress the warning.


# E### — PEP8 style violations (whitespace, imports, line length)
# F### — PyFlakes errors (unused variables, undefined names, shadowing)
# W### — PyFlakes warnings (style preferences)
# D### — Docstring style (missing or malformed docstrings)
# C### — McCabe complexity (functions that are too complex)


E225: missing whitespace around operator
E231: missing whitespace after ','
E302: expected 2 blank lines, found 0
E501: line too long (82 > 79 characters)
F401: imported but unused
F811: redefinition of unused name
F821: undefined name 'something'
W503: line break before binary operator
C901: 'function_name' is too complex (10 > 5)

The E2xx codes cover whitespace and formatting. E501 is one of the most common warnings in older codebases, flagging lines longer than 79 characters as specified in PEP8.

The F4xx codes from PyFlakes are the ones I find most valuable. F401 flags imports that are brought in but never used, and F821 catches references to names that do not exist in the current scope. These are the kinds of bugs that runtime errors are made of if left unchecked.

Configuring and Ignoring Errors in Flake8

For projects where certain checks should be ignored or adjusted, create a configuration section in setup.cfg or pyproject.toml. This lets you set project-wide defaults without passing long command-line arguments each time.


# setup.cfg
[flake8]
max-line-length = 100
exclude =
    .git,
    __pycache__,
    venv,
    build,
    dist
ignore =
    E501,   # line too long — project uses 100 char limit
    D100,   # missing docstring in public module
    D203,   # 1 blank line required before class docstring
per-file-ignores =
    __init__.py: F401
max-complexity = 10


[flake8]
max-line-length = 100
ignore = E501,D100,D203
exclude = .git,__pycache__,venv
per-file-ignores = __init__.py: F401
max-complexity = 10

The max-complexity setting controls McCabe complexity checking. Setting it to 10 means any function with a cyclomatic complexity above 10 will trigger a C901 error. I typically start at 10 and lower it gradually as the team adopts stricter standards.

Sometimes a specific line needs to suppress an error for a legitimate reason. Use the noqa comment at the end of the line to tell Flake8 to skip that check for that line only.


import sys  # noqa: F401  # sys is used for sys.exit in production

def long_function_name(arg1, arg2, arg3, arg4):
    pass  # noqa: E501  # legacy module, refactoring planned


# Running flake8 on the file above produces no output
# Both noqa comments suppress their respective errors on those lines

Using Flake8 with Editors and Other Tools

Running Flake8 manually from the terminal works, but the real productivity gain comes from having it run automatically in your editor. In VS Code, install the Python extension and enable linting with “python.linting.flake8Enabled”: true. Errors appear inline as squiggly underlines, and the Problems panel lists all violations with their codes and file locations.

{
“python.linting.flake8Enabled”: true,
“python.linting.enabled”: true,
“python.linting.flake8Args”: [
“–max-line-length=100”,
“–ignore=E501,D100”
]
}


# VS Code Problems panel after running Flake8:
# file.py(5, 10): F401 'os' imported but unused
# file.py(12, 1): E302 expected 2 blank lines, found 1

In PyCharm, go to Settings, then Tools, then External Tools, and add Flake8 as an external tool. Point it to the flake8 executable in your virtual environment and set the arguments to $FilePath$. You can bind it to a keyboard shortcut for quick access.

Flake8 is one of several linting options in the Python ecosystem. pylint is more thorough and enforces a wider range of style rules but is also slower and noisier by default. Ruff is a newer alternative written in Rust that claims to be 10-100x faster than Flake8 while supporting the same rule sets. Black and isort handle formatting and import sorting respectively, complementing rather than replacing Flake8.


# Install Black for formatting, isort for import sorting, Flake8 for linting
# Each tool does one job well and they compose cleanly
pip install black isort flake8


black .       # Reformats code to match Black's style
isort .       # Sorts and organizes import statements
flake8 .      # Checks for errors and style issues

FAQ

Q: What is the difference between Flake8 and pylint?

pylint is a more comprehensive tool that checks for code correctness, style, and complexity in a single pass. Flake8 focuses on style (PEP8) and common errors (PyFlakes) with a lighter touch and faster execution. pylint produces more detailed reports but has a steeper learning curve and a higher noise floor. Teams often use Flake8 for quick feedback during development and pylint for deeper analysis in CI.

Q: Can Flake8 fix errors automatically?

Flake8 does not modify files. It only reads and reports issues. For auto-fixing style issues, use a formatter like Black which reformats code to match a predefined style. Flake8 and Black complement each other: Black handles formatting, and Flake8 catches logical errors and remaining style issues.

Q: How do I suppress specific error codes in Flake8?

Add an ignore list in setup.cfg under [flake8] or use the –ignore command-line flag. For a specific line, append # noqa: CODE at the end of the line. For example, # noqa: F401 suppresses the unused import warning on that line.

Q: What does the McCabe complexity check measure?

McCabe complexity counts the number of independent paths through a function. A simple function with one if statement has a complexity of 2. Functions with complexity above 10 are generally considered hard to test and maintain. The max-complexity configuration option in Flake8 sets the threshold for triggering a C901 error.

Q: Does Flake8 check for security vulnerabilities?

Flake8 does not specifically check for security issues. It catches common programming mistakes like unused imports, undefined names, and style violations. For security-focused scanning, use a dedicated tool like Bandit, which is designed to detect security issues in Python code.

Share.
Leave A Reply