1414
1515import asyncio
1616import json
17+ import sys
1718from pathlib import Path
1819from types import SimpleNamespace
1920from typing import (
5960 URLMatcher ,
6061 async_readfile ,
6162 async_writefile ,
62- is_safe_close_error ,
6363 locals_to_params ,
6464 prepare_record_har_options ,
6565 to_impl ,
7171
7272if TYPE_CHECKING : # pragma: no cover
7373 from playwright ._impl ._browser import Browser
74- from playwright ._impl ._browser_type import BrowserType
74+
75+ if sys .version_info >= (3 , 8 ): # pragma: no cover
76+ from typing import Literal
77+ else : # pragma: no cover
78+ from typing_extensions import Literal
7579
7680
7781class BrowserContext (ChannelOwner ):
@@ -90,11 +94,15 @@ def __init__(
9094 self , parent : ChannelOwner , type : str , guid : str , initializer : Dict
9195 ) -> None :
9296 super ().__init__ (parent , type , guid , initializer )
97+ # circular import workaround:
98+ self ._browser : Optional ["Browser" ] = None
99+ if parent .__class__ .__name__ == "Browser" :
100+ self ._browser = cast ("Browser" , parent )
101+ self ._browser ._contexts .append (self )
93102 self ._pages : List [Page ] = []
94103 self ._routes : List [RouteHandler ] = []
95104 self ._bindings : Dict [str , Any ] = {}
96105 self ._timeout_settings = TimeoutSettings (None )
97- self ._browser : Optional ["Browser" ] = None
98106 self ._owner_page : Optional [Page ] = None
99107 self ._options : Dict [str , Any ] = {}
100108 self ._background_pages : Set [Page ] = set ()
@@ -172,6 +180,7 @@ def __init__(
172180 BrowserContext .Events .RequestFailed : "requestFailed" ,
173181 }
174182 )
183+ self ._close_was_called = False
175184
176185 def __repr__ (self ) -> str :
177186 return f"<BrowserContext browser={ self .browser } >"
@@ -226,13 +235,14 @@ def pages(self) -> List[Page]:
226235 def browser (self ) -> Optional ["Browser" ]:
227236 return self ._browser
228237
229- def _set_browser_type (self , browser_type : "BrowserType" ) -> None :
230- self ._browser_type = browser_type
238+ def _set_options (self , context_options : Dict , browser_options : Dict ) -> None :
239+ self ._options = context_options
231240 if self ._options .get ("recordHar" ):
232241 self ._har_recorders ["" ] = {
233242 "path" : self ._options ["recordHar" ]["path" ],
234243 "content" : self ._options ["recordHar" ].get ("content" ),
235244 }
245+ self ._tracing ._traces_dir = browser_options .get ("tracesDir" )
236246
237247 async def new_page (self ) -> Page :
238248 if self ._owner_page :
@@ -328,36 +338,43 @@ async def _record_into_har(
328338 har : Union [Path , str ],
329339 page : Optional [Page ] = None ,
330340 url : Union [Pattern [str ], str ] = None ,
331- content : HarContentPolicy = None ,
332- mode : HarMode = None ,
341+ update_content : HarContentPolicy = None ,
342+ update_mode : HarMode = None ,
333343 ) -> None :
334344 params : Dict [str , Any ] = {
335345 "options" : prepare_record_har_options (
336346 {
337347 "recordHarPath" : har ,
338- "recordHarContent" : content or "attach" ,
339- "recordHarMode" : mode or "minimal" ,
348+ "recordHarContent" : update_content or "attach" ,
349+ "recordHarMode" : update_mode or "minimal" ,
340350 "recordHarUrlFilter" : url ,
341351 }
342352 )
343353 }
344354 if page :
345355 params ["page" ] = page ._channel
346356 har_id = await self ._channel .send ("harStart" , params )
347- self ._har_recorders [har_id ] = {"path" : str (har ), "content" : content or "attach" }
357+ self ._har_recorders [har_id ] = {
358+ "path" : str (har ),
359+ "content" : update_content or "attach" ,
360+ }
348361
349362 async def route_from_har (
350363 self ,
351364 har : Union [Path , str ],
352365 url : Union [Pattern [str ], str ] = None ,
353366 not_found : RouteFromHarNotFoundPolicy = None ,
354367 update : bool = None ,
355- content : HarContentPolicy = None ,
356- mode : HarMode = None ,
368+ update_content : Literal [ "attach" , "embed" ] = None ,
369+ update_mode : HarMode = None ,
357370 ) -> None :
358371 if update :
359372 await self ._record_into_har (
360- har = har , page = None , url = url , content = content , mode = mode
373+ har = har ,
374+ page = None ,
375+ url = url ,
376+ update_content = update_content ,
377+ update_mode = update_mode ,
361378 )
362379 return
363380 router = await HarRouter .create (
@@ -400,7 +417,11 @@ def _on_close(self) -> None:
400417 self .emit (BrowserContext .Events .Close , self )
401418
402419 async def close (self ) -> None :
403- try :
420+ if self ._close_was_called :
421+ return
422+ self ._close_was_called = True
423+
424+ async def _inner_close () -> None :
404425 for har_id , params in self ._har_recorders .items ():
405426 har = cast (
406427 Artifact ,
@@ -422,11 +443,10 @@ async def close(self) -> None:
422443 else :
423444 await har .save_as (params ["path" ])
424445 await har .delete ()
425- await self ._channel .send ("close" )
426- await self ._closed_future
427- except Exception as e :
428- if not is_safe_close_error (e ):
429- raise e
446+
447+ await self ._channel ._connection .wrap_api_call (_inner_close , True )
448+ await self ._channel .send ("close" )
449+ await self ._closed_future
430450
431451 async def _pause (self ) -> None :
432452 await self ._channel .send ("pause" )
0 commit comments