@@ -145,6 +145,29 @@ def get_status() -> str:
145145 assert attempts ["count" ] == 1
146146
147147
148+ def test_poll_until_terminal_status_does_not_retry_memoryview_client_errors ():
149+ attempts = {"count" : 0 }
150+
151+ def get_status () -> str :
152+ attempts ["count" ] += 1
153+ raise HyperbrowserError (
154+ "client failure" ,
155+ status_code = memoryview (b"400" ), # type: ignore[arg-type]
156+ )
157+
158+ with pytest .raises (HyperbrowserError , match = "client failure" ):
159+ poll_until_terminal_status (
160+ operation_name = "sync poll memoryview client error" ,
161+ get_status = get_status ,
162+ is_terminal_status = lambda value : value == "completed" ,
163+ poll_interval_seconds = 0.0001 ,
164+ max_wait_seconds = 1.0 ,
165+ max_status_failures = 5 ,
166+ )
167+
168+ assert attempts ["count" ] == 1
169+
170+
148171def test_poll_until_terminal_status_retries_overlong_numeric_status_codes ():
149172 attempts = {"count" : 0 }
150173
@@ -732,6 +755,29 @@ def operation() -> str:
732755 assert attempts ["count" ] == 3
733756
734757
758+ def test_retry_operation_retries_memoryview_rate_limit_errors ():
759+ attempts = {"count" : 0 }
760+
761+ def operation () -> str :
762+ attempts ["count" ] += 1
763+ if attempts ["count" ] < 3 :
764+ raise HyperbrowserError (
765+ "rate limited" ,
766+ status_code = memoryview (b"429" ), # type: ignore[arg-type]
767+ )
768+ return "ok"
769+
770+ result = retry_operation (
771+ operation_name = "sync retry memoryview rate limit" ,
772+ operation = operation ,
773+ max_attempts = 5 ,
774+ retry_delay_seconds = 0.0001 ,
775+ )
776+
777+ assert result == "ok"
778+ assert attempts ["count" ] == 3
779+
780+
735781def test_retry_operation_does_not_retry_numeric_bytes_client_errors ():
736782 attempts = {"count" : 0 }
737783
@@ -1189,6 +1235,32 @@ async def get_status() -> str:
11891235 asyncio .run (run ())
11901236
11911237
1238+ def test_poll_until_terminal_status_async_does_not_retry_memoryview_client_errors ():
1239+ async def run () -> None :
1240+ attempts = {"count" : 0 }
1241+
1242+ async def get_status () -> str :
1243+ attempts ["count" ] += 1
1244+ raise HyperbrowserError (
1245+ "client failure" ,
1246+ status_code = memoryview (b"404" ), # type: ignore[arg-type]
1247+ )
1248+
1249+ with pytest .raises (HyperbrowserError , match = "client failure" ):
1250+ await poll_until_terminal_status_async (
1251+ operation_name = "async poll memoryview client error" ,
1252+ get_status = get_status ,
1253+ is_terminal_status = lambda value : value == "completed" ,
1254+ poll_interval_seconds = 0.0001 ,
1255+ max_wait_seconds = 1.0 ,
1256+ max_status_failures = 5 ,
1257+ )
1258+
1259+ assert attempts ["count" ] == 1
1260+
1261+ asyncio .run (run ())
1262+
1263+
11921264def test_poll_until_terminal_status_async_retries_overlong_numeric_status_codes ():
11931265 async def run () -> None :
11941266 attempts = {"count" : 0 }
@@ -1470,6 +1542,32 @@ async def operation() -> str:
14701542 asyncio .run (run ())
14711543
14721544
1545+ def test_retry_operation_async_retries_memoryview_rate_limit_errors ():
1546+ async def run () -> None :
1547+ attempts = {"count" : 0 }
1548+
1549+ async def operation () -> str :
1550+ attempts ["count" ] += 1
1551+ if attempts ["count" ] < 3 :
1552+ raise HyperbrowserError (
1553+ "rate limited" ,
1554+ status_code = memoryview (b"429" ), # type: ignore[arg-type]
1555+ )
1556+ return "ok"
1557+
1558+ result = await retry_operation_async (
1559+ operation_name = "async retry memoryview rate limit" ,
1560+ operation = operation ,
1561+ max_attempts = 5 ,
1562+ retry_delay_seconds = 0.0001 ,
1563+ )
1564+
1565+ assert result == "ok"
1566+ assert attempts ["count" ] == 3
1567+
1568+ asyncio .run (run ())
1569+
1570+
14731571def test_retry_operation_async_retries_numeric_bytes_rate_limit_errors ():
14741572 async def run () -> None :
14751573 attempts = {"count" : 0 }
0 commit comments