3

Differences between revisions 1 and 12 (spanning 11 versions)
Revision 1 as of 2012-04-19 16:50:35
Size: 1403
Editor: barry
Comment:
Revision 12 as of 2012-04-23 18:09:13
Size: 8122
Editor: barry
Comment:
Deletions are marked like this. Additions are marked like this.
Line 7: Line 7:
== Before you start ==

Here are recommendations for you to follow before you start porting.

 * Target Python 3.2, 2.7, and optionally 2.6. Ignore anything older than that.
 * Use a single code base for both Python 2 and 3.
 * Do not rely on [[http://docs.python.org/py3k/library/2to3.html|2to3]] or the third party [[http://pypi.python.org/pypi/six|six]] module (the latter, only if absolutely necessary)
 * Modernize your Python 2 code first, getting it working in Python 2.7 before starting to port.
 * Clarify your data model: what are bytes (data) and what are strings (text)?

I cannot overemphasize the last point. Without a clear separation in your mind and data model between bytes and strings, your port will likely be much more painful than it needs to be. This is the biggest distinction between Python 2 and Python 3. Where Python 2 let you be sloppy, with its 8-bit strings that served as both data and ASCII strings, with automatic (but error prone) conversions between 8-bit strings and unicodes, in Python 3 there are only bytes and strings (i.e. unicodes), with no automatic conversion between the two. This is A Good Thing.

== Python source ==

=== Basic compatibility ===

Put the following at the top of all your Python files:

{{{
from __future__ import absolute_import, print_function, unicode_literals
}}}

This turns on three important compatibility flags.
 * Absolute imports are the default in Python 3 [[http://python3porting.com/differences.html#imports|[more info]]]
 * {{{print()}}} is a function in Python 3 [[http://python3porting.com/noconv.html#print-section|[more info]]]
 * Unadorned string literals are unicode type in Python 3 [[http://python3porting.com/problems.html#binary-section|[more info]]]

In your code, make these changes:
 * Change all your {{{print}}} statements to use {{{print()}}} functions, and remove all the {{{u''}}} prefixes from your strings.
 * If you have string literals in your code that represent data, prefix them all with the {{{b''}}} prefix [[http://python3porting.com/problems.html#byte-literals|[more info]]]
 * Remove all {{{L}}} suffixes from your long integers. [[http://python3porting.com/differences.html#long|[more info]]]

=== built-ins ===

 * Change usage of {{{xrange()}}} to {{{range()}}}. [[http://python3porting.com/differences.html#filter-map-range-and-xrange|[more info]]]

=== dictionaries ===

 * Change all your uses of the dictionary methods {{{iteritems()}}}, {{{iterkeys()}}}, and {{{itervalues()}}} to use the non-{{{iter}}} variety, e.g. {{{items()}}}, {{{keys()}}}, and {{{values()}}} respectively. These return dictionary views in Python 3, not concrete lists, so if you need a concrete list, wrap these calls in {{{list()}}} or {{{sorted()}}}. [[http://python3porting.com/differences.html#index-6|[more info]]]

=== iterators ===

 * Change your iterator classes from providing a {{{next()}}} method to providing a {{{__next__()}}} method. For cross-compatibility, in your class, set {{{next = __next__}}}. [[http://python3porting.com/differences.html#next|[more info]]]

=== operators ===

 * Python 3 has no {{{operator.isSequenceType()}}}. Use the following code for cross-compatibility.

{{{
def is_sequence(obj):
    try:
        from collections import Sequence
    except ImportError:
        from operator import isSequenceType
        return operator.isSequenceType(obj)
    else:
        return isinstance(obj, Sequence)
}}}

=== Metaclasses ===

 * Syntax for creating instances with different metaclasses is very different between Python 2 and 3. Use the ability to call {{{type}}} instances as a way to portably create such instances. [[http://cgit.freedesktop.org/dbus/dbus-python/tree/dbus/gobject_service.py|[example]]]

== Python extension modules ==

 * Define a {{{PY3}}} macro which you can later {{{#ifdef}}} on for C code which cannot be written portably for both Python 2 and Python 3. [[http://cgit.freedesktop.org/dbus/dbus-python/tree/include/dbus-python.h#n35|[example]]]

=== Compatibility macros ===

 * The {{{PyInt_*}}} functions are gone in Python 3. In your extension module, change all of these to {{{PyLong_*}}} functions, which will work in both versions. [[http://python3porting.com/cextensions.html#changes-in-python|[more info]]]
 * {{{#include <bytesobject.h>}}} and change all {{{PyString_*}}} functions with their {{{PyBytes_*}}} equivalents, changing those that really operate on unicodes to use {{{PyUnicode_*}}} functions. [[http://python3porting.com/cextensions.html#strings-and-unicode|[more info]]]
 * Instead of explicitly dereferencing {{{ob_type}}}, use the {{{Py_TYPE()}}} macro instead. [[http://python3porting.com/cextensions.html#object-initialization|[more info]]]

=== PyArg_Parse() ===

 * {{{PyArg_Parse()}}} and friends lack a {{{y}}} code (for bytes objects) in Python 2, so you will have to {{{#ifdef}}} around these.
 * In Python 3, there's no equivalent of the {{{z}}} code for bytes objects (accepting {{{None}}} as well). Write an {{{O&}}} converter.

=== PyCObject ===

 * Rewrite these to use {{{PyCapsule}}} instead. If you can drop Python 2.6, there's no need to {{{#ifdef}}} these, since {{{PyCapsule}}} is available in Python 2.7. [[http://cgit.freedesktop.org/dbus/dbus-python/tree/_dbus_bindings/module.c#n411|[example]]]
Line 9: Line 91:
 * [[http://wiki.debian.org/Python/LibraryStyleGuide|Debian Python packaging style guide (covers Python 2 and Python 3)]]
Line 10: Line 93:
 * '''Excellent''' [[http://python3porting.com/|in-depth Python 3 porting guide]]
 * [[http://python3wos.appspot.com/|Python 3 "Wall of Shame"]]
 * [[http://pypi.python.org/pypi?:action=browse&c=533&show=all|Cheeseshop packages explicitly claiming Python 3 support]]
 * [[http://wiki.python.org/moin/PortingPythonToPy3k|Python wiki porting guide (pure-Python)]]
 * [[http://wiki.python.org/moin/PortingExtensionModulesToPy3k|Python wiki porting guide (extension modules)]]
 * Barry Warsaw's blog
   * [[http://www.wefearchange.org/2012/01/debian-package-for-python-2-and-3.html|Debian packaging for Python 2 and 3]]
   * [[http://www.wefearchange.org/2011/12/lessons-in-porting-to-python-3.html|Python 3 porting (part 1)]]
   * [[http://www.wefearchange.org/2012/01/python-3-porting-fun-redux.html|Python 3 porting (part 2)]]
   * Python 3 plans for Ubuntu 12.10 (coming soon)
   * [[http://www.wefearchange.org/2011/11/update-on-ubuntus-python-plans.html|Python 3 plans for Ubuntu 12.04 Precise Pangolin]]
 * Ned Bachelder's Pycon 2012 talk [[http://pyvideo.org/video/948/pragmatic-unicode-or-how-do-i-stop-the-pain|Pragmatic Unicode, or How Do I Stop the Pain?]] '''''Watch this NOW'''''
 

Python 3 on Ubuntu

It is a release goal for Ubuntu 12.10 to have only Python 3 on the installation CD images. We have a Q-series blueprint for discussion of this goal at UDS-Q in Oakland, California, in May of 2012. There is a more detailed spec for this effort and a publicly shared Google docs spreadsheet to track this effort. This is an ambitious effort that will only succeed with help from the greater Ubuntu, Debian, and Python communities. In other words, we need you!

At the bottom of this page, you will find various resources for diving more into aspects of supporting Python 3, from the pure-Python, C extension module, Debian packaging, and other perspectives. The intent of this page is to provide specific guidelines in a quick reference format, so that you only need to go here once you're familiar with the basic concepts and approaches, but need a refresher on specific coding techniques. This is a wiki page, and you are encouraged to contribute, but try to keep your recommendations tightly focused on accomplishing the release goal of Python 3 only on the 12.10 CDs.

Before you start

Here are recommendations for you to follow before you start porting.

  • Target Python 3.2, 2.7, and optionally 2.6. Ignore anything older than that.
  • Use a single code base for both Python 2 and 3.
  • Do not rely on 2to3 or the third party six module (the latter, only if absolutely necessary)

  • Modernize your Python 2 code first, getting it working in Python 2.7 before starting to port.
  • Clarify your data model: what are bytes (data) and what are strings (text)?

I cannot overemphasize the last point. Without a clear separation in your mind and data model between bytes and strings, your port will likely be much more painful than it needs to be. This is the biggest distinction between Python 2 and Python 3. Where Python 2 let you be sloppy, with its 8-bit strings that served as both data and ASCII strings, with automatic (but error prone) conversions between 8-bit strings and unicodes, in Python 3 there are only bytes and strings (i.e. unicodes), with no automatic conversion between the two. This is A Good Thing.

Python source

Basic compatibility

Put the following at the top of all your Python files:

from __future__ import absolute_import, print_function, unicode_literals

This turns on three important compatibility flags.

  • Absolute imports are the default in Python 3 [more info]

  • print() is a function in Python 3 [more info]

  • Unadorned string literals are unicode type in Python 3 [more info]

In your code, make these changes:

  • Change all your print statements to use print() functions, and remove all the u'' prefixes from your strings.

  • If you have string literals in your code that represent data, prefix them all with the b'' prefix [more info]

  • Remove all L suffixes from your long integers. [more info]

built-ins

dictionaries

  • Change all your uses of the dictionary methods iteritems(), iterkeys(), and itervalues() to use the non-iter variety, e.g. items(), keys(), and values() respectively. These return dictionary views in Python 3, not concrete lists, so if you need a concrete list, wrap these calls in list() or sorted(). [more info]

iterators

  • Change your iterator classes from providing a next() method to providing a __next__() method. For cross-compatibility, in your class, set next = __next__. [more info]

operators

  • Python 3 has no operator.isSequenceType(). Use the following code for cross-compatibility.

def is_sequence(obj):
    try:
        from collections import Sequence
    except ImportError:
        from operator import isSequenceType
        return operator.isSequenceType(obj)
    else:
        return isinstance(obj, Sequence)

Metaclasses

  • Syntax for creating instances with different metaclasses is very different between Python 2 and 3. Use the ability to call type instances as a way to portably create such instances. [example]

Python extension modules

  • Define a PY3 macro which you can later #ifdef on for C code which cannot be written portably for both Python 2 and Python 3. [example]

Compatibility macros

  • The PyInt_* functions are gone in Python 3. In your extension module, change all of these to PyLong_* functions, which will work in both versions. [more info]

  • #include <bytesobject.h> and change all PyString_* functions with their PyBytes_* equivalents, changing those that really operate on unicodes to use PyUnicode_* functions. [more info]

  • Instead of explicitly dereferencing ob_type, use the Py_TYPE() macro instead. [more info]

PyArg_Parse()

  • PyArg_Parse() and friends lack a y code (for bytes objects) in Python 2, so you will have to #ifdef around these.

  • In Python 3, there's no equivalent of the z code for bytes objects (accepting None as well). Write an O& converter.

PyCObject

  • Rewrite these to use PyCapsule instead. If you can drop Python 2.6, there's no need to #ifdef these, since PyCapsule is available in Python 2.7. [example]

Resources

Python/3 (last edited 2016-02-26 01:40:43 by cmawebsite)