Fundamentally the issue is that the Python language is too dynamic for static analyzers to fully understand the code and perform conversions. I'm not just talking about type systems, but also monkey patching, reflections, etc.
What we really need is a tool that runs your Python 2 code, records types and other dynamic manipulations, and then produce Python 3 code. But I'm not aware of such a tool.
[1] https://github.com/dropbox/pyannotate [2] https://github.com/instagram/MonkeyType [3] https://github.com/google/pytype
That's a great idea, but it sounds pretty intense to implement. I ended up becoming addicted to ML-family languages pretty early (Scala, F#, OCaml, Rust) for a variety of reasons, but I never fully grasped how much strong/static types help for refactoring until I tried refactoring some Ruby code. I can't imagine trying to write an automated tool for the task.
For example in python 3 they actually made import statements more predictable they are now absolute by default, it was a bit ambiguous in python 2. Ignoring the ambiguity (which is a problem by itself) some people were creative and instead doing standard imports like god intended decided to do it dynamically using importlib, that can't be easily fixed if the file you're importing is a variable.
Another problem: unicode, actually most python 2 code is broken and it can crap out whenever you use characters outside of ascii. That's because it conflates bytes with text, python 3 makes the distinction strict, so you have to properly address it. Though for 99% of application user meant text, so perhaps this assumption could be made?
- division, in python 2 division worked similar to C, if both the parameters were integers you get integer as a result, python 3 changed it to be more what most people would expect, although python 3 also introduced // which had the prior behavior so I guess this could be automated
There are probably others too.
Dropbox's server code base is literally millions of lines of Python 2. The "stop all development" approach simply won't work there. The only thing that works is to port the whole code base to "straddling code" that works on both interpreters, then switch interpreters. Automated tooling to prevent regressions is essential.
People migrate when the allure of Python 3 outweighs the hassle of juggling 2 versions. Naturally, people who grew up on Python 2 are more hesitant than people who started later on Python 3.