Django 1.5 is the first version of Django to support Python 3. The same coderuns both on Python 2 (≥ 2.6.5) and Python 3 (≥ 3.2), thanks to the sixcompatibility layer.
These scriptlets shows you idioms for writing proof code that is compatible with both versions of Python: 2 and 3. Minimum versions. Python 2: 2.6+ Python 3: 3.3+ Setup. The imports below refer to these pip-installable packages on PyPI. Easy, clean, reliable Python 2/3 compatibility Table of Contents. What’s New; Overview: Easy, clean, reliable Python 2/3 compatibility; Quick-start guide; Cheat Sheet: Writing Python 2-3 compatible code. Setup; Essential syntax differences. Print; Raising exceptions; Catching exceptions; Division; Long integers; Octal constants; Backtick repr.
Python 3 was never intended to be compatible with Python 2. Freed from the shackles of backward compatibility, Python's core developers took the liberty of c. Easy, clean, reliable Python 2/3 compatibility Table of Contents. What’s New; Overview: Easy, clean, reliable Python 2/3 compatibility; Quick-start guide; Cheat Sheet: Writing Python 2-3 compatible code. Setup; Essential syntax differences; Strings and bytes; Imports relative to a package; Dictionaries; Custom class behaviour; Lists versus. Unfortunately you have legacy Python 2 source code that needs to stay compatible. This talk will show you that you can make your code be Python 2/3 source-compatible using various tools to pick up the nitty-gritty work and help modernize your Python code to newer Python 2 practices.
This document is primarily targeted at authors of pluggable applicationswho want to support both Python 2 and 3. It also describes guidelines thatapply to Django’s code.
Philosophy¶
This document assumes that you are familiar with the changes between Python 2and Python 3. If you aren’t, read Python’s official porting guide first. Refreshing your knowledge of unicode handling onPython 2 and 3 will help; the Pragmatic Unicode presentation is a goodresource.
Django uses the Python 2/3 Compatible Source strategy. Of course, you’refree to chose another strategy for your own code, especially if you don’t needto stay compatible with Python 2. But authors of pluggable applications areencouraged to use the same porting strategy as Django itself.
Writing compatible code is much easier if you target Python ≥ 2.6. Django 1.5introduces compatibility tools such as
django.utils.six
, which is acustomized version of the sixmodule
. For convenience,forwards-compatible aliases were introduced in Django 1.4.2. If yourapplication takes advantage of these tools, it will require Django ≥ 1.4.2.Obviously, writing compatible source code adds some overhead, and that cancause frustration. Django’s developers have found that attempting to writePython 3 code that’s compatible with Python 2 is much more rewarding than theopposite. Not only does that make your code more future-proof, but Python 3’sadvantages (like the saner string handling) start shining quickly. Dealingwith Python 2 becomes a backwards compatibility requirement, and we asdevelopers are used to dealing with such constraints.
Porting tools provided by Django are inspired by this philosophy, and it’sreflected throughout this guide.
Porting tips¶
Unicode literals¶
This step consists in:
- Adding
from__future__importunicode_literals
at the top of your Pythonmodules – it’s best to put it in each and every module, otherwise you’llkeep checking the top of your files to see which mode is in effect; - Removing the
u
prefix before unicode strings; - Adding a
b
prefix before bytestrings.
Performing these changes systematically guarantees backwards compatibility.
However, Django applications generally don’t need bytestrings, since Djangoonly exposes unicode interfaces to the programmer. Python 3 discourages usingbytestrings, except for binary data or byte-oriented interfaces. Python 2makes bytestrings and unicode strings effectively interchangeable, as long asthey only contain ASCII data. Take advantage of this to use unicode stringswherever possible and avoid the
b
prefixes.Note
Python 2’s
u
prefix is a syntax error in Python 3.2 but it will beallowed again in Python 3.3 thanks to PEP 414. Thus, thistransformation is optional if you target Python ≥ 3.3. It’s stillrecommended, per the “write Python 3 code” philosophy.String handling¶
Python 2’s unicode type was renamed
str
in Python 3,str()
was renamed bytes
, and basestring disappeared.six provides tools to deal with thesechanges.Django also contains several string related classes and functions in the
django.utils.encoding
and django.utils.safestring
modules. Theirnames used the words str
, which doesn’t mean the same thing in Python 2and Python 3, and unicode
, which doesn’t exist in Python 3. In order toavoid ambiguity and confusion these concepts were renamed bytes
andtext
.Here are the name changes in
django.utils.encoding
:Old name | New name |
---|---|
smart_str | smart_bytes |
smart_unicode | smart_text |
force_unicode | force_text |
For backwards compatibility, the old names still work on Python 2. UnderPython 3,
smart_str
is an alias for smart_text
.For forwards compatibility, the new names work as of Django 1.4.2.
Note
django.utils.encoding
was deeply refactored in Django 1.5 toprovide a more consistent API. Check its documentation for moreinformation.django.utils.safestring
is mostly used via themark_safe()
andmark_for_escaping()
functions, which didn’tchange. In case you’re using the internals, here are the name changes:![Python 2 python 3 coexist Python 2 python 3 coexist](https://raw.githubusercontent.com/izhangzhihao/intellij-rainbow-brackets/IC-2017.2/screenshots/with-scala.png)
Old name | New name |
---|---|
EscapeString | EscapeBytes |
EscapeUnicode | EscapeText |
SafeString | SafeBytes |
SafeUnicode | SafeText |
For backwards compatibility, the old names still work on Python 2. UnderPython 3,
EscapeString
and SafeString
are aliases for EscapeText
and SafeText
respectively.For forwards compatibility, the new names work as of Django 1.4.2.
__str__()
and __unicode__()
methods¶
In Python 2, the object model specifies
__str__()
and` __unicode__()`_ methods. If these methods exist, they must returnstr
(bytes) and unicode
(text) respectively.The
print
statement and the str
built-in call__str__()
to determine the human-readable representation of anobject. The unicode
built-in calls ` __unicode__()`_ if itexists, and otherwise falls back to __str__()
and decodes theresult with the system encoding. Conversely, theModel
base class automatically derives__str__()
from ` __unicode__()`_ by encoding to UTF-8.In Python 3, there’s simply
__str__()
, which must return str
(text).(It is also possible to define
__bytes__()
, but Django applicationshave little use for that method, because they hardly ever deal with bytes
.)Django provides a simple way to define
__str__()
and` __unicode__()`_ methods that work on Python 2 and 3: you mustdefine a __str__()
method returning text and to apply thepython_2_unicode_compatible()
decorator.On Python 3, the decorator is a no-op. On Python 2, it defines appropriate` __unicode__()`_ and
__str__()
methods (replacing theoriginal __str__()
method in the process). Here’s an example:This technique is the best match for Django’s porting philosophy.
For forwards compatibility, this decorator is available as of Django 1.4.2.
Finally, note that
__repr__()
must return a str
on allversions of Python.dict
and dict
-like classes¶
dict.keys()
, dict.items()
and dict.values()
return lists inPython 2 and iterators in Python 3. QueryDict
and thedict
-like classes defined in django.utils.datastructures
behave likewise in Python 3.https://free-kt.mystrikingly.com/blog/odds-on-craps-numbers. six provides compatibility functions to work around this change:
iterkeys()
, iteritems()
, and itervalues()
.It also contains an undocumented iterlists
function that works well fordjango.utils.datastructures.MultiValueDict
and its subclasses.HttpRequest
and HttpResponse
objects¶
According to PEP 3333:
- headers are always
str
objects, - input and output streams are always
bytes
objects.
Specifically,
HttpResponse.content
contains bytes
, which may become an issue if you compare it with astr
in your tests. The preferred solution is to rely onassertContains()
andassertNotContains()
. These methods accept aresponse and a unicode string as arguments.Coding guidelines¶
The following guidelines are enforced in Django’s source code. They’re alsorecommended for third-party applications that follow the same porting strategy.
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
becomesbytes
.You mustn’t use the
u
prefix before a unicode string literal because it’sa 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__
:If you need a byte string literal under Python 2 and a unicode string literalunder Python 3, use the
str
builtin:In Python 3, there aren’t any automatic conversions between
str
andbytes
, and the codecs
module became more strict. str.encode()
always returns bytes
, and bytes.decode
always returns str
. As aconsequence, the following pattern is sometimes necessary:Be cautious if you have to index bytestrings.
Exceptions¶
When you capture exceptions, use the
as
keyword:This older syntax was removed in Python 3:
The syntax to reraise an exception with a different traceback also changed.Use
six.reraise()
.Magic methods¶
Use the patterns below to handle magic methods renamed in Python 3.
Iterators¶
Boolean evaluation¶
Division¶
Special methods are looked up on the class and not on the instance to reflectthe behavior of the Python interpreter.
Writing compatible code with six¶
six is the canonical compatibility library for supporting Python 2 and 3 ina single codebase. Read its documentation!
A
customizedversionofsix
is bundled with Djangoas of version 1.4.2. You can import it as django.utils.six
.Here are the most common changes required to write compatible code.
String handling¶
The
basestring
and unicode
types were removed in Python 3, and themeaning of str
changed. To test these types, use the following idioms:Python ≥ 2.6 provides
bytes
as an alias for str
, so you don’t needsix.binary_type
.long
¶
The
long
type no longer exists in Python 3. 1L
is a syntax error. Usesix.integer_types
check if a value is an integer or a long:xrange
¶
If you use
xrange
on Python 2, import six.moves.range
and use thatinstead. You can also import six.moves.xrange
(it’s equivalent tosix.moves.range
) but the first technique allows you to simply drop theimport when dropping support for Python 2.Moved modules¶
Some modules were renamed in Python 3. The
django.utils.six.moves
module (based on the six.movesmodule
) provides acompatible location to import them.PY2
¶
Python 2 And 3 Compatible Codes
If you need different code in Python 2 and Python 3, check
six.PY2
: https://grow-download.mystrikingly.com/blog/is-cool-cat-casino-legit.This is a last resort solution when
six
doesn’t provide an appropriatefunction.Python 3.6 Vs 2.7
Django customized version of six
¶
Python Version 2 Vs 3
The version of six bundled with Django (
django.utils.six
) includes a fewcustomizations for internal use only.