RFC : Version comparison
Hi, We worked during Pycon on version comparisons. Distutils has one but it is a bit strict, setuptools has another one, but it's a bit heuristic. We would like to propose the inclusion for Python 2.7 of a new version comparison algorithm, based on the discussion Fedora, Ubuntu and Python people had. The plan would be to deprecate the current one (which is not really used anyway) and provide, promote this one. Trent Mick took the lead on this work at the end of Pycon, and worked on a prototype. It's explained here, and there's an implementation (I've put it at the top of the page for conveniency): http://wiki.python.org/moin/Distutils/VersionComparison Please comment, Regards Tarek -- Tarek Ziadé | http://ziade.org
On Wed, 22 Apr 2009 11:12:22 +0200, Tarek Ziadé <ziade.tarek@gmail.com> wrote:
Hi,
We worked during Pycon on version comparisons. Distutils has one but it is a bit strict, setuptools has another one, but it's a bit heuristic.
We would like to propose the inclusion for Python 2.7 of a new version comparison algorithm, based on the discussion Fedora, Ubuntu and Python people had. The plan would be to deprecate the current one (which is not really used anyway) and provide, promote this one.
Trent Mick took the lead on this work at the end of Pycon, and worked on a prototype.
It's explained here, and there's an implementation (I've put it at the top of the page for conveniency):
Clearly being able to parse the string representation is important, since this information will largely reside in non-Python text files. I suppose that many people will also be very comfortable with and happy about writing RationalVersion(somestring) and ">=somestring". However, it would also be great if there were a way to construct a version object out of structured data instead. Can a constructor which takes each part of the version data as a separate object be added? Jean-Paul
On Wed, Apr 22, 2009 at 3:38 PM, Jean-Paul Calderone <exarkun@divmod.com> wrote:
Clearly being able to parse the string representation is important, since this information will largely reside in non-Python text files. I suppose that many people will also be very comfortable with and happy about writing RationalVersion(somestring) and ">=somestring". However, it would also be great if there were a way to construct a version object out of structured data instead. Can a constructor which takes each part of the version data as a separate object be added?
Sounds good, I'd be in favor of making RationalVersion using explicit version bits, and having some kind of function: str2version(somestring) -> RationalVersion instance I have pushed the prototype in a bitbucket project so everyone can work it out (just join the project) http://bitbucket.org/tarek/distutilsversion/ I'll wait for Trent feedback to make that change, Tarek -- Tarek Ziadé | http://ziade.org
Can a constructor which takes each part of the version data as a separate object be added?
Sounds good, I'd be in favor of making RationalVersion using explicit version bits, and having some kind of function:
str2version(somestring) -> RationalVersion instance
Or we could have: RationalVersion(...version bits...) RationalVersion.from_string(s) # this is a @classmethod
I have pushed the prototype in a bitbucket project so everyone can work it out (just join the project)
Thanks for putting this up. If we provide a way to construct a RationalVersion with version bits, then we need to discuss what those "version bits" look like. Currently the internal tuple data structure (`self.info`) looks like this (from verlib.py's description of the 'f' marker used to help with sort ordering, http://bitbucket.org/tarek/distutilsversion/src/cc93f5e1df3f/verlib.py#cl-16...): # A marker used in the second and third parts of the `info` tuple, for # versions that don't have those segments, to sort properly. A example # of versions in sort order ('highest' last): # 1.0b1 ((1,0), ('b',1), ('f',)) # 1.0.dev345 ((1,0), ('f',), ('dev', 345)) # 1.0 ((1,0), ('f',), ('f',)) # 1.0.post345 ((1,0), ('f',), ('post', 345)) # ^ ^ # 'f' < 'b' -------------/ | # | # 'dev' < 'f' < 'post' -----------/ # Other letters would do, bug 'f' for 'final' is kind of nice. Is this what we would want the constructor to take? RationalVersion( (1,0), ('b', 1) ) # 1.0b1 RationalVersion( (1,0), ('f',), ('post', 345) ) # 1.0.post345 It seems a little too low-level. We could allow something a little nicer: RationalVersion( (1, 0, 'b', 1) ) # 1.0b1 RationalVersion( (1, 0, 'post', 345) ) # 1.0.post345 If we did this, then we'd probably want these attributes on RationalVersion:
v = RationalVersion((1,0,'b',1)) str(v) '1.0b1' v.info (1, 0, 'b', 1) v._cmp_info # use for comparison ((1, 0), ('b', 1), ('f',))
Thoughts? Trent -- Trent Mick trentm@gmail.com
On Mon, 27 Apr 2009 09:36:24 -0700, Trent Mick <trentm@gmail.com> wrote:
Can a constructor which takes each part of the version data as a separate object be added?
Sounds good, I'd be in favor of making RationalVersion using explicit version bits, and having some kind of function:
str2version(somestring) -> RationalVersion instance
Or we could have:
RationalVersion(...version bits...) RationalVersion.from_string(s) # this is a @classmethod
I like the sound of that.
I have pushed the prototype in a bitbucket project so everyone can work it out (just join the project)
Thanks for putting this up.
If we provide a way to construct a RationalVersion with version bits, then we need to discuss what those "version bits" look like. Currently the internal tuple data structure (`self.info`) looks like this (from verlib.py's description of the 'f' marker used to help with sort ordering, http://bitbucket.org/tarek/distutilsversion/src/cc93f5e1df3f/verlib.py#cl-16...):
# A marker used in the second and third parts of the `info` tuple, for # versions that don't have those segments, to sort properly. A example # of versions in sort order ('highest' last): # 1.0b1 ((1,0), ('b',1), ('f',)) # 1.0.dev345 ((1,0), ('f',), ('dev', 345)) # 1.0 ((1,0), ('f',), ('f',)) # 1.0.post345 ((1,0), ('f',), ('post', 345)) # ^ ^ # 'f' < 'b' -------------/ | # | # 'dev' < 'f' < 'post' -----------/ # Other letters would do, bug 'f' for 'final' is kind of nice.
Is this what we would want the constructor to take?
RationalVersion( (1,0), ('b', 1) ) # 1.0b1 RationalVersion( (1,0), ('f',), ('post', 345) ) # 1.0.post345
It seems a little too low-level. We could allow something a little nicer:
RationalVersion( (1, 0, 'b', 1) ) # 1.0b1 RationalVersion( (1, 0, 'post', 345) ) # 1.0.post345
If we did this, then we'd probably want these attributes on RationalVersion:
v = RationalVersion((1,0,'b',1)) str(v) '1.0b1' v.info (1, 0, 'b', 1) v._cmp_info # use for comparison ((1, 0), ('b', 1), ('f',))
Thoughts?
I'd be in favor of replacing the 'b' and 'post' and so forth with symbolic constants - eg, RationalVersion((1, 0, RationalVersion.POST, 345)). If not that, then I'd at least like 'final' instead of 'f', 'beta' instead of 'b' (is that what 'b' means?) - since this doesn't necessarily need to be tied to how the version is serialized: it's for programmers to type, so the more obvious it is what things mean, the better. Jean-Paul
I'd be in favor of replacing the 'b' and 'post' and so forth with symbolic constants - eg, RationalVersion((1, 0, RationalVersion.POST, 345)). If not that, then I'd at least like 'final' instead of 'f', 'beta' instead of 'b' (is that what 'b' means?) - since this doesn't necessarily need to be tied to how the version is serialized: it's for programmers to type, so the more obvious it is what things mean, the better.
Yes, it doesn't necessarily need to be tied to the version serialization, but there is some elegance if this is the case. Granted the 'f' for 'final' isn't obvious, but in the context of version strings 'b' for 'beta' and 'a' for 'alpha' is pretty obvious, no? The 'f' is just internal, anyway. I'd rather not get into the situation where we start allowing both "b" and "beta" as arguments to the constructor to mean the same thing. If people thought it would help, I'd be cool with: RationalVersion.BETA = 'b' et al. Trent -- Trent Mick trentm@gmail.com
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Trent Mick wrote:
Can a constructor which takes each part of the version data as a separate object be added? Sounds good, I'd be in favor of making RationalVersion using explicit version bits, and having some kind of function:
str2version(somestring) -> RationalVersion instance
Or we could have:
RationalVersion(...version bits...) RationalVersion.from_string(s) # this is a @classmethod
I would prefer keeping the string version of __init__, with the "I'm in control, dammit" version reserved for the non-default factory method. Tres. - -- =================================================================== Tres Seaver +1 540-429-0999 tseaver@palladion.com Palladion Software "Excellence by Design" http://palladion.com -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFJ9faB+gerLs4ltQ4RAsGtAJ9p6z3WjdM8AxLs6kfBgxcHOuheHQCeNSra JXKlglWpco8D1uFhSj0CLcA= =EdQY -----END PGP SIGNATURE-----
[Tarek]
Sounds good, I'd be in favor of making RationalVersion using explicit version bits, and having some kind of function:
str2version(somestring) -> RationalVersion instance
[Trent]
Or we could have:
RationalVersion(...version bits...) RationalVersion.from_string(s) # this is a @classmethod
[Tres]
I would prefer keeping the string version of __init__, with the "I'm in control, dammit" version reserved for the non-default factory method.
I'd tend to agree, but I don't feel strongly about it. Tarek, Why would you prefer the default constructor argument be the version bits form. Trent -- Trent Mick trentm@gmail.com
[Trent]
Or we could have:
RationalVersion(...version bits...) RationalVersion.from_string(s) # this is a @classmethod
[Tres]
I would prefer keeping the string version of __init__, with the "I'm in control, dammit" version reserved for the non-default factory method.
I'd tend to agree, but I don't feel strongly about it.
I agree. The more common one will be the string version, it should be __init__.
On 09-04-27 05:09 PM, Eric Smith wrote:
[Trent]
Or we could have:
RationalVersion(...version bits...) RationalVersion.from_string(s) # this is a @classmethod
[Tres]
I would prefer keeping the string version of __init__, with the "I'm in control, dammit" version reserved for the non-default factory method.
I'd tend to agree, but I don't feel strongly about it.
I agree. The more common one will be the string version, it should be __init__.
I prefer `from_string` for the following reasons: - `__init__` is typically expected to accept object components as arguments, rather than a parse-able string. - `RationalVersion.from_string('...')` is much more explicit than `RationalVersion('...')` and explicit is better than implicit. Besides, the standard library has several instances of `from_string`.
On Tue, Apr 28, 2009 at 1:25 AM, Trent Mick <trentm@gmail.com> wrote:
[Tarek]
Sounds good, I'd be in favor of making RationalVersion using explicit version bits, and having some kind of function:
str2version(somestring) -> RationalVersion instance
[Trent]
Or we could have:
RationalVersion(...version bits...) RationalVersion.from_string(s) # this is a @classmethod
[Tres]
I would prefer keeping the string version of __init__, with the "I'm in control, dammit" version reserved for the non-default factory method.
I'd tend to agree, but I don't feel strongly about it.
Tarek, Why would you prefer the default constructor argument be the version bits form.
The example that came in mind to me was datetime, that uses the bits in the constructor, plus provides conversion function or class methods to handle the string form: datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]]) So like Sridhar, I'd rather have an detailed constructor. I'm 0- on Tres proposal though, because the string form will be the most used form. Cheers Tarek
On Wed, Apr 22, 2009 at 11:12:22AM +0200, Tarek Ziadé wrote:
We worked during Pycon on version comparisons. Distutils has one but it is a bit strict, setuptools has another one, but it's a bit heuristic.
We would like to propose the inclusion for Python 2.7 of a new version comparison algorithm, based on the discussion Fedora, Ubuntu and Python people had. The plan would be to deprecate the current one (which is not really used anyway) and provide, promote this one.
I assume by "not really used" you refer to the distutils algorithm rather than the setuptools one?
Trent Mick took the lead on this work at the end of Pycon, and worked on a prototype.
It's explained here, and there's an implementation (I've put it at the top of the page for conveniency):
I find the dot separating the "1.0" from "dev" in "1.0.dev456" unappealing. Why was it added? The current common setuptools usage is "dev" with no dot and with no requirement to have at least one digit following the "dev". (The common usage also implies tarring and feathering anyone who releases a package with 'dev' in the version number into PyPI). I'm also kind of wondering why 'dev' rather than 'pre' if we want to unambiguously distinguish prereleases from postreleases. If it's for compatibility with setuptools, then why the extra dot in front of dev? (Personally, I like 1.2 < 1.2+svn1234 < 1.2.1 as opposed to the prevailing norm of 1.2 < 1.2.1dev < 1.2.1.)
Please comment,
-0.5 for inventing a new algorithm +0.5 for using an existing one (and an additional +0.1 on top of that if it's the one used by Debian) Marius Gedminas -- I've been in the sun for a week. I took the bold step of leaving my laptop at home. I found only 4K messages pending when I returned. -- Keith Packard
I find the dot separating the "1.0" from "dev" in "1.0.dev456" unappealing. Why was it added?
I believe the consensus at the PyCon open spaces was that it separated better in general. For example: 1.0a2.1dev1234 1.0a2.1.dev1234
I'm also kind of wondering why 'dev' rather than 'pre' if we want to unambiguously distinguish prereleases from postreleases.
Just seemed to be in more common usage for that (around 1000 of the about 8000 versions currently on PyPI used "dev"). "pre" was also discussed at PyCon.
(Personally, I like 1.2 < 1.2+svn1234 < 1.2.1 as opposed to the prevailing norm of 1.2 < 1.2.1dev < 1.2.1.)
In what is being proposed you'd need to use: 1.2 < 1.2.post1234 < 1.2.1 Trent -- Trent Mick trentm@gmail.com
On Tue, Apr 28, 2009 at 12:47:49PM -0700, Trent Mick wrote:
I find the dot separating the "1.0" from "dev" in "1.0.dev456" unappealing. Why was it added?
I believe the consensus at the PyCon open spaces was that it separated better in general. For example:
1.0a2.1dev1234 1.0a2.1.dev1234
I respectfully disagree with the applicability of the word "better" for these examples. "Less worse", maybe. Picking a less extreme example: 2.1.5dev1234 2.1.5.dev1234 Hm. Let me stare at it a bit more. Hm. Why not 2.1.5.dev.1234 then? Marius Gedminas -- MCSE == Minesweeper Consultant / Solitaire Expert
On Wed, Apr 29, 2009 at 1:35 AM, Marius Gedminas <marius@pov.lt> wrote:
Picking a less extreme example:
2.1.5dev1234 2.1.5.dev1234
Hm. Let me stare at it a bit more. Hm. Why not
2.1.5.dev.1234
then?
-1, imho the semantic of the "." here is to separate the atomic parts of the version, and "dev1234" is one atomic part with its own meaning. (1234 doesn't mean much alone)
Marius Gedminas -- MCSE == Minesweeper Consultant / Solitaire Expert
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux)
iD8DBQFJ95K1kVdEXeem148RAqLkAKCBsSlQ9zZXUjP3oUJD+ne1joy5pgCfVH6p BTC/i9/MRo8I6FWKMf1g38w= =Trbk -----END PGP SIGNATURE-----
_______________________________________________ Distutils-SIG maillist - Distutils-SIG@python.org http://mail.python.org/mailman/listinfo/distutils-sig
-- Tarek Ziadé | http://ziade.org
participants (7)
-
Eric Smith -
Jean-Paul Calderone -
Marius Gedminas -
Sridhar Ratnakumar -
Tarek Ziadé -
Trent Mick -
Tres Seaver