pypa/packaging — pull request #15 by dstufft (2014-10-06 00:42:53+00:00)
Title: [WIP] Refactor specifiers to handle legacy specifiers

The original specifier code assumed that the only kind of specifiers that would ever be in play are PEP 440 compliant specifiers. However it quickly came to light that there are a lot of legacy cases where a specifier cannot be cleanly parsed using PEP 440.

This changes the specifier handling code to have:

* An abstract base class, ``ASpecifier`` which functions as the definition for what a specifier class must contain.
* A ``LegacySpecifier`` which interprets all versions as a ``LegacyVersion``. This does not implement any of the new operator types such as ``~=`` or ``===`` and is intended to act like setuptools previously did.
* A ``Specifier`` which interprets specifiers as defined in PEP 440.
* A ``SpecifierSet`` which can hold one or more specifiers and attempts to sanely allow the mixed usage of both ``Specifier`` and ``LegacySpecifier``.

A major change in behavior is that a ``Specifier`` (and now a ``LegacySpecifier``) will only represent one single specifier and will not accept a comma separated list of them. The new ``SpecifierSet`` will handle cases where you have one or more specifiers and will attempt to sanely handle the case where you have a mixture of
``Specifier`` and ``LegacySpecifier`` instances.

In particular, a ``SpecifierSet`` has the following behaviors:

If given no specifiers:

* It will *not* match any ``LegacyVersion`` items.
* It will *not* match any pre-release versions, unless there are no final releases available that match.

If given any specifiers:

* It will match only if the given version(s) match each and every specifier contained within the ``Specifier`` set.

The side effects of this are:

* If two specifiers are given, one that matches pre-releases and one that doesn't, then the ``SpecifierSet`` as a whole will not accept any pre-releases.
* Even versions that can be parsed as PEP 440 will not use any of the new semantics when being interpreted by a ``LegacySpecifier``, so something like ``SpecifierSet(">=1.0-1-1")`` will end up allowing pre-releases since ``LegacyVersion`` has no concept of them.