22from typing import Any , TypeVar , Callable , Optional
33from dataclasses import dataclass
44
5- T = TypeVar ('T' )
5+ T = TypeVar ("T" )
6+
67
78@dataclass
89class PollingConfig :
910 """Configuration for polling behavior"""
11+
1012 interval_seconds : float = 1.0
1113 max_attempts : int = 120
1214 timeout_seconds : Optional [float ] = None
1315
16+
1417class PollingTimeout (Exception ):
1518 """Raised when polling exceeds max attempts or timeout"""
19+
1620 def __init__ (self , message : str , last_value : Any ):
1721 self .last_value = last_value
1822 super ().__init__ (f"{ message } . Last retrieved value: { last_value } " )
1923
24+
2025def poll_until (
2126 retriever : Callable [[], T ],
2227 is_terminal : Callable [[T ], bool ],
@@ -25,27 +30,27 @@ def poll_until(
2530) -> T :
2631 """
2732 Poll until a condition is met or timeout/max attempts are reached.
28-
33+
2934 Args:
3035 retriever: Callable that returns the object to check
3136 is_terminal: Callable that returns True when polling should stop
3237 config: Optional polling configuration
3338 on_error: Optional error handler that can return a value to continue polling
3439 or re-raise the exception to stop polling
35-
40+
3641 Returns:
3742 The final state of the polled object
38-
43+
3944 Raises:
4045 PollingTimeout: When max attempts or timeout is reached
4146 """
4247 if config is None :
4348 config = PollingConfig ()
44-
49+
4550 attempts = 0
4651 start_time = time .time ()
4752 last_result = None
48-
53+
4954 while True :
5055 try :
5156 last_result = retriever ()
@@ -54,23 +59,17 @@ def poll_until(
5459 last_result = on_error (e )
5560 else :
5661 raise
57-
62+
5863 if is_terminal (last_result ):
5964 return last_result
60-
65+
6166 attempts += 1
6267 if attempts >= config .max_attempts :
63- raise PollingTimeout (
64- f"Exceeded maximum attempts ({ config .max_attempts } )" ,
65- last_result
66- )
67-
68+ raise PollingTimeout (f"Exceeded maximum attempts ({ config .max_attempts } )" , last_result )
69+
6870 if config .timeout_seconds is not None :
6971 elapsed = time .time () - start_time
7072 if elapsed >= config .timeout_seconds :
71- raise PollingTimeout (
72- f"Exceeded timeout of { config .timeout_seconds } seconds" ,
73- last_result
74- )
75-
73+ raise PollingTimeout (f"Exceeded timeout of { config .timeout_seconds } seconds" , last_result )
74+
7675 time .sleep (config .interval_seconds )
0 commit comments