There's things that are tricky, don't get me wrong: unicode handling can be tricky, though six.ensure_str/bytes usually allows you to defer that problem. Futurize and 2to3 do so much of the work that in my experience the majority of files can be migrated by automation, unicode warts included.
The hard stuff is when you have extension modules or weird metaprogramming stuff (there's also one particular case I had to deal with around code generation). That takes effort to migrate, but it's the long tail.
If you need to rewrite your code to enable the py3 transition, the issue isn't python, it's your coding choices, and you should rewrite your code anyway.