As the name implies, 2to3 gets you from 2 to 3, but it leaves 2 behind entirely which isn't something most people are ready to do (myself included). I'm a fan of trying to run a single codebase that supports 2 and 3, so the method I like is to run 2to3 up front but don't immediately apply the patch it generates. Use that patch as a guide for the area that needs attention, then manually apply changes where the patch points you to and ensure they will work for both versions.
For example, 2to3 changes "print 'hello'" to "print('hello')", but if you need to support 2.4-3.2, you'll need something like "sys.stdout.write('hello')". Even supporting 2.7-3.2, 2to3 will make the same suggestion, but I would add "from future import print_function" at the top in order to function across both versions.
The same goes for imports. "import ConfigParser" will be changed to "import configparser", but what in my case I want...
try:
import configparser
except ImportError:
import ConfigParser as configparser
I've never had much difficulty in porting using this method. It's more work than creating a 3.x branch for your product and just letting 2to3 apply its changes there, but then you have the ongoing maintenance of two separate branches.
For example, 2to3 changes "print 'hello'" to "print('hello')", but if you need to support 2.4-3.2, you'll need something like "sys.stdout.write('hello')". Even supporting 2.7-3.2, 2to3 will make the same suggestion, but I would add "from future import print_function" at the top in order to function across both versions.
The same goes for imports. "import ConfigParser" will be changed to "import configparser", but what in my case I want...
I've never had much difficulty in porting using this method. It's more work than creating a 3.x branch for your product and just letting 2to3 apply its changes there, but then you have the ongoing maintenance of two separate branches.