FormatterHQ

Python Code Formatter

Format Python in the Black code style using the Ruff formatter. Choose line length, indentation and quote style; syntax errors are reported with a line number.

Input PYTHON
Output PYTHON
Ready.

How to use the Python Formatter

  1. Paste your Python code into the Input editor, or use Sample, Upload file or Load URL to load a .py file.
  2. Set Indent (4 spaces per PEP 8), Line width (88 like Black) and Quotes: Double, Single or Preserve.
  3. Press Format. If the code cannot be parsed, the status bar shows the error and its line.
  4. Use Copy or Download above the output panel to take the formatted Python with you.

A Python formatter with Black-compatible output

This Python formatter runs the Ruff formatter, compiled to WebAssembly, directly in your browser. Ruff's formatter was designed as a drop-in replacement for Black, the "uncompromising" formatter adopted by a large part of the Python ecosystem, and produces nearly identical output. You get the same deterministic style Black would give you, without installing anything.

Example

import os,sys
from typing import Optional
def load(path:str,default:Optional[dict]=None)->dict:
  if not os.path.exists(path): return default or {}
  with open(path,encoding='utf-8') as f:
        rows=[l.strip() for l in f if l.strip() and not l.startswith('#')]
  return {k:v for k,v in (r.split('=',1) for r in rows)}
class Config( object ):
  def __init__(self,values={ 'debug':False,'level':3, }):
    self.values=values
import os, sys
from typing import Optional


def load(path: str, default: Optional[dict] = None) -> dict:
    if not os.path.exists(path):
        return default or {}
    with open(path, encoding="utf-8") as f:
        rows = [l.strip() for l in f if l.strip() and not l.startswith("#")]
    return {k: v for k, v in (r.split("=", 1) for r in rows)}


class Config(object):
    def __init__(
        self,
        values={
            "debug": False,
            "level": 3,
        },
    ):
        self.values = values

Indentation became a consistent 4 spaces, the one-line if body moved to its own line, operators and annotations gained PEP 8 spacing, strings switched to double quotes, and top-level definitions are separated by two blank lines. The dictionary in __init__ was exploded one item per line because of the magic trailing comma after 'level':3,.

The magic trailing comma

Black and Ruff treat a trailing comma inside brackets as an instruction: keep this collection expanded, one element per line, even if it would fit on one line. Remove the comma and the formatter joins the elements again when they fit.

colors = [
    "red",
    "green",
]
sizes = ["s", "m"]

The first list had a trailing comma in the input, the second did not. This is the easiest way to control layout without any configuration.

Options explained

  • Indent – 4 spaces is the PEP 8 recommendation and the default. Tabs are available, but PEP 8 advises spaces for new code.
  • Line width – 88 by default, Black's choice: about 10% more than PEP 8's 79 characters, which Black's authors found reduces awkward wrapping. Set 79 for strict PEP 8, or 100–120 if your team prefers.
  • Quotes – Double matches Black. Single prefers '. Preserve leaves each string's quotes as written. In all modes, a string keeps the quote that avoids escaping, so "it's" is never turned into 'it\'s'.

Formatter vs. linter

A formatter only changes layout; it never changes what your program does. That also means it leaves some PEP 8 issues alone:

  • import os, sys stays on one line; PEP 8 prefers separate import lines, a rule enforced by linters such as Ruff's E401 or isort-style import sorting.
  • The mutable default argument values={...} in the example is a classic bug, flagged by linters (flake8-bugbear's B006), but not by a formatter.
  • Unused imports and variables are not removed.

In practice teams run both: the formatter on save, the linter in CI.

Common Python syntax errors

  • "Expected ':'" – a missing colon after if, for, def or class.
  • "Unexpected indentation" / "Expected an indented block" – inconsistent indentation, often from mixing tabs and spaces in pasted code.
  • Unclosed brackets – a missing ) is reported at the end of the file or at the next statement, so look upward from the reported line.
  • Python 2 code such as print "hi" is not valid Python 3 and cannot be formatted.

What is supported

Ruff's parser handles modern Python 3 syntax: f-strings, match statements, walrus :=, type hints with X | Y, async / await, decorators and the type statement. Comments, docstrings and # fmt: off / # fmt: on regions are respected.

Need Python classes for JSON data? JSON to Python generates dataclasses you can format here. For quick one-off snippets in other languages, the Online Code Editor is handy. Your code is formatted locally and never uploaded.

Frequently asked questions

Is this the same as running Black?
The tool uses the Ruff formatter, which is designed to match Black’s style. For the vast majority of code the output is identical; the Ruff documentation lists the few intentional differences.
What line length should I use for Python?
Black and Ruff default to 88 characters. PEP 8 recommends 79 for code and 72 for docstrings and comments, and many teams use 100 or 120. Pick one and use it everywhere.
Why did my list get expanded to one item per line?
It ends with a trailing comma, which Black-style formatters treat as a request to keep the collection expanded. Remove the comma to let the formatter collapse it.
Does the formatter sort imports?
No. Import sorting is a separate lint rule (isort, or Ruff’s I rules). The formatter keeps import order and grouping as written.
Can I stop the formatter touching part of my code?
Yes. Put # fmt: off before and # fmt: on after the region, or add # fmt: skip at the end of a single line.

Last updated September 26, 2026

Related tools