Skip to content

Commit 809ea7c

Browse files
authored
pythongh-107432 Update Porting Python 2 Code to Python 3 how-to (pythonGH-107434)
https://docs.python.org/3/howto/pyporting.html#porting-python-2-code-to-python-3 was written for another time. In this patch: - material that frames Python 3 as "new" is removed - descriptions and directions have been trimmed
1 parent 2eb60c1 commit 809ea7c

File tree

1 file changed

+94
-121
lines changed

1 file changed

+94
-121
lines changed

Doc/howto/pyporting.rst

Lines changed: 94 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,47 @@
11
.. _pyporting-howto:
22

3-
*********************************
4-
Porting Python 2 Code to Python 3
5-
*********************************
3+
*************************************
4+
How to port Python 2 Code to Python 3
5+
*************************************
66

77
:author: Brett Cannon
88

99
.. topic:: Abstract
1010

11-
With Python 3 being the future of Python while Python 2 is still in active
12-
use, it is good to have your project available for both major releases of
13-
Python. This guide is meant to help you figure out how best to support both
14-
Python 2 & 3 simultaneously.
11+
Python 2 reached its official end-of-life at the start of 2020. This means
12+
that no new bug reports, fixes, or changes will be made to Python 2 - it's
13+
no longer supported.
14+
15+
This guide is intended to provide you with a path to Python 3 for your
16+
code, that includes compatibility with Python 2 as a first step.
1517

1618
If you are looking to port an extension module instead of pure Python code,
1719
please see :ref:`cporting-howto`.
1820

19-
If you would like to read one core Python developer's take on why Python 3
20-
came into existence, you can read Nick Coghlan's `Python 3 Q & A`_ or
21-
Brett Cannon's `Why Python 3 exists`_.
22-
21+
The archived python-porting_ mailing list may contain some useful guidance.
2322

24-
For help with porting, you can view the archived python-porting_ mailing list.
2523

2624
The Short Explanation
2725
=====================
2826

29-
To make your project be single-source Python 2/3 compatible, the basic steps
27+
To achieve Python 2/3 compatibility in a single code base, the basic steps
3028
are:
3129

3230
#. Only worry about supporting Python 2.7
3331
#. Make sure you have good test coverage (coverage.py_ can help;
3432
``python -m pip install coverage``)
35-
#. Learn the differences between Python 2 & 3
33+
#. Learn the differences between Python 2 and 3
3634
#. Use Futurize_ (or Modernize_) to update your code (e.g. ``python -m pip install future``)
3735
#. Use Pylint_ to help make sure you don't regress on your Python 3 support
3836
(``python -m pip install pylint``)
3937
#. Use caniusepython3_ to find out which of your dependencies are blocking your
4038
use of Python 3 (``python -m pip install caniusepython3``)
4139
#. Once your dependencies are no longer blocking you, use continuous integration
42-
to make sure you stay compatible with Python 2 & 3 (tox_ can help test
40+
to make sure you stay compatible with Python 2 and 3 (tox_ can help test
4341
against multiple versions of Python; ``python -m pip install tox``)
4442
#. Consider using optional static type checking to make sure your type usage
45-
works in both Python 2 & 3 (e.g. use mypy_ to check your typing under both
46-
Python 2 & Python 3; ``python -m pip install mypy``).
43+
works in both Python 2 and 3 (e.g. use mypy_ to check your typing under both
44+
Python 2 and Python 3; ``python -m pip install mypy``).
4745

4846
.. note::
4947

@@ -55,43 +53,30 @@ are:
5553
Details
5654
=======
5755

58-
A key point about supporting Python 2 & 3 simultaneously is that you can start
59-
**today**! Even if your dependencies are not supporting Python 3 yet that does
60-
not mean you can't modernize your code **now** to support Python 3. Most changes
61-
required to support Python 3 lead to cleaner code using newer practices even in
62-
Python 2 code.
56+
Even if other factors - say, dependencies over which you have no control -
57+
still require you to support Python 2, that does not prevent you taking the
58+
step of including Python 3 support.
6359

64-
Another key point is that modernizing your Python 2 code to also support
65-
Python 3 is largely automated for you. While you might have to make some API
66-
decisions thanks to Python 3 clarifying text data versus binary data, the
67-
lower-level work is now mostly done for you and thus can at least benefit from
68-
the automated changes immediately.
60+
Most changes required to support Python 3 lead to cleaner code using newer
61+
practices even in Python 2 code.
6962

70-
Keep those key points in mind while you read on about the details of porting
71-
your code to support Python 2 & 3 simultaneously.
7263

64+
Different versions of Python 2
65+
------------------------------
7366

74-
Drop support for Python 2.6 and older
75-
-------------------------------------
67+
Ideally, your code should be compatible with Python 2.7, which was the
68+
last supported version of Python 2.
7669

77-
While you can make Python 2.5 work with Python 3, it is **much** easier if you
78-
only have to work with Python 2.7. If dropping Python 2.5 is not an
79-
option then the six_ project can help you support Python 2.5 & 3 simultaneously
80-
(``python -m pip install six``). Do realize, though, that nearly all the projects listed
81-
in this HOWTO will not be available to you.
70+
Some of the tools mentioned in this guide will not work with Python 2.6.
8271

83-
If you are able to skip Python 2.5 and older, then the required changes
84-
to your code should continue to look and feel like idiomatic Python code. At
85-
worst you will have to use a function instead of a method in some instances or
86-
have to import a function instead of using a built-in one, but otherwise the
87-
overall transformation should not feel foreign to you.
72+
If absolutely necessary, the six_ project can help you support Python 2.5 and
73+
3 simultaneously. Do realize, though, that nearly all the projects listed in
74+
this guide will not be available to you.
8875

89-
But you should aim for only supporting Python 2.7. Python 2.6 is no longer
90-
freely supported and thus is not receiving bugfixes. This means **you** will have
91-
to work around any issues you come across with Python 2.6. There are also some
92-
tools mentioned in this HOWTO which do not support Python 2.6 (e.g., Pylint_),
93-
and this will become more commonplace as time goes on. It will simply be easier
94-
for you if you only support the versions of Python that you have to support.
76+
If you are able to skip Python 2.5 and older, the required changes to your
77+
code will be minimal. At worst you will have to use a function instead of a
78+
method in some instances or have to import a function instead of using a
79+
built-in one.
9580

9681

9782
Make sure you specify the proper version support in your ``setup.py`` file
@@ -118,62 +103,57 @@ coverage). If you don't already have a tool to measure test coverage then
118103
coverage.py_ is recommended.
119104

120105

121-
Learn the differences between Python 2 & 3
122-
-------------------------------------------
106+
Be aware of the differences between Python 2 and 3
107+
--------------------------------------------------
123108

124109
Once you have your code well-tested you are ready to begin porting your code to
125110
Python 3! But to fully understand how your code is going to change and what
126111
you want to look out for while you code, you will want to learn what changes
127-
Python 3 makes in terms of Python 2. Typically the two best ways of doing that
128-
is reading the :ref:`"What's New" <whatsnew-index>` doc for each release of Python 3 and the
129-
`Porting to Python 3`_ book (which is free online). There is also a handy
130-
`cheat sheet`_ from the Python-Future project.
112+
Python 3 makes in terms of Python 2.
113+
114+
Some resources for understanding the differences and their implications for you
115+
code:
116+
117+
* the :ref:`"What's New" <whatsnew-index>` doc for each release of Python 3
118+
* the `Porting to Python 3`_ book (which is free online)
119+
* the handy `cheat sheet`_ from the Python-Future project.
131120

132121

133122
Update your code
134123
----------------
135124

136-
Once you feel like you know what is different in Python 3 compared to Python 2,
137-
it's time to update your code! You have a choice between two tools in porting
138-
your code automatically: Futurize_ and Modernize_. Which tool you choose will
139-
depend on how much like Python 3 you want your code to be. Futurize_ does its
140-
best to make Python 3 idioms and practices exist in Python 2, e.g. backporting
141-
the ``bytes`` type from Python 3 so that you have semantic parity between the
142-
major versions of Python. Modernize_,
143-
on the other hand, is more conservative and targets a Python 2/3 subset of
144-
Python, directly relying on six_ to help provide compatibility. As Python 3 is
145-
the future, it might be best to consider Futurize to begin adjusting to any new
146-
practices that Python 3 introduces which you are not accustomed to yet.
147-
148-
Regardless of which tool you choose, they will update your code to run under
149-
Python 3 while staying compatible with the version of Python 2 you started with.
150-
Depending on how conservative you want to be, you may want to run the tool over
151-
your test suite first and visually inspect the diff to make sure the
152-
transformation is accurate. After you have transformed your test suite and
153-
verified that all the tests still pass as expected, then you can transform your
154-
application code knowing that any tests which fail is a translation failure.
125+
There are tools available that can port your code automatically.
126+
127+
Futurize_ does its best to make Python 3 idioms and practices exist in Python
128+
2, e.g. backporting the ``bytes`` type from Python 3 so that you have
129+
semantic parity between the major versions of Python. This is the better
130+
approach for most cases.
131+
132+
Modernize_, on the other hand, is more conservative and targets a Python 2/3
133+
subset of Python, directly relying on six_ to help provide compatibility.
134+
135+
A good approach is to run the tool over your test suite first and visually
136+
inspect the diff to make sure the transformation is accurate. After you have
137+
transformed your test suite and verified that all the tests still pass as
138+
expected, then you can transform your application code knowing that any tests
139+
which fail is a translation failure.
155140

156141
Unfortunately the tools can't automate everything to make your code work under
157-
Python 3 and so there are a handful of things you will need to update manually
158-
to get full Python 3 support (which of these steps are necessary vary between
159-
the tools). Read the documentation for the tool you choose to use to see what it
160-
fixes by default and what it can do optionally to know what will (not) be fixed
161-
for you and what you may have to fix on your own (e.g. using ``io.open()`` over
162-
the built-in ``open()`` function is off by default in Modernize). Luckily,
163-
though, there are only a couple of things to watch out for which can be
164-
considered large issues that may be hard to debug if not watched for.
142+
Python 3, and you will also need to read the tools' documentation in case some
143+
options you need are turned off by default.
165144

145+
Key issues to be aware of and check for:
166146

167147
Division
168148
++++++++
169149

170-
In Python 3, ``5 / 2 == 2.5`` and not ``2``; all division between ``int`` values
171-
result in a ``float``. This change has actually been planned since Python 2.2
172-
which was released in 2002. Since then users have been encouraged to add
173-
``from __future__ import division`` to any and all files which use the ``/`` and
174-
``//`` operators or to be running the interpreter with the ``-Q`` flag. If you
175-
have not been doing this then you will need to go through your code and do two
176-
things:
150+
In Python 3, ``5 / 2 == 2.5`` and not ``2`` as it was in Python 2; all
151+
division between ``int`` values result in a ``float``. This change has
152+
actually been planned since Python 2.2 which was released in 2002. Since then
153+
users have been encouraged to add ``from __future__ import division`` to any
154+
and all files which use the ``/`` and ``//`` operators or to be running the
155+
interpreter with the ``-Q`` flag. If you have not been doing this then you
156+
will need to go through your code and do two things:
177157

178158
#. Add ``from __future__ import division`` to your files
179159
#. Update any division operator as necessary to either use ``//`` to use floor
@@ -197,30 +177,29 @@ specific type. This complicated the situation especially for anyone supporting
197177
multiple languages as APIs wouldn't bother explicitly supporting ``unicode``
198178
when they claimed text data support.
199179

200-
To make the distinction between text and binary data clearer and more
201-
pronounced, Python 3 did what most languages created in the age of the internet
202-
have done and made text and binary data distinct types that cannot blindly be
203-
mixed together (Python predates widespread access to the internet). For any code
204-
that deals only with text or only binary data, this separation doesn't pose an
205-
issue. But for code that has to deal with both, it does mean you might have to
206-
now care about when you are using text compared to binary data, which is why
207-
this cannot be entirely automated.
208-
209-
To start, you will need to decide which APIs take text and which take binary
210-
(it is **highly** recommended you don't design APIs that can take both due to
211-
the difficulty of keeping the code working; as stated earlier it is difficult to
212-
do well). In Python 2 this means making sure the APIs that take text can work
213-
with ``unicode`` and those that work with binary data work with the
214-
``bytes`` type from Python 3 (which is a subset of ``str`` in Python 2 and acts
215-
as an alias for ``bytes`` type in Python 2). Usually the biggest issue is
216-
realizing which methods exist on which types in Python 2 & 3 simultaneously
217-
(for text that's ``unicode`` in Python 2 and ``str`` in Python 3, for binary
218-
that's ``str``/``bytes`` in Python 2 and ``bytes`` in Python 3). The following
219-
table lists the **unique** methods of each data type across Python 2 & 3
220-
(e.g., the ``decode()`` method is usable on the equivalent binary data type in
221-
either Python 2 or 3, but it can't be used by the textual data type consistently
222-
between Python 2 and 3 because ``str`` in Python 3 doesn't have the method). Do
223-
note that as of Python 3.5 the ``__mod__`` method was added to the bytes type.
180+
Python 3 made text and binary data distinct types that cannot simply be mixed
181+
together. For any code that deals only with text or only binary data, this
182+
separation doesn't pose an issue. But for code that has to deal with both, it
183+
does mean you might have to now care about when you are using text compared
184+
to binary data, which is why this cannot be entirely automated.
185+
186+
Decide which APIs take text and which take binary (it is **highly** recommended
187+
you don't design APIs that can take both due to the difficulty of keeping the
188+
code working; as stated earlier it is difficult to do well). In Python 2 this
189+
means making sure the APIs that take text can work with ``unicode`` and those
190+
that work with binary data work with the ``bytes`` type from Python 3
191+
(which is a subset of ``str`` in Python 2 and acts as an alias for ``bytes``
192+
type in Python 2). Usually the biggest issue is realizing which methods exist
193+
on which types in Python 2 and 3 simultaneously (for text that's ``unicode``
194+
in Python 2 and ``str`` in Python 3, for binary that's ``str``/``bytes`` in
195+
Python 2 and ``bytes`` in Python 3).
196+
197+
The following table lists the **unique** methods of each data type across
198+
Python 2 and 3 (e.g., the ``decode()`` method is usable on the equivalent binary
199+
data type in either Python 2 or 3, but it can't be used by the textual data
200+
type consistently between Python 2 and 3 because ``str`` in Python 3 doesn't
201+
have the method). Do note that as of Python 3.5 the ``__mod__`` method was
202+
added to the bytes type.
224203

225204
======================== =====================
226205
**Text data** **Binary data**
@@ -246,12 +225,11 @@ having to keep track of what type of data you are working with.
246225
The next issue is making sure you know whether the string literals in your code
247226
represent text or binary data. You should add a ``b`` prefix to any
248227
literal that presents binary data. For text you should add a ``u`` prefix to
249-
the text literal. (there is a :mod:`__future__` import to force all unspecified
228+
the text literal. (There is a :mod:`__future__` import to force all unspecified
250229
literals to be Unicode, but usage has shown it isn't as effective as adding a
251230
``b`` or ``u`` prefix to all literals explicitly)
252231

253-
As part of this dichotomy you also need to be careful about opening files.
254-
Unless you have been working on Windows, there is a chance you have not always
232+
You also need to be careful about opening files. Possibly you have not always
255233
bothered to add the ``b`` mode when opening a binary file (e.g., ``rb`` for
256234
binary reading). Under Python 3, binary files and text files are clearly
257235
distinct and mutually incompatible; see the :mod:`io` module for details.
@@ -265,7 +243,7 @@ outdated practice of using :func:`codecs.open` as that's only necessary for
265243
keeping compatibility with Python 2.5.
266244

267245
The constructors of both ``str`` and ``bytes`` have different semantics for the
268-
same arguments between Python 2 & 3. Passing an integer to ``bytes`` in Python 2
246+
same arguments between Python 2 and 3. Passing an integer to ``bytes`` in Python 2
269247
will give you the string representation of the integer: ``bytes(3) == '3'``.
270248
But in Python 3, an integer argument to ``bytes`` will give you a bytes object
271249
as long as the integer specified, filled with null bytes:
@@ -400,7 +378,7 @@ Use continuous integration to stay compatible
400378
---------------------------------------------
401379

402380
Once you are able to fully run under Python 3 you will want to make sure your
403-
code always works under both Python 2 & 3. Probably the best tool for running
381+
code always works under both Python 2 and 3. Probably the best tool for running
404382
your tests under multiple Python interpreters is tox_. You can then integrate
405383
tox with your continuous integration system so that you never accidentally break
406384
Python 2 or 3 support.
@@ -413,11 +391,6 @@ separation of text/binary data handling or indexing on bytes you wouldn't easily
413391
find the mistake. This flag will raise an exception when these kinds of
414392
comparisons occur, making the mistake much easier to track down.
415393

416-
And that's mostly it! At this point your code base is compatible with both
417-
Python 2 and 3 simultaneously. Your testing will also be set up so that you
418-
don't accidentally break Python 2 or 3 compatibility regardless of which version
419-
you typically run your tests under while developing.
420-
421394

422395
Consider using optional static type checking
423396
--------------------------------------------

0 commit comments

Comments
 (0)