Commits

Anonymous committed da25e80

more doc

Comments (0)

Files changed (1)

 Being able to manage version numbers for a project is mandatory to properly
 release it.
 
-In Python there are no real restriction yet on how a project should manage 
-its versions, and how they should be incremented.
+Managing version numbers means being able to compare them, and being able to
+make sure each version number is a `valid` number for a given standard.
 
-While there 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` 
-metadata any string they want, and push a new release at PyPI. This version 
-will appear as the `latest` for end users.
+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 are sometimes quite exotic.
+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 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 we needs to package.
 
-Existing versioning systems
-===========================
+Existing version systems
+========================
 
-There are two main version comparison systems:
+There are two main systems in Python:
 
-- Distutils 
-- Setuptools
+- Distutils [#distutils]_
+- Setuptools [#setuptools]_
+
+Distutils
+---------
 
 Distutils, provides a `StrictVersion` and a `LooseVersion` class that can be
-used to manage versions, but the
-XXX
-Python developer manager
+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, that provides a version parsing system
-XXX
+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.
 
-The major problem with setuptools' versioning was that it was too permissive. 
-Many of the versions on 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. 
+From the doc::
 
-While setuptools *does* provide a mechanism for comparing/sorting versions, 
+    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')
+
+Distutils and Setuptools version comparison caveats
+===================================================
+
+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.
+reasonable attempt at that sorting without having to run it against some code.
 
-Also there's a problem is 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 
+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".
 
-XXX
+Last, the meaning of `-` is specific to Setuptools, while it is avoided in
+some packaging systems like the one used by Debian or Ubuntu.
 
-What is verlib
-==============
+verlib
+======
 
-``verlib`` provides a version managment system.
+During Pycon, members of the Python, Ubuntu and Fedora community worked on
+a version standard that would be acceptable for everyone.
 
 The pseudo-format supported is::
 
     N.N[.N]+[abc]N[.N]+[.(dev|post)N+|(devNpostN)]
 
+Some examples probably make it clearer::
 
-XXX explain why it's better than setuptools, from debian/red-hat PoV
+    >>> 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
 
-XXX explain here in details (no code example)
-XXX give tons of examples
+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
     '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/
+