[Distutils] [Python-Dev] [Python-checkins] peps: PEP 426: replace implied 'version starts with' with new ~= operator

Nick Coghlan ncoghlan at gmail.com
Tue Feb 26 04:22:52 CET 2013


On Tue, Feb 26, 2013 at 11:06 AM, Donald Stufft <donald.stufft at gmail.com> wrote:
> !=1.3 allowing 1.3.1 makes sense to me. 1.3 is equivalent to 1.3.0, 1.3.1 !=
> 1.3.0.

Nope, the PEP explicitly disclaims the historical equivalence between
1.3 and 1.3.0. It has to, because they're very different when it comes
to what the PEP now calls a "compatible release clause"
(http://www.python.org/dev/peps/pep-0426/#compatible-release), Ruby
gems call a "pessimistic version constraint"
(http://docs.rubygems.org/read/chapter/16#page74), PHP composer calls
"next significant release"
(http://getcomposer.org/doc/01-basic-usage.md#package-versions) and
Node.js npm calls "Tilde version range"
(https://npmjs.org/doc/json.html) (Note: I also checked CPAN version
ordering to see if it had an equivalent operation, but Perl's approach
appears to be closer to the way pkg_resources handles ordering:
http://search.cpan.org/~jpeacock/version-0.9901/lib/version.pod#How_to_compare_version_objects)

However, while numeric maintenance releases are part of the problem
here, the real issue is correctly handling *post* releases.

Does "== 1.3" allow "1.3.post1"? Does "!= 1.3" allow "1.3.post1"? Both? Neither?

If you use strict string matching for == and !=, then "!= 1.3" will
allow "1.3.post1", which is utterly insane given the PEP's recommended
usage of post releases solely for non-functional changes like tweaking
the release notes or project metadata.

Leaving == as strict and making != prefix based breaks the fundamental
relationship between equality and inequality checks, so that's also
not a reasonable option.

That leaves making both == and != prefix based as the most reasonable
alternative, as "!= 1.3" will then correctly reject "1.3.post1" and
the appropriate logical relationship is maintained between the two
operators.

However, you then need a way to spell an *exact* version request (for
use with tools like zc.buildout and pip freeze that are designed to
snapshot an application configuration rather than for dependency
publication in an index).

My plan for that use case is to allow "is" as a comparison operator
that means exactly what it says: the version required is precisely the
specified version, with no prefix matching or release compatibility
assessments allowed.

That gives a natural progression in dependency constraints from more
permissive to less permissive:

    Compatible version: some-dist (X.Y)  # roughly equivalent to (>=
X.Y, < X+1.dev0)
    Version equality: some-dist (== X.Y)  # roughly equivalent to (>=
X.Y, < X.Y+1.dev0)
    Version identity: some-dist (is X.Y)  # must be exactly X.Y

All three clauses also have clearly defined use cases:

1. Use compatible version clauses in published metadata for stable
dependencies with a good backwards compatibility policy
2. Use version equality clauses in published metadata for dependencies
without a good backwards compatibility policy
3. Use version identity clauses for application and deployment
dependency snapshots

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Distutils-SIG mailing list