mirror of https://github.com/python/peps
623 lines
62 KiB
HTML
623 lines
62 KiB
HTML
|
||
<!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> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </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é <tarek at ziade.org></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">></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 it’s 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 < 3.1)</li>
|
||
<li>some projects also need “post-releases” of regular versions,
|
||
mainly for installer work which can’t 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">"want"</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">>>> </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">>>> </span><span class="n">v1</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">'FunkyVersion'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">v2</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">'GroovieVersion'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">v1</span> <span class="o">></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 doesn’t 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">"pre-release"</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">'a'</span> <span class="ow">or</span> <span class="s1">'b'</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">>>> </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">>>> </span><span class="n">v2</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">'GroovieVersion'</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 'GroovieVersion'</span>
|
||
<span class="gp">>>> </span><span class="n">v2</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.1'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">v3</span> <span class="o">=</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.3'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">v2</span> <span class="o"><</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">' 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">"2.4.0"</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">"2.4"</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">"-"</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">"final"</span> <span class="n">represents</span> <span class="n">a</span> <span class="s2">"patch level"</span><span class="o">.</span> <span class="n">So</span><span class="p">,</span> <span class="s2">"2.4-1"</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">"2.4"</span><span class="p">,</span> <span class="ow">and</span> <span class="n">therefore</span> <span class="s2">"2.4.1"</span> <span class="ow">is</span>
|
||
<span class="n">considered</span> <span class="n">newer</span> <span class="n">than</span> <span class="s2">"2.4-1"</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">"2.4"</span><span class="o">.</span>
|
||
|
||
<span class="n">Strings</span> <span class="n">like</span> <span class="s2">"a"</span><span class="p">,</span> <span class="s2">"b"</span><span class="p">,</span> <span class="s2">"c"</span><span class="p">,</span> <span class="s2">"alpha"</span><span class="p">,</span> <span class="s2">"beta"</span><span class="p">,</span> <span class="s2">"candidate"</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">"final"</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">"2.4"</span> <span class="ow">is</span> <span class="n">considered</span> <span class="n">newer</span> <span class="n">than</span> <span class="s2">"2.4a1"</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">"pre"</span><span class="p">,</span> <span class="s2">"preview"</span><span class="p">,</span> <span class="ow">and</span>
|
||
<span class="s2">"rc"</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">"c"</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">"dev"</span> <span class="ow">is</span> <span class="n">replaced</span> <span class="k">with</span> <span class="n">an</span> <span class="s1">'@'</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">>>> </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">>>> </span><span class="n">V</span><span class="p">(</span><span class="s1">'1.2'</span><span class="p">)</span>
|
||
<span class="go">('00000001', '00000002', '*final')</span>
|
||
<span class="gp">>>> </span><span class="n">V</span><span class="p">(</span><span class="s1">'1.2b2'</span><span class="p">)</span>
|
||
<span class="go">('00000001', '00000002', '*b', '00000002', '*final')</span>
|
||
<span class="gp">>>> </span><span class="n">V</span><span class="p">(</span><span class="s1">'FunkyVersion'</span><span class="p">)</span>
|
||
<span class="go">('*funkyversion', '*final')</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>In this schema practicality takes priority over purity, but as a result it
|
||
doesn’t 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, aren’t 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 it’s 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 there’s 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>It’s 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">"""^</span>
|
||
<span class="s2">(?P<version>\d+\.\d+) # minimum 'N.N'</span>
|
||
<span class="s2">(?P<extraversion>(?:\.\d+)*) # any number of extra '.N' segments</span>
|
||
<span class="s2">(?:</span>
|
||
<span class="s2"> (?P<prerel>[abc]|rc) # 'a' = alpha, 'b' = beta</span>
|
||
<span class="s2"> # 'c' or 'rc' = release candidate</span>
|
||
<span class="s2"> (?P<prerelversion>\d+(?:\.\d+)*)</span>
|
||
<span class="s2">)?</span>
|
||
<span class="s2">(?P<postdev>(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?)?</span>
|
||
<span class="s2">$"""</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">>>> </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">>>> </span><span class="p">(</span><span class="n">V</span><span class="p">(</span><span class="s1">'1.0a1'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0a2.dev456'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0a2'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0a2.1.dev456'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0a2.1'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0b1.dev456'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0b2'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0b2.post345'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0c1.dev456'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0c1'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0.dev456'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0.post456.dev34'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0.post456'</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 Python’s 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">>>> </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">>>> </span><span class="p">(</span><span class="n">V</span><span class="p">(</span><span class="s1">'1.0a1'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0a2'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0b3'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0c1'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0rc2'</span><span class="p">)</span>
|
||
<span class="gp">... </span> <span class="o"><</span> <span class="n">V</span><span class="p">(</span><span class="s1">'1.0'</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">>>> </span><span class="kn">from</span> <span class="nn">verlib</span> <span class="kn">import</span> <span class="n">NormalizedVersion</span>
|
||
<span class="gp">>>> </span><span class="n">version</span> <span class="o">=</span> <span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">'1.0'</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">>>> </span><span class="nb">str</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
|
||
<span class="go">'1.0'</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Or compared with others:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">'1.0'</span><span class="p">)</span> <span class="o">></span> <span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">'0.9'</span><span class="p">)</span>
|
||
<span class="go">True</span>
|
||
<span class="gp">>>> </span><span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">'1.0'</span><span class="p">)</span> <span class="o"><</span> <span class="n">NormalizedVersion</span><span class="p">(</span><span class="s1">'1.1'</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">>>> </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">>>> </span><span class="nb">str</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
|
||
<span class="go">'1.0'</span>
|
||
|
||
<span class="gp">>>> </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">'c'</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span>
|
||
<span class="gp">>>> </span><span class="nb">str</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
|
||
<span class="go">'1.0c4'</span>
|
||
|
||
<span class="gp">>>> </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">'c'</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span> <span class="p">(</span><span class="s1">'dev'</span><span class="p">,</span> <span class="mi">34</span><span class="p">))</span>
|
||
<span class="gp">>>> </span><span class="nb">str</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
|
||
<span class="go">'1.0c4.dev34'</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 isn’t
|
||
normalized (i.e. <code class="docutils literal notranslate"><span class="pre">NormalizedVersion</span></code> doesn’t 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%) don’t 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, it’s a suggested normalized version. Last, if it
|
||
returns the same string, it means that the version matches the scheme.</p>
|
||
<p>Here’s an example of usage:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </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">>>> </span><span class="kn">import</span> <span class="nn">warnings</span>
|
||
<span class="gp">>>> </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">'Cannot work with "</span><span class="si">%s</span><span class="s1">"'</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">'"</span><span class="si">%s</span><span class="s1">" is not a normalized version.</span><span class="se">\n</span><span class="s1">'</span>
|
||
<span class="gp">... </span> <span class="s1">'It has been transformed into "</span><span class="si">%s</span><span class="s1">" '</span>
|
||
<span class="gp">... </span> <span class="s1">'for interoperability.'</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">>>> </span><span class="n">validate_version</span><span class="p">(</span><span class="s1">'2.4-rc1'</span><span class="p">)</span>
|
||
<span class="go">__main__:8: UserWarning: "2.4-rc1" is not a normalized version.</span>
|
||
<span class="go">It has been transformed into "2.4c1" for interoperability.</span>
|
||
<span class="go">NormalizedVersion('2.4c1')</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">validate_version</span><span class="p">(</span><span class="s1">'2.4c1'</span><span class="p">)</span>
|
||
<span class="go">NormalizedVersion('2.4c1')</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">validate_version</span><span class="p">(</span><span class="s1">'foo'</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
<span class="gr">File "<stdin>", line 1, in <module></span>
|
||
<span class="gr">File "<stdin>", line 4, in validate_version</span>
|
||
<span class="gr">ValueError</span>: <span class="n">Cannot work with "foo"</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> |