diff options
| author | Tim Graham <timograham@gmail.com> | 2017-01-18 11:51:29 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-01-18 11:51:29 -0500 |
| commit | f6acd1d271122d66de8061e75ae26137ddf02658 (patch) | |
| tree | 26392839b0cf03b48696240d7ce6d835ec1011dc /docs/topics/python3.txt | |
| parent | c716fe87821df00f9f03ecc761c914d1682591a2 (diff) | |
Refs #23919 -- Removed Python 2 notes in docs.
Diffstat (limited to 'docs/topics/python3.txt')
| -rw-r--r-- | docs/topics/python3.txt | 369 |
1 files changed, 0 insertions, 369 deletions
diff --git a/docs/topics/python3.txt b/docs/topics/python3.txt deleted file mode 100644 index 5b40f57bd3..0000000000 --- a/docs/topics/python3.txt +++ /dev/null @@ -1,369 +0,0 @@ -=================== -Porting to Python 3 -=================== - -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. - -.. _six: https://pythonhosted.org/six/ - -This document is primarily targeted at authors of pluggable applications -who want to support both Python 2 and 3. It also describes guidelines that -apply to Django's code. - -Philosophy -========== - -This document assumes that you are familiar with the changes between Python 2 -and Python 3. If you aren't, read :ref:`Python's official porting guide -<pyporting-howto>` first. Refreshing your knowledge of unicode handling on -Python 2 and 3 will help; the `Pragmatic Unicode`_ presentation is a good -resource. - -Django uses the *Python 2/3 Compatible Source* strategy. Of course, you're -free to chose another strategy for your own code, especially if you don't need -to stay compatible with Python 2. But authors of pluggable applications are -encouraged to use the same porting strategy as Django itself. - -Writing compatible code is much easier if you target Python ≥ 2.6. Django 1.5 -introduces compatibility tools such as :mod:`django.utils.six`, which is a -customized version of the :mod:`six module <six>`. For convenience, -forwards-compatible aliases were introduced in Django 1.4.2. If your -application takes advantage of these tools, it will require Django ≥ 1.4.2. - -Obviously, writing compatible source code adds some overhead, and that can -cause frustration. Django's developers have found that attempting to write -Python 3 code that's compatible with Python 2 is much more rewarding than the -opposite. Not only does that make your code more future-proof, but Python 3's -advantages (like the saner string handling) start shining quickly. Dealing -with Python 2 becomes a backwards compatibility requirement, and we as -developers are used to dealing with such constraints. - -Porting tools provided by Django are inspired by this philosophy, and it's -reflected throughout this guide. - -.. _Pragmatic Unicode: http://nedbatchelder.com/text/unipain.html - -Porting tips -============ - -Unicode literals ----------------- - -This step consists in: - -- Adding ``from __future__ import unicode_literals`` at the top of your Python - modules -- it's best to put it in each and every module, otherwise you'll - keep 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 Django -only exposes unicode interfaces to the programmer. Python 3 discourages using -bytestrings, except for binary data or byte-oriented interfaces. Python 2 -makes bytestrings and unicode strings effectively interchangeable, as long as -they only contain ASCII data. Take advantage of this to use unicode strings -wherever possible and avoid the ``b`` prefixes. - -.. note:: - - Python 2's ``u`` prefix is a syntax error in Python 3.2 but it will be - allowed again in Python 3.3 thanks to :pep:`414`. Thus, this - transformation is optional if you target Python ≥ 3.3. It's still - recommended, per the "write Python 3 code" philosophy. - -String handling ---------------- - -Python 2's `unicode`_ type was renamed :class:`str` in Python 3, -``str()`` was renamed :class:`bytes`, and `basestring`_ disappeared. -six_ provides :ref:`tools <string-handling-with-six>` to deal with these -changes. - -Django also contains several string related classes and functions in the -:mod:`django.utils.encoding` and :mod:`django.utils.safestring` modules. Their -names used the words ``str``, which doesn't mean the same thing in Python 2 -and Python 3, and ``unicode``, which doesn't exist in Python 3. In order to -avoid ambiguity and confusion these concepts were renamed ``bytes`` and -``text``. - -Here are the name changes in :mod:`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. Under -Python 3, ``smart_str`` is an alias for ``smart_text``. - -For forwards compatibility, the new names work as of Django 1.4.2. - -.. note:: - - :mod:`django.utils.encoding` was deeply refactored in Django 1.5 to - provide a more consistent API. Check its documentation for more - information. - -:mod:`django.utils.safestring` is mostly used via the -:func:`~django.utils.safestring.mark_safe` function, which didn't change. In -case you're using the internals, here are the name changes: - -================== ================== -Old name New name -================== ================== -``SafeString`` ``SafeBytes`` -``SafeUnicode`` ``SafeText`` -================== ================== - -For backwards compatibility, the old names still work on Python 2. On Python 3, -``SafeString`` is an alias for ``SafeText``. - -For forwards compatibility, the new names work as of Django 1.4.2. - -``__str__()`` and ``__unicode__()`` methods -------------------------------------------- - -In Python 2, the object model specifies :meth:`~object.__str__` and -` __unicode__()`_ methods. If these methods exist, they must return -``str`` (bytes) and ``unicode`` (text) respectively. - -The ``print`` statement and the :class:`str` built-in call -:meth:`~object.__str__` to determine the human-readable representation of an -object. The ``unicode`` built-in calls ` __unicode__()`_ if it -exists, and otherwise falls back to :meth:`~object.__str__` and decodes the -result with the system encoding. Conversely, the -:class:`~django.db.models.Model` base class automatically derives -:meth:`~object.__str__` from ` __unicode__()`_ by encoding to UTF-8. - -In Python 3, there's simply :meth:`~object.__str__`, which must return ``str`` -(text). - -(It is also possible to define :meth:`~object.__bytes__`, but Django applications -have little use for that method, because they hardly ever deal with ``bytes``.) - -Finally, note that :meth:`~object.__repr__` must return a ``str`` on all -versions of Python. - -:class:`dict` and :class:`dict`-like classes --------------------------------------------- - -:meth:`dict.keys`, :meth:`dict.items` and :meth:`dict.values` return lists in -Python 2 and iterators in Python 3. :class:`~django.http.QueryDict` and the -:class:`dict`-like classes defined in ``django.utils.datastructures`` -behave likewise in Python 3. - -six_ provides compatibility functions to work around this change: -:func:`~six.iterkeys`, :func:`~six.iteritems`, and :func:`~six.itervalues`. -It also contains an undocumented ``iterlists`` function that works well for -``django.utils.datastructures.MultiValueDict`` and its subclasses. - -:class:`~django.http.HttpRequest` and :class:`~django.http.HttpResponse` objects --------------------------------------------------------------------------------- - -According to :pep:`3333`: - -- headers are always ``str`` objects, -- input and output streams are always ``bytes`` objects. - -Specifically, :attr:`HttpResponse.content <django.http.HttpResponse.content>` -contains ``bytes``, which may become an issue if you compare it with a -``str`` in your tests. The preferred solution is to rely on -:meth:`~django.test.SimpleTestCase.assertContains` and -:meth:`~django.test.SimpleTestCase.assertNotContains`. These methods accept a -response and a unicode string as arguments. - -Coding guidelines -================= - -The following guidelines are enforced in Django's source code. They're also -recommended 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`` 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" - -If you need a byte string literal under Python 2 and a unicode string literal -under Python 3, use the :class:`str` builtin:: - - str('my string') - -In Python 3, there aren't any automatic conversions between ``str`` and -``bytes``, and the :mod:`codecs` module became more strict. :meth:`str.encode` -always returns ``bytes``, and ``bytes.decode`` always returns ``str``. As a -consequence, the following pattern is sometimes necessary:: - - value = value.encode('ascii', 'ignore').decode('ascii') - -Be cautious if you have to `index bytestrings`_. - -.. _index bytestrings: https://docs.python.org/3/howto/pyporting.html#text-versus-binary-data - -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: # Don't do that! - ... - -The syntax to reraise an exception with a different traceback also changed. -Use :func:`six.reraise`. - -Magic methods -------------- - -Use the patterns below to handle magic methods renamed in Python 3. - -Iterators -~~~~~~~~~ - -:: - - class MyIterator(six.Iterator): - def __iter__(self): - return self # implement some logic here - - def __next__(self): - raise StopIteration # implement some logic here - -Boolean evaluation -~~~~~~~~~~~~~~~~~~ - -:: - - class MyBoolean(object): - - def __bool__(self): - return True # implement some logic here - - def __nonzero__(self): # Python 2 compatibility - return type(self).__bool__(self) - -Division -~~~~~~~~ - -:: - - class MyDivisible(object): - - def __truediv__(self, other): - return self / other # implement some logic here - - def __div__(self, other): # Python 2 compatibility - return type(self).__truediv__(self, other) - - def __itruediv__(self, other): - return self // other # implement some logic here - - def __idiv__(self, other): # Python 2 compatibility - return type(self).__itruediv__(self, other) - -Special methods are looked up on the class and not on the instance to reflect -the behavior of the Python interpreter. - -.. 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! - -A :mod:`customized version of six <django.utils.six>` is bundled with Django -as 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-with-six: - -String handling -~~~~~~~~~~~~~~~ - -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 -:data:`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`` -~~~~~~~~~~ - -If you use ``xrange`` on Python 2, import ``six.moves.range`` and use that -instead. You can also import ``six.moves.xrange`` (it's equivalent to -``six.moves.range``) but the first technique allows you to simply drop the -import when dropping support for Python 2. - -Moved modules -~~~~~~~~~~~~~ - -Some modules were renamed in Python 3. The ``django.utils.six.moves`` -module (based on the :mod:`six.moves module <six.moves>`) provides a -compatible location to import them. - -``PY2`` -~~~~~~~ - -If you need different code in Python 2 and Python 3, check :data:`six.PY2`:: - - if six.PY2: - # compatibility code for Python 2 - -This is a last resort solution when :mod:`six` doesn't provide an appropriate -function. - -.. module:: django.utils.six - -Django customized version of ``six`` ------------------------------------- - -The version of six bundled with Django (``django.utils.six``) includes a few -customizations for internal use only. - -.. _unicode: https://docs.python.org/2/library/functions.html#unicode -.. _ __unicode__(): https://docs.python.org/2/reference/datamodel.html#object.__unicode__ -.. _basestring: https://docs.python.org/2/library/functions.html#basestring |
