Python code cleaner — fix mixed tabs and uneven indentation

Paste Python code and this cleaner re-indents every block to 4 or 2 spaces, trims trailing spaces and caps blank lines, without touching anything else in the code.

Live demo · real result from this tool
Indent

Cleaned Python

def total(items):    result = 0    for item in items:        if item.get("price"):            result += item["price"] * item.get("qty", 1)      return result  class Cart:    def __init__(self):        self.items = [] 
Lines re-indented7

Re-indents by the existing block structure (tabs count as 8 columns, as in Python), trims trailing whitespace and limits blank lines. It does not wrap lines or change quotes like Black does.

Processed on your device — nothing is uploaded.

How to use the Python code cleaner

  1. Paste your code into the Python box. The sample mixes tab and 2-space indentation on purpose.
  2. Choose the Indent: 4 spaces (PEP 8) or 2 spaces.
  3. Set Max blank lines in a row (0–5, default 2).
  4. Read the Cleaned Python and the Lines re-indented count, then copy it or download cleaned.py.

What it does and when to use it

Python treats indentation as syntax, so a file that mixes tabs and spaces, or 2- and 4-space blocks, can fail with TabError or behave in ways that are hard to see. Code pasted from forums and old scripts often has this problem. The cleaner turns all of it into one clean step size without changing a single statement.

To see exactly what moved, paste the before and after into the code diff viewer. For tab-to-space jobs in other languages, the indentation converter works line by line, and the code beautifier re-indents Python alongside many other languages.

How it works

The cleaner reads your code line by line and keeps a stack of the indent widths it has seen:

  1. Each line’s leading whitespace is measured, with a tab moving to the next multiple of 8.
  2. Deeper than the top of the stack: a new block starts. Shallower: levels are closed until one matches exactly, or the IndentationError message appears.
  3. The new indent is the block depth times your chosen size.
  4. A small scanner follows strings, comments and brackets, so triple-quoted text is copied unchanged and continuation lines keep their offset.

Trailing spaces are trimmed, blank lines over the limit are dropped and the file ends with one newline. Everything runs in your browser.

Worked examples

These are the tool’s own outputs with the default settings.

A 2-space function.

def area(w, h):
  if w <= 0:
      return 0   
  return w * h

becomes

def area(w, h):
    if w <= 0:
        return 0
    return w * h

with Lines re-indented: 3, and the spaces after return 0 removed.

A bad dedent. In if a: / x = 1 / y = 2, the last line sits at column 2, which matches no block. The result is “Line 3: this line’s indentation does not match any outer block (Python would raise IndentationError).”

A dictionary over several lines. data = { followed by items indented 8 spaces, then } and x=1, comes back unchanged: bracket contents keep their layout, and x=1 is not re-spaced.

Limits and tips

  • Only whitespace changes. x=1;y = [1,2] stays exactly as written.
  • Tabs mean 8 columns. In a file that mixes tabs and spaces, a tab line and a 4-space line are different levels, just as Python sees them. If you get an error you did not expect, look for a mixed line there.
  • Long lines are not wrapped. Use Black, Ruff or autopep8 for full PEP 8 formatting.

Frequently asked questions

Is this the same as Black or autopep8?
No. It changes only indentation, trailing whitespace and the number of blank lines in a row. It does not wrap long lines, add spaces around operators, change quote style or sort imports. Run Black or Ruff in your project for that.
How does it decide the indent level of each line?
It follows the block structure that is already there. A line indented deeper than the line before opens a new level; a shallower line must line up with an earlier level. Tabs count as 8 columns, the same rule Python's tokenizer uses.
Why do I get an IndentationError message?
A line dedents to a column that matches no outer block, so Python itself would refuse the file. The tool names the line instead of guessing what you meant. Fix that line and try again.
Are strings and comments safe?
Yes. Lines inside triple-quoted strings are kept exactly, tabs included. Comment lines are re-indented to the level of the code around them, and the text after # is not changed.

Written by the ToolsRift team · Last updated

Pages are drafted with AI assistance and checked by automated tests. How we write and check pages.

Was this tool useful?

Report a problem

Start typing to search every tool.

↑ ↓ to moveEnter to openEsc to close