@@ -124,6 +124,26 @@ def get_status() -> str:
124124 assert attempts ["count" ] == 1
125125
126126
127+ def test_poll_until_terminal_status_does_not_retry_numeric_string_client_errors ():
128+ attempts = {"count" : 0 }
129+
130+ def get_status () -> str :
131+ attempts ["count" ] += 1
132+ raise HyperbrowserError ("client failure" , status_code = "400" ) # type: ignore[arg-type]
133+
134+ with pytest .raises (HyperbrowserError , match = "client failure" ):
135+ poll_until_terminal_status (
136+ operation_name = "sync poll numeric-string client error" ,
137+ get_status = get_status ,
138+ is_terminal_status = lambda value : value == "completed" ,
139+ poll_interval_seconds = 0.0001 ,
140+ max_wait_seconds = 1.0 ,
141+ max_status_failures = 5 ,
142+ )
143+
144+ assert attempts ["count" ] == 1
145+
146+
127147def test_poll_until_terminal_status_does_not_retry_stop_iteration_errors ():
128148 attempts = {"count" : 0 }
129149
@@ -367,7 +387,7 @@ async def get_status() -> str:
367387 if attempts ["count" ] < 3 :
368388 raise HyperbrowserError (
369389 "malformed status code" ,
370- status_code = "400 " , # type: ignore[arg-type]
390+ status_code = "invalid-status " , # type: ignore[arg-type]
371391 )
372392 return "completed"
373393
@@ -559,6 +579,29 @@ def operation() -> str:
559579 assert attempts ["count" ] == 1
560580
561581
582+ def test_retry_operation_retries_numeric_string_rate_limit_errors ():
583+ attempts = {"count" : 0 }
584+
585+ def operation () -> str :
586+ attempts ["count" ] += 1
587+ if attempts ["count" ] < 3 :
588+ raise HyperbrowserError (
589+ "rate limited" ,
590+ status_code = " 429 " , # type: ignore[arg-type]
591+ )
592+ return "ok"
593+
594+ result = retry_operation (
595+ operation_name = "sync retry numeric-string rate limit" ,
596+ operation = operation ,
597+ max_attempts = 5 ,
598+ retry_delay_seconds = 0.0001 ,
599+ )
600+
601+ assert result == "ok"
602+ assert attempts ["count" ] == 3
603+
604+
562605def test_retry_operation_does_not_retry_stop_iteration_errors ():
563606 attempts = {"count" : 0 }
564607
@@ -733,7 +776,7 @@ def operation() -> str:
733776 if attempts ["count" ] < 3 :
734777 raise HyperbrowserError (
735778 "malformed status code" ,
736- status_code = "400 " , # type: ignore[arg-type]
779+ status_code = "invalid-status " , # type: ignore[arg-type]
737780 )
738781 return "ok"
739782
@@ -882,6 +925,32 @@ async def get_status() -> str:
882925 asyncio .run (run ())
883926
884927
928+ def test_poll_until_terminal_status_async_does_not_retry_numeric_string_client_errors ():
929+ async def run () -> None :
930+ attempts = {"count" : 0 }
931+
932+ async def get_status () -> str :
933+ attempts ["count" ] += 1
934+ raise HyperbrowserError (
935+ "client failure" ,
936+ status_code = "404" , # type: ignore[arg-type]
937+ )
938+
939+ with pytest .raises (HyperbrowserError , match = "client failure" ):
940+ await poll_until_terminal_status_async (
941+ operation_name = "async poll numeric-string client error" ,
942+ get_status = get_status ,
943+ is_terminal_status = lambda value : value == "completed" ,
944+ poll_interval_seconds = 0.0001 ,
945+ max_wait_seconds = 1.0 ,
946+ max_status_failures = 5 ,
947+ )
948+
949+ assert attempts ["count" ] == 1
950+
951+ asyncio .run (run ())
952+
953+
885954def test_poll_until_terminal_status_async_does_not_retry_stop_async_iteration_errors ():
886955 async def run () -> None :
887956 attempts = {"count" : 0 }
@@ -1086,6 +1155,32 @@ async def operation() -> str:
10861155 asyncio .run (run ())
10871156
10881157
1158+ def test_retry_operation_async_retries_numeric_string_rate_limit_errors ():
1159+ async def run () -> None :
1160+ attempts = {"count" : 0 }
1161+
1162+ async def operation () -> str :
1163+ attempts ["count" ] += 1
1164+ if attempts ["count" ] < 3 :
1165+ raise HyperbrowserError (
1166+ "rate limited" ,
1167+ status_code = "429" , # type: ignore[arg-type]
1168+ )
1169+ return "ok"
1170+
1171+ result = await retry_operation_async (
1172+ operation_name = "async retry numeric-string rate limit" ,
1173+ operation = operation ,
1174+ max_attempts = 5 ,
1175+ retry_delay_seconds = 0.0001 ,
1176+ )
1177+
1178+ assert result == "ok"
1179+ assert attempts ["count" ] == 3
1180+
1181+ asyncio .run (run ())
1182+
1183+
10891184def test_retry_operation_async_does_not_retry_stop_async_iteration_errors ():
10901185 async def run () -> None :
10911186 attempts = {"count" : 0 }
0 commit comments