123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715 |
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
- <meta property="og:title" content="How to port Python 2 Code to Python 3" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://docs.python.org/3/howto/pyporting.html" />
- <meta property="og:site_name" content="Python documentation" />
- <meta property="og:description" content="author, Brett Cannon,. Abstract: Python 2 reached its official end-of-life at the start of 2020. This means that no new bug reports, fixes, or changes will be made to Python 2 - it’s no longer supp..." />
- <meta property="og:image" content="https://docs.python.org/3/_static/og-image.png" />
- <meta property="og:image:alt" content="Python documentation" />
- <meta name="description" content="author, Brett Cannon,. Abstract: Python 2 reached its official end-of-life at the start of 2020. This means that no new bug reports, fixes, or changes will be made to Python 2 - it’s no longer supp..." />
- <meta property="og:image:width" content="200" />
- <meta property="og:image:height" content="200" />
- <meta name="theme-color" content="#3776ab" />
- <title>How to port Python 2 Code to Python 3 — Python 3.12.0 documentation</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
-
- <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
- <link rel="stylesheet" type="text/css" href="../_static/pydoctheme.css?digest=b37c26da2f7529d09fe70b41c4b2133fe4931a90" />
- <link id="pygments_dark_css" media="(prefers-color-scheme: dark)" rel="stylesheet" type="text/css" href="../_static/pygments_dark.css" />
-
- <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
- <script src="../_static/jquery.js"></script>
- <script src="../_static/underscore.js"></script>
- <script src="../_static/doctools.js"></script>
-
- <script src="../_static/sidebar.js"></script>
-
- <link rel="search" type="application/opensearchdescription+xml"
- title="Search within Python 3.12.0 documentation"
- href="../_static/opensearch.xml"/>
- <link rel="author" title="About these documents" href="../about.html" />
- <link rel="index" title="Index" href="../genindex.html" />
- <link rel="search" title="Search" href="../search.html" />
- <link rel="copyright" title="Copyright" href="../copyright.html" />
- <link rel="next" title="Porting Extension Modules to Python 3" href="cporting.html" />
- <link rel="prev" title="Python HOWTOs" href="index.html" />
- <link rel="canonical" href="https://docs.python.org/3/howto/pyporting.html" />
-
-
-
-
- <style>
- @media only screen {
- table.full-width-table {
- width: 100%;
- }
- }
- </style>
- <link rel="stylesheet" href="../_static/pydoctheme_dark.css" media="(prefers-color-scheme: dark)" id="pydoctheme_dark_css">
- <link rel="shortcut icon" type="image/png" href="../_static/py.svg" />
- <script type="text/javascript" src="../_static/copybutton.js"></script>
- <script type="text/javascript" src="../_static/menu.js"></script>
- <script type="text/javascript" src="../_static/themetoggle.js"></script>
- </head>
- <body>
- <div class="mobile-nav">
- <input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
- aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu" />
- <nav class="nav-content" role="navigation">
- <label for="menuToggler" class="toggler__label">
- <span></span>
- </label>
- <span class="nav-items-wrapper">
- <a href="https://www.python.org/" class="nav-logo">
- <img src="../_static/py.svg" alt="Logo"/>
- </a>
- <span class="version_switcher_placeholder"></span>
- <form role="search" class="search" action="../search.html" method="get">
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
- <path fill-rule="nonzero" fill="currentColor" d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path>
- </svg>
- <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" />
- <input type="submit" value="Go"/>
- </form>
- </span>
- </nav>
- <div class="menu-wrapper">
- <nav class="menu" role="navigation" aria-label="main navigation">
- <div class="language_switcher_placeholder"></div>
-
- <label class="theme-selector-label">
- Theme
- <select class="theme-selector" oninput="activateTheme(this.value)">
- <option value="auto" selected>Auto</option>
- <option value="light">Light</option>
- <option value="dark">Dark</option>
- </select>
- </label>
- <div>
- <h3><a href="../contents.html">Table of Contents</a></h3>
- <ul>
- <li><a class="reference internal" href="#">How to port Python 2 Code to Python 3</a><ul>
- <li><a class="reference internal" href="#the-short-explanation">The Short Explanation</a></li>
- <li><a class="reference internal" href="#details">Details</a><ul>
- <li><a class="reference internal" href="#different-versions-of-python-2">Different versions of Python 2</a></li>
- <li><a class="reference internal" href="#make-sure-you-specify-the-proper-version-support-in-your-setup-py-file">Make sure you specify the proper version support in your <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> file</a></li>
- <li><a class="reference internal" href="#have-good-test-coverage">Have good test coverage</a></li>
- <li><a class="reference internal" href="#be-aware-of-the-differences-between-python-2-and-3">Be aware of the differences between Python 2 and 3</a></li>
- <li><a class="reference internal" href="#update-your-code">Update your code</a><ul>
- <li><a class="reference internal" href="#division">Division</a></li>
- <li><a class="reference internal" href="#text-versus-binary-data">Text versus binary data</a></li>
- <li><a class="reference internal" href="#use-feature-detection-instead-of-version-detection">Use feature detection instead of version detection</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#prevent-compatibility-regressions">Prevent compatibility regressions</a></li>
- <li><a class="reference internal" href="#check-which-dependencies-block-your-transition">Check which dependencies block your transition</a></li>
- <li><a class="reference internal" href="#update-your-setup-py-file-to-denote-python-3-compatibility">Update your <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> file to denote Python 3 compatibility</a></li>
- <li><a class="reference internal" href="#use-continuous-integration-to-stay-compatible">Use continuous integration to stay compatible</a></li>
- <li><a class="reference internal" href="#consider-using-optional-static-type-checking">Consider using optional static type checking</a></li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </div>
- <div>
- <h4>Previous topic</h4>
- <p class="topless"><a href="index.html"
- title="previous chapter">Python HOWTOs</a></p>
- </div>
- <div>
- <h4>Next topic</h4>
- <p class="topless"><a href="cporting.html"
- title="next chapter">Porting Extension Modules to Python 3</a></p>
- </div>
- <div role="note" aria-label="source link">
- <h3>This Page</h3>
- <ul class="this-page-menu">
- <li><a href="../bugs.html">Report a Bug</a></li>
- <li>
- <a href="https://github.com/python/cpython/blob/main/Doc/howto/pyporting.rst"
- rel="nofollow">Show Source
- </a>
- </li>
- </ul>
- </div>
- </nav>
- </div>
- </div>
-
- <div class="related" role="navigation" aria-label="related navigation">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="../genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="../py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li class="right" >
- <a href="cporting.html" title="Porting Extension Modules to Python 3"
- accesskey="N">next</a> |</li>
- <li class="right" >
- <a href="index.html" title="Python HOWTOs"
- accesskey="P">previous</a> |</li>
- <li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
- <li><a href="https://www.python.org/">Python</a> »</li>
- <li class="switchers">
- <div class="language_switcher_placeholder"></div>
- <div class="version_switcher_placeholder"></div>
- </li>
- <li>
-
- </li>
- <li id="cpython-language-and-version">
- <a href="../index.html">3.12.0 Documentation</a> »
- </li>
- <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python HOWTOs</a> »</li>
- <li class="nav-item nav-item-this"><a href="">How to port Python 2 Code to Python 3</a></li>
- <li class="right">
-
- <div class="inline-search" role="search">
- <form class="inline-search" action="../search.html" method="get">
- <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" />
- <input type="submit" value="Go" />
- </form>
- </div>
- |
- </li>
- <li class="right">
- <label class="theme-selector-label">
- Theme
- <select class="theme-selector" oninput="activateTheme(this.value)">
- <option value="auto" selected>Auto</option>
- <option value="light">Light</option>
- <option value="dark">Dark</option>
- </select>
- </label> |</li>
-
- </ul>
- </div>
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body" role="main">
-
- <section id="how-to-port-python-2-code-to-python-3">
- <span id="pyporting-howto"></span><h1>How to port Python 2 Code to Python 3<a class="headerlink" href="#how-to-port-python-2-code-to-python-3" title="Permalink to this headline">¶</a></h1>
- <dl class="field-list simple">
- <dt class="field-odd">author</dt>
- <dd class="field-odd"><p>Brett Cannon</p>
- </dd>
- </dl>
- <div class="topic">
- <p class="topic-title">Abstract</p>
- <p>Python 2 reached its official end-of-life at the start of 2020. This means
- that no new bug reports, fixes, or changes will be made to Python 2 - it’s
- no longer supported.</p>
- <p>This guide is intended to provide you with a path to Python 3 for your
- code, that includes compatibility with Python 2 as a first step.</p>
- <p>If you are looking to port an extension module instead of pure Python code,
- please see <a class="reference internal" href="cporting.html#cporting-howto"><span class="std std-ref">Porting Extension Modules to Python 3</span></a>.</p>
- <p>The archived <a class="reference external" href="https://mail.python.org/pipermail/python-porting/">python-porting</a> mailing list may contain some useful guidance.</p>
- </div>
- <section id="the-short-explanation">
- <h2>The Short Explanation<a class="headerlink" href="#the-short-explanation" title="Permalink to this headline">¶</a></h2>
- <p>To achieve Python 2/3 compatibility in a single code base, the basic steps
- are:</p>
- <ol class="arabic simple">
- <li><p>Only worry about supporting Python 2.7</p></li>
- <li><p>Make sure you have good test coverage (<a class="reference external" href="https://pypi.org/project/coverage">coverage.py</a> can help;
- <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">pip</span> <span class="pre">install</span> <span class="pre">coverage</span></code>)</p></li>
- <li><p>Learn the differences between Python 2 and 3</p></li>
- <li><p>Use <a class="reference external" href="https://python-future.org/automatic_conversion.html">Futurize</a> (or <a class="reference external" href="https://python-modernize.readthedocs.io/">Modernize</a>) to update your code (e.g. <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">pip</span> <span class="pre">install</span> <span class="pre">future</span></code>)</p></li>
- <li><p>Use <a class="reference external" href="https://pypi.org/project/pylint">Pylint</a> to help make sure you don’t regress on your Python 3 support
- (<code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">pip</span> <span class="pre">install</span> <span class="pre">pylint</span></code>)</p></li>
- <li><p>Use <a class="reference external" href="https://pypi.org/project/caniusepython3">caniusepython3</a> to find out which of your dependencies are blocking your
- use of Python 3 (<code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">pip</span> <span class="pre">install</span> <span class="pre">caniusepython3</span></code>)</p></li>
- <li><p>Once your dependencies are no longer blocking you, use continuous integration
- to make sure you stay compatible with Python 2 and 3 (<a class="reference external" href="https://pypi.org/project/tox">tox</a> can help test
- against multiple versions of Python; <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">pip</span> <span class="pre">install</span> <span class="pre">tox</span></code>)</p></li>
- <li><p>Consider using optional static type checking to make sure your type usage
- works in both Python 2 and 3 (e.g. use <a class="reference external" href="https://mypy-lang.org/">mypy</a> to check your typing under both
- Python 2 and Python 3; <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">pip</span> <span class="pre">install</span> <span class="pre">mypy</span></code>).</p></li>
- </ol>
- <div class="admonition note">
- <p class="admonition-title">Note</p>
- <p>Note: Using <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">pip</span> <span class="pre">install</span></code> guarantees that the <code class="docutils literal notranslate"><span class="pre">pip</span></code> you invoke
- is the one installed for the Python currently in use, whether it be
- a system-wide <code class="docutils literal notranslate"><span class="pre">pip</span></code> or one installed within a
- <a class="reference internal" href="../tutorial/venv.html#tut-venv"><span class="std std-ref">virtual environment</span></a>.</p>
- </div>
- </section>
- <section id="details">
- <h2>Details<a class="headerlink" href="#details" title="Permalink to this headline">¶</a></h2>
- <p>Even if other factors - say, dependencies over which you have no control -
- still require you to support Python 2, that does not prevent you taking the
- step of including Python 3 support.</p>
- <p>Most changes required to support Python 3 lead to cleaner code using newer
- practices even in Python 2 code.</p>
- <section id="different-versions-of-python-2">
- <h3>Different versions of Python 2<a class="headerlink" href="#different-versions-of-python-2" title="Permalink to this headline">¶</a></h3>
- <p>Ideally, your code should be compatible with Python 2.7, which was the
- last supported version of Python 2.</p>
- <p>Some of the tools mentioned in this guide will not work with Python 2.6.</p>
- <p>If absolutely necessary, the <a class="reference external" href="https://pypi.org/project/six">six</a> project can help you support Python 2.5 and
- 3 simultaneously. Do realize, though, that nearly all the projects listed in
- this guide will not be available to you.</p>
- <p>If you are able to skip Python 2.5 and older, the required changes to your
- code will be minimal. At worst you will have to use a function instead of a
- method in some instances or have to import a function instead of using a
- built-in one.</p>
- </section>
- <section id="make-sure-you-specify-the-proper-version-support-in-your-setup-py-file">
- <h3>Make sure you specify the proper version support in your <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> file<a class="headerlink" href="#make-sure-you-specify-the-proper-version-support-in-your-setup-py-file" title="Permalink to this headline">¶</a></h3>
- <p>In your <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> file you should have the proper <a class="reference external" href="https://pypi.org/classifiers">trove classifier</a>
- specifying what versions of Python you support. As your project does not support
- Python 3 yet you should at least have
- <code class="docutils literal notranslate"><span class="pre">Programming</span> <span class="pre">Language</span> <span class="pre">::</span> <span class="pre">Python</span> <span class="pre">::</span> <span class="pre">2</span> <span class="pre">::</span> <span class="pre">Only</span></code> specified. Ideally you should
- also specify each major/minor version of Python that you do support, e.g.
- <code class="docutils literal notranslate"><span class="pre">Programming</span> <span class="pre">Language</span> <span class="pre">::</span> <span class="pre">Python</span> <span class="pre">::</span> <span class="pre">2.7</span></code>.</p>
- </section>
- <section id="have-good-test-coverage">
- <h3>Have good test coverage<a class="headerlink" href="#have-good-test-coverage" title="Permalink to this headline">¶</a></h3>
- <p>Once you have your code supporting the oldest version of Python 2 you want it
- to, you will want to make sure your test suite has good coverage. A good rule of
- thumb is that if you want to be confident enough in your test suite that any
- failures that appear after having tools rewrite your code are actual bugs in the
- tools and not in your code. If you want a number to aim for, try to get over 80%
- coverage (and don’t feel bad if you find it hard to get better than 90%
- coverage). If you don’t already have a tool to measure test coverage then
- <a class="reference external" href="https://pypi.org/project/coverage">coverage.py</a> is recommended.</p>
- </section>
- <section id="be-aware-of-the-differences-between-python-2-and-3">
- <h3>Be aware of the differences between Python 2 and 3<a class="headerlink" href="#be-aware-of-the-differences-between-python-2-and-3" title="Permalink to this headline">¶</a></h3>
- <p>Once you have your code well-tested you are ready to begin porting your code to
- Python 3! But to fully understand how your code is going to change and what
- you want to look out for while you code, you will want to learn what changes
- Python 3 makes in terms of Python 2.</p>
- <p>Some resources for understanding the differences and their implications for you
- code:</p>
- <ul class="simple">
- <li><p>the <a class="reference internal" href="../whatsnew/index.html#whatsnew-index"><span class="std std-ref">“What’s New”</span></a> doc for each release of Python 3</p></li>
- <li><p>the <a class="reference external" href="http://python3porting.com/">Porting to Python 3</a> book (which is free online)</p></li>
- <li><p>the handy <a class="reference external" href="https://python-future.org/compatible_idioms.html">cheat sheet</a> from the Python-Future project.</p></li>
- </ul>
- </section>
- <section id="update-your-code">
- <h3>Update your code<a class="headerlink" href="#update-your-code" title="Permalink to this headline">¶</a></h3>
- <p>There are tools available that can port your code automatically.</p>
- <p><a class="reference external" href="https://python-future.org/automatic_conversion.html">Futurize</a> does its best to make Python 3 idioms and practices exist in Python
- 2, e.g. backporting the <code class="docutils literal notranslate"><span class="pre">bytes</span></code> type from Python 3 so that you have
- semantic parity between the major versions of Python. This is the better
- approach for most cases.</p>
- <p><a class="reference external" href="https://python-modernize.readthedocs.io/">Modernize</a>, on the other hand, is more conservative and targets a Python 2/3
- subset of Python, directly relying on <a class="reference external" href="https://pypi.org/project/six">six</a> to help provide compatibility.</p>
- <p>A good approach is to run the tool over your test suite first and visually
- inspect the diff to make sure the transformation is accurate. After you have
- transformed your test suite and verified that all the tests still pass as
- expected, then you can transform your application code knowing that any tests
- which fail is a translation failure.</p>
- <p>Unfortunately the tools can’t automate everything to make your code work under
- Python 3, and you will also need to read the tools’ documentation in case some
- options you need are turned off by default.</p>
- <p>Key issues to be aware of and check for:</p>
- <section id="division">
- <h4>Division<a class="headerlink" href="#division" title="Permalink to this headline">¶</a></h4>
- <p>In Python 3, <code class="docutils literal notranslate"><span class="pre">5</span> <span class="pre">/</span> <span class="pre">2</span> <span class="pre">==</span> <span class="pre">2.5</span></code> and not <code class="docutils literal notranslate"><span class="pre">2</span></code> as it was in Python 2; all
- division between <code class="docutils literal notranslate"><span class="pre">int</span></code> values result in a <code class="docutils literal notranslate"><span class="pre">float</span></code>. This change has
- actually been planned since Python 2.2 which was released in 2002. Since then
- users have been encouraged to add <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">division</span></code> to any
- and all files which use the <code class="docutils literal notranslate"><span class="pre">/</span></code> and <code class="docutils literal notranslate"><span class="pre">//</span></code> operators or to be running the
- interpreter with the <code class="docutils literal notranslate"><span class="pre">-Q</span></code> flag. If you have not been doing this then you
- will need to go through your code and do two things:</p>
- <ol class="arabic simple">
- <li><p>Add <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">division</span></code> to your files</p></li>
- <li><p>Update any division operator as necessary to either use <code class="docutils literal notranslate"><span class="pre">//</span></code> to use floor
- division or continue using <code class="docutils literal notranslate"><span class="pre">/</span></code> and expect a float</p></li>
- </ol>
- <p>The reason that <code class="docutils literal notranslate"><span class="pre">/</span></code> isn’t simply translated to <code class="docutils literal notranslate"><span class="pre">//</span></code> automatically is that if
- an object defines a <code class="docutils literal notranslate"><span class="pre">__truediv__</span></code> method but not <code class="docutils literal notranslate"><span class="pre">__floordiv__</span></code> then your
- code would begin to fail (e.g. a user-defined class that uses <code class="docutils literal notranslate"><span class="pre">/</span></code> to
- signify some operation but not <code class="docutils literal notranslate"><span class="pre">//</span></code> for the same thing or at all).</p>
- </section>
- <section id="text-versus-binary-data">
- <h4>Text versus binary data<a class="headerlink" href="#text-versus-binary-data" title="Permalink to this headline">¶</a></h4>
- <p>In Python 2 you could use the <code class="docutils literal notranslate"><span class="pre">str</span></code> type for both text and binary data.
- Unfortunately this confluence of two different concepts could lead to brittle
- code which sometimes worked for either kind of data, sometimes not. It also
- could lead to confusing APIs if people didn’t explicitly state that something
- that accepted <code class="docutils literal notranslate"><span class="pre">str</span></code> accepted either text or binary data instead of one
- specific type. This complicated the situation especially for anyone supporting
- multiple languages as APIs wouldn’t bother explicitly supporting <code class="docutils literal notranslate"><span class="pre">unicode</span></code>
- when they claimed text data support.</p>
- <p>Python 3 made text and binary data distinct types that cannot simply be mixed
- together. For any code that deals only with text or only binary data, this
- separation doesn’t pose an issue. But for code that has to deal with both, it
- does mean you might have to now care about when you are using text compared
- to binary data, which is why this cannot be entirely automated.</p>
- <p>Decide which APIs take text and which take binary (it is <strong>highly</strong> recommended
- you don’t design APIs that can take both due to the difficulty of keeping the
- code working; as stated earlier it is difficult to do well). In Python 2 this
- means making sure the APIs that take text can work with <code class="docutils literal notranslate"><span class="pre">unicode</span></code> and those
- that work with binary data work with the <code class="docutils literal notranslate"><span class="pre">bytes</span></code> type from Python 3
- (which is a subset of <code class="docutils literal notranslate"><span class="pre">str</span></code> in Python 2 and acts as an alias for <code class="docutils literal notranslate"><span class="pre">bytes</span></code>
- type in Python 2). Usually the biggest issue is realizing which methods exist
- on which types in Python 2 and 3 simultaneously (for text that’s <code class="docutils literal notranslate"><span class="pre">unicode</span></code>
- in Python 2 and <code class="docutils literal notranslate"><span class="pre">str</span></code> in Python 3, for binary that’s <code class="docutils literal notranslate"><span class="pre">str</span></code>/<code class="docutils literal notranslate"><span class="pre">bytes</span></code> in
- Python 2 and <code class="docutils literal notranslate"><span class="pre">bytes</span></code> in Python 3).</p>
- <p>The following table lists the <strong>unique</strong> methods of each data type across
- Python 2 and 3 (e.g., the <code class="docutils literal notranslate"><span class="pre">decode()</span></code> method is usable on the equivalent binary
- data type in either Python 2 or 3, but it can’t be used by the textual data
- type consistently between Python 2 and 3 because <code class="docutils literal notranslate"><span class="pre">str</span></code> in Python 3 doesn’t
- have the method). Do note that as of Python 3.5 the <code class="docutils literal notranslate"><span class="pre">__mod__</span></code> method was
- added to the bytes type.</p>
- <table class="docutils align-default">
- <colgroup>
- <col style="width: 53%" />
- <col style="width: 47%" />
- </colgroup>
- <tbody>
- <tr class="row-odd"><td><p><strong>Text data</strong></p></td>
- <td><p><strong>Binary data</strong></p></td>
- </tr>
- <tr class="row-even"><td><p></p></td>
- <td><p>decode</p></td>
- </tr>
- <tr class="row-odd"><td><p>encode</p></td>
- <td></td>
- </tr>
- <tr class="row-even"><td><p>format</p></td>
- <td></td>
- </tr>
- <tr class="row-odd"><td><p>isdecimal</p></td>
- <td></td>
- </tr>
- <tr class="row-even"><td><p>isnumeric</p></td>
- <td></td>
- </tr>
- </tbody>
- </table>
- <p>Making the distinction easier to handle can be accomplished by encoding and
- decoding between binary data and text at the edge of your code. This means that
- when you receive text in binary data, you should immediately decode it. And if
- your code needs to send text as binary data then encode it as late as possible.
- This allows your code to work with only text internally and thus eliminates
- having to keep track of what type of data you are working with.</p>
- <p>The next issue is making sure you know whether the string literals in your code
- represent text or binary data. You should add a <code class="docutils literal notranslate"><span class="pre">b</span></code> prefix to any
- literal that presents binary data. For text you should add a <code class="docutils literal notranslate"><span class="pre">u</span></code> prefix to
- the text literal. (There is a <a class="reference internal" href="../library/__future__.html#module-__future__" title="__future__: Future statement definitions"><code class="xref py py-mod docutils literal notranslate"><span class="pre">__future__</span></code></a> import to force all unspecified
- literals to be Unicode, but usage has shown it isn’t as effective as adding a
- <code class="docutils literal notranslate"><span class="pre">b</span></code> or <code class="docutils literal notranslate"><span class="pre">u</span></code> prefix to all literals explicitly)</p>
- <p>You also need to be careful about opening files. Possibly you have not always
- bothered to add the <code class="docutils literal notranslate"><span class="pre">b</span></code> mode when opening a binary file (e.g., <code class="docutils literal notranslate"><span class="pre">rb</span></code> for
- binary reading). Under Python 3, binary files and text files are clearly
- distinct and mutually incompatible; see the <a class="reference internal" href="../library/io.html#module-io" title="io: Core tools for working with streams."><code class="xref py py-mod docutils literal notranslate"><span class="pre">io</span></code></a> module for details.
- Therefore, you <strong>must</strong> make a decision of whether a file will be used for
- binary access (allowing binary data to be read and/or written) or textual access
- (allowing text data to be read and/or written). You should also use <a class="reference internal" href="../library/io.html#io.open" title="io.open"><code class="xref py py-func docutils literal notranslate"><span class="pre">io.open()</span></code></a>
- for opening files instead of the built-in <a class="reference internal" href="../library/functions.html#open" title="open"><code class="xref py py-func docutils literal notranslate"><span class="pre">open()</span></code></a> function as the <a class="reference internal" href="../library/io.html#module-io" title="io: Core tools for working with streams."><code class="xref py py-mod docutils literal notranslate"><span class="pre">io</span></code></a>
- module is consistent from Python 2 to 3 while the built-in <a class="reference internal" href="../library/functions.html#open" title="open"><code class="xref py py-func docutils literal notranslate"><span class="pre">open()</span></code></a> function
- is not (in Python 3 it’s actually <a class="reference internal" href="../library/io.html#io.open" title="io.open"><code class="xref py py-func docutils literal notranslate"><span class="pre">io.open()</span></code></a>). Do not bother with the
- outdated practice of using <a class="reference internal" href="../library/codecs.html#codecs.open" title="codecs.open"><code class="xref py py-func docutils literal notranslate"><span class="pre">codecs.open()</span></code></a> as that’s only necessary for
- keeping compatibility with Python 2.5.</p>
- <p>The constructors of both <code class="docutils literal notranslate"><span class="pre">str</span></code> and <code class="docutils literal notranslate"><span class="pre">bytes</span></code> have different semantics for the
- same arguments between Python 2 and 3. Passing an integer to <code class="docutils literal notranslate"><span class="pre">bytes</span></code> in Python 2
- will give you the string representation of the integer: <code class="docutils literal notranslate"><span class="pre">bytes(3)</span> <span class="pre">==</span> <span class="pre">'3'</span></code>.
- But in Python 3, an integer argument to <code class="docutils literal notranslate"><span class="pre">bytes</span></code> will give you a bytes object
- as long as the integer specified, filled with null bytes:
- <code class="docutils literal notranslate"><span class="pre">bytes(3)</span> <span class="pre">==</span> <span class="pre">b'\x00\x00\x00'</span></code>. A similar worry is necessary when passing a
- bytes object to <code class="docutils literal notranslate"><span class="pre">str</span></code>. In Python 2 you just get the bytes object back:
- <code class="docutils literal notranslate"><span class="pre">str(b'3')</span> <span class="pre">==</span> <span class="pre">b'3'</span></code>. But in Python 3 you get the string representation of the
- bytes object: <code class="docutils literal notranslate"><span class="pre">str(b'3')</span> <span class="pre">==</span> <span class="pre">"b'3'"</span></code>.</p>
- <p>Finally, the indexing of binary data requires careful handling (slicing does
- <strong>not</strong> require any special handling). In Python 2,
- <code class="docutils literal notranslate"><span class="pre">b'123'[1]</span> <span class="pre">==</span> <span class="pre">b'2'</span></code> while in Python 3 <code class="docutils literal notranslate"><span class="pre">b'123'[1]</span> <span class="pre">==</span> <span class="pre">50</span></code>. Because binary data
- is simply a collection of binary numbers, Python 3 returns the integer value for
- the byte you index on. But in Python 2 because <code class="docutils literal notranslate"><span class="pre">bytes</span> <span class="pre">==</span> <span class="pre">str</span></code>, indexing
- returns a one-item slice of bytes. The <a class="reference external" href="https://pypi.org/project/six">six</a> project has a function
- named <code class="docutils literal notranslate"><span class="pre">six.indexbytes()</span></code> which will return an integer like in Python 3:
- <code class="docutils literal notranslate"><span class="pre">six.indexbytes(b'123',</span> <span class="pre">1)</span></code>.</p>
- <p>To summarize:</p>
- <ol class="arabic simple">
- <li><p>Decide which of your APIs take text and which take binary data</p></li>
- <li><p>Make sure that your code that works with text also works with <code class="docutils literal notranslate"><span class="pre">unicode</span></code> and
- code for binary data works with <code class="docutils literal notranslate"><span class="pre">bytes</span></code> in Python 2 (see the table above
- for what methods you cannot use for each type)</p></li>
- <li><p>Mark all binary literals with a <code class="docutils literal notranslate"><span class="pre">b</span></code> prefix, textual literals with a <code class="docutils literal notranslate"><span class="pre">u</span></code>
- prefix</p></li>
- <li><p>Decode binary data to text as soon as possible, encode text as binary data as
- late as possible</p></li>
- <li><p>Open files using <a class="reference internal" href="../library/io.html#io.open" title="io.open"><code class="xref py py-func docutils literal notranslate"><span class="pre">io.open()</span></code></a> and make sure to specify the <code class="docutils literal notranslate"><span class="pre">b</span></code> mode when
- appropriate</p></li>
- <li><p>Be careful when indexing into binary data</p></li>
- </ol>
- </section>
- <section id="use-feature-detection-instead-of-version-detection">
- <h4>Use feature detection instead of version detection<a class="headerlink" href="#use-feature-detection-instead-of-version-detection" title="Permalink to this headline">¶</a></h4>
- <p>Inevitably you will have code that has to choose what to do based on what
- version of Python is running. The best way to do this is with feature detection
- of whether the version of Python you’re running under supports what you need.
- If for some reason that doesn’t work then you should make the version check be
- against Python 2 and not Python 3. To help explain this, let’s look at an
- example.</p>
- <p>Let’s pretend that you need access to a feature of <a class="reference internal" href="../library/importlib.html#module-importlib" title="importlib: The implementation of the import machinery."><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a> that
- is available in Python’s standard library since Python 3.3 and available for
- Python 2 through <a class="reference external" href="https://pypi.org/project/importlib2">importlib2</a> on PyPI. You might be tempted to write code to
- access e.g. the <a class="reference internal" href="../library/importlib.html#module-importlib.abc" title="importlib.abc: Abstract base classes related to import"><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib.abc</span></code></a> module by doing the following:</p>
- <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sys</span>
- <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">version_info</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
- <span class="kn">from</span> <span class="nn">importlib</span> <span class="kn">import</span> <span class="n">abc</span>
- <span class="k">else</span><span class="p">:</span>
- <span class="kn">from</span> <span class="nn">importlib2</span> <span class="kn">import</span> <span class="n">abc</span>
- </pre></div>
- </div>
- <p>The problem with this code is what happens when Python 4 comes out? It would
- be better to treat Python 2 as the exceptional case instead of Python 3 and
- assume that future Python versions will be more compatible with Python 3 than
- Python 2:</p>
- <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sys</span>
- <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">version_info</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">></span> <span class="mi">2</span><span class="p">:</span>
- <span class="kn">from</span> <span class="nn">importlib</span> <span class="kn">import</span> <span class="n">abc</span>
- <span class="k">else</span><span class="p">:</span>
- <span class="kn">from</span> <span class="nn">importlib2</span> <span class="kn">import</span> <span class="n">abc</span>
- </pre></div>
- </div>
- <p>The best solution, though, is to do no version detection at all and instead rely
- on feature detection. That avoids any potential issues of getting the version
- detection wrong and helps keep you future-compatible:</p>
- <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
- <span class="kn">from</span> <span class="nn">importlib</span> <span class="kn">import</span> <span class="n">abc</span>
- <span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
- <span class="kn">from</span> <span class="nn">importlib2</span> <span class="kn">import</span> <span class="n">abc</span>
- </pre></div>
- </div>
- </section>
- </section>
- <section id="prevent-compatibility-regressions">
- <h3>Prevent compatibility regressions<a class="headerlink" href="#prevent-compatibility-regressions" title="Permalink to this headline">¶</a></h3>
- <p>Once you have fully translated your code to be compatible with Python 3, you
- will want to make sure your code doesn’t regress and stop working under
- Python 3. This is especially true if you have a dependency which is blocking you
- from actually running under Python 3 at the moment.</p>
- <p>To help with staying compatible, any new modules you create should have
- at least the following block of code at the top of it:</p>
- <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">absolute_import</span>
- <span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">division</span>
- <span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">print_function</span>
- </pre></div>
- </div>
- <p>You can also run Python 2 with the <code class="docutils literal notranslate"><span class="pre">-3</span></code> flag to be warned about various
- compatibility issues your code triggers during execution. If you turn warnings
- into errors with <code class="docutils literal notranslate"><span class="pre">-Werror</span></code> then you can make sure that you don’t accidentally
- miss a warning.</p>
- <p>You can also use the <a class="reference external" href="https://pypi.org/project/pylint">Pylint</a> project and its <code class="docutils literal notranslate"><span class="pre">--py3k</span></code> flag to lint your code
- to receive warnings when your code begins to deviate from Python 3
- compatibility. This also prevents you from having to run <a class="reference external" href="https://python-modernize.readthedocs.io/">Modernize</a> or <a class="reference external" href="https://python-future.org/automatic_conversion.html">Futurize</a>
- over your code regularly to catch compatibility regressions. This does require
- you only support Python 2.7 and Python 3.4 or newer as that is Pylint’s
- minimum Python version support.</p>
- </section>
- <section id="check-which-dependencies-block-your-transition">
- <h3>Check which dependencies block your transition<a class="headerlink" href="#check-which-dependencies-block-your-transition" title="Permalink to this headline">¶</a></h3>
- <p><strong>After</strong> you have made your code compatible with Python 3 you should begin to
- care about whether your dependencies have also been ported. The <a class="reference external" href="https://pypi.org/project/caniusepython3">caniusepython3</a>
- project was created to help you determine which projects
- – directly or indirectly – are blocking you from supporting Python 3. There
- is both a command-line tool as well as a web interface at
- <a class="reference external" href="https://caniusepython3.com">https://caniusepython3.com</a>.</p>
- <p>The project also provides code which you can integrate into your test suite so
- that you will have a failing test when you no longer have dependencies blocking
- you from using Python 3. This allows you to avoid having to manually check your
- dependencies and to be notified quickly when you can start running on Python 3.</p>
- </section>
- <section id="update-your-setup-py-file-to-denote-python-3-compatibility">
- <h3>Update your <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> file to denote Python 3 compatibility<a class="headerlink" href="#update-your-setup-py-file-to-denote-python-3-compatibility" title="Permalink to this headline">¶</a></h3>
- <p>Once your code works under Python 3, you should update the classifiers in
- your <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> to contain <code class="docutils literal notranslate"><span class="pre">Programming</span> <span class="pre">Language</span> <span class="pre">::</span> <span class="pre">Python</span> <span class="pre">::</span> <span class="pre">3</span></code> and to not
- specify sole Python 2 support. This will tell anyone using your code that you
- support Python 2 <strong>and</strong> 3. Ideally you will also want to add classifiers for
- each major/minor version of Python you now support.</p>
- </section>
- <section id="use-continuous-integration-to-stay-compatible">
- <h3>Use continuous integration to stay compatible<a class="headerlink" href="#use-continuous-integration-to-stay-compatible" title="Permalink to this headline">¶</a></h3>
- <p>Once you are able to fully run under Python 3 you will want to make sure your
- code always works under both Python 2 and 3. Probably the best tool for running
- your tests under multiple Python interpreters is <a class="reference external" href="https://pypi.org/project/tox">tox</a>. You can then integrate
- tox with your continuous integration system so that you never accidentally break
- Python 2 or 3 support.</p>
- <p>You may also want to use the <code class="docutils literal notranslate"><span class="pre">-bb</span></code> flag with the Python 3 interpreter to
- trigger an exception when you are comparing bytes to strings or bytes to an int
- (the latter is available starting in Python 3.5). By default type-differing
- comparisons simply return <code class="docutils literal notranslate"><span class="pre">False</span></code>, but if you made a mistake in your
- separation of text/binary data handling or indexing on bytes you wouldn’t easily
- find the mistake. This flag will raise an exception when these kinds of
- comparisons occur, making the mistake much easier to track down.</p>
- </section>
- <section id="consider-using-optional-static-type-checking">
- <h3>Consider using optional static type checking<a class="headerlink" href="#consider-using-optional-static-type-checking" title="Permalink to this headline">¶</a></h3>
- <p>Another way to help port your code is to use a static type checker like
- <a class="reference external" href="https://mypy-lang.org/">mypy</a> or <a class="reference external" href="https://github.com/google/pytype">pytype</a> on your code. These tools can be used to analyze your code as
- if it’s being run under Python 2, then you can run the tool a second time as if
- your code is running under Python 3. By running a static type checker twice like
- this you can discover if you’re e.g. misusing binary data type in one version
- of Python compared to another. If you add optional type hints to your code you
- can also explicitly state whether your APIs use textual or binary data, helping
- to make sure everything functions as expected in both versions of Python.</p>
- </section>
- </section>
- </section>
- <div class="clearer"></div>
- </div>
- </div>
- </div>
- <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
- <div class="sphinxsidebarwrapper">
- <div>
- <h3><a href="../contents.html">Table of Contents</a></h3>
- <ul>
- <li><a class="reference internal" href="#">How to port Python 2 Code to Python 3</a><ul>
- <li><a class="reference internal" href="#the-short-explanation">The Short Explanation</a></li>
- <li><a class="reference internal" href="#details">Details</a><ul>
- <li><a class="reference internal" href="#different-versions-of-python-2">Different versions of Python 2</a></li>
- <li><a class="reference internal" href="#make-sure-you-specify-the-proper-version-support-in-your-setup-py-file">Make sure you specify the proper version support in your <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> file</a></li>
- <li><a class="reference internal" href="#have-good-test-coverage">Have good test coverage</a></li>
- <li><a class="reference internal" href="#be-aware-of-the-differences-between-python-2-and-3">Be aware of the differences between Python 2 and 3</a></li>
- <li><a class="reference internal" href="#update-your-code">Update your code</a><ul>
- <li><a class="reference internal" href="#division">Division</a></li>
- <li><a class="reference internal" href="#text-versus-binary-data">Text versus binary data</a></li>
- <li><a class="reference internal" href="#use-feature-detection-instead-of-version-detection">Use feature detection instead of version detection</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#prevent-compatibility-regressions">Prevent compatibility regressions</a></li>
- <li><a class="reference internal" href="#check-which-dependencies-block-your-transition">Check which dependencies block your transition</a></li>
- <li><a class="reference internal" href="#update-your-setup-py-file-to-denote-python-3-compatibility">Update your <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> file to denote Python 3 compatibility</a></li>
- <li><a class="reference internal" href="#use-continuous-integration-to-stay-compatible">Use continuous integration to stay compatible</a></li>
- <li><a class="reference internal" href="#consider-using-optional-static-type-checking">Consider using optional static type checking</a></li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </div>
- <div>
- <h4>Previous topic</h4>
- <p class="topless"><a href="index.html"
- title="previous chapter">Python HOWTOs</a></p>
- </div>
- <div>
- <h4>Next topic</h4>
- <p class="topless"><a href="cporting.html"
- title="next chapter">Porting Extension Modules to Python 3</a></p>
- </div>
- <div role="note" aria-label="source link">
- <h3>This Page</h3>
- <ul class="this-page-menu">
- <li><a href="../bugs.html">Report a Bug</a></li>
- <li>
- <a href="https://github.com/python/cpython/blob/main/Doc/howto/pyporting.rst"
- rel="nofollow">Show Source
- </a>
- </li>
- </ul>
- </div>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related" role="navigation" aria-label="related navigation">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="../genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="../py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li class="right" >
- <a href="cporting.html" title="Porting Extension Modules to Python 3"
- >next</a> |</li>
- <li class="right" >
- <a href="index.html" title="Python HOWTOs"
- >previous</a> |</li>
- <li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
- <li><a href="https://www.python.org/">Python</a> »</li>
- <li class="switchers">
- <div class="language_switcher_placeholder"></div>
- <div class="version_switcher_placeholder"></div>
- </li>
- <li>
-
- </li>
- <li id="cpython-language-and-version">
- <a href="../index.html">3.12.0 Documentation</a> »
- </li>
- <li class="nav-item nav-item-1"><a href="index.html" >Python HOWTOs</a> »</li>
- <li class="nav-item nav-item-this"><a href="">How to port Python 2 Code to Python 3</a></li>
- <li class="right">
-
- <div class="inline-search" role="search">
- <form class="inline-search" action="../search.html" method="get">
- <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" />
- <input type="submit" value="Go" />
- </form>
- </div>
- |
- </li>
- <li class="right">
- <label class="theme-selector-label">
- Theme
- <select class="theme-selector" oninput="activateTheme(this.value)">
- <option value="auto" selected>Auto</option>
- <option value="light">Light</option>
- <option value="dark">Dark</option>
- </select>
- </label> |</li>
-
- </ul>
- </div>
- <div class="footer">
- © <a href="../copyright.html">Copyright</a> 2001-2023, Python Software Foundation.
- <br />
- This page is licensed under the Python Software Foundation License Version 2.
- <br />
- Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
- <br />
- See <a href="/license.html">History and License</a> for more information.<br />
- <br />
- The Python Software Foundation is a non-profit corporation.
- <a href="https://www.python.org/psf/donations/">Please donate.</a>
- <br />
- <br />
- Last updated on Oct 02, 2023.
- <a href="/bugs.html">Found a bug</a>?
- <br />
- Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 4.5.0.
- </div>
- </body>
- </html>
|