[Python-checkins] r73205 - peps/trunk/pep-0386.txt
tarek.ziade
python-checkins at python.org
Thu Jun 4 11:13:09 CEST 2009
Author: tarek.ziade
Date: Thu Jun 4 11:13:08 2009
New Revision: 73205
Log:
added PEP 386 (version comparison in Distutils)
Added:
peps/trunk/pep-0386.txt (contents, props changed)
Added: peps/trunk/pep-0386.txt
==============================================================================
--- (empty file)
+++ peps/trunk/pep-0386.txt Thu Jun 4 11:13:08 2009
@@ -0,0 +1,391 @@
+PEP: 386
+Title: Changing the version comparison module in Distutils
+Version: $Revision$
+Last-Modified: $Date$
+Author: Tarek Ziadé <tarek at ziade.org>
+Status: Draft
+Type: Standards Track
+Content-Type: text/x-rst
+Created: 4-June-2009
+
+
+Abstract
+========
+
+This PEP proposes the inclusion of a new version comparison system in
+Distutils.
+
+
+Motivation
+==========
+
+Distutils will soon extend the metadata standard, by including the
+`install_requires` field from Setuptools [#requires]_ among other changes.
+
+These changes are a work in progress in PEP 345 [#pep345]_, but validating
+the current PEP is mandatory to continue the work.
+
+The `install_requires` field will allow a package to define a dependency on
+another package and optionally restrict this dependency to a set of
+compatible versions.
+
+That's why Distutils needs to provide a robust standard and reference
+implementation to compare versions numbers.
+
+
+Proposal
+========
+
+In Python there are no real restriction yet on how a project should manage
+its versions, and how they should be incremented. They are no standard
+either, even if they are a few conventions widely used, like having a major
+and a minor revision (1.1, 1.2, etc.).
+
+Developers are free to put in the `version` meta-data of their package any
+string they want, and push a new release at PyPI. This version will appear
+as the `latest` for end users.
+
+Some project are also using dates as their major version numbers, or a custom
+versioning standard that is sometimes quite exotic.
+
+The problem with this freedom is that the package will be harder to re-package
+for OS packagers, that need to have stricter conventions. The worst case is
+when a packager is unable to easily compare the versions he needs to package.
+
+This PEP proposes to change the `version` module in Distutils with a new one
+that complies with the needs.
+
+
+Existing version systems
+========================
+
+There are two main systems in Python:
+
+- The current Distutils system [#distutils]_
+- Setuptools [#setuptools]_
+
+Distutils
+---------
+
+Distutils currently provides a `StrictVersion` and a `LooseVersion` class
+that can be used to manage versions.
+
+The `LooseVersion` class is quite laxest. From Distutils doc::
+
+ Version numbering for anarchists and software realists.
+ Implements the standard interface for version number classes as
+ described above. A version number consists of a series of numbers,
+ separated by either periods or strings of letters. When comparing
+ version numbers, the numeric components will be compared
+ numerically, and the alphabetic components lexically. The following
+ are all valid version numbers, in no particular order:
+
+ 1.5.1
+ 1.5.2b2
+ 161
+ 3.10a
+ 8.02
+ 3.4j
+ 1996年07月12日
+ 3.2.pl0
+ 3.1.1.6
+ 2g6
+ 11g
+ 0.960923
+ 2.2beta29
+ 1.13++
+ 5.5.kw
+ 2.0b1pl0
+
+ In fact, there is no such thing as an invalid version number under
+ this scheme; the rules for comparison are simple and predictable,
+ but may not always give the results you want (for some definition
+ of "want").
+
+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::
+
+ >>> from distutils.version import LooseVersion as V
+ >>> v1 = V('FunkyVersion')
+ >>> v2 = V('GroovieVersion')
+ >>> v1 > v2
+ False
+
+The `StrictVersion` class is more strict. From the doc::
+
+ Version numbering for anal retentive and software idealists.
+ Implements the standard interface for version number classes as
+ described above. A version number consists of two or three
+ dot-separated numeric components, with an optional "pre-release" tag
+ on the end. The pre-release tag consists of the letter 'a' or 'b'
+ followed by a number. If the numeric components of two version
+ numbers are equal, then one with a pre-release tag will always
+ be deemed earlier (lesser) than one without.
+
+ The following are valid version numbers (shown in the order that
+ would be obtained by sorting according to the supplied cmp function):
+
+ 0.4 0.4.0 (these two are equivalent)
+ 0.4.1
+ 0.5a1
+ 0.5b3
+ 0.5
+ 0.9.6
+ 1.0
+ 1.0.4a3
+ 1.0.4b1
+ 1.0.4
+
+ The following are examples of invalid version numbers:
+
+ 1
+ 2.7.2.2
+ 1.3.a4
+ 1.3pl1
+ 1.3c4
+
+This class enforces a few rules, and makes a decent tool to work with version
+numbers::
+
+ >>> from distutils.version import StrictVersion as V
+ >>> v2 = V('GroovieVersion')
+ Traceback (most recent call last):
+ ...
+ ValueError: invalid version number 'GroovieVersion'
+ >>> v2 = V('1.1')
+ >>> v3 = V('1.3')
+ >>> v2 < v3
+ True
+
+Although, it lacks a few elements to make it usable:
+
+- development releases
+- post-release tags
+- development releases of post-release tags.
+
+Notice that Distutils version classes are not really used in the community.
+
+Setuptools
+----------
+
+Setuptools provides another version comparison tool [#setuptools-version]_
+which does not enforce any rule for the version, but try to provide a better
+algorithm to convert the strings to sortable keys, with a ``parse_version``
+function.
+
+From the doc::
+
+ Convert a version string to a chronologically-sortable key
+
+ This is a rough cross between Distutils' StrictVersion and LooseVersion;
+ if you give it versions that would work with StrictVersion, then it behaves
+ the same; otherwise it acts like a slightly-smarter LooseVersion. It is
+ *possible* to create pathological version coding schemes that will fool
+ this parser, but they should be very rare in practice.
+
+ The returned value will be a tuple of strings. Numeric portions of the
+ version are padded to 8 digits so they will compare numerically, but
+ without relying on how numbers compare relative to strings. Dots are
+ dropped, but dashes are retained. Trailing zeros between alpha segments
+ or dashes are suppressed, so that e.g. "2.4.0" is considered the same as
+ "2.4". Alphanumeric parts are lower-cased.
+
+ The algorithm assumes that strings like "-" and any alpha string that
+ alphabetically follows "final" represents a "patch level". So, "2.4-1"
+ is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is
+ considered newer than "2.4-1", which in turn is newer than "2.4".
+
+ Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that
+ come before "final" alphabetically) are assumed to be pre-release versions,
+ so that the version "2.4" is considered newer than "2.4a1".
+
+ Finally, to handle miscellaneous cases, the strings "pre", "preview", and
+ "rc" are treated as if they were "c", i.e. as though they were release
+ candidates, and therefore are not as new as a version string that does not
+ contain them, and "dev" is replaced with an '@' so that it sorts lower than
+ than any other pre-release tag.
+
+In other words, ``parse_version`` will return a tuple for each version string,
+that is compatible with ``StrictVersion`` but also accept arbitrary version and
+deal with them so they can be compared::
+
+ >>> from pkg_resources import parse_version as V
+ >>> V('1.2')
+ ('00000001', '00000002', '*final')
+ >>> V('1.2b2')
+ ('00000001', '00000002', '*b', '00000002', '*final')
+ >>> V('FunkyVersion')
+ ('*funkyversion', '*final')
+
+Caveats of existing systems
+---------------------------
+
+The major problem with the described version comparison tools is that they are
+too permissive. Many of the versions on PyPI [#pypi]_ 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.
+
+Distutils classes are not really used in Python projects, but the
+Setuptools function is quite spread because it's used by tools like
+`easy_install` [#ezinstall]_, `pip` [#pip]_ or `zc.buildout` [#zc.buildout]_
+to install dependencies of a given project.
+
+While Setuptools *does* 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.
+
+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".
+
+Last, the meaning of `-` is specific to Setuptools, while it is avoided in
+some packaging systems like the one used by Debian or Ubuntu.
+
+The new versioning algorithm
+============================
+
+During Pycon, members of the Python, Ubuntu and Fedora community worked on
+a version standard that would be acceptable for everyone.
+
+It's currently called `verlib` and a prototype lives here :
+http://bitbucket.org/tarek/distutilsversion/src/
+
+The pseudo-format supported is::
+
+ N.N[.N]+[abc]N[.N]+[.(dev|post)N+|(devNpostN)]
+
+Some examples probably make it clearer::
+
+ >>> from verlib import RationalVersion as V
+ >>> (V('1.0a1')
+ ... < V('1.0a2.dev456')
+ ... < V('1.0a2')
+ ... < V('1.0a2.1.dev456')
+ ... < V('1.0a2.1')
+ ... < V('1.0b1.dev456')
+ ... < V('1.0b2')
+ ... < V('1.0c1.dev456')
+ ... < V('1.0c1')
+ ... < V('1.0.dev456')
+ ... < V('1.0')
+ ... < V('1.0.dev456post623')
+ ... < V('1.0.post456'))
+ True
+
+The trailing ".dev123" is for pre-releases. The ".post123" is for
+post-releases -- which apparently is used by a number of projects out there
+(e.g. Twisted [#twisted]_). For example *after* a "1.2.0" release there might
+be a "1.2.0-r678" release. We used "post" instead of "r" because the "r" is
+ambiguous as to whether it indicates a pre- or post-release.
+Last ".dev456post623" is a development version of a post-release.
+
+``verlib`` provides a ``RationalVersion`` class and a
+``suggest_rational_version`` function.
+
+RationalVersion
+---------------
+
+The `RationalVersion` 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::
+
+ >>> from verlib import RationalVersion
+ >>> version = RationalVersion('1.0')
+
+The version can be represented as a string::
+
+ >>> str(version)
+ '1.0'
+
+Or compared with others::
+
+ >>> RationalVersion('1.0') > RationalVersion('0.9')
+ True
+ >>> RationalVersion('1.0') < RationalVersion('1.1')
+ True
+
+A class method called ``from_parts`` is available if you want to create an
+instance by providing the parts that composes the version.
+
+Each part is a tuple and there are three parts:
+
+- the main version part
+- the pre-release part
+- the `devpost` marker part
+
+Examples ::
+
+ >>> version = RationalVersion.from_parts((1, 0))
+ >>> str(version)
+ '1.0'
+
+ >>> version = RationalVersion.from_parts((1, 0), ('c', 4))
+ >>> str(version)
+ '1.0c4'
+
+ >>> version = RationalVersion.from_parts((1, 0), ('c', 4), ('dev', 34))
+ >>> str(version)
+ '1.0c4.dev34'
+
+suggest_rational_version
+------------------------
+
+XXX explain here suggest_rational_version
+
+
+References
+==========
+
+.. [#distutils]
+ http://docs.python.org/distutils
+
+.. [#setuptools]
+ http://peak.telecommunity.com/DevCenter/setuptools
+
+.. [#setuptools-version]
+ http://peak.telecommunity.com/DevCenter/setuptools#specifying-your-project-s-version
+
+.. [#pypi]
+ http://pypi.python.org/pypi
+
+.. [#pip]
+ http://pypi.python.org/pypi/pip
+
+.. [#ezinstall]
+ http://peak.telecommunity.com/DevCenter/EasyInstall
+
+.. [#zc.buildout]
+ http://pypi.python.org/pypi/zc.buildout
+
+.. [#twisted]
+ http://twistedmatrix.com/trac/
+
+.. [#requires]
+ http://peak.telecommunity.com/DevCenter/setuptools
+
+.. [#pep345]
+ http://svn.python.org/projects/peps/branches/jim-update-345/pep-0345.txt
+
+Aknowledgments
+==============
+
+Trent Mick, Matthias Klose, Phillip Eby, and many people at Pycon and
+Distutils-SIG.
+
+Copyright
+=========
+
+This document has been placed in the public domain.
+
+
+
+..
+ Local Variables:
+ mode: indented-text
+ indent-tabs-mode: nil
+ sentence-end-double-space: t
+ fill-column: 70
+ coding: utf-8
+ End:
More information about the Python-checkins
mailing list