Moving EVE Online's 2.4 Million Lines to Python 3

EVE Online begins migrating its 23-year-old Python 2 codebase to Python 3 using a dual-compatibility stage that keeps Tranquility running while automated syntax fixes clear the way for the harder semantic review.

Moving EVE Online's 2.4 Million Lines to Python 3

The hard part of EVE Online’s Python 2-to-3 migration isn’t the syntax differences — it’s the roughly 20,000 lines that parse correctly under both versions but produce different results, where those results might be damage values, ISK amounts, or coordinate offsets.

Source

The Move to Python 3 Begins!

By: EVE Online Team (Fenris Creations)
Published: Aug 25 2026
Type: Engineering update

Few migration write-ups involve 23 years of live player data and a server running 23.75 hours a day. The stage-by-stage approach here is worth understanding as a pattern for any large-scale runtime migration.

Stage-by-Stage Migration Under Live Load

EVE Online launched in 2003 on Stackless Python, a variant of CPython that replaced the standard call stack with lightweight tasklets — cooperative threads that let a single server node manage thousands of concurrent connections without preemptive scheduling overhead. The game upgraded to Stackless 2.5 in 2007 and Stackless 2.7 in 2010, then held that version for 16 years. Python 2.7 reached official end-of-life in 2020, but for EVE the migration risk was never justified until the compound cost of staying — losing access to modern libraries, debuggers, and profilers; maintaining tooling the rest of the ecosystem had abandoned — finally outweighed the risk of touching 23 years of accumulated code.

The codebase is 2.4 million lines across approximately 20,000 Python files, some of it written to Python 2.3-era standards that Python 3 refuses to parse at all. The first step was measurement: scan every file against both a Python 2.7 and a Python 3 interpreter and count the blockers. The result was unexpectedly good. 95.9% of files already compiled under both versions. The remaining ~3,300 blocking lines broke into four categories: roughly 1,500 old-style print statements, 800 integer literals with an L suffix (the Python 2 long integer marker), 600 exception clauses using deprecated syntax, and 50 uses of <> as the not-equal operator — a construct so old that most active Python developers have never seen it.

Stage 1 uses Python-Future, a library built on top of 2to3 (the migration tool Python’s own project shipped to help exactly this kind of transition), to automatically rewrite these patterns into forms that are valid under both Python 2.7 and Python 3. The critical constraint is that Stage 1 code continues running in production on Python 2.7. The runtime doesn’t flip until the entire codebase is clean on both. This is the standard dual-compatibility pattern for large-scale migrations: decouple the parseable step from the behaviorally identical step, and never switch runtimes before verifying the first.

Stage 2 is where human judgment is required. Those ~20,000 lines that compile correctly under both versions but behave differently each need a developer decision. The canonical example is integer division: 1 / 2 equals 0 in Python 2 but 0.5 in Python 3. In EVE, those values could be damage multipliers, skill point curves, market price rounding, or coordinate math. There is no automated fix for ambiguity about intent. Stage 1’s job is to clear every line that can be fixed mechanically so that Stage 2 review budget goes only to lines where behavior actually changes — that’s not a secondary benefit of the ordering, it’s the primary reason for it.

The existence proof that the migration is achievable is EVE Frontier, Fenris Creations’ other title, which already runs the Carbon engine on Python 3. Frontier’s migration covered 12 minor Python versions in a single project — 16 years of language evolution at once. Tranquility has more accumulated code and 23 years of real player history that must survive intact, but the engine has made the journey before.

The payoff compounds rather than arriving immediately. Recent Python 3 releases have delivered some of the largest interpreter speedups in the language’s history, which over time opens the door to better performance under fleet fights and market load. Modern libraries, debuggers, and profilers reduce internal maintenance work. New developers joining the team can work in a language version they actually know. None of these materialise in Stage 1 — they’re the infrastructure investment that pays out over the next decade, which is what makes this the kind of migration that’s easy to keep deferring until the deferral itself becomes the risk.

What I want to remember

Remember: The dual-compatibility strategy — make all code parseable by both Python 2.7 and 3 before flipping the runtime — separates mechanical syntax fixes from semantic review, keeping human attention only for the ~20,000 lines where behavior actually differs.