Coverage for src/fastapi_cloud_cli/api/_retry.py: 100%
45 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
1import logging 1eafbgcd
2import time 1eafbgcd
3from collections.abc import Callable, Generator 1eafbgcd
4from contextlib import contextmanager 1eafbgcd
5from datetime import timedelta 1eafbgcd
6from functools import wraps 1eafbgcd
7from typing import TypeVar 1eafbgcd
9import httpx 1eafbgcd
10from typing_extensions import ParamSpec 1eafbgcd
12from ._errors import StreamLogError, TooManyRetriesError 1eafbgcd
14logger = logging.getLogger(__name__) 1eafbgcd
16STREAM_LOGS_MAX_RETRIES = 3 1eafbgcd
17STREAM_LOGS_TIMEOUT = timedelta(minutes=5) 1eafbgcd
20@contextmanager 1eafbgcd
21def attempt(attempt_number: int) -> Generator[None, None, None]: 1eafbgcd
22 def _backoff() -> None: 2OgcbdbX v HgIdJdKdLdw x Mdy h NdOdPdqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$dY Z 0 1 2 Rb%d'd(d)d*d+d,dPgebfb3 z Ig-d.d/d:dA B ;dC j =d?d@dSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemene4 5 6 7 8 ,boepeqereseteueQggbhb9 D JgvewexeyeE F zeG l AeBeCe-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjcDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe! # $ % ' kc0e1e2e3e4e5e6eRgibjb( H Kg7e8e9e!eI J #eK n $e%e'elcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eaf) * + , - McbfcfdfefffgfhfSgkblb. L LgifjfkflfM N mfO p nfofpfNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%cqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMf/ : ; = ? 'cNfOfPfQfRfSfTfTgmbnb@ P MgUfVfWfXfQ R YfS r Zf0f1f(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f[ ] ^ _ ` fd=f?f@f[f]f^f_fUgobpb{ T Ng`f{f|f}fU V ~fW t agbgcggdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGddgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzg| } ~ abbbHdAgBgCgDgEgFgGg
23 backoff_seconds = min(2**attempt_number, 30) 2cbdbv w x y h i ebfbz A B C j k gbhbD E F G l m ibjbH I J K n o kblbL M N O p q mbnbP Q R S r s obpbT U V W t u
24 logger.debug( 2cbdbv w x y h i ebfbz A B C j k gbhbD E F G l m ibjbH I J K n o kblbL M N O p q mbnbP Q R S r s obpbT U V W t u
25 "Retrying in %ds (attempt %d)",
26 backoff_seconds,
27 attempt_number,
28 )
29 time.sleep(backoff_seconds) 2cbdbv w x y h i ebfbz A B C j k gbhbD E F G l m ibjbH I J K n o kblbL M N O p q mbnbP Q R S r s obpbT U V W t u
31 try: 2OgcbdbX v HgIdJdKdLdw x Mdy h NdOdPdqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$dY Z 0 1 2 Rb%d'd(d)d*d+d,dPgebfb3 z Ig-d.d/d:dA B ;dC j =d?d@dSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemene4 5 6 7 8 ,boepeqereseteueQggbhb9 D JgvewexeyeE F zeG l AeBeCe-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjcDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe! # $ % ' kc0e1e2e3e4e5e6eRgibjb( H Kg7e8e9e!eI J #eK n $e%e'elcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eaf) * + , - McbfcfdfefffgfhfSgkblb. L LgifjfkflfM N mfO p nfofpfNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%cqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMf/ : ; = ? 'cNfOfPfQfRfSfTfTgmbnb@ P MgUfVfWfXfQ R YfS r Zf0f1f(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f[ ] ^ _ ` fd=f?f@f[f]f^f_fUgobpb{ T Ng`f{f|f}fU V ~fW t agbgcggdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGddgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzg| } ~ abbbHdAgBgCgDgEgFgGg
32 yield 2OgcbdbX v HgIdJdKdLdw x Mdy h NdOdPdqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$dY Z 0 1 2 Rb%d'd(d)d*d+d,dPgebfb3 z Ig-d.d/d:dA B ;dC j =d?d@dSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemene4 5 6 7 8 ,boepeqereseteueQggbhb9 D JgvewexeyeE F zeG l AeBeCe-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjcDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe! # $ % ' kc0e1e2e3e4e5e6eRgibjb( H Kg7e8e9e!eI J #eK n $e%e'elcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eaf) * + , - McbfcfdfefffgfhfSgkblb. L LgifjfkflfM N mfO p nfofpfNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%cqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMf/ : ; = ? 'cNfOfPfQfRfSfTfTgmbnb@ P MgUfVfWfXfQ R YfS r Zf0f1f(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f[ ] ^ _ ` fd=f?f@f[f]f^f_fUgobpb{ T Ng`f{f|f}fU V ~fW t agbgcggdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGddgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzg| } ~ abbbHdAgBgCgDgEgFgGg
34 except ( 2e cbdbX v w x y h qbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbY Z 0 1 2 Rba ebfb3 z A B C j SbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b4 5 6 7 8 ,bf gbhb9 D E F G l -b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjc! # $ % ' kcb ibjb( H I J K n lcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc) * + , - Mcg kblb. L M N O p NcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%c/ : ; = ? 'cc mbnb@ P Q R S r (c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded[ ] ^ _ ` fdd obpb{ T U V W t gdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGd| } ~ abbbHd
35 httpx.TimeoutException,
36 httpx.NetworkError,
37 httpx.RemoteProtocolError,
38 ) as error:
39 logger.debug("Network error (will retry): %s", error) 1vwxyzABCDEFGHIJKLMNOPQRSTUVW
41 _backoff() 1vwxyzABCDEFGHIJKLMNOPQRSTUVW
43 except httpx.HTTPStatusError as error: 2e cbdbX h qbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbY Z 0 1 2 Rba ebfb3 j SbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b4 5 6 7 8 ,bf gbhb9 l -b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjc! # $ % ' kcb ibjb( n lcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc) * + , - Mcg kblb. p NcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%c/ : ; = ? 'cc mbnb@ r (c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded[ ] ^ _ ` fdd obpb{ t gdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGd| } ~ abbbHd
44 if error.response.status_code >= 500: 2cbdbX h i Y Z 0 1 2 ebfb3 j k 4 5 6 7 8 gbhb9 l m ! # $ % ' ibjb( n o ) * + , - kblb. p q / : ; = ? mbnb@ r s [ ] ^ _ ` obpb{ t u | } ~ abbb
45 logger.debug( 2cbdbh i ebfbj k gbhbl m ibjbn o kblbp q mbnbr s obpbt u
46 "Server error %d (will retry): %s",
47 error.response.status_code,
48 error,
49 )
50 _backoff() 2cbdbh i ebfbj k gbhbl m ibjbn o kblbp q mbnbr s obpbt u
51 else:
52 # The streaming callers read the body before raising, so the
53 # server's error detail is available here.
54 raise StreamLogError( 2X Y Z 0 1 2 3 4 5 6 7 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } ~ abbb
55 f"HTTP {error.response.status_code}: {error.response.text}",
56 status_code=error.response.status_code,
57 ) from error
60P = ParamSpec("P") 1eafbgcd
61T = TypeVar("T") 1eafbgcd
64def attempts( 1eafbgcd
65 total_attempts: int = 3, timeout: timedelta = timedelta(minutes=5)
66) -> Callable[
67 [Callable[P, Generator[T, None, None]]], Callable[P, Generator[T, None, None]]
68]:
69 def decorator( 1eafbgcd
70 func: Callable[P, Generator[T, None, None]],
71 ) -> Callable[P, Generator[T, None, None]]:
72 @wraps(func) 1eafbgcd
73 def wrapper(*args: P.args, **kwargs: P.kwargs) -> Generator[T, None, None]: 1eafbgcd
74 start = time.monotonic() 2X v HgIdJdKdLdw x Mdy h NdOdPdqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$dY Z 0 1 2 Rb%d'd(d)d*d+d,d3 z Ig-d.d/d:dA B ;dC j =d?d@dSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemene4 5 6 7 8 ,boepeqereseteue9 D JgvewexeyeE F zeG l AeBeCe-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjcDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe! # $ % ' kc0e1e2e3e4e5e6e( H Kg7e8e9e!eI J #eK n $e%e'elcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eaf) * + , - Mcbfcfdfefffgfhf. L LgifjfkflfM N mfO p nfofpfNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%cqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMf/ : ; = ? 'cNfOfPfQfRfSfTf@ P MgUfVfWfXfQ R YfS r Zf0f1f(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f[ ] ^ _ ` fd=f?f@f[f]f^f_f{ T Ng`f{f|f}fU V ~fW t agbgcggdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGddgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzg| } ~ abbbHdAgBgCgDgEgFgGg
76 for attempt_number in range(total_attempts): 2X v HgIdJdKdLdw x Mdy h NdOdPdqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$dY Z 0 1 2 Rb%d'd(d)d*d+d,d3 z Ig-d.d/d:dA B ;dC j =d?d@dSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemene4 5 6 7 8 ,boepeqereseteue9 D JgvewexeyeE F zeG l AeBeCe-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjcDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe! # $ % ' kc0e1e2e3e4e5e6e( H Kg7e8e9e!eI J #eK n $e%e'elcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eaf) * + , - Mcbfcfdfefffgfhf. L LgifjfkflfM N mfO p nfofpfNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%cqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMf/ : ; = ? 'cNfOfPfQfRfSfTf@ P MgUfVfWfXfQ R YfS r Zf0f1f(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f[ ] ^ _ ` fd=f?f@f[f]f^f_f{ T Ng`f{f|f}fU V ~fW t agbgcggdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGddgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzg| } ~ abbbHdAgBgCgDgEgFgGg
77 if time.monotonic() - start > timeout.total_seconds(): 2X v HgIdJdKdLdw x Mdy h NdOdPdqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$dY Z 0 1 2 Rb%d'd(d)d*d+d,d3 z Ig-d.d/d:dA B ;dC j =d?d@dSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemene4 5 6 7 8 ,boepeqereseteue9 D JgvewexeyeE F zeG l AeBeCe-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjcDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe! # $ % ' kc0e1e2e3e4e5e6e( H Kg7e8e9e!eI J #eK n $e%e'elcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eaf) * + , - Mcbfcfdfefffgfhf. L LgifjfkflfM N mfO p nfofpfNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%cqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMf/ : ; = ? 'cNfOfPfQfRfSfTf@ P MgUfVfWfXfQ R YfS r Zf0f1f(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f[ ] ^ _ ` fd=f?f@f[f]f^f_f{ T Ng`f{f|f}fU V ~fW t agbgcggdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGddgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzg| } ~ abbbHdAgBgCgDgEgFgGg
78 raise TimeoutError( 1yCGKOSW
79 f"Log streaming timed out after {timeout.total_seconds():.0f}s"
80 )
82 with attempt(attempt_number): 2e X v HgIdJdKdLdw x Mdy h NdOdPdqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$dY Z 0 1 2 Rb%d'd(d)d*d+d,da 3 z Ig-d.d/d:dA B ;dC j =d?d@dSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemene4 5 6 7 8 ,boepeqereseteuef 9 D JgvewexeyeE F zeG l AeBeCe-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjcDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe! # $ % ' kc0e1e2e3e4e5e6eb ( H Kg7e8e9e!eI J #eK n $e%e'elcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eaf) * + , - Mcbfcfdfefffgfhfg . L LgifjfkflfM N mfO p nfofpfNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%cqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMf/ : ; = ? 'cNfOfPfQfRfSfTfc @ P MgUfVfWfXfQ R YfS r Zf0f1f(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f[ ] ^ _ ` fd=f?f@f[f]f^f_fd { T Ng`f{f|f}fU V ~fW t agbgcggdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGddgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzg| } ~ abbbHdAgBgCgDgEgFgGg
83 yield from func(*args, **kwargs) 2X v HgIdJdKdLdw x Mdy h NdOdPdqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbi MbNbObPbQbQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$dY Z 0 1 2 Rb%d'd(d)d*d+d,da 3 z Ig-d.d/d:dA B ;dC j =d?d@dSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%bk 'b(b)b*b+b[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemene4 5 6 7 8 ,boepeqereseteue9 D JgvewexeyeE F zeG l AeBeCe-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecm fcgchcicjcDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe! # $ % ' kc0e1e2e3e4e5e6eb ( H Kg7e8e9e!eI J #eK n $e%e'elcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGco HcIcJcKcLc(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eaf) * + , - Mcbfcfdfefffgfhf. L LgifjfkflfM N mfO p nfofpfNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8cq 9c!c#c$c%cqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMf/ : ; = ? 'cNfOfPfQfRfSfTfc @ P MgUfVfWfXfQ R YfS r Zf0f1f(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c~cs adbdcddded2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f[ ] ^ _ ` fd=f?f@f[f]f^f_fd { T Ng`f{f|f}fU V ~fW t agbgcggdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzdAdBdu CdDdEdFdGddgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzg| } ~ abbbHdAgBgCgDgEgFgGg
84 # If we get here without exception, the generator completed successfully
85 return 2IdJdKdLdx Mdh NdOdPdQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$d%d'd(d)d*d+d,d-d.d/d:dB ;dj =d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemeneoepeqereseteuevewexeyeF zel AeBeCeDeEeFeGeHeIeJeKeLeMeNeOePeQeReSeTeUeVeWeXeYeZe0e1e2e3e4e5e6e7e8e9e!eJ #en $e%e'e(e)e*e+e,e-e.e/e:e;e=e?e@e[e]e^e_e`e{e|e}e~eafbfcfdfefffgfhfifjfkflfN mfp nfofpfqfrfsftfufvfwfxfyfzfAfBfCfDfEfFfGfHfIfJfKfLfMfNfOfPfQfRfSfTfUfVfWfXfR Yfr Zf0f1f2f3f4f5f6f7f8f9f!f#f$f%f'f(f)f*f+f,f-f.f/f:f;f=f?f@f[f]f^f_f`f{f|f}fV ~ft agbgcgdgegfggghgigjgkglgmgngogpgqgrgsgtgugvgwgxgygzgAgBgCgDgEgFgGg
87 raise TooManyRetriesError(f"Failed after {total_attempts} attempts") 1vwizAkDEmHIoLMqPQsTUu
89 return wrapper 1eafbgcd
91 return decorator 1eafbgcd