2020"""
2121
2222import datetime
23- from typing import TYPE_CHECKING , Optional , TypedDict , Union
24-
23+ import math
24+ from typing import (
25+ TYPE_CHECKING ,
26+ Awaitable ,
27+ Callable ,
28+ Optional ,
29+ TypedDict ,
30+ TypeVar ,
31+ Union ,
32+ )
33+
34+ from playwright ._impl .channel_owner import ApiCallOptions , ApiZone , api_call
35+ from playwright ._impl .errors import Error
36+ from playwright ._impl .isomorphic .string_utils import js_string
2537from playwright ._impl .timeout_settings import NO_TIMEOUT
2638
2739if TYPE_CHECKING : # pragma: no cover
2840 from playwright ._impl .browser_context import BrowserContext
2941
42+ R = TypeVar ("R" )
43+
3044
3145class Clock :
3246 def __init__ (self , browser_context : "BrowserContext" ) -> None :
@@ -36,6 +50,14 @@ def __init__(self, browser_context: "BrowserContext") -> None:
3650 self ._loop = browser_context ._loop
3751 self ._dispatcher_fiber = browser_context ._dispatcher_fiber
3852
53+ def _wrap_api_call (
54+ self ,
55+ func : Callable [[ApiZone ], Awaitable [R ]],
56+ options : Optional [ApiCallOptions ] = None ,
57+ ) -> Awaitable [R ]:
58+ # Python: include the API name in errors raised before the channel call.
59+ return self ._browser_context ._wrap_api_call (func , options )
60+
3961 async def install (
4062 self , time : Optional [Union [float , str , datetime .datetime ]]
4163 ) -> None :
@@ -46,6 +68,7 @@ async def install(
4668 timeout = NO_TIMEOUT ,
4769 )
4870
71+ @api_call ()
4972 async def fast_forward (self , ticks : Union [int , str ]) -> None :
5073 params = parse_ticks (ticks )
5174 await self ._browser_context ._channel .clockFastForward (
@@ -65,6 +88,7 @@ async def pause_at(self, time: Union[float, str, datetime.datetime]) -> None:
6588 async def resume (self ) -> None :
6689 await self ._browser_context ._channel .clockResume (timeout = NO_TIMEOUT )
6790
91+ @api_call ()
6892 async def run_for (self , ticks : Union [int , str ]) -> None :
6993 params = parse_ticks (ticks )
7094 await self ._browser_context ._channel .clockRunFor (
@@ -113,6 +137,10 @@ def parse_time(time: Union[float, str, datetime.datetime]) -> _TimeParams:
113137
114138
115139def parse_ticks (ticks : Union [int , str ]) -> _TicksParams :
140+ # Python: reject non-finite ticks before JSON serialization; upstream rejects
141+ # them in the server, but JSON cannot carry NaN or Infinity to the driver.
142+ if isinstance (ticks , float ) and not math .isfinite (ticks ):
143+ raise Error (f"Invalid ticks: { js_string (ticks )} " )
116144 return {
117145 "ticksNumber" : ticks if isinstance (ticks , (int , float )) else None ,
118146 "ticksString" : ticks if isinstance (ticks , str ) else None ,
0 commit comments