diff options
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/retrying.py')
-rw-r--r-- | venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/retrying.py | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/retrying.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/retrying.py new file mode 100644 index 0000000..f8d743b --- /dev/null +++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/retrying.py | |||
@@ -0,0 +1,267 @@ | |||
1 | ## Copyright 2013-2014 Ray Holder | ||
2 | ## | ||
3 | ## Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | ## you may not use this file except in compliance with the License. | ||
5 | ## You may obtain a copy of the License at | ||
6 | ## | ||
7 | ## http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | ## | ||
9 | ## Unless required by applicable law or agreed to in writing, software | ||
10 | ## distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | ## See the License for the specific language governing permissions and | ||
13 | ## limitations under the License. | ||
14 | |||
15 | import random | ||
16 | from pip._vendor import six | ||
17 | import sys | ||
18 | import time | ||
19 | import traceback | ||
20 | |||
21 | |||
22 | # sys.maxint / 2, since Python 3.2 doesn't have a sys.maxint... | ||
23 | MAX_WAIT = 1073741823 | ||
24 | |||
25 | |||
26 | def retry(*dargs, **dkw): | ||
27 | """ | ||
28 | Decorator function that instantiates the Retrying object | ||
29 | @param *dargs: positional arguments passed to Retrying object | ||
30 | @param **dkw: keyword arguments passed to the Retrying object | ||
31 | """ | ||
32 | # support both @retry and @retry() as valid syntax | ||
33 | if len(dargs) == 1 and callable(dargs[0]): | ||
34 | def wrap_simple(f): | ||
35 | |||
36 | @six.wraps(f) | ||
37 | def wrapped_f(*args, **kw): | ||
38 | return Retrying().call(f, *args, **kw) | ||
39 | |||
40 | return wrapped_f | ||
41 | |||
42 | return wrap_simple(dargs[0]) | ||
43 | |||
44 | else: | ||
45 | def wrap(f): | ||
46 | |||
47 | @six.wraps(f) | ||
48 | def wrapped_f(*args, **kw): | ||
49 | return Retrying(*dargs, **dkw).call(f, *args, **kw) | ||
50 | |||
51 | return wrapped_f | ||
52 | |||
53 | return wrap | ||
54 | |||
55 | |||
56 | class Retrying(object): | ||
57 | |||
58 | def __init__(self, | ||
59 | stop=None, wait=None, | ||
60 | stop_max_attempt_number=None, | ||
61 | stop_max_delay=None, | ||
62 | wait_fixed=None, | ||
63 | wait_random_min=None, wait_random_max=None, | ||
64 | wait_incrementing_start=None, wait_incrementing_increment=None, | ||
65 | wait_exponential_multiplier=None, wait_exponential_max=None, | ||
66 | retry_on_exception=None, | ||
67 | retry_on_result=None, | ||
68 | wrap_exception=False, | ||
69 | stop_func=None, | ||
70 | wait_func=None, | ||
71 | wait_jitter_max=None): | ||
72 | |||
73 | self._stop_max_attempt_number = 5 if stop_max_attempt_number is None else stop_max_attempt_number | ||
74 | self._stop_max_delay = 100 if stop_max_delay is None else stop_max_delay | ||
75 | self._wait_fixed = 1000 if wait_fixed is None else wait_fixed | ||
76 | self._wait_random_min = 0 if wait_random_min is None else wait_random_min | ||
77 | self._wait_random_max = 1000 if wait_random_max is None else wait_random_max | ||
78 | self._wait_incrementing_start = 0 if wait_incrementing_start is None else wait_incrementing_start | ||
79 | self._wait_incrementing_increment = 100 if wait_incrementing_increment is None else wait_incrementing_increment | ||
80 | self._wait_exponential_multiplier = 1 if wait_exponential_multiplier is None else wait_exponential_multiplier | ||
81 | self._wait_exponential_max = MAX_WAIT if wait_exponential_max is None else wait_exponential_max | ||
82 | self._wait_jitter_max = 0 if wait_jitter_max is None else wait_jitter_max | ||
83 | |||
84 | # TODO add chaining of stop behaviors | ||
85 | # stop behavior | ||
86 | stop_funcs = [] | ||
87 | if stop_max_attempt_number is not None: | ||
88 | stop_funcs.append(self.stop_after_attempt) | ||
89 | |||
90 | if stop_max_delay is not None: | ||
91 | stop_funcs.append(self.stop_after_delay) | ||
92 | |||
93 | if stop_func is not None: | ||
94 | self.stop = stop_func | ||
95 | |||
96 | elif stop is None: | ||
97 | self.stop = lambda attempts, delay: any(f(attempts, delay) for f in stop_funcs) | ||
98 | |||
99 | else: | ||
100 | self.stop = getattr(self, stop) | ||
101 | |||
102 | # TODO add chaining of wait behaviors | ||
103 | # wait behavior | ||
104 | wait_funcs = [lambda *args, **kwargs: 0] | ||
105 | if wait_fixed is not None: | ||
106 | wait_funcs.append(self.fixed_sleep) | ||
107 | |||
108 | if wait_random_min is not None or wait_random_max is not None: | ||
109 | wait_funcs.append(self.random_sleep) | ||
110 | |||
111 | if wait_incrementing_start is not None or wait_incrementing_increment is not None: | ||
112 | wait_funcs.append(self.incrementing_sleep) | ||
113 | |||
114 | if wait_exponential_multiplier is not None or wait_exponential_max is not None: | ||
115 | wait_funcs.append(self.exponential_sleep) | ||
116 | |||
117 | if wait_func is not None: | ||
118 | self.wait = wait_func | ||
119 | |||
120 | elif wait is None: | ||
121 | self.wait = lambda attempts, delay: max(f(attempts, delay) for f in wait_funcs) | ||
122 | |||
123 | else: | ||
124 | self.wait = getattr(self, wait) | ||
125 | |||
126 | # retry on exception filter | ||
127 | if retry_on_exception is None: | ||
128 | self._retry_on_exception = self.always_reject | ||
129 | else: | ||
130 | self._retry_on_exception = retry_on_exception | ||
131 | |||
132 | # TODO simplify retrying by Exception types | ||
133 | # retry on result filter | ||
134 | if retry_on_result is None: | ||
135 | self._retry_on_result = self.never_reject | ||
136 | else: | ||
137 | self._retry_on_result = retry_on_result | ||
138 | |||
139 | self._wrap_exception = wrap_exception | ||
140 | |||
141 | def stop_after_attempt(self, previous_attempt_number, delay_since_first_attempt_ms): | ||
142 | """Stop after the previous attempt >= stop_max_attempt_number.""" | ||
143 | return previous_attempt_number >= self._stop_max_attempt_number | ||
144 | |||
145 | def stop_after_delay(self, previous_attempt_number, delay_since_first_attempt_ms): | ||
146 | """Stop after the time from the first attempt >= stop_max_delay.""" | ||
147 | return delay_since_first_attempt_ms >= self._stop_max_delay | ||
148 | |||
149 | def no_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): | ||
150 | """Don't sleep at all before retrying.""" | ||
151 | return 0 | ||
152 | |||
153 | def fixed_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): | ||
154 | """Sleep a fixed amount of time between each retry.""" | ||
155 | return self._wait_fixed | ||
156 | |||
157 | def random_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): | ||
158 | """Sleep a random amount of time between wait_random_min and wait_random_max""" | ||
159 | return random.randint(self._wait_random_min, self._wait_random_max) | ||
160 | |||
161 | def incrementing_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): | ||
162 | """ | ||
163 | Sleep an incremental amount of time after each attempt, starting at | ||
164 | wait_incrementing_start and incrementing by wait_incrementing_increment | ||
165 | """ | ||
166 | result = self._wait_incrementing_start + (self._wait_incrementing_increment * (previous_attempt_number - 1)) | ||
167 | if result < 0: | ||
168 | result = 0 | ||
169 | return result | ||
170 | |||
171 | def exponential_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): | ||
172 | exp = 2 ** previous_attempt_number | ||
173 | result = self._wait_exponential_multiplier * exp | ||
174 | if result > self._wait_exponential_max: | ||
175 | result = self._wait_exponential_max | ||
176 | if result < 0: | ||
177 | result = 0 | ||
178 | return result | ||
179 | |||
180 | def never_reject(self, result): | ||
181 | return False | ||
182 | |||
183 | def always_reject(self, result): | ||
184 | return True | ||
185 | |||
186 | def should_reject(self, attempt): | ||
187 | reject = False | ||
188 | if attempt.has_exception: | ||
189 | reject |= self._retry_on_exception(attempt.value[1]) | ||
190 | else: | ||
191 | reject |= self._retry_on_result(attempt.value) | ||
192 | |||
193 | return reject | ||
194 | |||
195 | def call(self, fn, *args, **kwargs): | ||
196 | start_time = int(round(time.time() * 1000)) | ||
197 | attempt_number = 1 | ||
198 | while True: | ||
199 | try: | ||
200 | attempt = Attempt(fn(*args, **kwargs), attempt_number, False) | ||
201 | except: | ||
202 | tb = sys.exc_info() | ||
203 | attempt = Attempt(tb, attempt_number, True) | ||
204 | |||
205 | if not self.should_reject(attempt): | ||
206 | return attempt.get(self._wrap_exception) | ||
207 | |||
208 | delay_since_first_attempt_ms = int(round(time.time() * 1000)) - start_time | ||
209 | if self.stop(attempt_number, delay_since_first_attempt_ms): | ||
210 | if not self._wrap_exception and attempt.has_exception: | ||
211 | # get() on an attempt with an exception should cause it to be raised, but raise just in case | ||
212 | raise attempt.get() | ||
213 | else: | ||
214 | raise RetryError(attempt) | ||
215 | else: | ||
216 | sleep = self.wait(attempt_number, delay_since_first_attempt_ms) | ||
217 | if self._wait_jitter_max: | ||
218 | jitter = random.random() * self._wait_jitter_max | ||
219 | sleep = sleep + max(0, jitter) | ||
220 | time.sleep(sleep / 1000.0) | ||
221 | |||
222 | attempt_number += 1 | ||
223 | |||
224 | |||
225 | class Attempt(object): | ||
226 | """ | ||
227 | An Attempt encapsulates a call to a target function that may end as a | ||
228 | normal return value from the function or an Exception depending on what | ||
229 | occurred during the execution. | ||
230 | """ | ||
231 | |||
232 | def __init__(self, value, attempt_number, has_exception): | ||
233 | self.value = value | ||
234 | self.attempt_number = attempt_number | ||
235 | self.has_exception = has_exception | ||
236 | |||
237 | def get(self, wrap_exception=False): | ||
238 | """ | ||
239 | Return the return value of this Attempt instance or raise an Exception. | ||
240 | If wrap_exception is true, this Attempt is wrapped inside of a | ||
241 | RetryError before being raised. | ||
242 | """ | ||
243 | if self.has_exception: | ||
244 | if wrap_exception: | ||
245 | raise RetryError(self) | ||
246 | else: | ||
247 | six.reraise(self.value[0], self.value[1], self.value[2]) | ||
248 | else: | ||
249 | return self.value | ||
250 | |||
251 | def __repr__(self): | ||
252 | if self.has_exception: | ||
253 | return "Attempts: {0}, Error:\n{1}".format(self.attempt_number, "".join(traceback.format_tb(self.value[2]))) | ||
254 | else: | ||
255 | return "Attempts: {0}, Value: {1}".format(self.attempt_number, self.value) | ||
256 | |||
257 | |||
258 | class RetryError(Exception): | ||
259 | """ | ||
260 | A RetryError encapsulates the last Attempt instance right before giving up. | ||
261 | """ | ||
262 | |||
263 | def __init__(self, last_attempt): | ||
264 | self.last_attempt = last_attempt | ||
265 | |||
266 | def __str__(self): | ||
267 | return "RetryError[{0}]".format(self.last_attempt) | ||