See IPEP 4: Python 3 Compatibility.
[Meta] Python 2 and 3 compatibility without 2to3... "2and3"
We've discussed using a Python 2 & 3 compatible syntax in our source in the past, and have included changes from several of the 2to3 fixers. C.f.,
With the release of Python 3.3 in the next few days (which again allows unicode literals u"..."), porting our code to a jointly compatible syntax should be more feasible.
Now there are some headaches, but they all can be worked around. I've been playing with this on a branch bfroehle/py3k but it's an ugly mess at the moment.
If we are going to seriously consider this undertaking, I think we should first agree upon the parameters and break the process up into a lot of smaller chunks. In addition, since these changes will possibly conflict with existing pull requests, we should probably also decide on appropriate timing.
I expect this proposal to be rather controversial, so let me attempt to outline exactly what would be required... it's probably more than you expect.
The Bite-Sized Pieces
- six: Take much of the
six module and add it to IPython.utils.py3compat. Or decide to abandon part of py3compat and just ship a copy of six.
- exec: In Python 3 exec becomes a function. This necessitates replacing each call
exec code in globals, locals with exec_(code, globals, locals) where exec_ is a wrapper defined in six.
- execfile: Add a Python3 compatible definition of
execfile in ipython.py
- long: Replace long literals (
0L) with explicit calls to long (long(0)) or decide if the literal was actually necessary in the first place.
- dict: Apply the 2to3
dict fixer (iteritems -> items, etc) with a lot of manual oversight.
- print: Apply the 2to3
print fixer. (This is already partially applied).
- import: Apply the 2to3
import fixer to differentiate between absolute and relative imports.
- funcattrs: Workaround changes to attribute names on function objects (
f.func_code -> f.__code__), possibly by getattr(f, _func_code) where _func_code is defined in six or py3compat.
- imports: The builtin module was renamed from
__builtin__ to builtins. In addition many other modules were renamed (cPickle -> pickle, StringIO.StringIO -> io.StringIO, ConfigParser.ConfigParser -> configparser.ConfigParser, urllib2, etc). This means lots of try: import ...; except ImportError: ... or perhaps using six.moves.
- unicode/basestring:
unicode and basestring no longer exist. Use compatibility wrappers from six. Also functions like os.getcwdu are just os.getcwd now. Lastly, raw unicode strings are not allowed, but this can be worked around like u'' + r'...'
- metaclasses: The method to indicate a metaclass has changed. The 2and3 compatible syntax is obscure, but easy... just call the metaclass directly to instantiate the class (
_FormatterABC = abc.ABCMeta("_FormatterABC", (object,), {}))
- reraise: The method of raising an exception with a traceback changed. Use
six.reraise.
A taste (Python 2.7 & Python 3.3)
The following snippet shows me running ipython in Python 2.7 and 3.3 with the same source:
[bfroehle@highorder ipython (py3k)]$ python ipython.py
Python 2.7.3 (default, Aug 1 2012, 05:14:39)
Type "copyright", "credits" or "license" for more information.
IPython 0.14.dev -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: quit
[bfroehle@highorder ipython (py3k)]$ python3 ipython.py
WARNING: IPython History requires SQLite, your history will not be saved
Python 3.3.0rc3 (default, Sep 27 2012, 08:35:53)
Type "copyright", "credits" or "license" for more information.
IPython 0.14.dev -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: quit
See IPEP 4: Python 3 Compatibility.
[Meta] Python 2 and 3 compatibility without 2to3... "2and3"
We've discussed using a Python 2 & 3 compatible syntax in our source in the past, and have included changes from several of the
2to3fixers. C.f.,except)apply,repr)nextfix. #2134 (next)has_keyfixer. #2140 (has_key)With the release of Python 3.3 in the next few days (which again allows unicode literals
u"..."), porting our code to a jointly compatible syntax should be more feasible.Now there are some headaches, but they all can be worked around. I've been playing with this on a branch bfroehle/py3k but it's an ugly mess at the moment.
If we are going to seriously consider this undertaking, I think we should first agree upon the parameters and break the process up into a lot of smaller chunks. In addition, since these changes will possibly conflict with existing pull requests, we should probably also decide on appropriate timing.
I expect this proposal to be rather controversial, so let me attempt to outline exactly what would be required... it's probably more than you expect.
The Bite-Sized Pieces
sixmodule and add it toIPython.utils.py3compat. Or decide to abandon part ofpy3compatand just ship a copy ofsix.exec code in globals, localswithexec_(code, globals, locals)whereexec_is a wrapper defined insix.execfileinipython.py0L) with explicit calls to long (long(0)) or decide if the literal was actually necessary in the first place.dictfixer (iteritems->items, etc) with a lot of manual oversight.printfixer. (This is already partially applied).importfixer to differentiate between absolute and relative imports.f.func_code->f.__code__), possibly bygetattr(f, _func_code)where_func_codeis defined insixorpy3compat.__builtin__tobuiltins. In addition many other modules were renamed (cPickle->pickle,StringIO.StringIO->io.StringIO,ConfigParser.ConfigParser->configparser.ConfigParser,urllib2, etc). This means lots oftry: import ...; except ImportError: ...or perhaps usingsix.moves.unicodeandbasestringno longer exist. Use compatibility wrappers fromsix. Also functions likeos.getcwduare justos.getcwdnow. Lastly, raw unicode strings are not allowed, but this can be worked around likeu'' + r'...'_FormatterABC = abc.ABCMeta("_FormatterABC", (object,), {}))six.reraise.A taste (Python 2.7 & Python 3.3)
The following snippet shows me running
ipythonin Python 2.7 and 3.3 with the same source: