diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2012-07-20 11:32:38 +0200 |
|---|---|---|
| committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2012-07-22 09:29:44 +0200 |
| commit | 8b0190984116873158ee627c7a033a7bd4c3a199 (patch) | |
| tree | 6aff8fef9757da52e2c028dc2e157373f28cecba /docs/topics/python3.txt | |
| parent | 01c392623d988d7486bdaa870886df0ea3da5fa7 (diff) | |
[py3] Bundled six for Python 3 compatibility.
Refs #18363.
Diffstat (limited to 'docs/topics/python3.txt')
| -rw-r--r-- | docs/topics/python3.txt | 253 |
1 files changed, 25 insertions, 228 deletions
diff --git a/docs/topics/python3.txt b/docs/topics/python3.txt index 1aea252e3f..e4bfc1bd9c 100644 --- a/docs/topics/python3.txt +++ b/docs/topics/python3.txt @@ -2,251 +2,48 @@ Python 3 compatibility ====================== -Django 1.5 introduces a compatibility layer that allows the code to be run both -in Python 2 (2.6/2.7) and Python 3 (>= 3.2) (*work in progress*). +Django 1.5 is the first version of Django to support Python 3. -This document is not meant as a complete Python 2 to Python 3 migration guide. -There are many existing resources you can read. But we describe some utilities -and guidelines that we recommend you should use when you want to ensure your -code can be run with both Python 2 and 3. +The same code runs both on Python 2 (≥2.6.5) and Python 3 (≥3.2). To +achieve this: -* http://docs.python.org/py3k/howto/pyporting.html -* http://python3porting.com/ +- wherever possible, Django uses the six_ compatibility layer, +- all modules declare ``from __future__ import unicode_literals``. -django.utils.py3 -================ +.. _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`_. But +it describes guidelines that apply to Django's code and are recommended for +pluggable apps that run with both Python 2 and 3. -Whenever a symbol or module has different semantics or different locations on -Python 2 and Python 3, you can import it from ``django.utils.py3`` where it -will be automatically converted depending on your current Python version. +.. _Python's official porting guide: http://docs.python.org/py3k/howto/pyporting.html -PY3 ---- +.. module: django.utils.six -If you need to know anywhere in your code if you are running Python 3 or a -previous Python 2 version, you can check the ``PY3`` boolean variable:: +django.utils.six +================ - from django.utils.py3 import PY3 +Read the documentation of six_. It's the canonical compatibility library for +supporting Python 2 and 3 in a single codebase. - if PY3: - # Do stuff Python 3-wise - else: - # Do stuff Python 2-wise +``six`` is bundled with Django: you can import it as :mod:`django.utils.six`. -This should be considered as a last resort solution when it is not possible -to import a compatible name from django.utils.py3, as described in the sections -below. +.. _string-handling: String handling =============== -In Python 3, all strings are considered Unicode strings by default. Byte strings -have to be prefixed with the letter 'b'. To mimic the same behaviour in Python 2, -we recommend you import ``unicode_literals`` from the ``__future__`` library:: +In Python 3, all strings are considered Unicode strings by default. Byte +strings must be prefixed with the letter ``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. -See http://docs.python.org/py3k/howto/pyporting.html#bytes-literals - -Different expected strings --------------------------- - -Some method parameters have changed the expected string type of a parameter. -For example, ``strftime`` format parameter expects a bytestring on Python 2 but -a normal (Unicode) string on Python 3. For these cases, ``django.utils.py3`` -provides a ``n()`` function which encodes the string parameter only with -Python 2. - - >>> from __future__ import unicode_literals - >>> from datetime import datetime - - >>> print(datetime.date(2012, 5, 21).strftime(n("%m → %Y"))) - 05 → 2012 - -Renamed types -============= - -Several types are named differently in Python 2 and Python 3. In order to keep -compatibility while using those types, import their corresponding aliases from -``django.utils.py3``. - -=========== ========= ===================== -Python 2 Python 3 django.utils.py3 -=========== ========= ===================== -basestring, str, string_types (tuple) -unicode str text_type -int, long int, integer_types (tuple) -long int long_type -=========== ========= ===================== - -String aliases --------------- - -Code sample:: - - if isinstance(foo, basestring): - print("foo is a string") - - # I want to convert a number to a Unicode string - bar = 45 - bar_string = unicode(bar) - -Should be replaced by:: - - from django.utils.py3 import string_types, text_type - - if isinstance(foo, string_types): - print("foo is a string") - - # I want to convert a number to a Unicode string - bar = 45 - bar_string = text_type(bar) - -No more long type ------------------ - -``long`` and ``int`` types have been unified in Python 3, meaning that ``long`` -is no longer available. ``django.utils.py3`` provides both ``long_type`` and -``integer_types`` aliases. For example: - -.. code-block:: python - - # Old Python 2 code - my_var = long(333463247234623) - if isinstance(my_var, (int, long)): - # ... - -Should be replaced by: - -.. code-block:: python - - from django.utils.py3 import long_type, integer_types - - my_var = long_type(333463247234623) - if isinstance(my_var, integer_types): - # ... - - -Changed module locations -======================== - -The following modules have changed their location in Python 3. Therefore, it is -recommended to import them from the ``django.utils.py3`` compatibility layer: - -=============================== ====================================== ====================== -Python 2 Python3 django.utils.py3 -=============================== ====================================== ====================== -Cookie http.cookies cookies - -urlparse.urlparse urllib.parse.urlparse urlparse -urlparse.urlunparse urllib.parse.urlunparse urlunparse -urlparse.urljoin urllib.parse.urljoin urljoin -urlparse.urlsplit urllib.parse.urlsplit urlsplit -urlparse.urlunsplit urllib.parse.urlunsplit urlunsplit -urlparse.urldefrag urllib.parse.urldefrag urldefrag -urlparse.parse_qsl urllib.parse.parse_qsl parse_qsl -urllib.quote urllib.parse.quote quote -urllib.unquote urllib.parse.unquote unquote -urllib.quote_plus urllib.parse.quote_plus quote_plus -urllib.unquote_plus urllib.parse.unquote_plus unquote_plus -urllib.urlencode urllib.parse.urlencode urlencode -urllib.urlopen urllib.request.urlopen urlopen -urllib.url2pathname urllib.request.url2pathname url2pathname -urllib.urlretrieve urllib.request.urlretrieve urlretrieve -urllib2 urllib.request urllib2 -urllib2.Request urllib.request.Request Request -urllib2.OpenerDirector urllib.request.OpenerDirector OpenerDirector -urllib2.UnknownHandler urllib.request.UnknownHandler UnknownHandler -urllib2.HTTPHandler urllib.request.HTTPHandler HTTPHandler -urllib2.HTTPSHandler urllib.request.HTTPSHandler HTTPSHandler -urllib2.HTTPDefaultErrorHandler urllib.request.HTTPDefaultErrorHandler HTTPDefaultErrorHandler -urllib2.FTPHandler urllib.request.FTPHandler FTPHandler -urllib2.HTTPError urllib.request.HTTPError HTTPError -urllib2.HTTPErrorProcessor urllib.request.HTTPErrorProcessor HTTPErrorProcessor - -htmlentitydefs.name2codepoint html.entities.name2codepoint name2codepoint -HTMLParser html.parser HTMLParser -cPickle/pickle pickle pickle -thread/dummy_thread _thread/_dummy_thread thread - -os.getcwdu os.getcwd getcwdu -itertools.izip zip zip -sys.maxint sys.maxsize maxsize -unichr chr unichr -xrange range xrange -=============================== ====================================== ====================== - - -Output encoding now Unicode -=========================== - -If you want to catch stdout/stderr output, the output content is UTF-8 encoded -in Python 2, while it is Unicode strings in Python 3. You can use the OutputIO -stream to capture this output:: - - from django.utils.py3 import OutputIO - - try: - old_stdout = sys.stdout - out = OutputIO() - sys.stdout = out - # Do stuff which produces standard output - result = out.getvalue() - finally: - sys.stdout = old_stdout - -Dict iteritems/itervalues/iterkeys -================================== - -The iteritems(), itervalues() and iterkeys() methods of dictionaries do not -exist any more in Python 3, simply because they represent the default items() -values() and keys() behavior in Python 3. Therefore, to keep compatibility, -use similar functions from ``django.utils.py3``:: - - from django.utils.py3 import iteritems, itervalues, iterkeys - - my_dict = {'a': 21, 'b': 42} - for key, value in iteritems(my_dict): - # ... - for value in itervalues(my_dict): - # ... - for key in iterkeys(my_dict): - # ... - -Note that in Python 3, dict.keys(), dict.items() and dict.values() return -"views" instead of lists. Wrap them into list() if you really need their return -values to be in a list. - -http://docs.python.org/release/3.0.1/whatsnew/3.0.html#views-and-iterators-instead-of-lists - -Metaclass -========= - -The syntax for declaring metaclasses has changed in Python 3. -``django.utils.py3`` offers a compatible way to declare metaclasses:: - - from django.utils.py3 import with_metaclass - - class MyClass(with_metaclass(SubClass1, SubClass2,...)): - # ... - -Re-raising exceptions -===================== - -One of the syntaxes to raise exceptions (raise E, V, T) is gone in Python 3. -This is especially used in very specific cases where you want to re-raise a -different exception that the initial one, while keeping the original traceback. -So, instead of:: - - raise Exception, Exception(msg), traceback - -Use:: - - from django.utils.py3 import reraise - - reraise(Exception, Exception(msg), traceback) +Be cautious if you have to `slice bytestrings`_. +.. _slice bytestrings: http://docs.python.org/py3k/howto/pyporting.html#bytes-literals |
