715 lines
51 KiB
HTML
715 lines
51 KiB
HTML
|
||
<!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> |