Python 2 → Python 3
Python 2.7 is end-of-life. Moving to Python 3 is a high-risk legacy modernization dominated by the unicode/bytes split, print as a function, true division, and changed exception/iteration syntax.
Last verified · Updated May 22, 2026
Python 2.7 is end-of-life, so this is a security-driven, high-risk migration. The mechanical changes (print, exception syntax, iteritems, xrange) are automatable; the unicode/bytes split is where the real work and risk live.
Should you upgrade directly?
Yes — there is no intermediate version. Move from 2.7 straight to a supported Python 3 (target 3.12), but do it on a branch with a green test suite as the safety net, and consider running a 2-and-3 compatible interim state via six/__future__ for very large codebases.
Key differences
- print is a function; wrap every print statement.
- from __future__ import division/print_function eases the interim state.
- True division: 5 / 2 == 2.5; use // where integer division was intended.
- Strict unicode/bytes split — decide encoding explicitly at every I/O boundary.
- except Foo as e replaces except Foo, e.
- dict.iteritems/iterkeys/itervalues and xrange removed; six normalizes these.
Files and patterns to inspect
- Modules using print as a statement.
- Code relying on integer division semantics of /.
- String handling that mixes str/unicode/bytes or opens files in text vs binary mode.
- except Foo, e: exception syntax.
- dict.iteritems/iterkeys/itervalues, xrange, and has_key usage.
# Bridge 2 and 3 in one codebase before fully cutting over
from __future__ import print_function, division, unicode_literals
import six
for key, value in six.iteritems(mapping):
print(key, value)Pre-migration checklist
- Green test suite on Python 2.7
- Dependencies confirmed to have Python 3.12-compatible releases
- A dedicated upgrade branch and reproducible venv
A bytes/str fix that passes on ASCII fixtures can still corrupt or crash on real non-ASCII input. Add tests with non-ASCII data before changing encoding boundaries.
Related paths
Official sources
Backs the breaking-change and migration-step claims.
Backs the breaking-change and migration-step claims.
Copy-ready AI prompts
Structured prompts for an AI coding assistant. Inspect first, then execute incrementally, and keep a human in the review loop.
You are helping migrate a Python codebase from Python 2 to Python 3. Do not edit files yet. First inspect the repository and report: 1. The exact Python version requirement in setup.py / pyproject.toml / tox.ini / CI config, and the interpreter the project runs on. 2. Python 2-only syntax: print statements, integer-division reliance, except Foo, e: syntax, dict.iteritems/iterkeys/itervalues, xrange, and unicode/str/bytes confusion. 3. Removed/deprecated module usage: distutils, imp, and deprecated collections ABC aliases (collections.Mapping etc.). 4. The dependency manifest (requirements.txt vs lock vs pyproject), any C-extension builds, and pinned versions. 5. The test runner, virtualenv/venv setup, and the install/build/test commands. Return: a migration risk summary, the files most likely to break, a suggested migration order, the commands to run before editing, and any questions that need human confirmation.
Safety: Inspection only. The agent must not modify files in this step.
Works with Claude Code, Cursor, GitHub Copilot
Migrate this codebase from Python 2 to Python 3, one concern at a time. Work in this order and pause for review after each: (1) create and activate a fresh virtualenv/venv on the target interpreter, (2) run an automated pass with python -m future.utilities futurize (or 2to3) and review the diff, (3) replace removed/deprecated modules (distutils -> setuptools/pyproject, imp -> importlib, collections ABC aliases), (4) fix unicode/bytes boundaries explicitly, (5) reinstall dependencies and resolve pip resolver conflicts. After each step run pip check and the project's lint and tests, and report results before continuing. Do not refactor unrelated code.
Safety: Apply changes incrementally and keep each step reviewable. Never bundle unrelated refactors.
Works with Claude Code, Cursor, GitHub Copilot
Test plan
Commands
python -m venv .venv && . .venv/bin/activatepip install -e .pip checkpython -m pytest -q
Manual checks
- Text/bytes: confirm file and network I/O encode/decode explicitly and round-trips.
- Division: verify code that relied on Python 2 integer division still produces expected results.
- C extensions: confirm any compiled dependencies build against the target interpreter.
Regression risks
- Silent behavior change from true division replacing integer division.
- Bytes/str mix-ups surfacing only at runtime on non-ASCII input.
- C-extension dependencies without wheels for the target interpreter.
Acceptance criteria
- pip check reports no broken requirements and pytest passes on the target version.
- No imports of distutils, imp, or deprecated collections ABC aliases remain.
- All dependencies resolve to versions supporting the target Python.
Frequently asked questions
Can I skip straight to Python 3 from 2.7?
Yes — there is no intermediate Python between 2.7 and 3. For very large codebases, run a transitional 2-and-3 compatible state using __future__ imports and six before fully dropping Python 2.
Is 2to3 enough on its own?
No. 2to3 (and futurize) handle the mechanical syntax, but the unicode/bytes split, integer-division assumptions, and C-extension compatibility need human review and tests.