3232)
3333
3434from playwright ._impl ._api_structures import (
35+ Cookie ,
3536 Geolocation ,
36- PartitionedCookie ,
37- PartitionedStorageState ,
3837 SetCookieParam ,
38+ StorageState ,
3939)
4040from playwright ._impl ._artifact import Artifact
4141from playwright ._impl ._cdp_session import CDPSession
6666 async_writefile ,
6767 locals_to_params ,
6868 parse_error ,
69- prepare_record_har_options ,
7069 to_impl ,
7170)
7271from playwright ._impl ._network import (
@@ -106,6 +105,7 @@ def __init__(
106105 self , parent : ChannelOwner , type : str , guid : str , initializer : Dict
107106 ) -> None :
108107 super ().__init__ (parent , type , guid , initializer )
108+ # Browser is null for browser contexts created outside of normal browser, e.g. android or electron.
109109 # circular import workaround:
110110 self ._browser : Optional ["Browser" ] = None
111111 if parent .__class__ .__name__ == "Browser" :
@@ -220,7 +220,7 @@ def __init__(
220220 BrowserContext .Events .RequestFailed : "requestFailed" ,
221221 }
222222 )
223- self ._close_was_called = False
223+ self ._closing_or_closed = False
224224
225225 def __repr__ (self ) -> str :
226226 return f"<BrowserContext browser={ self .browser } >"
@@ -237,7 +237,7 @@ async def _on_route(self, route: Route) -> None:
237237 route_handlers = self ._routes .copy ()
238238 for route_handler in route_handlers :
239239 # If the page or the context was closed we stall all requests right away.
240- if (page and page ._close_was_called ) or self ._close_was_called :
240+ if (page and page ._close_was_called ) or self ._closing_or_closed :
241241 return
242242 if not route_handler .matches (route .request .url ):
243243 continue
@@ -312,14 +312,29 @@ def _set_options(self, context_options: Dict, browser_options: Dict) -> None:
312312 }
313313 self ._tracing ._traces_dir = browser_options .get ("tracesDir" )
314314
315+ async def _initialize_har_from_options (self , options : Dict ) -> None :
316+ record_har_path = str (options ["recordHarPath" ])
317+ if not record_har_path or len (record_har_path ) == 0 :
318+ return
319+ default_policy = "attach" if record_har_path .endswith (".zip" ) else "embed"
320+ content_policy = options .get (
321+ "recordHarContent" ,
322+ "omit" if options ["recordHarOmitContent" ] is True else default_policy ,
323+ )
324+ await self ._record_into_har (
325+ har = record_har_path ,
326+ page = None ,
327+ url = options ["recordHarUrlFilter" ],
328+ update_content = content_policy ,
329+ update_mode = options .get ("recordHarMode" , "full" ),
330+ )
331+
315332 async def new_page (self ) -> Page :
316333 if self ._owner_page :
317334 raise Error ("Please use browser.new_context()" )
318335 return from_channel (await self ._channel .send ("newPage" ))
319336
320- async def cookies (
321- self , urls : Union [str , Sequence [str ]] = None
322- ) -> List [PartitionedCookie ]:
337+ async def cookies (self , urls : Union [str , Sequence [str ]] = None ) -> List [Cookie ]:
323338 if urls is None :
324339 urls = []
325340 if isinstance (urls , str ):
@@ -471,22 +486,25 @@ async def _record_into_har(
471486 update_content : HarContentPolicy = None ,
472487 update_mode : HarMode = None ,
473488 ) -> None :
489+ update_content = update_content or "attach"
474490 params : Dict [str , Any ] = {
475- "options" : prepare_record_har_options (
476- {
477- "recordHarPath" : har ,
478- "recordHarContent" : update_content or "attach" ,
479- "recordHarMode" : update_mode or "minimal" ,
480- "recordHarUrlFilter" : url ,
481- }
482- )
491+ "options" : {
492+ "zip" : str (har ).endswith (".zip" ),
493+ "content" : update_content ,
494+ "urlGlob" : url if isinstance (url , str ) else None ,
495+ "urlRegexSource" : url .pattern if isinstance (url , Pattern ) else None ,
496+ "urlRegexFlags" : (
497+ escape_regex_flags (url ) if isinstance (url , Pattern ) else None
498+ ),
499+ "mode" : update_mode or "minimal" ,
500+ }
483501 }
484502 if page :
485503 params ["page" ] = page ._channel
486504 har_id = await self ._channel .send ("harStart" , params )
487505 self ._har_recorders [har_id ] = {
488506 "path" : str (har ),
489- "content" : update_content or "attach" ,
507+ "content" : update_content ,
490508 }
491509
492510 async def route_from_har (
@@ -550,22 +568,30 @@ def expect_event(
550568 return EventContextManagerImpl (waiter .result ())
551569
552570 def _on_close (self ) -> None :
571+ self ._closing_or_closed = True
553572 if self ._browser :
554- self ._browser ._contexts .remove (self )
573+ try :
574+ self ._browser ._contexts .remove (self )
575+ except ValueError :
576+ pass
577+ try :
578+ self ._browser ._browser_type ._playwright .selectors ._contextsForSelectors .remove (
579+ self
580+ )
581+ except ValueError :
582+ pass
555583
556584 self ._dispose_har_routers ()
557585 self ._tracing ._reset_stack_counter ()
558586 self .emit (BrowserContext .Events .Close , self )
559587
560588 async def close (self , reason : str = None ) -> None :
561- if self ._close_was_called :
589+ if self ._closing_or_closed :
562590 return
563591 self ._close_reason = reason
564- self ._close_was_called = True
592+ self ._closing_or_closed = True
565593
566- await self ._channel ._connection .wrap_api_call (
567- lambda : self .request .dispose (reason = reason ), True
568- )
594+ await self .request .dispose (reason = reason )
569595
570596 async def _inner_close () -> None :
571597 for har_id , params in self ._har_recorders .items ():
@@ -596,7 +622,7 @@ async def _inner_close() -> None:
596622
597623 async def storage_state (
598624 self , path : Union [str , Path ] = None , indexedDB : bool = None
599- ) -> PartitionedStorageState :
625+ ) -> StorageState :
600626 result = await self ._channel .send_return_as_dict (
601627 "storageState" , {"indexedDB" : indexedDB }
602628 )
0 commit comments