Python Code Formatter
Clean up Python source: normalize existing indentation to a consistent width, tidy comma/operator spacing, collapse long blank-line runs, and trim trailing whitespace — without touching triple-quoted strings, f-strings, or comments.
Input
Formatting Options
Output
Guides
Paste messy Python and get back cleaner, more consistent source — instantly, in your browser. The Python Code Formatter normalizes indentation to a consistent width, tidies spacing around commas and operators, collapses long runs of blank lines, and trims trailing whitespace, without touching the content of strings, f-strings, or comments.
An important honesty note
This tool is a whitespace/style normalizer, not a full PEP 8 or Black-equivalent formatter. In a brace-based language (Java, PHP, JavaScript...), a formatter can safely re-derive indentation from scratch by counting {/} pairs — brace depth is block structure. Python has no braces: indentation itself is the block structure. Rebuilding it correctly from nothing needs a real parser — get it wrong and you don't just misalign a line, you can change which lines belong to which block.
So instead of guessing new block structure, this tool takes the indentation you already wrote and remaps it onto a consistent depth, the same "INDENT/DEDENT" technique CPython's own tokenizer uses: it walks your existing indentation as a stack of levels and re-emits each level at your chosen width, even if the file mixes 2-space, 4-space, and tab indentation, or grows each nested level unevenly. It never invents an indent level that wasn't already present.
How to use it
- Paste your Python source, or upload a
.pyfile. - Pick your Indent width (2, 4, or 8 spaces, or tabs — 4 spaces is the PEP 8 default).
- Toggle Normalize comma & operator spacing and Normalize blank lines to taste.
- Copy the result, or download it as
formatted.py.
Formatting runs automatically as you type or change an option.
What it normalizes
- Indentation, remapped as described above. Lines inside an open
(/[/{or after a trailing\continuation are left exactly as authored — that's your own alignment choice, not a block boundary. - Comma spacing — no space before, exactly one space after.
- Operator spacing — an unambiguous set gets forced single-space padding:
==,!=,<=,>=,->,:=, and the augmented-assignment operators (+=,-=,*=,/=,//=,%=,**=,&=,|=,^=,>>=,<<=). - Blank lines — runs of 3+ collapse to 2.
- Trailing whitespace — stripped from every code line.
What it deliberately leaves alone
- A bare
=. Telling an assignment (x = 1, wants spaces) from a keyword argument or default (f(x=1), must stay tight) requires knowing whether you're inside a call ordefsignature — exactly the parsing this tool avoids. Your=spacing passes through unchanged. - Quote style, import sorting, and line wrapping — all three need real semantic understanding to do without risking corrupting meaning.
- Anything inside a string. Triple-quoted strings (
'''...'''/"""...""") are preserved byte-for-byte — including internal indentation, blank lines, and trailing spaces — since they're often used for exact-format text like docstring examples. F-string{expr}interpolation is treated as opaque and never reformatted. - Comment text itself — only the whitespace before a
#is touched; everything from#onward is copied through verbatim.
Is it the same as Black or autopep8?
No. Black and autopep8 parse Python into a real syntax tree, so they can safely rewrap lines, normalize quotes, and rebuild indentation from nothing. This tool works on text and existing whitespace — a fast, dependency-free cleanup for pasted snippets or generated code with inconsistent indentation, not a replacement for your project's formatter in CI.
Is my code private?
Completely. All formatting happens locally in your browser. Your source is never sent to a server, logged, or stored.
Does it handle f-strings and decorators?
Yes. F-strings (any prefix combination, like rf or Fr) are tokenized as whole strings, so their content — including {expr} interpolation — is never touched. Decorators (@decorator) and block-opening colons (if x:, def f():) need no special handling: they're ordinary code whose indentation is carried by the same depth-remapping as everything else.