peps/pep-0386/index.html

623 lines
62 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 386 Changing the version comparison module in Distutils | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0386/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 386 Changing the version comparison module in Distutils | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0386/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 386</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 386 Changing the version comparison module in Distutils</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Tarek Ziadé &lt;tarek&#32;&#97;t&#32;ziade.org&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Replaced by another succeeding PEP">Superseded</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Topic<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="../topic/packaging/">Packaging</a></dd>
<dt class="field-odd">Created<span class="colon">:</span></dt>
<dd class="field-odd">04-Jun-2009</dd>
<dt class="field-even">Superseded-By<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="../pep-0440/">440</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#requisites-and-current-status">Requisites and current status</a><ul>
<li><a class="reference internal" href="#distutils">Distutils</a></li>
<li><a class="reference internal" href="#setuptools">Setuptools</a></li>
<li><a class="reference internal" href="#caveats-of-existing-systems">Caveats of existing systems</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-new-versioning-algorithm">The new versioning algorithm</a><ul>
<li><a class="reference internal" href="#normalizedversion">NormalizedVersion</a></li>
<li><a class="reference internal" href="#suggest-normalized-version">suggest_normalized_version</a></li>
</ul>
</li>
<li><a class="reference internal" href="#roadmap">Roadmap</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>Note: This PEP has been superseded by the version identification and
dependency specification scheme defined in <a class="pep reference internal" href="../pep-0440/" title="PEP 440 Version Identification and Dependency Specification">PEP 440</a>.</p>
<p>This PEP proposed a new version comparison schema system in Distutils.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>In Python there are no real restrictions yet on how a project should manage its
versions, and how they should be incremented.</p>
<p>Distutils provides a <code class="docutils literal notranslate"><span class="pre">version</span></code> distribution meta-data field but it is freeform and
current users, such as PyPI usually consider the latest version pushed as the
<code class="docutils literal notranslate"><span class="pre">latest</span></code> one, regardless of the expected semantics.</p>
<p>Distutils will soon extend its capabilities to allow distributions to express a
dependency on other distributions through the <code class="docutils literal notranslate"><span class="pre">Requires-Dist</span></code> metadata field
(see <a class="pep reference internal" href="../pep-0345/" title="PEP 345 Metadata for Python Software Packages 1.2">PEP 345</a>) and it will optionally allow use of that field to
restrict the dependency to a set of compatible versions. Notice that this field
is replacing <code class="docutils literal notranslate"><span class="pre">Requires</span></code> that was expressing dependencies on modules and packages.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">Requires-Dist</span></code> field will allow a distribution to define a dependency on
another package and optionally restrict this dependency to a set of
compatible versions, so one may write:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Requires</span><span class="o">-</span><span class="n">Dist</span><span class="p">:</span> <span class="n">zope</span><span class="o">.</span><span class="n">interface</span> <span class="p">(</span><span class="o">&gt;</span><span class="mf">3.5.0</span><span class="p">)</span>
</pre></div>
</div>
<p>This means that the distribution requires <code class="docutils literal notranslate"><span class="pre">zope.interface</span></code> with a version
greater than <code class="docutils literal notranslate"><span class="pre">3.5.0</span></code>.</p>
<p>This also means that Python projects will need to follow the same convention
as the tool that will be used to install them, so they are able to compare
versions.</p>
<p>That is why this PEP proposes, for the sake of interoperability, a standard
schema to express version information and its comparison semantics.</p>
<p>Furthermore, this will make OS packagers work easier when repackaging standards
compliant distributions, because as of now it can be difficult to decide how two
distribution versions compare.</p>
</section>
<section id="requisites-and-current-status">
<h2><a class="toc-backref" href="#requisites-and-current-status" role="doc-backlink">Requisites and current status</a></h2>
<p>It is not in the scope of this PEP to provide a universal versioning schema
intended to support all or even most of existing versioning schemas. There
will always be competing grammars, either mandated by distro or project
policies or by historical reasons that we cannot expect to change.</p>
<p>The proposed schema should be able to express the usual versioning semantics,
so its possible to parse any alternative versioning schema and transform it
into a compliant one. This is how OS packagers usually deal with the existing
version schemas and is a preferable alternative than supporting an arbitrary
set of versioning schemas.</p>
<p>Conformance to usual practice and conventions, as well as a simplicity are a
plus, to ease frictionless adoption and painless transition. Practicality beats
purity, sometimes.</p>
<p>Projects have very different versioning needs, but the following are widely
considered important semantics:</p>
<ol class="arabic simple">
<li>it should be possible to express more than one versioning level
(usually this is expressed as major and minor revision and, sometimes,
also a micro revision).</li>
<li>a significant number of projects need special meaning versions for
“pre-releases” (such as “alpha”, “beta”, “rc”), and these have widely
used aliases (“a” stands for “alpha”, “b” for “beta” and “c” for “rc”).
And these pre-release versions make it impossible to use a simple
alphanumerical ordering of the version string components.
(Example: 3.1a1 &lt; 3.1)</li>
<li>some projects also need “post-releases” of regular versions,
mainly for installer work which cant be clearly expressed otherwise.</li>
<li>development versions allow packagers of unreleased work to avoid version
clash with later regular releases.</li>
</ol>
<p>For people that want to go further and use a tool to manage their version
numbers, the two major ones are:</p>
<ul class="simple">
<li>The current Distutils system <a class="footnote-reference brackets" href="#id10" id="id1">[1]</a></li>
<li>Setuptools <a class="footnote-reference brackets" href="#id11" id="id2">[2]</a></li>
</ul>
<section id="distutils">
<h3><a class="toc-backref" href="#distutils" role="doc-backlink">Distutils</a></h3>
<p>Distutils currently provides a <code class="docutils literal notranslate"><span class="pre">StrictVersion</span></code> and a <code class="docutils literal notranslate"><span class="pre">LooseVersion</span></code> class
that can be used to manage versions.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">LooseVersion</span></code> class is quite lax. From Distutils doc:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Version</span> <span class="n">numbering</span> <span class="k">for</span> <span class="n">anarchists</span> <span class="ow">and</span> <span class="n">software</span> <span class="n">realists</span><span class="o">.</span>
<span class="n">Implements</span> <span class="n">the</span> <span class="n">standard</span> <span class="n">interface</span> <span class="k">for</span> <span class="n">version</span> <span class="n">number</span> <span class="n">classes</span> <span class="k">as</span>
<span class="n">described</span> <span class="n">above</span><span class="o">.</span> <span class="n">A</span> <span class="n">version</span> <span class="n">number</span> <span class="n">consists</span> <span class="n">of</span> <span class="n">a</span> <span class="n">series</span> <span class="n">of</span> <span class="n">numbers</span><span class="p">,</span>
<span class="n">separated</span> <span class="n">by</span> <span class="n">either</span> <span class="n">periods</span> <span class="ow">or</span> <span class="n">strings</span> <span class="n">of</span> <span class="n">letters</span><span class="o">.</span> <span class="n">When</span> <span class="n">comparing</span>
<span class="n">version</span> <span class="n">numbers</span><span class="p">,</span> <span class="n">the</span> <span class="n">numeric</span> <span class="n">components</span> <span class="n">will</span> <span class="n">be</span> <span class="n">compared</span>
<span class="n">numerically</span><span class="p">,</span> <span class="ow">and</span> <span class="n">the</span> <span class="n">alphabetic</span> <span class="n">components</span> <span class="n">lexically</span><span class="o">.</span> <span class="n">The</span> <span class="n">following</span>
<span class="n">are</span> <span class="nb">all</span> <span class="n">valid</span> <span class="n">version</span> <span class="n">numbers</span><span class="p">,</span> <span class="ow">in</span> <span class="n">no</span> <span class="n">particular</span> <span class="n">order</span><span class="p">:</span>
<span class="mf">1.5.1</span>
<span class="mf">1.5.2</span><span class="n">b2</span>
<span class="mi">161</span>
<span class="mf">3.10</span><span class="n">a</span>
<span class="mf">8.02</span>
<span class="mf">3.4</span><span class="n">j</span>
<span class="mf">1996.07.12</span>
<span class="mf">3.2</span><span class="o">.</span><span class="n">pl0</span>
<span class="mf">3.1.1.6</span>
<span class="mi">2</span><span class="n">g6</span>
<span class="mi">11</span><span class="n">g</span>
<span class="mf">0.960923</span>
<span class="mf">2.2</span><span class="n">beta29</span>
<span class="mf">1.13</span><span class="o">++</span>
<span class="mf">5.5</span><span class="o">.</span><span class="n">kw</span>
<span class="mf">2.0</span><span class="n">b1pl0</span>
<span class="n">In</span> <span class="n">fact</span><span class="p">,</span> <span class="n">there</span> <span class="ow">is</span> <span class="n">no</span> <span class="n">such</span> <span class="n">thing</span> <span class="k">as</span> <span class="n">an</span> <span class="n">invalid</span> <span class="n">version</span> <span class="n">number</span> <span class="n">under</span>
<span class="n">this</span> <span class="n">scheme</span><span class="p">;</span> <span class="n">the</span> <span class="n">rules</span> <span class="k">for</span> <span class="n">comparison</span> <span class="n">are</span> <span class="n">simple</span> <span class="ow">and</span> <span class="n">predictable</span><span class="p">,</span>
<span class="n">but</span> <span class="n">may</span> <span class="ow">not</span> <span class="n">always</span> <span class="n">give</span> <span class="n">the</span> <span class="n">results</span> <span class="n">you</span> <span class="n">want</span> <span class="p">(</span><span class="k">for</span> <span class="n">some</span> <span class="n">definition</span>
<span class="n">of</span> <span class="s2">&quot;want&quot;</span><span class="p">)</span><span class="o">.</span>
</pre></div>
</div>
<p>This class makes any version string valid, and provides an algorithm to sort
them numerically then lexically. It means that anything can be used to version
your project:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">distutils.version</span> <span class="kn">import</span> <span class="n">LooseVersion</span> <span class="k">as</span> <span class="n">V</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">v1</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;FunkyVersion&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">v2</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;GroovieVersion&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">v1</span> <span class="o">&gt;</span> <span class="n">v2</span>
<span class="go">False</span>
</pre></div>
</div>
<p>The problem with this is that while it allows expressing any
nesting level it doesnt allow giving special meaning to versions
(pre and post-releases as well as development versions), as expressed in
requisites 2, 3 and 4.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">StrictVersion</span></code> class is more strict. From the doc:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Version</span> <span class="n">numbering</span> <span class="k">for</span> <span class="n">meticulous</span> <span class="n">retentive</span> <span class="ow">and</span> <span class="n">software</span> <span class="n">idealists</span><span class="o">.</span>
<span class="n">Implements</span> <span class="n">the</span> <span class="n">standard</span> <span class="n">interface</span> <span class="k">for</span> <span class="n">version</span> <span class="n">number</span> <span class="n">classes</span> <span class="k">as</span>
<span class="n">described</span> <span class="n">above</span><span class="o">.</span> <span class="n">A</span> <span class="n">version</span> <span class="n">number</span> <span class="n">consists</span> <span class="n">of</span> <span class="n">two</span> <span class="ow">or</span> <span class="n">three</span>
<span class="n">dot</span><span class="o">-</span><span class="n">separated</span> <span class="n">numeric</span> <span class="n">components</span><span class="p">,</span> <span class="k">with</span> <span class="n">an</span> <span class="n">optional</span> <span class="s2">&quot;pre-release&quot;</span> <span class="n">tag</span>
<span class="n">on</span> <span class="n">the</span> <span class="n">end</span><span class="o">.</span> <span class="n">The</span> <span class="n">pre</span><span class="o">-</span><span class="n">release</span> <span class="n">tag</span> <span class="n">consists</span> <span class="n">of</span> <span class="n">the</span> <span class="n">letter</span> <span class="s1">&#39;a&#39;</span> <span class="ow">or</span> <span class="s1">&#39;b&#39;</span>
<span class="n">followed</span> <span class="n">by</span> <span class="n">a</span> <span class="n">number</span><span class="o">.</span> <span class="n">If</span> <span class="n">the</span> <span class="n">numeric</span> <span class="n">components</span> <span class="n">of</span> <span class="n">two</span> <span class="n">version</span>
<span class="n">numbers</span> <span class="n">are</span> <span class="n">equal</span><span class="p">,</span> <span class="n">then</span> <span class="n">one</span> <span class="k">with</span> <span class="n">a</span> <span class="n">pre</span><span class="o">-</span><span class="n">release</span> <span class="n">tag</span> <span class="n">will</span> <span class="n">always</span>
<span class="n">be</span> <span class="n">deemed</span> <span class="n">earlier</span> <span class="p">(</span><span class="n">lesser</span><span class="p">)</span> <span class="n">than</span> <span class="n">one</span> <span class="n">without</span><span class="o">.</span>
<span class="n">The</span> <span class="n">following</span> <span class="n">are</span> <span class="n">valid</span> <span class="n">version</span> <span class="n">numbers</span> <span class="p">(</span><span class="n">shown</span> <span class="ow">in</span> <span class="n">the</span> <span class="n">order</span> <span class="n">that</span>
<span class="n">would</span> <span class="n">be</span> <span class="n">obtained</span> <span class="n">by</span> <span class="n">sorting</span> <span class="n">according</span> <span class="n">to</span> <span class="n">the</span> <span class="n">supplied</span> <span class="n">cmp</span> <span class="n">function</span><span class="p">):</span>
<span class="mf">0.4</span> <span class="mf">0.4.0</span> <span class="p">(</span><span class="n">these</span> <span class="n">two</span> <span class="n">are</span> <span class="n">equivalent</span><span class="p">)</span>
<span class="mf">0.4.1</span>
<span class="mf">0.5</span><span class="n">a1</span>
<span class="mf">0.5</span><span class="n">b3</span>
<span class="mf">0.5</span>
<span class="mf">0.9.6</span>
<span class="mf">1.0</span>
<span class="mf">1.0.4</span><span class="n">a3</span>
<span class="mf">1.0.4</span><span class="n">b1</span>
<span class="mf">1.0.4</span>
<span class="n">The</span> <span class="n">following</span> <span class="n">are</span> <span class="n">examples</span> <span class="n">of</span> <span class="n">invalid</span> <span class="n">version</span> <span class="n">numbers</span><span class="p">:</span>
<span class="mi">1</span>
<span class="mf">2.7.2.2</span>
<span class="mf">1.3</span><span class="o">.</span><span class="n">a4</span>
<span class="mf">1.3</span><span class="n">pl1</span>
<span class="mf">1.3</span><span class="n">c4</span>
</pre></div>
</div>
<p>This class enforces a few rules, and makes a decent tool to work with version
numbers:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">distutils.version</span> <span class="kn">import</span> <span class="n">StrictVersion</span> <span class="k">as</span> <span class="n">V</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">v2</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;GroovieVersion&#39;</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
<span class="c">...</span>
<span class="gr">ValueError</span>: <span class="n">invalid version number &#39;GroovieVersion&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">v2</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.1&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">v3</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.3&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">v2</span> <span class="o">&lt;</span> <span class="n">v3</span>
<span class="go">True</span>
</pre></div>
</div>
<p>It adds pre-release versions, and some structure, but lacks a few semantic
elements to make it usable, such as development releases or post-release tags,
as expressed in requisites 3 and 4.</p>
<p>Also, note that Distutils version classes have been present for years
but are not really used in the community.</p>
</section>
<section id="setuptools">
<h3><a class="toc-backref" href="#setuptools" role="doc-backlink">Setuptools</a></h3>
<p>Setuptools provides another version comparison tool <a class="footnote-reference brackets" href="#setuptools-version" id="id3">[3]</a>
which does not enforce any rules for the version, but tries to provide a better
algorithm to convert the strings to sortable keys, with a <code class="docutils literal notranslate"><span class="pre">parse_version</span></code>
function.</p>
<p>From the doc:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Convert</span> <span class="n">a</span> <span class="n">version</span> <span class="n">string</span> <span class="n">to</span> <span class="n">a</span> <span class="n">chronologically</span><span class="o">-</span><span class="n">sortable</span> <span class="n">key</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">rough</span> <span class="n">cross</span> <span class="n">between</span> <span class="n">Distutils</span><span class="s1">&#39; StrictVersion and LooseVersion;</span>
<span class="k">if</span> <span class="n">you</span> <span class="n">give</span> <span class="n">it</span> <span class="n">versions</span> <span class="n">that</span> <span class="n">would</span> <span class="n">work</span> <span class="k">with</span> <span class="n">StrictVersion</span><span class="p">,</span> <span class="n">then</span> <span class="n">it</span> <span class="n">behaves</span>
<span class="n">the</span> <span class="n">same</span><span class="p">;</span> <span class="n">otherwise</span> <span class="n">it</span> <span class="n">acts</span> <span class="n">like</span> <span class="n">a</span> <span class="n">slightly</span><span class="o">-</span><span class="n">smarter</span> <span class="n">LooseVersion</span><span class="o">.</span> <span class="n">It</span> <span class="ow">is</span>
<span class="o">*</span><span class="n">possible</span><span class="o">*</span> <span class="n">to</span> <span class="n">create</span> <span class="n">pathological</span> <span class="n">version</span> <span class="n">coding</span> <span class="n">schemes</span> <span class="n">that</span> <span class="n">will</span> <span class="n">fool</span>
<span class="n">this</span> <span class="n">parser</span><span class="p">,</span> <span class="n">but</span> <span class="n">they</span> <span class="n">should</span> <span class="n">be</span> <span class="n">very</span> <span class="n">rare</span> <span class="ow">in</span> <span class="n">practice</span><span class="o">.</span>
<span class="n">The</span> <span class="n">returned</span> <span class="n">value</span> <span class="n">will</span> <span class="n">be</span> <span class="n">a</span> <span class="nb">tuple</span> <span class="n">of</span> <span class="n">strings</span><span class="o">.</span> <span class="n">Numeric</span> <span class="n">portions</span> <span class="n">of</span> <span class="n">the</span>
<span class="n">version</span> <span class="n">are</span> <span class="n">padded</span> <span class="n">to</span> <span class="mi">8</span> <span class="n">digits</span> <span class="n">so</span> <span class="n">they</span> <span class="n">will</span> <span class="n">compare</span> <span class="n">numerically</span><span class="p">,</span> <span class="n">but</span>
<span class="n">without</span> <span class="n">relying</span> <span class="n">on</span> <span class="n">how</span> <span class="n">numbers</span> <span class="n">compare</span> <span class="n">relative</span> <span class="n">to</span> <span class="n">strings</span><span class="o">.</span> <span class="n">Dots</span> <span class="n">are</span>
<span class="n">dropped</span><span class="p">,</span> <span class="n">but</span> <span class="n">dashes</span> <span class="n">are</span> <span class="n">retained</span><span class="o">.</span> <span class="n">Trailing</span> <span class="n">zeros</span> <span class="n">between</span> <span class="n">alpha</span> <span class="n">segments</span>
<span class="ow">or</span> <span class="n">dashes</span> <span class="n">are</span> <span class="n">suppressed</span><span class="p">,</span> <span class="n">so</span> <span class="n">that</span> <span class="n">e</span><span class="o">.</span><span class="n">g</span><span class="o">.</span> <span class="s2">&quot;2.4.0&quot;</span> <span class="ow">is</span> <span class="n">considered</span> <span class="n">the</span> <span class="n">same</span> <span class="k">as</span>
<span class="s2">&quot;2.4&quot;</span><span class="o">.</span> <span class="n">Alphanumeric</span> <span class="n">parts</span> <span class="n">are</span> <span class="n">lower</span><span class="o">-</span><span class="n">cased</span><span class="o">.</span>
<span class="n">The</span> <span class="n">algorithm</span> <span class="n">assumes</span> <span class="n">that</span> <span class="n">strings</span> <span class="n">like</span> <span class="s2">&quot;-&quot;</span> <span class="ow">and</span> <span class="nb">any</span> <span class="n">alpha</span> <span class="n">string</span> <span class="n">that</span>
<span class="n">alphabetically</span> <span class="n">follows</span> <span class="s2">&quot;final&quot;</span> <span class="n">represents</span> <span class="n">a</span> <span class="s2">&quot;patch level&quot;</span><span class="o">.</span> <span class="n">So</span><span class="p">,</span> <span class="s2">&quot;2.4-1&quot;</span>
<span class="ow">is</span> <span class="n">assumed</span> <span class="n">to</span> <span class="n">be</span> <span class="n">a</span> <span class="n">branch</span> <span class="ow">or</span> <span class="n">patch</span> <span class="n">of</span> <span class="s2">&quot;2.4&quot;</span><span class="p">,</span> <span class="ow">and</span> <span class="n">therefore</span> <span class="s2">&quot;2.4.1&quot;</span> <span class="ow">is</span>
<span class="n">considered</span> <span class="n">newer</span> <span class="n">than</span> <span class="s2">&quot;2.4-1&quot;</span><span class="p">,</span> <span class="n">which</span> <span class="ow">in</span> <span class="n">turn</span> <span class="ow">is</span> <span class="n">newer</span> <span class="n">than</span> <span class="s2">&quot;2.4&quot;</span><span class="o">.</span>
<span class="n">Strings</span> <span class="n">like</span> <span class="s2">&quot;a&quot;</span><span class="p">,</span> <span class="s2">&quot;b&quot;</span><span class="p">,</span> <span class="s2">&quot;c&quot;</span><span class="p">,</span> <span class="s2">&quot;alpha&quot;</span><span class="p">,</span> <span class="s2">&quot;beta&quot;</span><span class="p">,</span> <span class="s2">&quot;candidate&quot;</span> <span class="ow">and</span> <span class="n">so</span> <span class="n">on</span> <span class="p">(</span><span class="n">that</span>
<span class="n">come</span> <span class="n">before</span> <span class="s2">&quot;final&quot;</span> <span class="n">alphabetically</span><span class="p">)</span> <span class="n">are</span> <span class="n">assumed</span> <span class="n">to</span> <span class="n">be</span> <span class="n">pre</span><span class="o">-</span><span class="n">release</span> <span class="n">versions</span><span class="p">,</span>
<span class="n">so</span> <span class="n">that</span> <span class="n">the</span> <span class="n">version</span> <span class="s2">&quot;2.4&quot;</span> <span class="ow">is</span> <span class="n">considered</span> <span class="n">newer</span> <span class="n">than</span> <span class="s2">&quot;2.4a1&quot;</span><span class="o">.</span>
<span class="n">Finally</span><span class="p">,</span> <span class="n">to</span> <span class="n">handle</span> <span class="n">miscellaneous</span> <span class="n">cases</span><span class="p">,</span> <span class="n">the</span> <span class="n">strings</span> <span class="s2">&quot;pre&quot;</span><span class="p">,</span> <span class="s2">&quot;preview&quot;</span><span class="p">,</span> <span class="ow">and</span>
<span class="s2">&quot;rc&quot;</span> <span class="n">are</span> <span class="n">treated</span> <span class="k">as</span> <span class="k">if</span> <span class="n">they</span> <span class="n">were</span> <span class="s2">&quot;c&quot;</span><span class="p">,</span> <span class="n">i</span><span class="o">.</span><span class="n">e</span><span class="o">.</span> <span class="k">as</span> <span class="n">though</span> <span class="n">they</span> <span class="n">were</span> <span class="n">release</span>
<span class="n">candidates</span><span class="p">,</span> <span class="ow">and</span> <span class="n">therefore</span> <span class="n">are</span> <span class="ow">not</span> <span class="k">as</span> <span class="n">new</span> <span class="k">as</span> <span class="n">a</span> <span class="n">version</span> <span class="n">string</span> <span class="n">that</span> <span class="n">does</span> <span class="ow">not</span>
<span class="n">contain</span> <span class="n">them</span><span class="p">,</span> <span class="ow">and</span> <span class="s2">&quot;dev&quot;</span> <span class="ow">is</span> <span class="n">replaced</span> <span class="k">with</span> <span class="n">an</span> <span class="s1">&#39;@&#39;</span> <span class="n">so</span> <span class="n">that</span> <span class="n">it</span> <span class="n">sorts</span> <span class="n">lower</span>
<span class="n">than</span> <span class="nb">any</span> <span class="n">other</span> <span class="n">pre</span><span class="o">-</span><span class="n">release</span> <span class="n">tag</span><span class="o">.</span>
</pre></div>
</div>
<p>In other words, <code class="docutils literal notranslate"><span class="pre">parse_version</span></code> will return a tuple for each version string,
that is compatible with <code class="docutils literal notranslate"><span class="pre">StrictVersion</span></code> but also accept arbitrary version and
deal with them so they can be compared:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">pkg_resources</span> <span class="kn">import</span> <span class="n">parse_version</span> <span class="k">as</span> <span class="n">V</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.2&#39;</span><span class="p">)</span>
<span class="go">(&#39;00000001&#39;, &#39;00000002&#39;, &#39;*final&#39;)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.2b2&#39;</span><span class="p">)</span>
<span class="go">(&#39;00000001&#39;, &#39;00000002&#39;, &#39;*b&#39;, &#39;00000002&#39;, &#39;*final&#39;)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;FunkyVersion&#39;</span><span class="p">)</span>
<span class="go">(&#39;*funkyversion&#39;, &#39;*final&#39;)</span>
</pre></div>
</div>
<p>In this schema practicality takes priority over purity, but as a result it
doesnt enforce any policy and leads to very complex semantics due to the lack
of a clear standard. It just tries to adapt to widely used conventions.</p>
</section>
<section id="caveats-of-existing-systems">
<h3><a class="toc-backref" href="#caveats-of-existing-systems" role="doc-backlink">Caveats of existing systems</a></h3>
<p>The major problem with the described version comparison tools is that they are
too permissive and, at the same time, arent capable of expressing some of the
required semantics. Many of the versions on PyPI <a class="footnote-reference brackets" href="#pypi" id="id4">[4]</a> are obviously not
useful versions, which makes it difficult for users to grok the versioning that
a particular package was using and to provide tools on top of PyPI.</p>
<p>Distutils classes are not really used in Python projects, but the
Setuptools function is quite widespread because its used by tools like
<code class="docutils literal notranslate"><span class="pre">easy_install</span></code> <a class="footnote-reference brackets" href="#ezinstall" id="id5">[6]</a>, <code class="docutils literal notranslate"><span class="pre">pip</span></code> <a class="footnote-reference brackets" href="#pip" id="id6">[5]</a> or <code class="docutils literal notranslate"><span class="pre">zc.buildout</span></code>
<a class="footnote-reference brackets" href="#zc-buildout" id="id7">[7]</a> to install dependencies of a given project.</p>
<p>While Setuptools <em>does</em> provide a mechanism for comparing/sorting versions,
it is much preferable if the versioning spec is such that a human can make a
reasonable attempt at that sorting without having to run it against some code.</p>
<p>Also theres a problem with the use of dates at the “major” version number
(e.g. a version string “20090421”) with RPMs: it means that any attempt to
switch to a more typical “major.minor…” version scheme is problematic because
it will always sort less than “20090421”.</p>
<p>Last, the meaning of <code class="docutils literal notranslate"><span class="pre">-</span></code> is specific to Setuptools, while it is avoided in
some packaging systems like the one used by Debian or Ubuntu.</p>
</section>
</section>
<section id="the-new-versioning-algorithm">
<h2><a class="toc-backref" href="#the-new-versioning-algorithm" role="doc-backlink">The new versioning algorithm</a></h2>
<p>During Pycon, members of the Python, Ubuntu and Fedora community worked on
a version standard that would be acceptable for everyone.</p>
<p>Its currently called <code class="docutils literal notranslate"><span class="pre">verlib</span></code> and a prototype lives at <a class="footnote-reference brackets" href="#prototype" id="id8">[10]</a>.</p>
<p>The pseudo-format supported is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">N</span><span class="o">.</span><span class="n">N</span><span class="p">[</span><span class="o">.</span><span class="n">N</span><span class="p">]</span><span class="o">+</span><span class="p">[{</span><span class="n">a</span><span class="o">|</span><span class="n">b</span><span class="o">|</span><span class="n">c</span><span class="o">|</span><span class="n">rc</span><span class="p">}</span><span class="n">N</span><span class="p">[</span><span class="o">.</span><span class="n">N</span><span class="p">]</span><span class="o">+</span><span class="p">][</span><span class="o">.</span><span class="n">postN</span><span class="p">][</span><span class="o">.</span><span class="n">devN</span><span class="p">]</span>
</pre></div>
</div>
<p>The real regular expression is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">expr</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">&quot;&quot;&quot;^</span>
<span class="s2">(?P&lt;version&gt;\d+\.\d+) # minimum &#39;N.N&#39;</span>
<span class="s2">(?P&lt;extraversion&gt;(?:\.\d+)*) # any number of extra &#39;.N&#39; segments</span>
<span class="s2">(?:</span>
<span class="s2"> (?P&lt;prerel&gt;[abc]|rc) # &#39;a&#39; = alpha, &#39;b&#39; = beta</span>
<span class="s2"> # &#39;c&#39; or &#39;rc&#39; = release candidate</span>
<span class="s2"> (?P&lt;prerelversion&gt;\d+(?:\.\d+)*)</span>
<span class="s2">)?</span>
<span class="s2">(?P&lt;postdev&gt;(\.post(?P&lt;post&gt;\d+))?(\.dev(?P&lt;dev&gt;\d+))?)?</span>
<span class="s2">$&quot;&quot;&quot;</span>
</pre></div>
</div>
<p>Some examples probably make it clearer:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">verlib</span> <span class="kn">import</span> <span class="n">NormalizedVersion</span> <span class="k">as</span> <span class="n">V</span>
<span class="gp">&gt;&gt;&gt; </span><span class="p">(</span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0a1&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0a2.dev456&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0a2&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0a2.1.dev456&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0a2.1&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0b1.dev456&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0b2&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0b2.post345&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0c1.dev456&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0c1&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0.dev456&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0.post456.dev34&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0.post456&#39;</span><span class="p">))</span>
<span class="go">True</span>
</pre></div>
</div>
<p>The trailing <code class="docutils literal notranslate"><span class="pre">.dev123</span></code> is for pre-releases. The <code class="docutils literal notranslate"><span class="pre">.post123</span></code> is for
post-releases which apparently are used by a number of projects out there
(e.g. Twisted <a class="footnote-reference brackets" href="#twisted" id="id9">[8]</a>). For example, <em>after</em> a <code class="docutils literal notranslate"><span class="pre">1.2.0</span></code> release there might
be a <code class="docutils literal notranslate"><span class="pre">1.2.0-r678</span></code> release. We used <code class="docutils literal notranslate"><span class="pre">post</span></code> instead of <code class="docutils literal notranslate"><span class="pre">r</span></code> because the
<code class="docutils literal notranslate"><span class="pre">r</span></code> is ambiguous as to whether it indicates a pre- or post-release.</p>
<p><code class="docutils literal notranslate"><span class="pre">.post456.dev34</span></code> indicates a dev marker for a post release, that sorts
before a <code class="docutils literal notranslate"><span class="pre">.post456</span></code> marker. This can be used to do development versions
of post releases.</p>
<p>Pre-releases can use <code class="docutils literal notranslate"><span class="pre">a</span></code> for “alpha”, <code class="docutils literal notranslate"><span class="pre">b</span></code> for “beta” and <code class="docutils literal notranslate"><span class="pre">c</span></code> for
“release candidate”. <code class="docutils literal notranslate"><span class="pre">rc</span></code> is an alternative notation for “release candidate”
that is added to make the version scheme compatible with Pythons own version
scheme. <code class="docutils literal notranslate"><span class="pre">rc</span></code> sorts after <code class="docutils literal notranslate"><span class="pre">c</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">verlib</span> <span class="kn">import</span> <span class="n">NormalizedVersion</span> <span class="k">as</span> <span class="n">V</span>
<span class="gp">&gt;&gt;&gt; </span><span class="p">(</span><span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0a1&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0a2&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0b3&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0c1&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0rc2&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">(</span><span class="s1">&#39;1.0&#39;</span><span class="p">))</span>
<span class="go">True</span>
</pre></div>
</div>
<p>Note that <code class="docutils literal notranslate"><span class="pre">c</span></code> is the preferred marker for third party projects.</p>
<p><code class="docutils literal notranslate"><span class="pre">verlib</span></code> provides a <code class="docutils literal notranslate"><span class="pre">NormalizedVersion</span></code> class and a
<code class="docutils literal notranslate"><span class="pre">suggest_normalized_version</span></code> function.</p>
<section id="normalizedversion">
<h3><a class="toc-backref" href="#normalizedversion" role="doc-backlink">NormalizedVersion</a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">NormalizedVersion</span></code> class is used to hold a version and to compare it
with others. It takes a string as an argument, that contains the representation
of the version:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">verlib</span> <span class="kn">import</span> <span class="n">NormalizedVersion</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">version</span> <span class="o">=</span> <span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">&#39;1.0&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>The version can be represented as a string:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
<span class="go">&#39;1.0&#39;</span>
</pre></div>
</div>
<p>Or compared with others:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">&#39;1.0&#39;</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">&#39;0.9&#39;</span><span class="p">)</span>
<span class="go">True</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">&#39;1.0&#39;</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">&#39;1.1&#39;</span><span class="p">)</span>
<span class="go">True</span>
</pre></div>
</div>
<p>A class method called <code class="docutils literal notranslate"><span class="pre">from_parts</span></code> is available if you want to create an
instance by providing the parts that composes the version.</p>
<p>Examples</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">version</span> <span class="o">=</span> <span class="n">NormalizedVersion</span><span class="o">.</span><span class="n">from_parts</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
<span class="go">&#39;1.0&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">version</span> <span class="o">=</span> <span class="n">NormalizedVersion</span><span class="o">.</span><span class="n">from_parts</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="s1">&#39;c&#39;</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
<span class="go">&#39;1.0c4&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">version</span> <span class="o">=</span> <span class="n">NormalizedVersion</span><span class="o">.</span><span class="n">from_parts</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="s1">&#39;c&#39;</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span> <span class="p">(</span><span class="s1">&#39;dev&#39;</span><span class="p">,</span> <span class="mi">34</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
<span class="go">&#39;1.0c4.dev34&#39;</span>
</pre></div>
</div>
</section>
<section id="suggest-normalized-version">
<h3><a class="toc-backref" href="#suggest-normalized-version" role="doc-backlink">suggest_normalized_version</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">suggest_normalized_version</span></code> is a function that suggests a normalized version
close to the given version string. If you have a version string that isnt
normalized (i.e. <code class="docutils literal notranslate"><span class="pre">NormalizedVersion</span></code> doesnt like it) then you might be able
to get an equivalent (or close) normalized version from this function.</p>
<p>This does a number of simple normalizations to the given string, based
on an observation of versions currently in use on PyPI.</p>
<p>Given a dump of those versions on January 6th 2010, the function has given those
results out of the 8821 distributions PyPI had:</p>
<ul class="simple">
<li>7822 (88.67%) already match <code class="docutils literal notranslate"><span class="pre">NormalizedVersion</span></code> without any change</li>
<li>717 (8.13%) match when using this suggestion method</li>
<li>282 (3.20%) dont match at all.</li>
</ul>
<p>The 3.20% of projects that are incompatible with <code class="docutils literal notranslate"><span class="pre">NormalizedVersion</span></code>
and cannot be transformed into a compatible form, are for most of them date-based
version schemes, versions with custom markers, or dummy versions. Examples:</p>
<ul class="simple">
<li>working proof of concept</li>
<li>1 (first draft)</li>
<li>unreleased.unofficialdev</li>
<li>0.1.alphadev</li>
<li>2008-03-29_r219</li>
<li>etc.</li>
</ul>
<p>When a tool needs to work with versions, a strategy is to use
<code class="docutils literal notranslate"><span class="pre">suggest_normalized_version</span></code> on the versions string. If this function returns
<code class="docutils literal notranslate"><span class="pre">None</span></code>, it means that the provided version is not close enough to the
standard scheme. If it returns a version that slightly differs from
the original version, its a suggested normalized version. Last, if it
returns the same string, it means that the version matches the scheme.</p>
<p>Heres an example of usage:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">verlib</span> <span class="kn">import</span> <span class="n">suggest_normalized_version</span><span class="p">,</span> <span class="n">NormalizedVersion</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">warnings</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">validate_version</span><span class="p">(</span><span class="n">version</span><span class="p">):</span>
<span class="gp">... </span> <span class="n">rversion</span> <span class="o">=</span> <span class="n">suggest_normalized_version</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
<span class="gp">... </span> <span class="k">if</span> <span class="n">rversion</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Cannot work with &quot;</span><span class="si">%s</span><span class="s1">&quot;&#39;</span> <span class="o">%</span> <span class="n">version</span><span class="p">)</span>
<span class="gp">... </span> <span class="k">if</span> <span class="n">rversion</span> <span class="o">!=</span> <span class="n">version</span><span class="p">:</span>
<span class="gp">... </span> <span class="n">warnings</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s1">&#39;&quot;</span><span class="si">%s</span><span class="s1">&quot; is not a normalized version.</span><span class="se">\n</span><span class="s1">&#39;</span>
<span class="gp">... </span> <span class="s1">&#39;It has been transformed into &quot;</span><span class="si">%s</span><span class="s1">&quot; &#39;</span>
<span class="gp">... </span> <span class="s1">&#39;for interoperability.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">version</span><span class="p">,</span> <span class="n">rversion</span><span class="p">))</span>
<span class="gp">... </span> <span class="k">return</span> <span class="n">NormalizedVersion</span><span class="p">(</span><span class="n">rversion</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">validate_version</span><span class="p">(</span><span class="s1">&#39;2.4-rc1&#39;</span><span class="p">)</span>
<span class="go">__main__:8: UserWarning: &quot;2.4-rc1&quot; is not a normalized version.</span>
<span class="go">It has been transformed into &quot;2.4c1&quot; for interoperability.</span>
<span class="go">NormalizedVersion(&#39;2.4c1&#39;)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">validate_version</span><span class="p">(</span><span class="s1">&#39;2.4c1&#39;</span><span class="p">)</span>
<span class="go">NormalizedVersion(&#39;2.4c1&#39;)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">validate_version</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
<span class="gr">File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;</span>
<span class="gr">File &quot;&lt;stdin&gt;&quot;, line 4, in validate_version</span>
<span class="gr">ValueError</span>: <span class="n">Cannot work with &quot;foo&quot;</span>
</pre></div>
</div>
</section>
</section>
<section id="roadmap">
<h2><a class="toc-backref" href="#roadmap" role="doc-backlink">Roadmap</a></h2>
<p>Distutils will deprecate its existing versions class in favor of
<code class="docutils literal notranslate"><span class="pre">NormalizedVersion</span></code>. The <code class="docutils literal notranslate"><span class="pre">verlib</span></code> module presented in this PEP will be
renamed to <code class="docutils literal notranslate"><span class="pre">version</span></code> and placed into the <code class="docutils literal notranslate"><span class="pre">distutils</span></code> package.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id10" role="doc-footnote">
<dt class="label" id="id10">[<a href="#id1">1</a>]</dt>
<dd><a class="reference external" href="http://docs.python.org/distutils">http://docs.python.org/distutils</a></aside>
<aside class="footnote brackets" id="id11" role="doc-footnote">
<dt class="label" id="id11">[<a href="#id2">2</a>]</dt>
<dd><a class="reference external" href="http://peak.telecommunity.com/DevCenter/setuptools">http://peak.telecommunity.com/DevCenter/setuptools</a></aside>
<aside class="footnote brackets" id="setuptools-version" role="doc-footnote">
<dt class="label" id="setuptools-version">[<a href="#id3">3</a>]</dt>
<dd><a class="reference external" href="http://peak.telecommunity.com/DevCenter/setuptools#specifying-your-project-s-version">http://peak.telecommunity.com/DevCenter/setuptools#specifying-your-project-s-version</a></aside>
<aside class="footnote brackets" id="pypi" role="doc-footnote">
<dt class="label" id="pypi">[<a href="#id4">4</a>]</dt>
<dd><a class="reference external" href="http://pypi.python.org/pypi">http://pypi.python.org/pypi</a></aside>
<aside class="footnote brackets" id="pip" role="doc-footnote">
<dt class="label" id="pip">[<a href="#id6">5</a>]</dt>
<dd><a class="reference external" href="http://pypi.python.org/pypi/pip">http://pypi.python.org/pypi/pip</a></aside>
<aside class="footnote brackets" id="ezinstall" role="doc-footnote">
<dt class="label" id="ezinstall">[<a href="#id5">6</a>]</dt>
<dd><a class="reference external" href="http://peak.telecommunity.com/DevCenter/EasyInstall">http://peak.telecommunity.com/DevCenter/EasyInstall</a></aside>
<aside class="footnote brackets" id="zc-buildout" role="doc-footnote">
<dt class="label" id="zc-buildout">[<a href="#id7">7</a>]</dt>
<dd><a class="reference external" href="http://pypi.python.org/pypi/zc.buildout">http://pypi.python.org/pypi/zc.buildout</a></aside>
<aside class="footnote brackets" id="twisted" role="doc-footnote">
<dt class="label" id="twisted">[<a href="#id9">8</a>]</dt>
<dd><a class="reference external" href="http://twistedmatrix.com/trac/">http://twistedmatrix.com/trac/</a></aside>
<aside class="footnote brackets" id="requires" role="doc-footnote">
<dt class="label" id="requires">[9]</dt>
<dd><a class="reference external" href="http://peak.telecommunity.com/DevCenter/setuptools">http://peak.telecommunity.com/DevCenter/setuptools</a></aside>
<aside class="footnote brackets" id="prototype" role="doc-footnote">
<dt class="label" id="prototype">[<a href="#id8">10</a>]</dt>
<dd><a class="reference external" href="http://bitbucket.org/tarek/distutilsversion/">http://bitbucket.org/tarek/distutilsversion/</a></aside>
</aside>
</section>
<section id="acknowledgments">
<h2><a class="toc-backref" href="#acknowledgments" role="doc-backlink">Acknowledgments</a></h2>
<p>Trent Mick, Matthias Klose, Phillip Eby, David Lyon, and many people at Pycon
and Distutils-SIG.</p>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0386.rst">https://github.com/python/peps/blob/main/peps/pep-0386.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0386.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#requisites-and-current-status">Requisites and current status</a><ul>
<li><a class="reference internal" href="#distutils">Distutils</a></li>
<li><a class="reference internal" href="#setuptools">Setuptools</a></li>
<li><a class="reference internal" href="#caveats-of-existing-systems">Caveats of existing systems</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-new-versioning-algorithm">The new versioning algorithm</a><ul>
<li><a class="reference internal" href="#normalizedversion">NormalizedVersion</a></li>
<li><a class="reference internal" href="#suggest-normalized-version">suggest_normalized_version</a></li>
</ul>
</li>
<li><a class="reference internal" href="#roadmap">Roadmap</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0386.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>