@@ -37,7 +37,6 @@ def patch_file(file_path: str, patched_tree: ast.AST) -> None:
3737 with open ("playwright-python/pyproject.toml" , "w" ) as f :
3838 toml .dump (pyproject_source , f )
3939
40-
4140# Patching setup.py
4241with open ("playwright-python/setup.py" ) as f :
4342 setup_source = f .read ()
@@ -163,8 +162,96 @@ def patch_file(file_path: str, patched_tree: ast.AST) -> None:
163162 if isinstance (function_node , ast .Return ):
164163 function_node .value = ast .Name (id = "source" , ctx = ast .Load ())
165164
165+ if isinstance (node , ast .AsyncFunctionDef ) and node .name in ["evaluate" , "evaluate_handle" ]:
166+ node .args .kwonlyargs .append (ast .arg (
167+ arg = "isolatedContext" ,
168+ annotation = ast .Subscript (
169+ value = ast .Name (id = "Optional" , ctx = ast .Load ()),
170+ slice = ast .Name (id = "bool" , ctx = ast .Load ()),
171+ ctx = ast .Load (),
172+ ),
173+ ))
174+ node .args .kw_defaults .append (ast .Constant (value = True ))
175+
176+ for subnode in ast .walk (node ):
177+ if isinstance (subnode , ast .Return ) and isinstance (subnode .value , ast .Call ):
178+ if subnode .value .args and isinstance (subnode .value .args [0 ], ast .Await ):
179+ inner_call = subnode .value .args [0 ].value
180+ if isinstance (inner_call , ast .Call ) and inner_call .func .attr == "send" :
181+ for i , arg in enumerate (inner_call .args ):
182+ if isinstance (arg , ast .Call ) and arg .func .id == "dict" :
183+ arg .keywords .append (ast .keyword (
184+ arg = "isolatedContext" ,
185+ value = ast .Name (id = "isolatedContext" , ctx = ast .Load ())
186+ ))
187+
166188 patch_file ("playwright-python/playwright/_impl/_js_handle.py" , js_handle_tree )
167189
190+ # Patching playwright/_impl/_frame.py
191+ with open ("playwright-python/playwright/_impl/_frame.py" ) as f :
192+ frame_source = f .read ()
193+ frame_tree = ast .parse (frame_source )
194+
195+ for node in ast .walk (frame_tree ):
196+ if isinstance (node , ast .AsyncFunctionDef ) and node .name in ["evaluate" , "evaluate_handle" ]:
197+ node .args .kwonlyargs .append (ast .arg (
198+ arg = "isolatedContext" ,
199+ annotation = ast .Subscript (
200+ value = ast .Name (id = "Optional" , ctx = ast .Load ()),
201+ slice = ast .Name (id = "bool" , ctx = ast .Load ()),
202+ ctx = ast .Load (),
203+ ),
204+ ))
205+ node .args .kw_defaults .append (ast .Constant (value = True ))
206+
207+ for subnode in ast .walk (node ):
208+ if isinstance (subnode , ast .Return ) and isinstance (subnode .value , ast .Call ):
209+ if subnode .value .args and isinstance (subnode .value .args [0 ], ast .Await ):
210+ inner_call = subnode .value .args [0 ].value
211+ if isinstance (inner_call , ast .Call ) and inner_call .func .attr == "send" :
212+ for i , arg in enumerate (inner_call .args ):
213+ if isinstance (arg , ast .Call ) and arg .func .id == "dict" :
214+ arg .keywords .append (ast .keyword (
215+ arg = "isolatedContext" ,
216+ value = ast .Name (id = "isolatedContext" , ctx = ast .Load ())
217+ ))
218+
219+ patch_file ("playwright-python/playwright/_impl/_frame.py" , frame_tree )
220+
221+ # Patching playwright/_impl/_locator.py
222+ with open ("playwright-python/playwright/_impl/_locator.py" ) as f :
223+ frame_source = f .read ()
224+ frame_tree = ast .parse (frame_source )
225+
226+ for node in ast .walk (frame_tree ):
227+ if isinstance (node , ast .AsyncFunctionDef ) and node .name in ["evaluate" , "evaluate_handle" ]:
228+ node .args .kwonlyargs .append (ast .arg (
229+ arg = "isolatedContext" ,
230+ annotation = ast .Subscript (
231+ value = ast .Name (id = "Optional" , ctx = ast .Load ()),
232+ slice = ast .Name (id = "bool" , ctx = ast .Load ()),
233+ ctx = ast .Load (),
234+ ),
235+ ))
236+ node .args .kw_defaults .append (ast .Constant (value = True ))
237+
238+ for subnode in ast .walk (node ):
239+ if isinstance (subnode , ast .Return ) and isinstance (subnode .value , ast .Await ):
240+ call_expr = subnode .value .value
241+ if isinstance (call_expr , ast .Call ):
242+ if node .name in ["evaluate" , "evaluate_handle" ] and isinstance (call_expr .func , ast .Attribute ):
243+ if call_expr .func .attr == "_with_element" :
244+ if call_expr .args and isinstance (call_expr .args [0 ], ast .Lambda ):
245+ lambda_func = call_expr .args [0 ].body
246+ if isinstance (lambda_func , ast .Call ) and isinstance (lambda_func .func , ast .Attribute ):
247+ if lambda_func .func .attr == node .name :
248+ lambda_func .keywords .append (ast .keyword (
249+ arg = "isolatedContext" ,
250+ value = ast .Name (id = "isolatedContext" , ctx = ast .Load ())
251+ ))
252+
253+ patch_file ("playwright-python/playwright/_impl/_locator.py" , frame_tree )
254+
168255# Patching playwright/_impl/_browser_context.py
169256with open ("playwright-python/playwright/_impl/_browser_context.py" ) as f :
170257 browser_context_source = f .read ()
@@ -271,6 +358,38 @@ async def route_handler(route: Route) -> None:
271358 await self.route("**/*", mapping.wrap_handler(route_handler))
272359 self.route_injecting = True""" ).body [0 ])
273360
361+ if isinstance (node , ast .AsyncFunctionDef ) and node .name in ["evaluate" , "evaluate_handle" ]:
362+ node .args .kwonlyargs .append (ast .arg (
363+ arg = "isolatedContext" ,
364+ annotation = ast .Subscript (
365+ value = ast .Name (id = "Optional" , ctx = ast .Load ()),
366+ slice = ast .Name (id = "bool" , ctx = ast .Load ()),
367+ ctx = ast .Load (),
368+ ),
369+ ))
370+ node .args .kw_defaults .append (ast .Constant (value = True ))
371+
372+ if "evaluateExpression" in ast .unparse (node .body [0 ]):
373+ for subnode in ast .walk (node ):
374+ if isinstance (subnode , ast .Return ) and isinstance (subnode .value , ast .Call ):
375+ if subnode .value .args and isinstance (subnode .value .args [0 ], ast .Await ):
376+ inner_call = subnode .value .args [0 ].value
377+ if isinstance (inner_call , ast .Call ) and inner_call .func .attr == "send" :
378+ for i , arg in enumerate (inner_call .args ):
379+ if isinstance (arg , ast .Call ) and arg .func .id == "dict" :
380+ arg .keywords .append (ast .keyword (
381+ arg = "isolatedContext" ,
382+ value = ast .Name (id = "isolatedContext" , ctx = ast .Load ())
383+ ))
384+ elif "_main_frame" in ast .unparse (node .body [0 ]):
385+ for subnode in ast .walk (node ):
386+ if isinstance (subnode , ast .Return ) and isinstance (subnode .value , ast .Await ) and isinstance (subnode .value .value , ast .Call ):
387+ subnode .value .value .keywords .append (ast .keyword (
388+ arg = "isolatedContext" ,
389+ value = ast .Name (id = "isolatedContext" , ctx = ast .Load ())
390+ ))
391+
392+
274393 patch_file ("playwright-python/playwright/_impl/_page.py" , page_tree )
275394
276395# Patching playwright/_impl/_clock.py
@@ -286,6 +405,66 @@ async def route_handler(route: Route) -> None:
286405
287406 patch_file ("playwright-python/playwright/_impl/_clock.py" , clock_tree )
288407
408+ # Patching playwright/async_api/_generated.py
409+ with open ("playwright-python/playwright/async_api/_generated.py" ) as f :
410+ async_generated_source = f .read ()
411+ async_generated_tree = ast .parse (async_generated_source )
412+
413+ for class_node in ast .walk (async_generated_tree ):
414+ if isinstance (class_node , ast .ClassDef ) and class_node .name in ["Page" , "Frame" , "Worker" , "Locator" ]:
415+ for node in class_node .body :
416+ if isinstance (node , ast .AsyncFunctionDef ) and node .name in ["evaluate" , "evaluate_handle" ]: # , "evaluate_all"
417+ new_arg = ast .arg (arg = "isolated_context" , annotation = ast .Subscript (
418+ value = ast .Name (id = "typing.Optional" , ctx = ast .Load ()),
419+ slice = ast .Name (id = "bool" , ctx = ast .Load ()),
420+ ctx = ast .Load (),
421+ ))
422+ # Append the argument to kwonlyargs
423+ node .args .kwonlyargs .append (new_arg )
424+ node .args .kw_defaults .append (ast .Constant (value = True ))
425+
426+ # Modify the inner function call inside return statement
427+ for subnode in ast .walk (node ):
428+ if isinstance (subnode , ast .Call ) and subnode .func .attr == node .name :
429+ subnode .keywords .append (
430+ ast .keyword (arg = "isolatedContext" ,
431+ value = ast .Name (id = "isolated_context" ,
432+ ctx = ast .Load ())
433+ )
434+ )
435+
436+ patch_file ("playwright-python/playwright/async_api/_generated.py" , async_generated_tree )
437+
438+ # Patching playwright/sync_api/_generated.py
439+ with open ("playwright-python/playwright/sync_api/_generated.py" ) as f :
440+ async_generated_source = f .read ()
441+ async_generated_tree = ast .parse (async_generated_source )
442+
443+ for class_node in ast .walk (async_generated_tree ):
444+ if isinstance (class_node , ast .ClassDef ) and class_node .name in ["Page" , "Frame" , "Worker" , "Locator" ]:
445+ for node in class_node .body :
446+ if isinstance (node , ast .FunctionDef ) and node .name in ["evaluate" , "evaluate_handle" ]: # , "evaluate_all"
447+ new_arg = ast .arg (arg = "isolated_context" , annotation = ast .Subscript (
448+ value = ast .Name (id = "typing.Optional" , ctx = ast .Load ()),
449+ slice = ast .Name (id = "bool" , ctx = ast .Load ()),
450+ ctx = ast .Load (),
451+ ))
452+ # Append the argument to kwonlyargs
453+ node .args .kwonlyargs .append (new_arg )
454+ node .args .kw_defaults .append (ast .Constant (value = True ))
455+
456+ # Modify the inner function call inside return statement
457+ for subnode in ast .walk (node ):
458+ if isinstance (subnode , ast .Call ) and subnode .func .attr == node .name :
459+ subnode .keywords .append (
460+ ast .keyword (arg = "isolatedContext" ,
461+ value = ast .Name (id = "isolated_context" ,
462+ ctx = ast .Load ())
463+ )
464+ )
465+
466+ patch_file ("playwright-python/playwright/sync_api/_generated.py" , async_generated_tree )
467+
289468# Patching Imports of every python file under the playwright-python/playwright directory
290469for python_file in glob .glob ("playwright-python/playwright/**.py" ) + glob .glob ("playwright-python/playwright/**/**.py" ):
291470 with open (python_file ) as f :
0 commit comments