0
# Core Decorator & Classes
1
2
This document covers the main `@retry` decorator and core retry controller classes that form the foundation of tenacity's retry framework.
3
4
## Main Decorator
5
6
```python { .api }
7
from tenacity import retry
8
9
def retry(
10
sleep: Callable[[float], None] = sleep,
11
stop: StopBaseT = stop_never,
12
wait: WaitBaseT = wait_none(),
13
retry: RetryBaseT = retry_if_exception_type(),
14
before: Callable[[RetryCallState], None] = before_nothing,
15
after: Callable[[RetryCallState], None] = after_nothing,
16
before_sleep: Optional[Callable[[RetryCallState], None]] = None,
17
reraise: bool = False,
18
retry_error_cls: type = RetryError,
19
retry_error_callback: Optional[Callable[[RetryCallState], Any]] = None
20
) -> Callable[[WrappedFn], WrappedFn]:
21
"""
22
Main decorator to add retry behavior to functions.
23
24
Auto-detects async/tornado functions and applies appropriate retry controller.
25
Supports both synchronous and asynchronous functions seamlessly.
26
27
Parameters:
28
- sleep: Function to use for sleeping between retries (default: time.sleep)
29
- stop: Strategy determining when to stop retrying (default: never stop)
30
- wait: Strategy determining delay between retries (default: no wait)
31
- retry: Strategy determining whether to retry after failure (default: retry on any exception)
32
- before: Callback executed before each attempt (default: no-op)
33
- after: Callback executed after each attempt (default: no-op)
34
- before_sleep: Callback executed before sleeping between retries (default: None)
35
- reraise: If True, reraise original exception instead of RetryError (default: False)
36
- retry_error_cls: Exception class to raise when retries exhausted (default: RetryError)
37
- retry_error_callback: Callback executed when retries exhausted (default: None)
38
39
Returns:
40
Decorated function with retry behavior applied.
41
"""
42
```
43
44
### Usage Examples
45
46
```python { .api }
47
# Basic retry on any exception
48
@retry
49
def might_fail():
50
pass
51
52
# Retry with exponential backoff and attempt limit
53
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
54
def api_call():
55
pass
56
57
# Retry specific exceptions only
58
@retry(retry=retry_if_exception_type((ConnectionError, TimeoutError)))
59
def network_operation():
60
pass
61
62
# Auto-detects async functions
63
@retry(stop=stop_after_delay(30))
64
async def async_operation():
65
pass
66
```
67
68
## Core Retry Controllers
69
70
### BaseRetrying
71
72
```python { .api }
73
from tenacity import BaseRetrying
74
75
class BaseRetrying(ABC):
76
"""
77
Abstract base class for all retry controllers.
78
79
Provides the common interface and shared functionality for retry behavior.
80
All concrete retry controllers inherit from this class.
81
"""
82
83
def __init__(
84
self,
85
sleep: Callable[[float], None] = sleep,
86
stop: StopBaseT = stop_never,
87
wait: WaitBaseT = wait_none(),
88
retry: RetryBaseT = retry_if_exception_type(),
89
before: Callable[[RetryCallState], None] = before_nothing,
90
after: Callable[[RetryCallState], None] = after_nothing,
91
before_sleep: Optional[Callable[[RetryCallState], None]] = None,
92
reraise: bool = False,
93
retry_error_cls: type = RetryError,
94
retry_error_callback: Optional[Callable[[RetryCallState], Any]] = None
95
):
96
"""Initialize retry controller with strategies and callbacks."""
97
98
def copy(self, **kwargs) -> 'Self':
99
"""
100
Create a copy of this retrying object with modified parameters.
101
102
Parameters can be any of the constructor parameters.
103
Useful for creating variations of retry behavior.
104
"""
105
106
def wraps(self, f: WrappedFn) -> WrappedFn:
107
"""
108
Wrap a function with this retry behavior.
109
110
Returns a new function that will retry according to this controller's configuration.
111
"""
112
113
def begin(self) -> RetryCallState:
114
"""
115
Initialize a new retry session.
116
117
Creates and returns a RetryCallState tracking the retry session.
118
"""
119
120
def iter(self, retry_state: RetryCallState) -> Iterator[AttemptManager]:
121
"""
122
Execute one iteration of the retry loop.
123
124
Yields AttemptManager context managers for each retry attempt.
125
"""
126
127
@abstractmethod
128
def __call__(self, fn: Callable[..., Any], *args, **kwargs) -> Any:
129
"""Execute function with retry logic. Must be implemented by subclasses."""
130
131
def __iter__(self) -> Iterator[AttemptManager]:
132
"""Iterator interface for attempt managers."""
133
134
@property
135
def statistics(self) -> dict:
136
"""Runtime statistics for this retry controller."""
137
138
@property
139
def iter_state(self) -> IterState:
140
"""Current iteration state."""
141
```
142
143
### Retrying
144
145
```python { .api }
146
from tenacity import Retrying
147
148
class Retrying(BaseRetrying):
149
"""
150
Standard synchronous retry controller.
151
152
Handles retry logic for regular (non-async) functions.
153
This is the default controller used by the @retry decorator for sync functions.
154
"""
155
156
def __call__(self, fn: Callable[..., Any], *args, **kwargs) -> Any:
157
"""
158
Execute function with synchronous retry logic.
159
160
Parameters:
161
- fn: Function to execute with retries
162
- *args: Positional arguments to pass to fn
163
- **kwargs: Keyword arguments to pass to fn
164
165
Returns:
166
Result of successful function execution.
167
168
Raises:
169
RetryError: When all retry attempts are exhausted
170
"""
171
```
172
173
### AsyncRetrying
174
175
```python { .api }
176
from tenacity import AsyncRetrying
177
178
class AsyncRetrying(BaseRetrying):
179
"""
180
Asynchronous retry controller for coroutines.
181
182
Handles retry logic for async/await functions and coroutines.
183
Auto-detects trio vs asyncio for appropriate sleep function.
184
"""
185
186
async def __call__(self, fn: Callable[..., Any], *args, **kwargs) -> Any:
187
"""
188
Execute coroutine with asynchronous retry logic.
189
190
Parameters:
191
- fn: Async function/coroutine to execute with retries
192
- *args: Positional arguments to pass to fn
193
- **kwargs: Keyword arguments to pass to fn
194
195
Returns:
196
Result of successful coroutine execution.
197
198
Raises:
199
RetryError: When all retry attempts are exhausted
200
"""
201
202
def __aiter__(self) -> AsyncIterator[AttemptManager]:
203
"""Async iterator interface for attempt managers."""
204
205
async def __anext__(self) -> AttemptManager:
206
"""Async iteration support."""
207
```
208
209
### TornadoRetrying
210
211
```python { .api }
212
from tenacity.tornadoweb import TornadoRetrying
213
214
class TornadoRetrying(BaseRetrying):
215
"""
216
Tornado web framework retry controller.
217
218
Specialized retry controller for Tornado's @gen.coroutine decorated functions.
219
Uses Tornado's IOLoop for asynchronous sleep operations.
220
"""
221
222
@gen.coroutine
223
def __call__(self, fn: Callable[..., Any], *args, **kwargs) -> Any:
224
"""
225
Execute Tornado coroutine with retry logic.
226
227
Uses Tornado's generator-based coroutine model and IOLoop.sleep.
228
229
Parameters:
230
- fn: Tornado coroutine to execute with retries
231
- *args: Positional arguments to pass to fn
232
- **kwargs: Keyword arguments to pass to fn
233
234
Returns:
235
tornado.concurrent.Future with result of successful execution.
236
"""
237
```
238
239
## State Management Classes
240
241
### RetryCallState
242
243
```python { .api }
244
from tenacity import RetryCallState
245
246
class RetryCallState:
247
"""
248
Tracks the complete state of a retry session.
249
250
Contains all information about the current retry attempt, timing,
251
outcomes, and configuration. Passed to all callbacks and strategies.
252
"""
253
254
# Core execution context
255
start_time: float # When the retry session began
256
retry_object: BaseRetrying # The retry controller instance
257
fn: Callable[..., Any] # Function being retried
258
args: tuple # Function positional arguments
259
kwargs: dict # Function keyword arguments
260
261
# Attempt tracking
262
attempt_number: int # Current attempt number (starts at 1)
263
outcome: Future # Result of last attempt
264
outcome_timestamp: Optional[float] # When outcome was set
265
266
# Timing information
267
idle_for: float # Total time spent sleeping
268
upcoming_sleep: float # Next sleep duration
269
seconds_since_start: float # Elapsed time since first attempt
270
271
# Flow control
272
next_action: Optional[BaseAction] # Next action to take (retry/stop)
273
274
def prepare_for_next_attempt(self) -> None:
275
"""Reset state for the next retry attempt."""
276
277
def set_result(self, val: Any) -> None:
278
"""Set successful result for this attempt."""
279
280
def set_exception(self, exc_info: tuple) -> None:
281
"""Set exception result for this attempt."""
282
```
283
284
### Future
285
286
```python { .api }
287
from tenacity import Future
288
289
class Future:
290
"""
291
Container for attempt results (success or exception).
292
293
Encapsulates the outcome of a single retry attempt, including
294
the attempt number and whether it failed.
295
"""
296
297
def __init__(self, attempt_number: int):
298
"""
299
Initialize Future for given attempt number.
300
301
Parameters:
302
- attempt_number: Which attempt this result represents
303
"""
304
305
@property
306
def attempt_number(self) -> int:
307
"""The attempt number this result is from."""
308
309
@property
310
def failed(self) -> bool:
311
"""True if this attempt resulted in an exception."""
312
313
@classmethod
314
def construct(
315
cls,
316
attempt_number: int,
317
value: Any,
318
has_exception: bool
319
) -> 'Future':
320
"""
321
Create Future with result value or exception.
322
323
Parameters:
324
- attempt_number: Which attempt this represents
325
- value: The result value or exception
326
- has_exception: True if value is an exception
327
328
Returns:
329
Future instance with the result set
330
"""
331
```
332
333
### AttemptManager
334
335
```python { .api }
336
from tenacity import AttemptManager
337
338
class AttemptManager:
339
"""
340
Context manager for individual retry attempts.
341
342
Handles entering/exiting attempt context and capturing
343
results or exceptions from the attempt.
344
"""
345
346
def __init__(self, retry_state: RetryCallState):
347
"""Initialize attempt manager with retry state."""
348
349
def __enter__(self) -> 'AttemptManager':
350
"""Enter attempt context."""
351
352
def __exit__(
353
self,
354
exc_type: Optional[type],
355
exc_value: Optional[BaseException],
356
traceback: Optional[Any]
357
) -> Optional[bool]:
358
"""
359
Exit attempt context and capture result.
360
361
Captures successful results or exceptions and updates retry state.
362
"""
363
```
364
365
## Action Classes
366
367
### BaseAction
368
369
```python { .api }
370
from tenacity import BaseAction
371
372
class BaseAction:
373
"""
374
Abstract base class for retry actions.
375
376
Represents different actions that can be taken during retry logic.
377
"""
378
379
REPR_FIELDS: tuple = () # Fields to include in string representation
380
NAME: str = "" # Human-readable action name
381
```
382
383
### RetryAction
384
385
```python { .api }
386
from tenacity import RetryAction
387
388
class RetryAction(BaseAction):
389
"""
390
Action representing a retry with specified sleep time.
391
392
Indicates that another attempt should be made after sleeping
393
for the specified duration.
394
"""
395
396
def __init__(self, sleep: float):
397
"""
398
Initialize retry action with sleep duration.
399
400
Parameters:
401
- sleep: Number of seconds to sleep before next attempt
402
"""
403
404
@property
405
def sleep(self) -> float:
406
"""Sleep duration for this retry action."""
407
```
408
409
### Control Flow Markers
410
411
```python { .api }
412
from tenacity import DoAttempt, DoSleep
413
414
class DoAttempt:
415
"""Marker class indicating an attempt should be made."""
416
pass
417
418
class DoSleep(float):
419
"""
420
Marker class indicating sleep should occur.
421
422
Inherits from float to carry the sleep duration.
423
"""
424
pass
425
```
426
427
### IterState
428
429
```python { .api }
430
from tenacity import IterState
431
432
@dataclass
433
class IterState:
434
"""
435
Tracks iteration state within the retry loop.
436
437
Maintains the current state of retry condition evaluation,
438
actions to execute, and timing information.
439
"""
440
441
actions: list = field(default_factory=list)
442
retry_run_result: bool = False
443
delay_since_first_attempt: float = 0
444
stop_run_result: bool = False
445
is_explicit_retry: bool = False
446
447
def reset(self) -> None:
448
"""Reset all fields to their default values."""
449
```
450
451
## Constants and Utilities
452
453
```python { .api }
454
from tenacity import NO_RESULT, WrappedFn, WrappedFnReturnT
455
456
# Sentinel object for unset results
457
NO_RESULT: object
458
459
# Type variables for function wrapping
460
WrappedFn = TypeVar('WrappedFn', bound=Callable[..., Any])
461
WrappedFnReturnT = TypeVar('WrappedFnReturnT')
462
```
463
464
## Usage Patterns
465
466
### Direct Controller Usage
467
468
```python { .api }
469
# Create retry controller directly
470
retrying = Retrying(
471
stop=stop_after_attempt(3),
472
wait=wait_exponential(multiplier=1, min=4, max=10)
473
)
474
475
# Use with different functions
476
result1 = retrying(function1, arg1, arg2)
477
result2 = retrying(function2, kwarg=value)
478
479
# Create variations
480
fast_retrying = retrying.copy(wait=wait_fixed(1))
481
```
482
483
### Async Controller Usage
484
485
```python { .api }
486
# Async retry controller
487
async_retrying = AsyncRetrying(
488
stop=stop_after_delay(30),
489
retry=retry_if_exception_type(ConnectionError)
490
)
491
492
# Use with async functions
493
result = await async_retrying(async_function, param=value)
494
```
495
496
### Iterator Interface
497
498
```python { .api }
499
# Manual retry loop with attempt managers
500
retrying = Retrying(stop=stop_after_attempt(3))
501
502
for attempt in retrying:
503
with attempt:
504
# Your code that might fail
505
result = risky_operation()
506
break # Success - exit retry loop
507
```
508
509
This comprehensive coverage of core classes provides the foundation for understanding tenacity's retry framework and enables building sophisticated retry logic for any use case.