summaryrefslogtreecommitdiff
path: root/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging
diff options
context:
space:
mode:
authorShubham Saini <shubham6405@gmail.com>2018-12-11 10:01:23 +0000
committerShubham Saini <shubham6405@gmail.com>2018-12-11 10:01:23 +0000
commit68df54d6629ec019142eb149dd037774f2d11e7c (patch)
tree345bc22d46b4e01a4ba8303b94278952a4ed2b9e /venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging
First commit
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging')
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/__about__.py21
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/__init__.py14
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/_compat.py30
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/_structures.py70
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/markers.py301
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/requirements.py130
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/specifiers.py774
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/utils.py63
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/version.py441
9 files changed, 1844 insertions, 0 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/__about__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/__about__.py
new file mode 100644
index 0000000..bb79fb7
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/__about__.py
@@ -0,0 +1,21 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6__all__ = [
7 "__title__", "__summary__", "__uri__", "__version__", "__author__",
8 "__email__", "__license__", "__copyright__",
9]
10
11__title__ = "packaging"
12__summary__ = "Core utilities for Python packages"
13__uri__ = "https://github.com/pypa/packaging"
14
15__version__ = "17.1"
16
17__author__ = "Donald Stufft and individual contributors"
18__email__ = "donald@stufft.io"
19
20__license__ = "BSD or Apache License, Version 2.0"
21__copyright__ = "Copyright 2014-2016 %s" % __author__
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/__init__.py
new file mode 100644
index 0000000..e520d35
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/__init__.py
@@ -0,0 +1,14 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6from .__about__ import (
7 __author__, __copyright__, __email__, __license__, __summary__, __title__,
8 __uri__, __version__
9)
10
11__all__ = [
12 "__title__", "__summary__", "__uri__", "__version__", "__author__",
13 "__email__", "__license__", "__copyright__",
14]
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/_compat.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/_compat.py
new file mode 100644
index 0000000..6daa860
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/_compat.py
@@ -0,0 +1,30 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6import sys
7
8
9PY2 = sys.version_info[0] == 2
10PY3 = sys.version_info[0] == 3
11
12# flake8: noqa
13
14if PY3:
15 string_types = str,
16else:
17 string_types = basestring,
18
19
20def with_metaclass(meta, *bases):
21 """
22 Create a base class with a metaclass.
23 """
24 # This requires a bit of explanation: the basic idea is to make a dummy
25 # metaclass for one level of class instantiation that replaces itself with
26 # the actual metaclass.
27 class metaclass(meta):
28 def __new__(cls, name, this_bases, d):
29 return meta(name, bases, d)
30 return type.__new__(metaclass, 'temporary_class', (), {})
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/_structures.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/_structures.py
new file mode 100644
index 0000000..3f0c27f
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/_structures.py
@@ -0,0 +1,70 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6
7class Infinity(object):
8
9 def __repr__(self):
10 return "Infinity"
11
12 def __hash__(self):
13 return hash(repr(self))
14
15 def __lt__(self, other):
16 return False
17
18 def __le__(self, other):
19 return False
20
21 def __eq__(self, other):
22 return isinstance(other, self.__class__)
23
24 def __ne__(self, other):
25 return not isinstance(other, self.__class__)
26
27 def __gt__(self, other):
28 return True
29
30 def __ge__(self, other):
31 return True
32
33 def __neg__(self):
34 return NegativeInfinity
35
36
37Infinity = Infinity()
38
39
40class NegativeInfinity(object):
41
42 def __repr__(self):
43 return "-Infinity"
44
45 def __hash__(self):
46 return hash(repr(self))
47
48 def __lt__(self, other):
49 return True
50
51 def __le__(self, other):
52 return True
53
54 def __eq__(self, other):
55 return isinstance(other, self.__class__)
56
57 def __ne__(self, other):
58 return not isinstance(other, self.__class__)
59
60 def __gt__(self, other):
61 return False
62
63 def __ge__(self, other):
64 return False
65
66 def __neg__(self):
67 return Infinity
68
69
70NegativeInfinity = NegativeInfinity()
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/markers.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/markers.py
new file mode 100644
index 0000000..b4dc0b9
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/markers.py
@@ -0,0 +1,301 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6import operator
7import os
8import platform
9import sys
10
11from pip._vendor.pyparsing import ParseException, ParseResults, stringStart, stringEnd
12from pip._vendor.pyparsing import ZeroOrMore, Group, Forward, QuotedString
13from pip._vendor.pyparsing import Literal as L # noqa
14
15from ._compat import string_types
16from .specifiers import Specifier, InvalidSpecifier
17
18
19__all__ = [
20 "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName",
21 "Marker", "default_environment",
22]
23
24
25class InvalidMarker(ValueError):
26 """
27 An invalid marker was found, users should refer to PEP 508.
28 """
29
30
31class UndefinedComparison(ValueError):
32 """
33 An invalid operation was attempted on a value that doesn't support it.
34 """
35
36
37class UndefinedEnvironmentName(ValueError):
38 """
39 A name was attempted to be used that does not exist inside of the
40 environment.
41 """
42
43
44class Node(object):
45
46 def __init__(self, value):
47 self.value = value
48
49 def __str__(self):
50 return str(self.value)
51
52 def __repr__(self):
53 return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
54
55 def serialize(self):
56 raise NotImplementedError
57
58
59class Variable(Node):
60
61 def serialize(self):
62 return str(self)
63
64
65class Value(Node):
66
67 def serialize(self):
68 return '"{0}"'.format(self)
69
70
71class Op(Node):
72
73 def serialize(self):
74 return str(self)
75
76
77VARIABLE = (
78 L("implementation_version") |
79 L("platform_python_implementation") |
80 L("implementation_name") |
81 L("python_full_version") |
82 L("platform_release") |
83 L("platform_version") |
84 L("platform_machine") |
85 L("platform_system") |
86 L("python_version") |
87 L("sys_platform") |
88 L("os_name") |
89 L("os.name") | # PEP-345
90 L("sys.platform") | # PEP-345
91 L("platform.version") | # PEP-345
92 L("platform.machine") | # PEP-345
93 L("platform.python_implementation") | # PEP-345
94 L("python_implementation") | # undocumented setuptools legacy
95 L("extra")
96)
97ALIASES = {
98 'os.name': 'os_name',
99 'sys.platform': 'sys_platform',
100 'platform.version': 'platform_version',
101 'platform.machine': 'platform_machine',
102 'platform.python_implementation': 'platform_python_implementation',
103 'python_implementation': 'platform_python_implementation'
104}
105VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
106
107VERSION_CMP = (
108 L("===") |
109 L("==") |
110 L(">=") |
111 L("<=") |
112 L("!=") |
113 L("~=") |
114 L(">") |
115 L("<")
116)
117
118MARKER_OP = VERSION_CMP | L("not in") | L("in")
119MARKER_OP.setParseAction(lambda s, l, t: Op(t[0]))
120
121MARKER_VALUE = QuotedString("'") | QuotedString('"')
122MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0]))
123
124BOOLOP = L("and") | L("or")
125
126MARKER_VAR = VARIABLE | MARKER_VALUE
127
128MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR)
129MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0]))
130
131LPAREN = L("(").suppress()
132RPAREN = L(")").suppress()
133
134MARKER_EXPR = Forward()
135MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN)
136MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR)
137
138MARKER = stringStart + MARKER_EXPR + stringEnd
139
140
141def _coerce_parse_result(results):
142 if isinstance(results, ParseResults):
143 return [_coerce_parse_result(i) for i in results]
144 else:
145 return results
146
147
148def _format_marker(marker, first=True):
149 assert isinstance(marker, (list, tuple, string_types))
150
151 # Sometimes we have a structure like [[...]] which is a single item list
152 # where the single item is itself it's own list. In that case we want skip
153 # the rest of this function so that we don't get extraneous () on the
154 # outside.
155 if (isinstance(marker, list) and len(marker) == 1 and
156 isinstance(marker[0], (list, tuple))):
157 return _format_marker(marker[0])
158
159 if isinstance(marker, list):
160 inner = (_format_marker(m, first=False) for m in marker)
161 if first:
162 return " ".join(inner)
163 else:
164 return "(" + " ".join(inner) + ")"
165 elif isinstance(marker, tuple):
166 return " ".join([m.serialize() for m in marker])
167 else:
168 return marker
169
170
171_operators = {
172 "in": lambda lhs, rhs: lhs in rhs,
173 "not in": lambda lhs, rhs: lhs not in rhs,
174 "<": operator.lt,
175 "<=": operator.le,
176 "==": operator.eq,
177 "!=": operator.ne,
178 ">=": operator.ge,
179 ">": operator.gt,
180}
181
182
183def _eval_op(lhs, op, rhs):
184 try:
185 spec = Specifier("".join([op.serialize(), rhs]))
186 except InvalidSpecifier:
187 pass
188 else:
189 return spec.contains(lhs)
190
191 oper = _operators.get(op.serialize())
192 if oper is None:
193 raise UndefinedComparison(
194 "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
195 )
196
197 return oper(lhs, rhs)
198
199
200_undefined = object()
201
202
203def _get_env(environment, name):
204 value = environment.get(name, _undefined)
205
206 if value is _undefined:
207 raise UndefinedEnvironmentName(
208 "{0!r} does not exist in evaluation environment.".format(name)
209 )
210
211 return value
212
213
214def _evaluate_markers(markers, environment):
215 groups = [[]]
216
217 for marker in markers:
218 assert isinstance(marker, (list, tuple, string_types))
219
220 if isinstance(marker, list):
221 groups[-1].append(_evaluate_markers(marker, environment))
222 elif isinstance(marker, tuple):
223 lhs, op, rhs = marker
224
225 if isinstance(lhs, Variable):
226 lhs_value = _get_env(environment, lhs.value)
227 rhs_value = rhs.value
228 else:
229 lhs_value = lhs.value
230 rhs_value = _get_env(environment, rhs.value)
231
232 groups[-1].append(_eval_op(lhs_value, op, rhs_value))
233 else:
234 assert marker in ["and", "or"]
235 if marker == "or":
236 groups.append([])
237
238 return any(all(item) for item in groups)
239
240
241def format_full_version(info):
242 version = '{0.major}.{0.minor}.{0.micro}'.format(info)
243 kind = info.releaselevel
244 if kind != 'final':
245 version += kind[0] + str(info.serial)
246 return version
247
248
249def default_environment():
250 if hasattr(sys, 'implementation'):
251 iver = format_full_version(sys.implementation.version)
252 implementation_name = sys.implementation.name
253 else:
254 iver = '0'
255 implementation_name = ''
256
257 return {
258 "implementation_name": implementation_name,
259 "implementation_version": iver,
260 "os_name": os.name,
261 "platform_machine": platform.machine(),
262 "platform_release": platform.release(),
263 "platform_system": platform.system(),
264 "platform_version": platform.version(),
265 "python_full_version": platform.python_version(),
266 "platform_python_implementation": platform.python_implementation(),
267 "python_version": platform.python_version()[:3],
268 "sys_platform": sys.platform,
269 }
270
271
272class Marker(object):
273
274 def __init__(self, marker):
275 try:
276 self._markers = _coerce_parse_result(MARKER.parseString(marker))
277 except ParseException as e:
278 err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
279 marker, marker[e.loc:e.loc + 8])
280 raise InvalidMarker(err_str)
281
282 def __str__(self):
283 return _format_marker(self._markers)
284
285 def __repr__(self):
286 return "<Marker({0!r})>".format(str(self))
287
288 def evaluate(self, environment=None):
289 """Evaluate a marker.
290
291 Return the boolean from evaluating the given marker against the
292 environment. environment is an optional argument to override all or
293 part of the determined environment.
294
295 The environment is determined from the current Python process.
296 """
297 current_environment = default_environment()
298 if environment is not None:
299 current_environment.update(environment)
300
301 return _evaluate_markers(self._markers, current_environment)
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/requirements.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/requirements.py
new file mode 100644
index 0000000..98bc507
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/requirements.py
@@ -0,0 +1,130 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6import string
7import re
8
9from pip._vendor.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
10from pip._vendor.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine
11from pip._vendor.pyparsing import Literal as L # noqa
12from pip._vendor.six.moves.urllib import parse as urlparse
13
14from .markers import MARKER_EXPR, Marker
15from .specifiers import LegacySpecifier, Specifier, SpecifierSet
16
17
18class InvalidRequirement(ValueError):
19 """
20 An invalid requirement was found, users should refer to PEP 508.
21 """
22
23
24ALPHANUM = Word(string.ascii_letters + string.digits)
25
26LBRACKET = L("[").suppress()
27RBRACKET = L("]").suppress()
28LPAREN = L("(").suppress()
29RPAREN = L(")").suppress()
30COMMA = L(",").suppress()
31SEMICOLON = L(";").suppress()
32AT = L("@").suppress()
33
34PUNCTUATION = Word("-_.")
35IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM)
36IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
37
38NAME = IDENTIFIER("name")
39EXTRA = IDENTIFIER
40
41URI = Regex(r'[^ ]+')("url")
42URL = (AT + URI)
43
44EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
45EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
46
47VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
48VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
49
50VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
51VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE),
52 joinString=",", adjacent=False)("_raw_spec")
53_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
54_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
55
56VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
57VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
58
59MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
60MARKER_EXPR.setParseAction(
61 lambda s, l, t: Marker(s[t._original_start:t._original_end])
62)
63MARKER_SEPARATOR = SEMICOLON
64MARKER = MARKER_SEPARATOR + MARKER_EXPR
65
66VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER)
67URL_AND_MARKER = URL + Optional(MARKER)
68
69NAMED_REQUIREMENT = \
70 NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
71
72REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
73# pyparsing isn't thread safe during initialization, so we do it eagerly, see
74# issue #104
75REQUIREMENT.parseString("x[]")
76
77
78class Requirement(object):
79 """Parse a requirement.
80
81 Parse a given requirement string into its parts, such as name, specifier,
82 URL, and extras. Raises InvalidRequirement on a badly-formed requirement
83 string.
84 """
85
86 # TODO: Can we test whether something is contained within a requirement?
87 # If so how do we do that? Do we need to test against the _name_ of
88 # the thing as well as the version? What about the markers?
89 # TODO: Can we normalize the name and extra name?
90
91 def __init__(self, requirement_string):
92 try:
93 req = REQUIREMENT.parseString(requirement_string)
94 except ParseException as e:
95 raise InvalidRequirement(
96 "Invalid requirement, parse error at \"{0!r}\"".format(
97 requirement_string[e.loc:e.loc + 8]))
98
99 self.name = req.name
100 if req.url:
101 parsed_url = urlparse.urlparse(req.url)
102 if not (parsed_url.scheme and parsed_url.netloc) or (
103 not parsed_url.scheme and not parsed_url.netloc):
104 raise InvalidRequirement("Invalid URL given")
105 self.url = req.url
106 else:
107 self.url = None
108 self.extras = set(req.extras.asList() if req.extras else [])
109 self.specifier = SpecifierSet(req.specifier)
110 self.marker = req.marker if req.marker else None
111
112 def __str__(self):
113 parts = [self.name]
114
115 if self.extras:
116 parts.append("[{0}]".format(",".join(sorted(self.extras))))
117
118 if self.specifier:
119 parts.append(str(self.specifier))
120
121 if self.url:
122 parts.append("@ {0}".format(self.url))
123
124 if self.marker:
125 parts.append("; {0}".format(self.marker))
126
127 return "".join(parts)
128
129 def __repr__(self):
130 return "<Requirement({0!r})>".format(str(self))
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/specifiers.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/specifiers.py
new file mode 100644
index 0000000..7d2fe4c
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/specifiers.py
@@ -0,0 +1,774 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6import abc
7import functools
8import itertools
9import re
10
11from ._compat import string_types, with_metaclass
12from .version import Version, LegacyVersion, parse
13
14
15class InvalidSpecifier(ValueError):
16 """
17 An invalid specifier was found, users should refer to PEP 440.
18 """
19
20
21class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
22
23 @abc.abstractmethod
24 def __str__(self):
25 """
26 Returns the str representation of this Specifier like object. This
27 should be representative of the Specifier itself.
28 """
29
30 @abc.abstractmethod
31 def __hash__(self):
32 """
33 Returns a hash value for this Specifier like object.
34 """
35
36 @abc.abstractmethod
37 def __eq__(self, other):
38 """
39 Returns a boolean representing whether or not the two Specifier like
40 objects are equal.
41 """
42
43 @abc.abstractmethod
44 def __ne__(self, other):
45 """
46 Returns a boolean representing whether or not the two Specifier like
47 objects are not equal.
48 """
49
50 @abc.abstractproperty
51 def prereleases(self):
52 """
53 Returns whether or not pre-releases as a whole are allowed by this
54 specifier.
55 """
56
57 @prereleases.setter
58 def prereleases(self, value):
59 """
60 Sets whether or not pre-releases as a whole are allowed by this
61 specifier.
62 """
63
64 @abc.abstractmethod
65 def contains(self, item, prereleases=None):
66 """
67 Determines if the given item is contained within this specifier.
68 """
69
70 @abc.abstractmethod
71 def filter(self, iterable, prereleases=None):
72 """
73 Takes an iterable of items and filters them so that only items which
74 are contained within this specifier are allowed in it.
75 """
76
77
78class _IndividualSpecifier(BaseSpecifier):
79
80 _operators = {}
81
82 def __init__(self, spec="", prereleases=None):
83 match = self._regex.search(spec)
84 if not match:
85 raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
86
87 self._spec = (
88 match.group("operator").strip(),
89 match.group("version").strip(),
90 )
91
92 # Store whether or not this Specifier should accept prereleases
93 self._prereleases = prereleases
94
95 def __repr__(self):
96 pre = (
97 ", prereleases={0!r}".format(self.prereleases)
98 if self._prereleases is not None
99 else ""
100 )
101
102 return "<{0}({1!r}{2})>".format(
103 self.__class__.__name__,
104 str(self),
105 pre,
106 )
107
108 def __str__(self):
109 return "{0}{1}".format(*self._spec)
110
111 def __hash__(self):
112 return hash(self._spec)
113
114 def __eq__(self, other):
115 if isinstance(other, string_types):
116 try:
117 other = self.__class__(other)
118 except InvalidSpecifier:
119 return NotImplemented
120 elif not isinstance(other, self.__class__):
121 return NotImplemented
122
123 return self._spec == other._spec
124
125 def __ne__(self, other):
126 if isinstance(other, string_types):
127 try:
128 other = self.__class__(other)
129 except InvalidSpecifier:
130 return NotImplemented
131 elif not isinstance(other, self.__class__):
132 return NotImplemented
133
134 return self._spec != other._spec
135
136 def _get_operator(self, op):
137 return getattr(self, "_compare_{0}".format(self._operators[op]))
138
139 def _coerce_version(self, version):
140 if not isinstance(version, (LegacyVersion, Version)):
141 version = parse(version)
142 return version
143
144 @property
145 def operator(self):
146 return self._spec[0]
147
148 @property
149 def version(self):
150 return self._spec[1]
151
152 @property
153 def prereleases(self):
154 return self._prereleases
155
156 @prereleases.setter
157 def prereleases(self, value):
158 self._prereleases = value
159
160 def __contains__(self, item):
161 return self.contains(item)
162
163 def contains(self, item, prereleases=None):
164 # Determine if prereleases are to be allowed or not.
165 if prereleases is None:
166 prereleases = self.prereleases
167
168 # Normalize item to a Version or LegacyVersion, this allows us to have
169 # a shortcut for ``"2.0" in Specifier(">=2")
170 item = self._coerce_version(item)
171
172 # Determine if we should be supporting prereleases in this specifier
173 # or not, if we do not support prereleases than we can short circuit
174 # logic if this version is a prereleases.
175 if item.is_prerelease and not prereleases:
176 return False
177
178 # Actually do the comparison to determine if this item is contained
179 # within this Specifier or not.
180 return self._get_operator(self.operator)(item, self.version)
181
182 def filter(self, iterable, prereleases=None):
183 yielded = False
184 found_prereleases = []
185
186 kw = {"prereleases": prereleases if prereleases is not None else True}
187
188 # Attempt to iterate over all the values in the iterable and if any of
189 # them match, yield them.
190 for version in iterable:
191 parsed_version = self._coerce_version(version)
192
193 if self.contains(parsed_version, **kw):
194 # If our version is a prerelease, and we were not set to allow
195 # prereleases, then we'll store it for later incase nothing
196 # else matches this specifier.
197 if (parsed_version.is_prerelease and not
198 (prereleases or self.prereleases)):
199 found_prereleases.append(version)
200 # Either this is not a prerelease, or we should have been
201 # accepting prereleases from the beginning.
202 else:
203 yielded = True
204 yield version
205
206 # Now that we've iterated over everything, determine if we've yielded
207 # any values, and if we have not and we have any prereleases stored up
208 # then we will go ahead and yield the prereleases.
209 if not yielded and found_prereleases:
210 for version in found_prereleases:
211 yield version
212
213
214class LegacySpecifier(_IndividualSpecifier):
215
216 _regex_str = (
217 r"""
218 (?P<operator>(==|!=|<=|>=|<|>))
219 \s*
220 (?P<version>
221 [^,;\s)]* # Since this is a "legacy" specifier, and the version
222 # string can be just about anything, we match everything
223 # except for whitespace, a semi-colon for marker support,
224 # a closing paren since versions can be enclosed in
225 # them, and a comma since it's a version separator.
226 )
227 """
228 )
229
230 _regex = re.compile(
231 r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
232
233 _operators = {
234 "==": "equal",
235 "!=": "not_equal",
236 "<=": "less_than_equal",
237 ">=": "greater_than_equal",
238 "<": "less_than",
239 ">": "greater_than",
240 }
241
242 def _coerce_version(self, version):
243 if not isinstance(version, LegacyVersion):
244 version = LegacyVersion(str(version))
245 return version
246
247 def _compare_equal(self, prospective, spec):
248 return prospective == self._coerce_version(spec)
249
250 def _compare_not_equal(self, prospective, spec):
251 return prospective != self._coerce_version(spec)
252
253 def _compare_less_than_equal(self, prospective, spec):
254 return prospective <= self._coerce_version(spec)
255
256 def _compare_greater_than_equal(self, prospective, spec):
257 return prospective >= self._coerce_version(spec)
258
259 def _compare_less_than(self, prospective, spec):
260 return prospective < self._coerce_version(spec)
261
262 def _compare_greater_than(self, prospective, spec):
263 return prospective > self._coerce_version(spec)
264
265
266def _require_version_compare(fn):
267 @functools.wraps(fn)
268 def wrapped(self, prospective, spec):
269 if not isinstance(prospective, Version):
270 return False
271 return fn(self, prospective, spec)
272 return wrapped
273
274
275class Specifier(_IndividualSpecifier):
276
277 _regex_str = (
278 r"""
279 (?P<operator>(~=|==|!=|<=|>=|<|>|===))
280 (?P<version>
281 (?:
282 # The identity operators allow for an escape hatch that will
283 # do an exact string match of the version you wish to install.
284 # This will not be parsed by PEP 440 and we cannot determine
285 # any semantic meaning from it. This operator is discouraged
286 # but included entirely as an escape hatch.
287 (?<====) # Only match for the identity operator
288 \s*
289 [^\s]* # We just match everything, except for whitespace
290 # since we are only testing for strict identity.
291 )
292 |
293 (?:
294 # The (non)equality operators allow for wild card and local
295 # versions to be specified so we have to define these two
296 # operators separately to enable that.
297 (?<===|!=) # Only match for equals and not equals
298
299 \s*
300 v?
301 (?:[0-9]+!)? # epoch
302 [0-9]+(?:\.[0-9]+)* # release
303 (?: # pre release
304 [-_\.]?
305 (a|b|c|rc|alpha|beta|pre|preview)
306 [-_\.]?
307 [0-9]*
308 )?
309 (?: # post release
310 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
311 )?
312
313 # You cannot use a wild card and a dev or local version
314 # together so group them with a | and make them optional.
315 (?:
316 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
317 (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
318 |
319 \.\* # Wild card syntax of .*
320 )?
321 )
322 |
323 (?:
324 # The compatible operator requires at least two digits in the
325 # release segment.
326 (?<=~=) # Only match for the compatible operator
327
328 \s*
329 v?
330 (?:[0-9]+!)? # epoch
331 [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
332 (?: # pre release
333 [-_\.]?
334 (a|b|c|rc|alpha|beta|pre|preview)
335 [-_\.]?
336 [0-9]*
337 )?
338 (?: # post release
339 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
340 )?
341 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
342 )
343 |
344 (?:
345 # All other operators only allow a sub set of what the
346 # (non)equality operators do. Specifically they do not allow
347 # local versions to be specified nor do they allow the prefix
348 # matching wild cards.
349 (?<!==|!=|~=) # We have special cases for these
350 # operators so we want to make sure they
351 # don't match here.
352
353 \s*
354 v?
355 (?:[0-9]+!)? # epoch
356 [0-9]+(?:\.[0-9]+)* # release
357 (?: # pre release
358 [-_\.]?
359 (a|b|c|rc|alpha|beta|pre|preview)
360 [-_\.]?
361 [0-9]*
362 )?
363 (?: # post release
364 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
365 )?
366 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
367 )
368 )
369 """
370 )
371
372 _regex = re.compile(
373 r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
374
375 _operators = {
376 "~=": "compatible",
377 "==": "equal",
378 "!=": "not_equal",
379 "<=": "less_than_equal",
380 ">=": "greater_than_equal",
381 "<": "less_than",
382 ">": "greater_than",
383 "===": "arbitrary",
384 }
385
386 @_require_version_compare
387 def _compare_compatible(self, prospective, spec):
388 # Compatible releases have an equivalent combination of >= and ==. That
389 # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
390 # implement this in terms of the other specifiers instead of
391 # implementing it ourselves. The only thing we need to do is construct
392 # the other specifiers.
393
394 # We want everything but the last item in the version, but we want to
395 # ignore post and dev releases and we want to treat the pre-release as
396 # it's own separate segment.
397 prefix = ".".join(
398 list(
399 itertools.takewhile(
400 lambda x: (not x.startswith("post") and not
401 x.startswith("dev")),
402 _version_split(spec),
403 )
404 )[:-1]
405 )
406
407 # Add the prefix notation to the end of our string
408 prefix += ".*"
409
410 return (self._get_operator(">=")(prospective, spec) and
411 self._get_operator("==")(prospective, prefix))
412
413 @_require_version_compare
414 def _compare_equal(self, prospective, spec):
415 # We need special logic to handle prefix matching
416 if spec.endswith(".*"):
417 # In the case of prefix matching we want to ignore local segment.
418 prospective = Version(prospective.public)
419 # Split the spec out by dots, and pretend that there is an implicit
420 # dot in between a release segment and a pre-release segment.
421 spec = _version_split(spec[:-2]) # Remove the trailing .*
422
423 # Split the prospective version out by dots, and pretend that there
424 # is an implicit dot in between a release segment and a pre-release
425 # segment.
426 prospective = _version_split(str(prospective))
427
428 # Shorten the prospective version to be the same length as the spec
429 # so that we can determine if the specifier is a prefix of the
430 # prospective version or not.
431 prospective = prospective[:len(spec)]
432
433 # Pad out our two sides with zeros so that they both equal the same
434 # length.
435 spec, prospective = _pad_version(spec, prospective)
436 else:
437 # Convert our spec string into a Version
438 spec = Version(spec)
439
440 # If the specifier does not have a local segment, then we want to
441 # act as if the prospective version also does not have a local
442 # segment.
443 if not spec.local:
444 prospective = Version(prospective.public)
445
446 return prospective == spec
447
448 @_require_version_compare
449 def _compare_not_equal(self, prospective, spec):
450 return not self._compare_equal(prospective, spec)
451
452 @_require_version_compare
453 def _compare_less_than_equal(self, prospective, spec):
454 return prospective <= Version(spec)
455
456 @_require_version_compare
457 def _compare_greater_than_equal(self, prospective, spec):
458 return prospective >= Version(spec)
459
460 @_require_version_compare
461 def _compare_less_than(self, prospective, spec):
462 # Convert our spec to a Version instance, since we'll want to work with
463 # it as a version.
464 spec = Version(spec)
465
466 # Check to see if the prospective version is less than the spec
467 # version. If it's not we can short circuit and just return False now
468 # instead of doing extra unneeded work.
469 if not prospective < spec:
470 return False
471
472 # This special case is here so that, unless the specifier itself
473 # includes is a pre-release version, that we do not accept pre-release
474 # versions for the version mentioned in the specifier (e.g. <3.1 should
475 # not match 3.1.dev0, but should match 3.0.dev0).
476 if not spec.is_prerelease and prospective.is_prerelease:
477 if Version(prospective.base_version) == Version(spec.base_version):
478 return False
479
480 # If we've gotten to here, it means that prospective version is both
481 # less than the spec version *and* it's not a pre-release of the same
482 # version in the spec.
483 return True
484
485 @_require_version_compare
486 def _compare_greater_than(self, prospective, spec):
487 # Convert our spec to a Version instance, since we'll want to work with
488 # it as a version.
489 spec = Version(spec)
490
491 # Check to see if the prospective version is greater than the spec
492 # version. If it's not we can short circuit and just return False now
493 # instead of doing extra unneeded work.
494 if not prospective > spec:
495 return False
496
497 # This special case is here so that, unless the specifier itself
498 # includes is a post-release version, that we do not accept
499 # post-release versions for the version mentioned in the specifier
500 # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0).
501 if not spec.is_postrelease and prospective.is_postrelease:
502 if Version(prospective.base_version) == Version(spec.base_version):
503 return False
504
505 # Ensure that we do not allow a local version of the version mentioned
506 # in the specifier, which is techincally greater than, to match.
507 if prospective.local is not None:
508 if Version(prospective.base_version) == Version(spec.base_version):
509 return False
510
511 # If we've gotten to here, it means that prospective version is both
512 # greater than the spec version *and* it's not a pre-release of the
513 # same version in the spec.
514 return True
515
516 def _compare_arbitrary(self, prospective, spec):
517 return str(prospective).lower() == str(spec).lower()
518
519 @property
520 def prereleases(self):
521 # If there is an explicit prereleases set for this, then we'll just
522 # blindly use that.
523 if self._prereleases is not None:
524 return self._prereleases
525
526 # Look at all of our specifiers and determine if they are inclusive
527 # operators, and if they are if they are including an explicit
528 # prerelease.
529 operator, version = self._spec
530 if operator in ["==", ">=", "<=", "~=", "==="]:
531 # The == specifier can include a trailing .*, if it does we
532 # want to remove before parsing.
533 if operator == "==" and version.endswith(".*"):
534 version = version[:-2]
535
536 # Parse the version, and if it is a pre-release than this
537 # specifier allows pre-releases.
538 if parse(version).is_prerelease:
539 return True
540
541 return False
542
543 @prereleases.setter
544 def prereleases(self, value):
545 self._prereleases = value
546
547
548_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
549
550
551def _version_split(version):
552 result = []
553 for item in version.split("."):
554 match = _prefix_regex.search(item)
555 if match:
556 result.extend(match.groups())
557 else:
558 result.append(item)
559 return result
560
561
562def _pad_version(left, right):
563 left_split, right_split = [], []
564
565 # Get the release segment of our versions
566 left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left)))
567 right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
568
569 # Get the rest of our versions
570 left_split.append(left[len(left_split[0]):])
571 right_split.append(right[len(right_split[0]):])
572
573 # Insert our padding
574 left_split.insert(
575 1,
576 ["0"] * max(0, len(right_split[0]) - len(left_split[0])),
577 )
578 right_split.insert(
579 1,
580 ["0"] * max(0, len(left_split[0]) - len(right_split[0])),
581 )
582
583 return (
584 list(itertools.chain(*left_split)),
585 list(itertools.chain(*right_split)),
586 )
587
588
589class SpecifierSet(BaseSpecifier):
590
591 def __init__(self, specifiers="", prereleases=None):
592 # Split on , to break each indidivual specifier into it's own item, and
593 # strip each item to remove leading/trailing whitespace.
594 specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
595
596 # Parsed each individual specifier, attempting first to make it a
597 # Specifier and falling back to a LegacySpecifier.
598 parsed = set()
599 for specifier in specifiers:
600 try:
601 parsed.add(Specifier(specifier))
602 except InvalidSpecifier:
603 parsed.add(LegacySpecifier(specifier))
604
605 # Turn our parsed specifiers into a frozen set and save them for later.
606 self._specs = frozenset(parsed)
607
608 # Store our prereleases value so we can use it later to determine if
609 # we accept prereleases or not.
610 self._prereleases = prereleases
611
612 def __repr__(self):
613 pre = (
614 ", prereleases={0!r}".format(self.prereleases)
615 if self._prereleases is not None
616 else ""
617 )
618
619 return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
620
621 def __str__(self):
622 return ",".join(sorted(str(s) for s in self._specs))
623
624 def __hash__(self):
625 return hash(self._specs)
626
627 def __and__(self, other):
628 if isinstance(other, string_types):
629 other = SpecifierSet(other)
630 elif not isinstance(other, SpecifierSet):
631 return NotImplemented
632
633 specifier = SpecifierSet()
634 specifier._specs = frozenset(self._specs | other._specs)
635
636 if self._prereleases is None and other._prereleases is not None:
637 specifier._prereleases = other._prereleases
638 elif self._prereleases is not None and other._prereleases is None:
639 specifier._prereleases = self._prereleases
640 elif self._prereleases == other._prereleases:
641 specifier._prereleases = self._prereleases
642 else:
643 raise ValueError(
644 "Cannot combine SpecifierSets with True and False prerelease "
645 "overrides."
646 )
647
648 return specifier
649
650 def __eq__(self, other):
651 if isinstance(other, string_types):
652 other = SpecifierSet(other)
653 elif isinstance(other, _IndividualSpecifier):
654 other = SpecifierSet(str(other))
655 elif not isinstance(other, SpecifierSet):
656 return NotImplemented
657
658 return self._specs == other._specs
659
660 def __ne__(self, other):
661 if isinstance(other, string_types):
662 other = SpecifierSet(other)
663 elif isinstance(other, _IndividualSpecifier):
664 other = SpecifierSet(str(other))
665 elif not isinstance(other, SpecifierSet):
666 return NotImplemented
667
668 return self._specs != other._specs
669
670 def __len__(self):
671 return len(self._specs)
672
673 def __iter__(self):
674 return iter(self._specs)
675
676 @property
677 def prereleases(self):
678 # If we have been given an explicit prerelease modifier, then we'll
679 # pass that through here.
680 if self._prereleases is not None:
681 return self._prereleases
682
683 # If we don't have any specifiers, and we don't have a forced value,
684 # then we'll just return None since we don't know if this should have
685 # pre-releases or not.
686 if not self._specs:
687 return None
688
689 # Otherwise we'll see if any of the given specifiers accept
690 # prereleases, if any of them do we'll return True, otherwise False.
691 return any(s.prereleases for s in self._specs)
692
693 @prereleases.setter
694 def prereleases(self, value):
695 self._prereleases = value
696
697 def __contains__(self, item):
698 return self.contains(item)
699
700 def contains(self, item, prereleases=None):
701 # Ensure that our item is a Version or LegacyVersion instance.
702 if not isinstance(item, (LegacyVersion, Version)):
703 item = parse(item)
704
705 # Determine if we're forcing a prerelease or not, if we're not forcing
706 # one for this particular filter call, then we'll use whatever the
707 # SpecifierSet thinks for whether or not we should support prereleases.
708 if prereleases is None:
709 prereleases = self.prereleases
710
711 # We can determine if we're going to allow pre-releases by looking to
712 # see if any of the underlying items supports them. If none of them do
713 # and this item is a pre-release then we do not allow it and we can
714 # short circuit that here.
715 # Note: This means that 1.0.dev1 would not be contained in something
716 # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0
717 if not prereleases and item.is_prerelease:
718 return False
719
720 # We simply dispatch to the underlying specs here to make sure that the
721 # given version is contained within all of them.
722 # Note: This use of all() here means that an empty set of specifiers
723 # will always return True, this is an explicit design decision.
724 return all(
725 s.contains(item, prereleases=prereleases)
726 for s in self._specs
727 )
728
729 def filter(self, iterable, prereleases=None):
730 # Determine if we're forcing a prerelease or not, if we're not forcing
731 # one for this particular filter call, then we'll use whatever the
732 # SpecifierSet thinks for whether or not we should support prereleases.
733 if prereleases is None:
734 prereleases = self.prereleases
735
736 # If we have any specifiers, then we want to wrap our iterable in the
737 # filter method for each one, this will act as a logical AND amongst
738 # each specifier.
739 if self._specs:
740 for spec in self._specs:
741 iterable = spec.filter(iterable, prereleases=bool(prereleases))
742 return iterable
743 # If we do not have any specifiers, then we need to have a rough filter
744 # which will filter out any pre-releases, unless there are no final
745 # releases, and which will filter out LegacyVersion in general.
746 else:
747 filtered = []
748 found_prereleases = []
749
750 for item in iterable:
751 # Ensure that we some kind of Version class for this item.
752 if not isinstance(item, (LegacyVersion, Version)):
753 parsed_version = parse(item)
754 else:
755 parsed_version = item
756
757 # Filter out any item which is parsed as a LegacyVersion
758 if isinstance(parsed_version, LegacyVersion):
759 continue
760
761 # Store any item which is a pre-release for later unless we've
762 # already found a final version or we are accepting prereleases
763 if parsed_version.is_prerelease and not prereleases:
764 if not filtered:
765 found_prereleases.append(item)
766 else:
767 filtered.append(item)
768
769 # If we've found no items except for pre-releases, then we'll go
770 # ahead and use the pre-releases
771 if not filtered and found_prereleases and prereleases is None:
772 return found_prereleases
773
774 return filtered
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/utils.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/utils.py
new file mode 100644
index 0000000..5151f9f
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/utils.py
@@ -0,0 +1,63 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6import re
7
8from .version import InvalidVersion, Version
9
10
11_canonicalize_regex = re.compile(r"[-_.]+")
12
13
14def canonicalize_name(name):
15 # This is taken from PEP 503.
16 return _canonicalize_regex.sub("-", name).lower()
17
18
19def canonicalize_version(version):
20 """
21 This is very similar to Version.__str__, but has one subtle differences
22 with the way it handles the release segment.
23 """
24
25 try:
26 version = Version(version)
27 except InvalidVersion:
28 # Legacy versions cannot be normalized
29 return version
30
31 parts = []
32
33 # Epoch
34 if version.epoch != 0:
35 parts.append("{0}!".format(version.epoch))
36
37 # Release segment
38 # NB: This strips trailing '.0's to normalize
39 parts.append(
40 re.sub(
41 r'(\.0)+$',
42 '',
43 ".".join(str(x) for x in version.release)
44 )
45 )
46
47 # Pre-release
48 if version.pre is not None:
49 parts.append("".join(str(x) for x in version.pre))
50
51 # Post-release
52 if version.post is not None:
53 parts.append(".post{0}".format(version.post))
54
55 # Development release
56 if version.dev is not None:
57 parts.append(".dev{0}".format(version.dev))
58
59 # Local version segment
60 if version.local is not None:
61 parts.append("+{0}".format(version.local))
62
63 return "".join(parts)
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/version.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/version.py
new file mode 100644
index 0000000..a8affbd
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/packaging/version.py
@@ -0,0 +1,441 @@
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4from __future__ import absolute_import, division, print_function
5
6import collections
7import itertools
8import re
9
10from ._structures import Infinity
11
12
13__all__ = [
14 "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
15]
16
17
18_Version = collections.namedtuple(
19 "_Version",
20 ["epoch", "release", "dev", "pre", "post", "local"],
21)
22
23
24def parse(version):
25 """
26 Parse the given version string and return either a :class:`Version` object
27 or a :class:`LegacyVersion` object depending on if the given version is
28 a valid PEP 440 version or a legacy version.
29 """
30 try:
31 return Version(version)
32 except InvalidVersion:
33 return LegacyVersion(version)
34
35
36class InvalidVersion(ValueError):
37 """
38 An invalid version was found, users should refer to PEP 440.
39 """
40
41
42class _BaseVersion(object):
43
44 def __hash__(self):
45 return hash(self._key)
46
47 def __lt__(self, other):
48 return self._compare(other, lambda s, o: s < o)
49
50 def __le__(self, other):
51 return self._compare(other, lambda s, o: s <= o)
52
53 def __eq__(self, other):
54 return self._compare(other, lambda s, o: s == o)
55
56 def __ge__(self, other):
57 return self._compare(other, lambda s, o: s >= o)
58
59 def __gt__(self, other):
60 return self._compare(other, lambda s, o: s > o)
61
62 def __ne__(self, other):
63 return self._compare(other, lambda s, o: s != o)
64
65 def _compare(self, other, method):
66 if not isinstance(other, _BaseVersion):
67 return NotImplemented
68
69 return method(self._key, other._key)
70
71
72class LegacyVersion(_BaseVersion):
73
74 def __init__(self, version):
75 self._version = str(version)
76 self._key = _legacy_cmpkey(self._version)
77
78 def __str__(self):
79 return self._version
80
81 def __repr__(self):
82 return "<LegacyVersion({0})>".format(repr(str(self)))
83
84 @property
85 def public(self):
86 return self._version
87
88 @property
89 def base_version(self):
90 return self._version
91
92 @property
93 def epoch(self):
94 return -1
95
96 @property
97 def release(self):
98 return None
99
100 @property
101 def pre(self):
102 return None
103
104 @property
105 def post(self):
106 return None
107
108 @property
109 def dev(self):
110 return None
111
112 @property
113 def local(self):
114 return None
115
116 @property
117 def is_prerelease(self):
118 return False
119
120 @property
121 def is_postrelease(self):
122 return False
123
124 @property
125 def is_devrelease(self):
126 return False
127
128
129_legacy_version_component_re = re.compile(
130 r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE,
131)
132
133_legacy_version_replacement_map = {
134 "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@",
135}
136
137
138def _parse_version_parts(s):
139 for part in _legacy_version_component_re.split(s):
140 part = _legacy_version_replacement_map.get(part, part)
141
142 if not part or part == ".":
143 continue
144
145 if part[:1] in "0123456789":
146 # pad for numeric comparison
147 yield part.zfill(8)
148 else:
149 yield "*" + part
150
151 # ensure that alpha/beta/candidate are before final
152 yield "*final"
153
154
155def _legacy_cmpkey(version):
156 # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
157 # greater than or equal to 0. This will effectively put the LegacyVersion,
158 # which uses the defacto standard originally implemented by setuptools,
159 # as before all PEP 440 versions.
160 epoch = -1
161
162 # This scheme is taken from pkg_resources.parse_version setuptools prior to
163 # it's adoption of the packaging library.
164 parts = []
165 for part in _parse_version_parts(version.lower()):
166 if part.startswith("*"):
167 # remove "-" before a prerelease tag
168 if part < "*final":
169 while parts and parts[-1] == "*final-":
170 parts.pop()
171
172 # remove trailing zeros from each series of numeric parts
173 while parts and parts[-1] == "00000000":
174 parts.pop()
175
176 parts.append(part)
177 parts = tuple(parts)
178
179 return epoch, parts
180
181
182# Deliberately not anchored to the start and end of the string, to make it
183# easier for 3rd party code to reuse
184VERSION_PATTERN = r"""
185 v?
186 (?:
187 (?:(?P<epoch>[0-9]+)!)? # epoch
188 (?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
189 (?P<pre> # pre-release
190 [-_\.]?
191 (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
192 [-_\.]?
193 (?P<pre_n>[0-9]+)?
194 )?
195 (?P<post> # post release
196 (?:-(?P<post_n1>[0-9]+))
197 |
198 (?:
199 [-_\.]?
200 (?P<post_l>post|rev|r)
201 [-_\.]?
202 (?P<post_n2>[0-9]+)?
203 )
204 )?
205 (?P<dev> # dev release
206 [-_\.]?
207 (?P<dev_l>dev)
208 [-_\.]?
209 (?P<dev_n>[0-9]+)?
210 )?
211 )
212 (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
213"""
214
215
216class Version(_BaseVersion):
217
218 _regex = re.compile(
219 r"^\s*" + VERSION_PATTERN + r"\s*$",
220 re.VERBOSE | re.IGNORECASE,
221 )
222
223 def __init__(self, version):
224 # Validate the version and parse it into pieces
225 match = self._regex.search(version)
226 if not match:
227 raise InvalidVersion("Invalid version: '{0}'".format(version))
228
229 # Store the parsed out pieces of the version
230 self._version = _Version(
231 epoch=int(match.group("epoch")) if match.group("epoch") else 0,
232 release=tuple(int(i) for i in match.group("release").split(".")),
233 pre=_parse_letter_version(
234 match.group("pre_l"),
235 match.group("pre_n"),
236 ),
237 post=_parse_letter_version(
238 match.group("post_l"),
239 match.group("post_n1") or match.group("post_n2"),
240 ),
241 dev=_parse_letter_version(
242 match.group("dev_l"),
243 match.group("dev_n"),
244 ),
245 local=_parse_local_version(match.group("local")),
246 )
247
248 # Generate a key which will be used for sorting
249 self._key = _cmpkey(
250 self._version.epoch,
251 self._version.release,
252 self._version.pre,
253 self._version.post,
254 self._version.dev,
255 self._version.local,
256 )
257
258 def __repr__(self):
259 return "<Version({0})>".format(repr(str(self)))
260
261 def __str__(self):
262 parts = []
263
264 # Epoch
265 if self.epoch != 0:
266 parts.append("{0}!".format(self.epoch))
267
268 # Release segment
269 parts.append(".".join(str(x) for x in self.release))
270
271 # Pre-release
272 if self.pre is not None:
273 parts.append("".join(str(x) for x in self.pre))
274
275 # Post-release
276 if self.post is not None:
277 parts.append(".post{0}".format(self.post))
278
279 # Development release
280 if self.dev is not None:
281 parts.append(".dev{0}".format(self.dev))
282
283 # Local version segment
284 if self.local is not None:
285 parts.append("+{0}".format(self.local))
286
287 return "".join(parts)
288
289 @property
290 def epoch(self):
291 return self._version.epoch
292
293 @property
294 def release(self):
295 return self._version.release
296
297 @property
298 def pre(self):
299 return self._version.pre
300
301 @property
302 def post(self):
303 return self._version.post[1] if self._version.post else None
304
305 @property
306 def dev(self):
307 return self._version.dev[1] if self._version.dev else None
308
309 @property
310 def local(self):
311 if self._version.local:
312 return ".".join(str(x) for x in self._version.local)
313 else:
314 return None
315
316 @property
317 def public(self):
318 return str(self).split("+", 1)[0]
319
320 @property
321 def base_version(self):
322 parts = []
323
324 # Epoch
325 if self.epoch != 0:
326 parts.append("{0}!".format(self.epoch))
327
328 # Release segment
329 parts.append(".".join(str(x) for x in self.release))
330
331 return "".join(parts)
332
333 @property
334 def is_prerelease(self):
335 return self.dev is not None or self.pre is not None
336
337 @property
338 def is_postrelease(self):
339 return self.post is not None
340
341 @property
342 def is_devrelease(self):
343 return self.dev is not None
344
345
346def _parse_letter_version(letter, number):
347 if letter:
348 # We consider there to be an implicit 0 in a pre-release if there is
349 # not a numeral associated with it.
350 if number is None:
351 number = 0
352
353 # We normalize any letters to their lower case form
354 letter = letter.lower()
355
356 # We consider some words to be alternate spellings of other words and
357 # in those cases we want to normalize the spellings to our preferred
358 # spelling.
359 if letter == "alpha":
360 letter = "a"
361 elif letter == "beta":
362 letter = "b"
363 elif letter in ["c", "pre", "preview"]:
364 letter = "rc"
365 elif letter in ["rev", "r"]:
366 letter = "post"
367
368 return letter, int(number)
369 if not letter and number:
370 # We assume if we are given a number, but we are not given a letter
371 # then this is using the implicit post release syntax (e.g. 1.0-1)
372 letter = "post"
373
374 return letter, int(number)
375
376
377_local_version_separators = re.compile(r"[\._-]")
378
379
380def _parse_local_version(local):
381 """
382 Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
383 """
384 if local is not None:
385 return tuple(
386 part.lower() if not part.isdigit() else int(part)
387 for part in _local_version_separators.split(local)
388 )
389
390
391def _cmpkey(epoch, release, pre, post, dev, local):
392 # When we compare a release version, we want to compare it with all of the
393 # trailing zeros removed. So we'll use a reverse the list, drop all the now
394 # leading zeros until we come to something non zero, then take the rest
395 # re-reverse it back into the correct order and make it a tuple and use
396 # that for our sorting key.
397 release = tuple(
398 reversed(list(
399 itertools.dropwhile(
400 lambda x: x == 0,
401 reversed(release),
402 )
403 ))
404 )
405
406 # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
407 # We'll do this by abusing the pre segment, but we _only_ want to do this
408 # if there is not a pre or a post segment. If we have one of those then
409 # the normal sorting rules will handle this case correctly.
410 if pre is None and post is None and dev is not None:
411 pre = -Infinity
412 # Versions without a pre-release (except as noted above) should sort after
413 # those with one.
414 elif pre is None:
415 pre = Infinity
416
417 # Versions without a post segment should sort before those with one.
418 if post is None:
419 post = -Infinity
420
421 # Versions without a development segment should sort after those with one.
422 if dev is None:
423 dev = Infinity
424
425 if local is None:
426 # Versions without a local segment should sort before those with one.
427 local = -Infinity
428 else:
429 # Versions with a local segment need that segment parsed to implement
430 # the sorting rules in PEP440.
431 # - Alpha numeric segments sort before numeric segments
432 # - Alpha numeric segments sort lexicographically
433 # - Numeric segments sort numerically
434 # - Shorter versions sort before longer versions when the prefixes
435 # match exactly
436 local = tuple(
437 (i, "") if isinstance(i, int) else (-Infinity, i)
438 for i in local
439 )
440
441 return epoch, release, pre, post, dev, local