Skip to content

Commit 476992f

Browse files
committed
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, ``BaseSpecifier`` 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.
1 parent 9542495 commit 476992f

File tree

2 files changed

+431
-148
lines changed

2 files changed

+431
-148
lines changed

packaging/_compat.py

+13
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,16 @@
2525
string_types = str,
2626
else:
2727
string_types = basestring,
28+
29+
30+
def with_metaclass(meta, *bases):
31+
"""
32+
Create a base class with a metaclass.
33+
"""
34+
# This requires a bit of explanation: the basic idea is to make a dummy
35+
# metaclass for one level of class instantiation that replaces itself with
36+
# the actual metaclass.
37+
class metaclass(meta):
38+
def __new__(cls, name, this_bases, d):
39+
return meta(name, bases, d)
40+
return type.__new__(metaclass, 'temporary_class', (), {})

0 commit comments

Comments
 (0)