First, I'd recommend python-future rather than 2to3, it has additional fixers and replaces some with better versions.
Second, those only do the fairly straightforward changes, fixers are simple AST transformations they don't do complex type analysis or anything, you should use them as a starting point but don't expect the work to be over by then: the 2->3 transitions has a number of API and semantics changes which these tools can't handle, text model changes are the biggest one[0] but they're not the only one by far.
If the project is non-trivial, having a good test coverage is absolutely crucial.
Basically, 2to3 handles the first 90% of the work which are mostly drudgery and syntactic fixes, you're still on the hook for the second 90% which is more subtle.
Source: finalising the conversion of a ~200k SLOC codebase to cross-version compatibility.
[0] not just the strict separation of text and bytes, but APIs being set to one or the other so you have places where you want to ensure bytes, others where you want to ensure text and yet others where you need "native strings", some APIs (csv) are also incompatibly altered.
Lots of people mention strings, but for a concreteish example: you have some code which reads bytes from the network, say "cookie", and uses that as a key into a dict. Later you try to access the stored value with headers["cookie"].
This works in python 2. It silently fails in python 3 because b"cookie" and "cookie" are different keys. Not really related to whether the original code supported Unicode or not.