Below are some tips for those interested in writing code that runs on Python 2 and Python 3 -- there are probably many other issues, but those were the ones I ran into while porting the code-completion code in Pydev (so, there's probably going to be a part 2 of this when I go on to port the debugger)
0. This may be one of the most important advices: breathe regularly while doing the porting... and be prepared to have uglier code waiting for you if you want to support both Python 2 and Python 3 -- if you do have a choice, don't try to support both versions of Python -- the way Python 3 is implemented, no one's supposed to do that.
1. Print can NEVER be used (use the write() method from objects or create your own print function -- with a different name and use it everywhere)
2. Catching exceptions putting the exception in a given var can NEVER be used (there's no compatible way of doing it in a way that's acceptable in both versions, so, just deal with it as you can using the traceback module)
3. socket.send needs bytearray: socket.send(bytearray(str, 'utf-8'))
4. socket.receive gets bytes (so, they need to be decoded: socket.recv(size).decode('utf-8')
5. Some imports:
import io as StringIO #Python 3.0
from urllib import quote_plus, unquote_plus
from urllib.parse import quote_plus, unquote_plus #Python 3.0
import builtins as __builtin__ #Python 3.0
There are way too many others, so, the approach for getting it right is basically running the 2to3 with that import to see the new version of it and then making it work as it used to.
6. True, False assign: in some scripts, to support older python/jython versions, the following construct was used:
__builtin__.True = 1
__builtin__.False = 0
As True and False are keywords now, this assignment will give a syntax error, so, to keep it working, one must do:
setattr(__builtin__, 'True', 1) -- as this will only be executed if True is not defined, that should be ok.
7. The long representation for values is not accepted anymore, so, 2L would not be accepted in python 3.
The solution for something as long_2 = 2L may be something as:
long = int
long_2 = long(2)
Note that if you want to define a number that's already higher than the int limit, that won't actually help you (in my particular case, that was used on some arithmetic, just to make sure that the number would be coerced to a long, so, that solution is ok -- note: if you were already on python 2.5, that would not be needed as the conversion int -> long is already automatic)
8. raw_input is now input and input should be written explicitly as eval(raw_input('enter value'))
So, to keep backwards compatibility, I think the best approach would be keeping on with the raw_input (and writing the "old input" explicitly, while removing the "new input" reference from the builtins)
original_input = builtins.input
def raw_input(*args, **kwargs):
return original_input(*args, **kwargs)
builtins.raw_input = raw_input
9. The compiler module is gone. So, to parse something, the solution seems to be using ast.parse and to compile, there's the builtins.compile (NOTE: right now, the 2to3 script doesn't seem to get this correctly)