"""helper_tools — helper utilities independent of a specific Session:- assembling/merging storage_state (cookies + localStorage)- unified navigation handler with soft retries"""from__future__importannotationsfromtypingimportTYPE_CHECKING,Awaitable,Callable,Literal,Optionalfromplaywright.async_apiimportBrowserContext,Pagefromplaywright.async_apiimportTimeoutErrorasPlaywrightTimeoutErrorifTYPE_CHECKING:fromplaywright._impl._api_structuresimportLocalStorageEntry,OriginStatefromplaywright.async_apiimportStorageState,StorageStateCookiefrom..abstraction.cookiesimportCookieManager# Зависящие типы простые и стабильные — импортируем прямо.# CookieManager нужен только как протокол поведения (to_playwright/add_from_playwright).
[docs]asyncdefmerge_storage_state_from_context(ctx:BrowserContext,*,cookie_manager:"CookieManager")->dict[str,dict[str,str]]:""" Reads storage_state from the context and synchronizes internal state: - localStorage: FULL overwrite and returned outward - cookies: ADD/UPDATE in the provided CookieManager """state=awaitctx.storage_state()# dict с 'cookies' и 'origins'# localStorage — точная перезаписьnew_ls:dict[str,dict[str,str]]={}foroinstate.get("origins",[])or[]:origin=str(o.get("origin",""))ifnotorigin:continuekv:dict[str,str]={}forpairino.get("localStorage",[])or[]:name=str(pair.get("name",""))value=""ifpair.get("value")isNoneelsestr(pair.get("value"))ifname:kv[name]=valuenew_ls[origin]=kv# cookies — пополняем CookieManagercookies_list=state.get("cookies",[])or[]ifcookies_list:cookie_manager.add_from_playwright(cookies_list)returnnew_ls
[docs]asyncdefhandle_nav_with_retries(page:Page,*,target_url:str,wait_until:Literal["commit","load","domcontentloaded","networkidle"],timeout_ms:int,attempts:int,on_retry:Optional[Callable[[],Awaitable[None]]]=None,)->None:""" Unified navigation handler with soft retries for goto/render. Catches ONLY PlaywrightTimeoutError. On retries calls on_retry() (if provided), then performs a reload (soft refresh). """try:awaitpage.goto(target_url,wait_until=wait_until,timeout=timeout_ms)exceptPlaywrightTimeoutErroraslast_err:whileattempts>0:attempts-=1ifon_retryisnotNone:awaiton_retry()try:awaitpage.reload(wait_until=wait_until,timeout=timeout_ms)last_err=None# type: ignore[assignment]breakexceptPlaywrightTimeoutErrorase:last_err=eiflast_errisnotNone:raiselast_err