16
16
# See the License for the specific language governing permissions and
17
17
# limitations under the License.
18
18
19
+
19
20
import functools
20
21
import sys
21
22
import threading
88
89
if t .TYPE_CHECKING :
89
90
import types
90
91
91
- from .wait import wait_base
92
- from .stop import stop_base
93
-
94
-
95
- WrappedFn = t .TypeVar ("WrappedFn" , bound = t .Callable )
96
- _RetValT = t .TypeVar ("_RetValT" )
97
-
98
-
99
- @t .overload
100
- def retry (fn : WrappedFn ) -> WrappedFn :
101
- pass
102
-
103
-
104
- @t .overload
105
- def retry (* dargs : t .Any , ** dkw : t .Any ) -> t .Callable [[WrappedFn ], WrappedFn ]: # noqa
106
- pass
107
-
108
-
109
- def retry (* dargs : t .Any , ** dkw : t .Any ) -> t .Union [WrappedFn , t .Callable [[WrappedFn ], WrappedFn ]]: # noqa
110
- """Wrap a function with a new `Retrying` object.
111
-
112
- :param dargs: positional arguments passed to Retrying object
113
- :param dkw: keyword arguments passed to the Retrying object
114
- """
115
- # support both @retry and @retry() as valid syntax
116
- if len (dargs ) == 1 and callable (dargs [0 ]):
117
- return retry ()(dargs [0 ])
118
- else :
119
-
120
- def wrap (f : WrappedFn ) -> WrappedFn :
121
- if isinstance (f , retry_base ):
122
- warnings .warn (
123
- f"Got retry_base instance ({ f .__class__ .__name__ } ) as callable argument, "
124
- f"this will probably hang indefinitely (did you mean retry={ f .__class__ .__name__ } (...)?)"
125
- )
126
- if iscoroutinefunction (f ):
127
- r : "BaseRetrying" = AsyncRetrying (* dargs , ** dkw )
128
- elif tornado and hasattr (tornado .gen , "is_coroutine_function" ) and tornado .gen .is_coroutine_function (f ):
129
- r = TornadoRetrying (* dargs , ** dkw )
130
- else :
131
- r = Retrying (* dargs , ** dkw )
92
+ from .retry import RetryBaseT
93
+ from .stop import StopBaseT
94
+ from .wait import WaitBaseT
132
95
133
- return r .wraps (f )
134
96
135
- return wrap
97
+ WrappedFnReturnT = t .TypeVar ("WrappedFnReturnT" )
98
+ WrappedFn = t .TypeVar ("WrappedFn" , bound = t .Callable [..., t .Any ])
136
99
137
100
138
101
class TryAgain (Exception ):
@@ -216,7 +179,7 @@ def __exit__(
216
179
exc_value : t .Optional [BaseException ],
217
180
traceback : t .Optional ["types.TracebackType" ],
218
181
) -> t .Optional [bool ]:
219
- if isinstance ( exc_value , BaseException ) :
182
+ if exc_type is not None and exc_value is not None :
220
183
self .retry_state .set_exception ((exc_type , exc_value , traceback ))
221
184
return True # Swallow exception.
222
185
else :
@@ -229,9 +192,9 @@ class BaseRetrying(ABC):
229
192
def __init__ (
230
193
self ,
231
194
sleep : t .Callable [[t .Union [int , float ]], None ] = sleep ,
232
- stop : "stop_base " = stop_never ,
233
- wait : "wait_base " = wait_none (),
234
- retry : retry_base = retry_if_exception_type (),
195
+ stop : "StopBaseT " = stop_never ,
196
+ wait : "WaitBaseT " = wait_none (),
197
+ retry : "RetryBaseT" = retry_if_exception_type (),
235
198
before : t .Callable [["RetryCallState" ], None ] = before_nothing ,
236
199
after : t .Callable [["RetryCallState" ], None ] = after_nothing ,
237
200
before_sleep : t .Optional [t .Callable [["RetryCallState" ], None ]] = None ,
@@ -254,8 +217,8 @@ def __init__(
254
217
def copy (
255
218
self ,
256
219
sleep : t .Union [t .Callable [[t .Union [int , float ]], None ], object ] = _unset ,
257
- stop : t .Union ["stop_base " , object ] = _unset ,
258
- wait : t .Union ["wait_base " , object ] = _unset ,
220
+ stop : t .Union ["StopBaseT " , object ] = _unset ,
221
+ wait : t .Union ["WaitBaseT " , object ] = _unset ,
259
222
retry : t .Union [retry_base , object ] = _unset ,
260
223
before : t .Union [t .Callable [["RetryCallState" ], None ], object ] = _unset ,
261
224
after : t .Union [t .Callable [["RetryCallState" ], None ], object ] = _unset ,
@@ -312,9 +275,9 @@ def statistics(self) -> t.Dict[str, t.Any]:
312
275
statistics from each thread).
313
276
"""
314
277
try :
315
- return self ._local .statistics
278
+ return self ._local .statistics # type: ignore[no-any-return]
316
279
except AttributeError :
317
- self ._local .statistics = {}
280
+ self ._local .statistics = t . cast ( t . Dict [ str , t . Any ], {})
318
281
return self ._local .statistics
319
282
320
283
def wraps (self , f : WrappedFn ) -> WrappedFn :
@@ -330,10 +293,10 @@ def wrapped_f(*args: t.Any, **kw: t.Any) -> t.Any:
330
293
def retry_with (* args : t .Any , ** kwargs : t .Any ) -> WrappedFn :
331
294
return self .copy (* args , ** kwargs ).wraps (f )
332
295
333
- wrapped_f .retry = self
334
- wrapped_f .retry_with = retry_with
296
+ wrapped_f .retry = self # type: ignore[attr-defined]
297
+ wrapped_f .retry_with = retry_with # type: ignore[attr-defined]
335
298
336
- return wrapped_f
299
+ return wrapped_f # type: ignore[return-value]
337
300
338
301
def begin (self ) -> None :
339
302
self .statistics .clear ()
@@ -348,15 +311,15 @@ def iter(self, retry_state: "RetryCallState") -> t.Union[DoAttempt, DoSleep, t.A
348
311
self .before (retry_state )
349
312
return DoAttempt ()
350
313
351
- is_explicit_retry = retry_state . outcome . failed and isinstance (retry_state . outcome .exception (), TryAgain )
352
- if not (is_explicit_retry or self .retry (retry_state = retry_state )):
314
+ is_explicit_retry = fut . failed and isinstance (fut .exception (), TryAgain )
315
+ if not (is_explicit_retry or self .retry (retry_state )):
353
316
return fut .result ()
354
317
355
318
if self .after is not None :
356
319
self .after (retry_state )
357
320
358
321
self .statistics ["delay_since_first_attempt" ] = retry_state .seconds_since_start
359
- if self .stop (retry_state = retry_state ):
322
+ if self .stop (retry_state ):
360
323
if self .retry_error_callback :
361
324
return self .retry_error_callback (retry_state )
362
325
retry_exc = self .retry_error_cls (fut )
@@ -365,7 +328,7 @@ def iter(self, retry_state: "RetryCallState") -> t.Union[DoAttempt, DoSleep, t.A
365
328
raise retry_exc from fut .exception ()
366
329
367
330
if self .wait :
368
- sleep = self .wait (retry_state = retry_state )
331
+ sleep = self .wait (retry_state )
369
332
else :
370
333
sleep = 0.0
371
334
retry_state .next_action = RetryAction (sleep )
@@ -393,14 +356,24 @@ def __iter__(self) -> t.Generator[AttemptManager, None, None]:
393
356
break
394
357
395
358
@abstractmethod
396
- def __call__ (self , fn : t .Callable [..., _RetValT ], * args : t .Any , ** kwargs : t .Any ) -> _RetValT :
359
+ def __call__ (
360
+ self ,
361
+ fn : t .Callable [..., WrappedFnReturnT ],
362
+ * args : t .Any ,
363
+ ** kwargs : t .Any ,
364
+ ) -> WrappedFnReturnT :
397
365
pass
398
366
399
367
400
368
class Retrying (BaseRetrying ):
401
369
"""Retrying controller."""
402
370
403
- def __call__ (self , fn : t .Callable [..., _RetValT ], * args : t .Any , ** kwargs : t .Any ) -> _RetValT :
371
+ def __call__ (
372
+ self ,
373
+ fn : t .Callable [..., WrappedFnReturnT ],
374
+ * args : t .Any ,
375
+ ** kwargs : t .Any ,
376
+ ) -> WrappedFnReturnT :
404
377
self .begin ()
405
378
406
379
retry_state = RetryCallState (retry_object = self , fn = fn , args = args , kwargs = kwargs )
@@ -410,17 +383,23 @@ def __call__(self, fn: t.Callable[..., _RetValT], *args: t.Any, **kwargs: t.Any)
410
383
try :
411
384
result = fn (* args , ** kwargs )
412
385
except BaseException : # noqa: B902
413
- retry_state .set_exception (sys .exc_info ())
386
+ retry_state .set_exception (sys .exc_info ()) # type: ignore[arg-type]
414
387
else :
415
388
retry_state .set_result (result )
416
389
elif isinstance (do , DoSleep ):
417
390
retry_state .prepare_for_next_attempt ()
418
391
self .sleep (do )
419
392
else :
420
- return do
393
+ return do # type: ignore[no-any-return]
394
+
395
+
396
+ if sys .version_info [1 ] >= 9 :
397
+ FutureGenericT = futures .Future [t .Any ]
398
+ else :
399
+ FutureGenericT = futures .Future
421
400
422
401
423
- class Future (futures . Future ):
402
+ class Future (FutureGenericT ):
424
403
"""Encapsulates a (future or past) attempted call to a target function."""
425
404
426
405
def __init__ (self , attempt_number : int ) -> None :
@@ -493,13 +472,15 @@ def set_result(self, val: t.Any) -> None:
493
472
fut .set_result (val )
494
473
self .outcome , self .outcome_timestamp = fut , ts
495
474
496
- def set_exception (self , exc_info : t .Tuple [t .Type [BaseException ], BaseException , "types.TracebackType" ]) -> None :
475
+ def set_exception (
476
+ self , exc_info : t .Tuple [t .Type [BaseException ], BaseException , "types.TracebackType| None" ]
477
+ ) -> None :
497
478
ts = time .monotonic ()
498
479
fut = Future (self .attempt_number )
499
480
fut .set_exception (exc_info [1 ])
500
481
self .outcome , self .outcome_timestamp = fut , ts
501
482
502
- def __repr__ (self ):
483
+ def __repr__ (self ) -> str :
503
484
if self .outcome is None :
504
485
result = "none yet"
505
486
elif self .outcome .failed :
@@ -513,7 +494,115 @@ def __repr__(self):
513
494
return f"<{ clsname } { id (self )} : attempt #{ self .attempt_number } ; slept for { slept } ; last result: { result } >"
514
495
515
496
497
+ @t .overload
498
+ def retry (func : WrappedFn ) -> WrappedFn :
499
+ ...
500
+
501
+
502
+ @t .overload
503
+ def retry (
504
+ sleep : t .Callable [[t .Union [int , float ]], None ] = sleep ,
505
+ stop : "StopBaseT" = stop_never ,
506
+ wait : "WaitBaseT" = wait_none (),
507
+ retry : "RetryBaseT" = retry_if_exception_type (),
508
+ before : t .Callable [["RetryCallState" ], None ] = before_nothing ,
509
+ after : t .Callable [["RetryCallState" ], None ] = after_nothing ,
510
+ before_sleep : t .Optional [t .Callable [["RetryCallState" ], None ]] = None ,
511
+ reraise : bool = False ,
512
+ retry_error_cls : t .Type ["RetryError" ] = RetryError ,
513
+ retry_error_callback : t .Optional [t .Callable [["RetryCallState" ], t .Any ]] = None ,
514
+ ) -> t .Callable [[WrappedFn ], WrappedFn ]:
515
+ ...
516
+
517
+
518
+ def retry (* dargs : t .Any , ** dkw : t .Any ) -> t .Any :
519
+ """Wrap a function with a new `Retrying` object.
520
+
521
+ :param dargs: positional arguments passed to Retrying object
522
+ :param dkw: keyword arguments passed to the Retrying object
523
+ """
524
+ # support both @retry and @retry() as valid syntax
525
+ if len (dargs ) == 1 and callable (dargs [0 ]):
526
+ return retry ()(dargs [0 ])
527
+ else :
528
+
529
+ def wrap (f : WrappedFn ) -> WrappedFn :
530
+ if isinstance (f , retry_base ):
531
+ warnings .warn (
532
+ f"Got retry_base instance ({ f .__class__ .__name__ } ) as callable argument, "
533
+ f"this will probably hang indefinitely (did you mean retry={ f .__class__ .__name__ } (...)?)"
534
+ )
535
+ r : "BaseRetrying"
536
+ if iscoroutinefunction (f ):
537
+ r = AsyncRetrying (* dargs , ** dkw )
538
+ elif tornado and hasattr (tornado .gen , "is_coroutine_function" ) and tornado .gen .is_coroutine_function (f ):
539
+ r = TornadoRetrying (* dargs , ** dkw )
540
+ else :
541
+ r = Retrying (* dargs , ** dkw )
542
+
543
+ return r .wraps (f )
544
+
545
+ return wrap
546
+
547
+
516
548
from pip ._vendor .tenacity ._asyncio import AsyncRetrying # noqa:E402,I100
517
549
518
550
if tornado :
519
551
from pip ._vendor .tenacity .tornadoweb import TornadoRetrying
552
+
553
+
554
+ __all__ = [
555
+ "retry_base" ,
556
+ "retry_all" ,
557
+ "retry_always" ,
558
+ "retry_any" ,
559
+ "retry_if_exception" ,
560
+ "retry_if_exception_type" ,
561
+ "retry_if_exception_cause_type" ,
562
+ "retry_if_not_exception_type" ,
563
+ "retry_if_not_result" ,
564
+ "retry_if_result" ,
565
+ "retry_never" ,
566
+ "retry_unless_exception_type" ,
567
+ "retry_if_exception_message" ,
568
+ "retry_if_not_exception_message" ,
569
+ "sleep" ,
570
+ "sleep_using_event" ,
571
+ "stop_after_attempt" ,
572
+ "stop_after_delay" ,
573
+ "stop_all" ,
574
+ "stop_any" ,
575
+ "stop_never" ,
576
+ "stop_when_event_set" ,
577
+ "wait_chain" ,
578
+ "wait_combine" ,
579
+ "wait_exponential" ,
580
+ "wait_fixed" ,
581
+ "wait_incrementing" ,
582
+ "wait_none" ,
583
+ "wait_random" ,
584
+ "wait_random_exponential" ,
585
+ "wait_full_jitter" ,
586
+ "wait_exponential_jitter" ,
587
+ "before_log" ,
588
+ "before_nothing" ,
589
+ "after_log" ,
590
+ "after_nothing" ,
591
+ "before_sleep_log" ,
592
+ "before_sleep_nothing" ,
593
+ "retry" ,
594
+ "WrappedFn" ,
595
+ "TryAgain" ,
596
+ "NO_RESULT" ,
597
+ "DoAttempt" ,
598
+ "DoSleep" ,
599
+ "BaseAction" ,
600
+ "RetryAction" ,
601
+ "RetryError" ,
602
+ "AttemptManager" ,
603
+ "BaseRetrying" ,
604
+ "Retrying" ,
605
+ "Future" ,
606
+ "RetryCallState" ,
607
+ "AsyncRetrying" ,
608
+ ]
0 commit comments