25
25
from contextlib import contextmanager
26
26
from copy import copy
27
27
from fractions import Fraction
28
+ from unittest import mock
28
29
29
30
import pytest
30
31
@@ -1073,7 +1074,7 @@ def test_retry_until_exception_of_type_attempt_number(self):
1073
1074
_retryable_test_with_unless_exception_type_name (NameErrorUntilCount (5 ))
1074
1075
)
1075
1076
except NameError as e :
1076
- s = _retryable_test_with_unless_exception_type_name .retry . statistics
1077
+ s = _retryable_test_with_unless_exception_type_name .statistics
1077
1078
self .assertTrue (s ["attempt_number" ] == 6 )
1078
1079
print (e )
1079
1080
else :
@@ -1088,7 +1089,7 @@ def test_retry_until_exception_of_type_no_type(self):
1088
1089
)
1089
1090
)
1090
1091
except NameError as e :
1091
- s = _retryable_test_with_unless_exception_type_no_input .retry . statistics
1092
+ s = _retryable_test_with_unless_exception_type_no_input .statistics
1092
1093
self .assertTrue (s ["attempt_number" ] == 6 )
1093
1094
print (e )
1094
1095
else :
@@ -1111,7 +1112,7 @@ def test_retry_if_exception_message(self):
1111
1112
_retryable_test_if_exception_message_message (NoCustomErrorAfterCount (3 ))
1112
1113
)
1113
1114
except CustomError :
1114
- print (_retryable_test_if_exception_message_message .retry . statistics )
1115
+ print (_retryable_test_if_exception_message_message .statistics )
1115
1116
self .fail ("CustomError should've been retried from errormessage" )
1116
1117
1117
1118
def test_retry_if_not_exception_message (self ):
@@ -1122,7 +1123,7 @@ def test_retry_if_not_exception_message(self):
1122
1123
)
1123
1124
)
1124
1125
except CustomError :
1125
- s = _retryable_test_if_not_exception_message_message .retry . statistics
1126
+ s = _retryable_test_if_not_exception_message_message .statistics
1126
1127
self .assertTrue (s ["attempt_number" ] == 1 )
1127
1128
1128
1129
def test_retry_if_not_exception_message_delay (self ):
@@ -1131,7 +1132,7 @@ def test_retry_if_not_exception_message_delay(self):
1131
1132
_retryable_test_not_exception_message_delay (NameErrorUntilCount (3 ))
1132
1133
)
1133
1134
except NameError :
1134
- s = _retryable_test_not_exception_message_delay .retry . statistics
1135
+ s = _retryable_test_not_exception_message_delay .statistics
1135
1136
print (s ["attempt_number" ])
1136
1137
self .assertTrue (s ["attempt_number" ] == 4 )
1137
1138
@@ -1151,7 +1152,7 @@ def test_retry_if_not_exception_message_match(self):
1151
1152
)
1152
1153
)
1153
1154
except CustomError :
1154
- s = _retryable_test_if_not_exception_message_message .retry . statistics
1155
+ s = _retryable_test_if_not_exception_message_message .statistics
1155
1156
self .assertTrue (s ["attempt_number" ] == 1 )
1156
1157
1157
1158
def test_retry_if_exception_cause_type (self ):
@@ -1209,6 +1210,43 @@ def __call__(self):
1209
1210
h = retrying .wraps (Hello ())
1210
1211
self .assertEqual (h (), "Hello" )
1211
1212
1213
+ def test_retry_function_attributes (self ):
1214
+ """Test that the wrapped function attributes are exposed as intended.
1215
+
1216
+ - statistics contains the value for the latest function run
1217
+ - retry object can be modified to change its behaviour (useful to patch in tests)
1218
+ - retry object statistics do not contain valid information
1219
+ """
1220
+
1221
+ self .assertTrue (_retryable_test_with_stop (NoneReturnUntilAfterCount (2 )))
1222
+
1223
+ expected_stats = {
1224
+ "attempt_number" : 3 ,
1225
+ "delay_since_first_attempt" : mock .ANY ,
1226
+ "idle_for" : mock .ANY ,
1227
+ "start_time" : mock .ANY ,
1228
+ }
1229
+ self .assertEqual (_retryable_test_with_stop .statistics , expected_stats )
1230
+ self .assertEqual (_retryable_test_with_stop .retry .statistics , {})
1231
+
1232
+ with mock .patch .object (
1233
+ _retryable_test_with_stop .retry , "stop" , tenacity .stop_after_attempt (1 )
1234
+ ):
1235
+ try :
1236
+ self .assertTrue (_retryable_test_with_stop (NoneReturnUntilAfterCount (2 )))
1237
+ except RetryError as exc :
1238
+ expected_stats = {
1239
+ "attempt_number" : 1 ,
1240
+ "delay_since_first_attempt" : mock .ANY ,
1241
+ "idle_for" : mock .ANY ,
1242
+ "start_time" : mock .ANY ,
1243
+ }
1244
+ self .assertEqual (_retryable_test_with_stop .statistics , expected_stats )
1245
+ self .assertEqual (exc .last_attempt .attempt_number , 1 )
1246
+ self .assertEqual (_retryable_test_with_stop .retry .statistics , {})
1247
+ else :
1248
+ self .fail ("RetryError should have been raised after 1 attempt" )
1249
+
1212
1250
1213
1251
class TestRetryWith :
1214
1252
def test_redefine_wait (self ):
@@ -1479,21 +1517,21 @@ def test_stats(self):
1479
1517
def _foobar ():
1480
1518
return 42
1481
1519
1482
- self .assertEqual ({}, _foobar .retry . statistics )
1520
+ self .assertEqual ({}, _foobar .statistics )
1483
1521
_foobar ()
1484
- self .assertEqual (1 , _foobar .retry . statistics ["attempt_number" ])
1522
+ self .assertEqual (1 , _foobar .statistics ["attempt_number" ])
1485
1523
1486
1524
def test_stats_failing (self ):
1487
1525
@retry (stop = tenacity .stop_after_attempt (2 ))
1488
1526
def _foobar ():
1489
1527
raise ValueError (42 )
1490
1528
1491
- self .assertEqual ({}, _foobar .retry . statistics )
1529
+ self .assertEqual ({}, _foobar .statistics )
1492
1530
try :
1493
1531
_foobar ()
1494
1532
except Exception : # noqa: B902
1495
1533
pass
1496
- self .assertEqual (2 , _foobar .retry . statistics ["attempt_number" ])
1534
+ self .assertEqual (2 , _foobar .statistics ["attempt_number" ])
1497
1535
1498
1536
1499
1537
class TestRetryErrorCallback (unittest .TestCase ):
0 commit comments