Which Python Code Formatter Works with Python 2 in 2026?
I tried formatting a Python 2.7 codebase with Black last week and got this error:
Error: cannot format legacy_code.py: Cannot parse: 24:7: print "Hello, World!"Wait, what? Black can’t handle print statements? I thought Black was the universal Python formatter.
Turns out, I was using Black 24.3.0 - a version that dropped Python 2 support years ago. Let me save you the hours I spent figuring this out.
The Problem
Python 2 reached end-of-life on January 1, 2020. But here we are in 2026, and I’m still maintaining a Jython project. The codebase works, but it’s messy - inconsistent indentation, mixed import styles, and zero formatting standards.
I just wanted to clean up the code. How hard could it be?
+------------------+-------------------------+----------------------+| Tool | Last Py2 Compatible Ver | Status in 2026 |+------------------+-------------------------+----------------------+| Black | 21.12b0 | Removed in 22.1.0 || autopep8 | < 1.6 | Gradual deprecation || yapf | Current | Still supported || isort | Current | Can format Py2 code || ruff | Current | ~99% compatible |+------------------+-------------------------+----------------------+Trial and Error with Black
First attempt - the obvious choice:
pip install blackblack --target-version py27 legacy_code.pyResult: Failed on Python 2 syntax. The --target-version flag exists, but Black’s parser can’t handle Python 2 code anymore.
Second attempt - pin an older version:
pip install "black<22.0"black --target-version py27 legacy_code.pyThis worked! Black 21.12b0 successfully formatted the file.
But here’s the catch - Black 21.x requires Python 3.6+ to run. So you need a Python 3 environment to format Python 2 code. Not ideal for CI/CD on a Python 2-only system.
The yapf Alternative
Since Black had limitations, I tried yapf (Yet Another Python Formatter):
pip install yapfyapf --in-place legacy_code.pyThis worked immediately. No version pinning, no Python 3 requirement for the runtime. yapf explicitly supports Python 2.7 and 3.4+.
# .style.yapf - custom configuration[style]based_on_style = pep8indent_width = 4column_limit = 79yapf gave me more control. I could choose PEP 8 style, Google style, or customize everything. For a legacy codebase, this flexibility matters - you can match existing code conventions instead of forcing a new style.
autopep8 for PEP 8 Compliance
Next, I tested autopep8:
pip install "autopep8<1.6"autopep8 --in-place --aggressive --aggressive legacy_code.pyThe --aggressive --aggressive flag enables level 2 fixes. autopep8 uses pycodestyle under the hood and fixes most PEP 8 violations.
One thing I noticed - autopep8 is less opinionated than Black. It follows PEP 8 rules rather than making arbitrary decisions about code style. For legacy code, this is often better since it respects existing conventions.
Import Sorting with isort
My codebase had messy imports:
import os,sys,refrom mymodule import somethingimport jsonisort cleaned this up:
pip install isortisort --py 27 legacy_code.pyThe --py 27 flag is crucial. Without it, isort might add Python 3-only imports like from __future__ import annotations.
Result:
import jsonimport osimport reimport sys
from mymodule import somethingisort runs on Python 3 while formatting Python 2 code - perfect for modern CI/CD pipelines.
The ruff Edge Case
Ruff is the new hot formatter - written in Rust, 30x faster than Black. I had to try it:
pip install ruffruff format legacy_code.py99% of the time, it works perfectly. But I hit this edge case:
# ruff formatted this:func( arg1, arg2, **kwargs, # Trailing comma)
# Python 2 syntax error:SyntaxError: invalid syntaxIn Python 2, trailing commas after **kwargs are invalid. Ruff adds them automatically.
The fix is simple - manually remove the trailing comma:
func( arg1, arg2, **kwargs # No trailing comma)For large codebases, this 1% edge case means you’ll need manual review after running ruff.
What I Learned
After testing all these tools on my Jython project, here’s what works:
For Black-style formatting:
pip install "black<22.0"black --target-version py27 legacy_code.pyFor maximum compatibility:
pip install yapfyapf --in-place legacy_code.pyFor import sorting:
pip install isortisort --py 27 legacy_code.pyComplete pre-commit setup for Python 2:
repos: - repo: local hooks: - id: isort-py2 name: isort (Python 2) entry: isort --py 27 language: system types: [python]
- id: yapf-py2 name: yapf entry: yapf --in-place language: system types: [python]Why This Still Matters in 2026
You might ask - why care about Python 2 formatting in 2026?
Legacy systems don’t disappear overnight. Jython enables Python on the JVM, and many enterprises still run Java-based systems where Jython is embedded. Migration timelines extend years beyond initial estimates.
Formatted code is easier to maintain. Consistent style reduces cognitive load. Automated formatting prevents team debates about spacing and quotes.
The tools exist. You just need the right versions.
My Recommendation
For Python 2 projects in 2026:
- Use yapf - most reliable, still officially supports Python 2.7
- Use isort with
--py 27- for import sorting - Avoid Black 22+ - Python 2 support was intentionally removed
- Be careful with ruff - check for trailing commas after
**kwargs
The exact versions matter. Pin them in your requirements.txt:
black<22.0autopep8<1.6yapfisortruffAnd in your pyproject.toml:
[tool.black]line-length = 88target-version = ['py27']required-version = "21.12b0"
[tool.isort]py_version = 27profile = "black"line_length = 88Now I can finally clean up that legacy codebase without syntax errors.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Black Release 22.1.0
- 👨💻 Black FAQ - Python Versions
- 👨💻 isort Configuration
- 👨💻 autopep8 PyPI
- 👨💻 YAPF GitHub
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments