8. Only support Python 3
● For end-user software and systems
● Run 2to3 once
● Then fix the code until it works.
9. Separate trees
● For stable Python libraries
● Make a branch or copy
● Run 2to3 once
● Fix until it works
● Bug fix both trees
10. How to distribute
Include both src2/ and src3/ and have different
parameters for different Python versions:
import sys
from distutils.core import setup
if sys.version < '3':
package_dir = {'': 'src2'}
else:
package_dir = {'': 'src3'}
setup(name='foo',
version='1.0',
package_dir = package_dir)
11. Continuous conversion with 2to3
● If you need to support Python 2 and Python 3
and the code is changing a lot
● Keep developing in Python 2
● Convert to Python 3 for testing and install
● Compatibility hacks may be needed
● Distribute helps
12. Single code base; no conversion
● If 2to3 for some reason is infeasible
● Support Python 2 and Python 3 from the
same code without 2to3
● Loads of compatibility hacks
● Fun, but ugly!
● Adding Python 2 support to Python 3 is often
less work than the other way around
● Check out six
13. Try with 2to3 first!
● Run 2to3 to see if it changes much
● If in doubt use Distribute!
14. When?
● For end-user systems: When you feel like it
● Not a good thing to do the week before
deployment
● Your customers want Python 3!
● For libraries: As soon as you can
● I.e. when your dependencies runs on Python 3
23. Use rich comparison methods
● No support for __cmp__ in Python 3
● Use rich comparison operators instead:
__lt__, __le__, __eq__,
__ge__, __gt__, __ne__
● Not entirely trivial to implement
● The @totalordering recipe is WRONG!
24. My mixin
class ComparableMixin(object):
def _compare(self, other, method):
try:
return method(self._cmpkey(), other._cmpkey())
except (AttributeError, TypeError):
# _cmpkey not implemented, or return different type,
# so I can't compare with "other".
return NotImplemented
def __lt__(self, other):
return self._compare(other, lambda s, o: s < o)
def __le__(self, other):
return self._compare(other, lambda s, o: s <= o)
def __eq__(self, other):
return self._compare(other, lambda s, o: s == o)
def __ge__(self, other):
return self._compare(other, lambda s, o: s >= o)
def __gt__(self, other):
return self._compare(other, lambda s, o: s > o)
def __ne__(self, other):
return self._compare(other, lambda s, o: s != o)
44. Workaround for except:
● Python 2:
except Exception, e:
● Python 3:
except Exception as e:
● Python 2.6 and 2.7 handles both
● Python 3 and Python <= 2.5:
except Exception:
e = sys.exc_info()[1]
45. Workaround for print()
● For simple print cases:
print(“Something”) works everywhere.
print(“Something”, “else”) doesn't.
● Use print_() from the six module
● Or make your own
52. Writing your own fixers
● If you must modify the API
● Can be very complex due to edge cases
● Requires a whole talk by itself
53. 2 * 3 = Six
● A module to help with compatibility
● Several compatibility methods:
● b() and u()
● print_()
● etc...
● Tons of helpful constants:
● integer_types
● string_types
● etc...
54. Additional Resources
● http://docs.python.org/py3k/howto/pyporting.html
● http://wiki.python.org/moin/PortingToPy3k/
● python-porting@python.org
● “Porting to Python 3”
● I'll be sprinting, come and ask!