14
14
15
15
import asyncio
16
16
import json
17
+ import sys
17
18
from pathlib import Path
18
19
from types import SimpleNamespace
19
20
from typing import (
59
60
URLMatcher ,
60
61
async_readfile ,
61
62
async_writefile ,
62
- is_safe_close_error ,
63
63
locals_to_params ,
64
64
prepare_record_har_options ,
65
65
to_impl ,
71
71
72
72
if TYPE_CHECKING : # pragma: no cover
73
73
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
75
79
76
80
77
81
class BrowserContext (ChannelOwner ):
@@ -90,11 +94,15 @@ def __init__(
90
94
self , parent : ChannelOwner , type : str , guid : str , initializer : Dict
91
95
) -> None :
92
96
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 )
93
102
self ._pages : List [Page ] = []
94
103
self ._routes : List [RouteHandler ] = []
95
104
self ._bindings : Dict [str , Any ] = {}
96
105
self ._timeout_settings = TimeoutSettings (None )
97
- self ._browser : Optional ["Browser" ] = None
98
106
self ._owner_page : Optional [Page ] = None
99
107
self ._options : Dict [str , Any ] = {}
100
108
self ._background_pages : Set [Page ] = set ()
@@ -172,6 +180,7 @@ def __init__(
172
180
BrowserContext .Events .RequestFailed : "requestFailed" ,
173
181
}
174
182
)
183
+ self ._close_was_called = False
175
184
176
185
def __repr__ (self ) -> str :
177
186
return f"<BrowserContext browser={ self .browser } >"
@@ -226,13 +235,14 @@ def pages(self) -> List[Page]:
226
235
def browser (self ) -> Optional ["Browser" ]:
227
236
return self ._browser
228
237
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
231
240
if self ._options .get ("recordHar" ):
232
241
self ._har_recorders ["" ] = {
233
242
"path" : self ._options ["recordHar" ]["path" ],
234
243
"content" : self ._options ["recordHar" ].get ("content" ),
235
244
}
245
+ self ._tracing ._traces_dir = browser_options .get ("tracesDir" )
236
246
237
247
async def new_page (self ) -> Page :
238
248
if self ._owner_page :
@@ -328,36 +338,43 @@ async def _record_into_har(
328
338
har : Union [Path , str ],
329
339
page : Optional [Page ] = None ,
330
340
url : Union [Pattern [str ], str ] = None ,
331
- content : HarContentPolicy = None ,
332
- mode : HarMode = None ,
341
+ update_content : HarContentPolicy = None ,
342
+ update_mode : HarMode = None ,
333
343
) -> None :
334
344
params : Dict [str , Any ] = {
335
345
"options" : prepare_record_har_options (
336
346
{
337
347
"recordHarPath" : har ,
338
- "recordHarContent" : content or "attach" ,
339
- "recordHarMode" : mode or "minimal" ,
348
+ "recordHarContent" : update_content or "attach" ,
349
+ "recordHarMode" : update_mode or "minimal" ,
340
350
"recordHarUrlFilter" : url ,
341
351
}
342
352
)
343
353
}
344
354
if page :
345
355
params ["page" ] = page ._channel
346
356
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
+ }
348
361
349
362
async def route_from_har (
350
363
self ,
351
364
har : Union [Path , str ],
352
365
url : Union [Pattern [str ], str ] = None ,
353
366
not_found : RouteFromHarNotFoundPolicy = None ,
354
367
update : bool = None ,
355
- content : HarContentPolicy = None ,
356
- mode : HarMode = None ,
368
+ update_content : Literal [ "attach" , "embed" ] = None ,
369
+ update_mode : HarMode = None ,
357
370
) -> None :
358
371
if update :
359
372
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 ,
361
378
)
362
379
return
363
380
router = await HarRouter .create (
@@ -400,7 +417,11 @@ def _on_close(self) -> None:
400
417
self .emit (BrowserContext .Events .Close , self )
401
418
402
419
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 :
404
425
for har_id , params in self ._har_recorders .items ():
405
426
har = cast (
406
427
Artifact ,
@@ -422,11 +443,10 @@ async def close(self) -> None:
422
443
else :
423
444
await har .save_as (params ["path" ])
424
445
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
430
450
431
451
async def _pause (self ) -> None :
432
452
await self ._channel .send ("pause" )
0 commit comments