Skip to main content
rule

flake8 — Cursor rule: Python linting with PEP 8

A Cursor rule that tells the agent how to configure flake8 and which checks to turn on. Useful when a Python project needs style and bug checks before commit.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/flake8.mdc
Open on GitHub

What flake8 does

The rule treats flake8 as a linter built from three tools: pycodestyle enforces PEP 8, pyflakes catches common bugs, and mccabe measures cyclomatic complexity. Plugins widen the set of checks.

Configuration should live in one place, pyproject.toml at the repository root, instead of .flake8 or setup.cfg. The example sets max-line-length = 88, excludes directories such as venv, migrations and docs, sets max-complexity = 10, and adds per-file-ignores for individual files. Plugins flake8-bandit, flake8-bugbear and flake8-mypy have to be installed first with pip install flake8 flake8-bandit flake8-bugbear flake8-mypy, otherwise the enable-extensions entries do nothing.

The rest covers workflow: run the linter in the IDE on save, wire it into pre-commit before every commit, and make it a required CI step where errors fail the build. A separate section deals with # noqa — suppress checks on a specific line, not across a whole file.

What it helps with

  • catch an unused import before review
  • split an overcomplicated function into smaller ones
  • keep linter config in a single file
  • replace assert with an explicit check in security code
  • block a commit that carries style errors

Example prompts for the agent

  • Set up flake8 for this project with the config in pyproject.toml and a line length of 88
  • Add flake8 to .pre-commit-config.yaml and run it on changed files
  • Walk through the flake8 errors in this file and suggest fixes

How to install flake8

Manually: put the files in place

.cursor/rules/flake8.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about flake8

How do I install the flake8 rule in Cursor?

Copy .cursor/rules/flake8.mdc into the .cursor/rules/ directory of your project. Cursor then applies the rule to files matching **/*.py.

What does this rule do?

It tells the agent how to configure and run flake8: where to keep the config, which checks to enable, how to add plugins, and how to wire the linter into pre-commit and CI.

Which flake8 plugins does it cover?

flake8-bandit for security checks, flake8-bugbear for common design bugs, and flake8-mypy for type checking. You install them with pip and list them under enable-extensions.

Source text

flake8.mdc · CC0-1.0
---
description: This guide provides definitive, actionable best practices for configuring and using flake8 to enforce Python code quality, style, and catch common errors.
globs: **/*.py
---
# flake8 Best Practices

`flake8` is your essential Python linter, combining `pycodestyle`, `pyflakes`, and `mccabe` complexity checks with a powerful plugin ecosystem. It ensures your codebase adheres to PEP 8, catches common bugs, and maintains high quality. This guide outlines the definitive approach to using `flake8` effectively.

## 1. Configuration: The Single Source of Truth

Always configure `flake8` at the repository root using `pyproject.toml`. This centralizes tooling configuration and ensures consistent behavior across all environments. Avoid `.flake8` or `setup.cfg` for new projects.

**✅ GOOD: `pyproject.toml`**

```toml
# pyproject.toml
[tool.flake8]
max-line-length = 88 # Black's default, ensures compatibility
extend-ignore = [
    "E203", # Black compatibility: whitespace before ':'
    "W503", # Black compatibility: line break before binary operator
    "E501", # Ignore line length for specific files/legacy (use sparingly)
]
exclude = [
    ".git",
    "__pycache__",
    "build",
    "dist",
    "venv",
    ".venv",
    "*.egg-info",
    "docs", # Exclude documentation build artifacts
    "migrations", # Django migrations often have long lines
]
max-complexity = 10 # Enforce reasonable function complexity
per-file-ignores = [
    "src/legacy_module.py:E501,F401", # Ignore specific errors in legacy files
    "tests/*:S101", # Allow assert for tests (flake8-bandit)
]
# Enable plugins (install them first: pip install flake8-bandit flake8-bugbear flake8-mypy)
enable-extensions = ["B", "B9", "S", "M"] # Bugbear, Bandit, Mypy
```

**❌ BAD: `.flake8` (Outdated)**

```ini
# .flake8 (Avoid this for new projects)
[flake8]
max-line-length = 88
ignore = E203,W503
exclude = .git,__pycache__,build,dist,venv,.venv,*.egg-info,docs,migrations
max-complexity = 10
```

## 2. Core Checks: What `flake8` Enforces

`flake8` combines `pycodestyle` (PEP 8 style), `pyflakes` (common bugs), and `mccabe` (cyclomatic complexity).

### a. `pycodestyle` (E/W codes) - Style Enforcement

**E501: Line Too Long**
Keep lines concise for readability. Pair `flake8` with `black` or `ruff format` for automatic formatting.

**❌ BAD**

```python
def calculate_complex_value(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10):
    return (param1 + param2) * (param3 - param4) / (param5 + param6) - (param7 * param8) + param9 - param10 # E501
```

**✅ GOOD**

```python
def calculate_complex_value(
    param1, param2, param3, param4, param5,
    param6, param7, param8, param9, param10
):
    intermediate_sum = (param1 + param2) * (param3 - param4)
    intermediate_diff = (param5 + param6) - (param7 * param8)
    return intermediate_sum / intermediate_diff + param9 - param10
```

### b. `pyflakes` (F codes) - Bug Detection

**F401: Unused Import**
Remove unused imports to keep your code clean and prevent circular dependencies.

**❌ BAD**

```python
import os # F401
import sys

def greet(name):
    print(f"Hello, {name}!")
```

**✅ GOOD**

```python
import sys

def greet(name):
    print(f"Hello, {name}!")
```

### c. `mccabe` (C901) - Cyclomatic Complexity

High cyclomatic complexity indicates a function is doing too much. Refactor complex functions into smaller, focused units. Aim for `max-complexity = 10`.

**❌ BAD**

```python
def process_data(data): # C901
    if data is None:
        return None
    if not isinstance(data, list):
        return []
    processed = []
    for item in data:
        if isinstance(item, dict):
            if "value" in item and item["value"] > 0:
                processed.append(item["value"] * 2)
            elif "default" in item:
                processed.append(item["default"])
        elif isinstance(item, int) and item % 2 == 0:
            processed.append(item / 2)
        else:
            processed.append(item)
    return processed
```

**✅ GOOD**

```python
def _process_dict_item(item):
    if "value" in item and item["value"] > 0:
        return item["value"] * 2
    if "default" in item:
        return item["default"]
    return None # Or raise an error, or return original item

def _process_int_item(item):
    if item % 2 == 0:
        return item / 2
    return item

def process_data(data):
    if data is None:
        return None
    if not isinstance(data, list):
        return []

    processed = []
    for item in data:
        if isinstance(item, dict):
            result = _process_dict_item(item)
            if result is not None:
                processed.append(result)
        elif isinstance(item, int):
            processed.append(_process_int_item(item))
        else:
            processed.append(item)
    return processed
```

## 3. Essential Plugins: Extend `flake8`'s Power

Always install and enable these plugins for a robust linting setup.

*   **`flake8-bandit` (S codes)**: Security linter. Catches common security issues.
*   **`flake8-bugbear` (B/B9 codes)**: Catches common "bear" bugs and design problems.
*   **`flake8-mypy` (M codes)**: Integrates `mypy` type checking into `flake8` output.

**Installation:**

```bash
pip install flake8 flake8-bandit flake8-bugbear flake8-mypy
```

**Configuration (already in `pyproject.toml` example):**

```toml
[tool.flake8]
enable-extensions = ["B", "B9", "S", "M"]
```

**Example: `flake8-bandit` (S101 - `assert` statement)**

**❌ BAD**

```python
def check_password(password):
    assert password is not None, "Password cannot be None" # S101
    # ... security checks ...
```

**✅ GOOD**

```python
def check_password(password):
    if password is None:
        raise ValueError("Password cannot be None")
    # ... security checks ...
```

## 4. Workflow Integration: Lint Early, Lint Often

Integrate `flake8` into your development workflow to catch issues as early as possible.

### a. Local Development (IDE Integration)

Configure your IDE (e.g., Cursor, VS Code) to run `flake8` on file save. This provides immediate feedback.

### b. Pre-commit Hooks

Use `pre-commit` to automatically run `flake8` (and formatters like `black` or `ruff format`) before every commit. This ensures no unlinted code ever reaches your repository.

**`pyproject.toml` (or `.pre-commit-config.yaml`)**

```yaml
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/PyCQA/flake8
    rev: 7.0.0 # Use the latest stable version
    hooks:
      - id: flake8
        args: ["--config=pyproject.toml"] # Ensure flake8 uses your pyproject.toml
```

### c. CI/CD Pipelines

Include `flake8` as a mandatory step in your CI pipeline. If `flake8` reports any errors, the build *must* fail. This acts as a quality gate.

## 5. Ignoring Errors: Be Specific, Not Lazy

Only ignore errors when absolutely necessary, and always be specific.

**❌ BAD: Blanket Ignore**

```python
import os, sys # noqa
```

**✅ GOOD: Specific Ignore**

```python
import os # noqa: F401,E402
import sys
```

**✅ GOOD: File-level Ignore (in `pyproject.toml`)**

```toml
[tool.flake8]
per-file-ignores = [
    "src/legacy_module.py:E501,F401",
]
```

## 6. Type Hints: Leverage `flake8-mypy`

While `mypy` is the primary type checker, `flake8-mypy` integrates type checking results into your `flake8` output, providing a unified view of code quality.

**❌ BAD**

```python
def add(a, b): # No type hints
    return a + b
```

**✅ GOOD**

```python
def add(a: int, b: int) -> int: # M501 (flake8-mypy will check these)
    return a + b
```

## 7. Virtual Environments: Isolate Dependencies

Always install `flake8` and its plugins within a project-specific virtual environment. This prevents dependency conflicts and ensures consistent behavior.

```bash
python -m venv .venv
source .venv/bin/activate
pip install flake8 flake8-bandit flake8-bugbear flake8-mypy
```

## 8. Code Organization & Structure

`flake8` indirectly encourages good structure by enforcing PEP 8 and catching issues.

*   **Separate Concerns**: Run `flake8` on `src/` and `tests/` directories. Exclude `docs/` or `migrations/` as needed.
*   **Import Order**: While `flake8` itself doesn't enforce strict import order, `isort` (or `ruff format`) does. Pair `flake8` with `isort` for this.
    *   Standard library
    *   Third-party
    *   Local application
*   **Avoid Circular Dependencies**: `pyflakes` (part of `flake8`) will warn about these.

## 9. Common Pitfalls & Gotchas

*   **Outdated Configuration**: Always use `pyproject.toml`.
*   **Ignoring too much**: A long `ignore` list hides real issues. Fix the code, don't ignore the linter.
*   **Not running `flake8` everywhere**: Ensure `flake8` runs on all relevant Python files (`src`, `tests`).
*   **Mixing `flake8` with `black` without `E203, W503` ignores**: This will lead to conflicts. Always configure `flake8` for `black` compatibility.

By following these guidelines, your team will maintain a consistent, high-quality Python codebase, reducing technical debt and improving collaboration.

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Similar IDE rules

All IDE rules for Programming languages →

From the same set69

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor