summaryrefslogtreecommitdiff
path: root/docs/topics/python3.txt
blob: 7c1cb53150d60c3e6df28db3b356c24e7ce13ae1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
======================
Python 3 compatibility
======================

Django 1.5 is the first version of Django to support Python 3. The same code
runs both on Python 2 (≥ 2.6.5) and Python 3 (≥ 3.2), thanks to the six_
compatibility layer and ``unicode_literals``.

.. _six: http://packages.python.org/six/

This document is not meant as a Python 2 to Python 3 migration guide. There
are many existing resources, including `Python's official porting guide`_.
Rather, it describes guidelines that apply to Django's code and are
recommended for pluggable apps that run with both Python 2 and 3.

.. _Python's official porting guide: http://docs.python.org/py3k/howto/pyporting.html

Syntax requirements
===================

Unicode
-------

In Python 3, all strings are considered Unicode by default. The ``unicode``
type from Python 2 is called ``str`` in Python 3, and ``str`` becomes
``bytes``.

You mustn't use the ``u`` prefix before a unicode string literal because it's
a syntax error in Python 3.2. You must prefix byte strings with ``b``.

In order to enable the same behavior in Python 2, every module must import
``unicode_literals`` from ``__future__``::

    from __future__ import unicode_literals

    my_string = "This is an unicode literal"
    my_bytestring = b"This is a bytestring"

Be cautious if you have to `slice bytestrings`_.

.. _slice bytestrings: http://docs.python.org/py3k/howto/pyporting.html#bytes-literals

Exceptions
----------

When you capture exceptions, use the ``as`` keyword::

    try:
        ...
    except MyException as exc:
        ...

This older syntax was removed in Python 3::

    try:
        ...
    except MyException, exc:
        ...

The syntax to reraise an exception with a different traceback also changed.
Use :func:`six.reraise`.


.. module: django.utils.six

Writing compatible code with six
================================

six_ is the canonical compatibility library for supporting Python 2 and 3 in
a single codebase. Read its documentation!

:mod:`six` is bundled with Django: you can import it as :mod:`django.utils.six`.

Here are the most common changes required to write compatible code.

String types
------------

The ``basestring`` and ``unicode`` types were removed in Python 3, and the
meaning of ``str`` changed. To test these types, use the following idioms::

    isinstance(myvalue, six.string_types)       # replacement for basestring
    isinstance(myvalue, six.text_type)          # replacement for unicode
    isinstance(myvalue, bytes)                  # replacement for str

Python ≥ 2.6 provides ``bytes`` as an alias for ``str``, so you don't need
:attr:`six.binary_type`.

``long``
--------

The ``long`` type no longer exists in Python 3. ``1L`` is a syntax error. Use
:data:`six.integer_types` check if a value is an integer or a long::

    isinstance(myvalue, six.integer_types)      # replacement for (int, long)

``xrange``
----------

Import :func:`six.moves.xrange` wherever you use ``xrange``.

Moved modules
-------------

Some modules were renamed in Python 3. The :mod:`django.utils.six.moves
<six.moves>` module provides a compatible location to import them.

In addition to six' defaults, Django's version provides ``dummy_thread`` as
``_dummy_thread``.

PY3
---

If you need different code in Python 2 and Python 3, check :data:`six.PY3`::

    if six.PY3:
        # do stuff Python 3-wise
    else:
        # do stuff Python 2-wise

This is a last resort solution when :mod:`six` doesn't provide an appropriate
function.