1919import inspect
2020import sys
2121import traceback
22+ from inspect import FrameInfo
2223from pathlib import Path
2324from typing import (
2425 TYPE_CHECKING ,
2526 Any ,
2627 Callable ,
2728 Dict ,
29+ Generator ,
2830 List ,
2931 Mapping ,
3032 Optional ,
@@ -362,7 +364,7 @@ def _send_message_to_server(
362364 "params" : self ._replace_channels_with_guids (params ),
363365 "metadata" : metadata ,
364366 }
365- if self ._tracing_count > 0 and frames and object ._guid != "localUtils" :
367+ if self .needs_full_stack_trace () and frames and object ._guid != "localUtils" :
366368 self .local_utils .add_stack_to_tracing_no_reply (id , frames )
367369
368370 self ._transport .send (message )
@@ -508,17 +510,42 @@ def _replace_guids_with_channels(self, payload: Any) -> Any:
508510 return result
509511 return payload
510512
513+ def needs_full_stack_trace (self ) -> bool :
514+ return self ._tracing_count > 0
515+
516+ def get_frame_info (self ) -> Generator [FrameInfo ]:
517+ current_frame = inspect .currentframe ()
518+
519+ while current_frame :
520+ traceback_info = inspect .getframeinfo (current_frame , 0 )
521+ # TODO: Used to be *frameinfo, but I couldn't figure out how to get the type checking to work correctly
522+ # frameinfo = (current_frame,) + traceback_info
523+ # yield FrameInfo(*frameinfo)
524+ # yield FrameInfo(cast(inspect.FrameType, *frameinfo))
525+ yield FrameInfo (
526+ current_frame ,
527+ traceback_info .filename ,
528+ traceback_info .lineno ,
529+ traceback_info .function ,
530+ traceback_info .code_context ,
531+ traceback_info .index ,
532+ # positions=current_frame.positions,
533+ )
534+
535+ current_frame = current_frame .f_back
536+
511537 async def wrap_api_call (
512538 self , cb : Callable [[], Any ], is_internal : bool = False
513539 ) -> Any :
514540 if self ._api_zone .get ():
515541 return await cb ()
516542 task = asyncio .current_task (self ._loop )
517- st : List [inspect .FrameInfo ] = getattr (
518- task , "__pw_stack__" , None
519- ) or inspect .stack (0 )
520-
521- parsed_st = _extract_stack_trace_information_from_stack (st , is_internal )
543+ st : Union [List [FrameInfo ], Generator [FrameInfo ]] = (
544+ getattr (task , "__pw_stack__" , None ) or self .get_frame_info ()
545+ )
546+ parsed_st = _extract_stack_trace_information_from_stack (
547+ st , is_internal , self .needs_full_stack_trace ()
548+ )
522549 self ._api_zone .set (parsed_st )
523550 try :
524551 return await cb ()
@@ -533,10 +560,12 @@ def wrap_api_call_sync(
533560 if self ._api_zone .get ():
534561 return cb ()
535562 task = asyncio .current_task (self ._loop )
536- st : List [inspect .FrameInfo ] = getattr (
537- task , "__pw_stack__" , None
538- ) or inspect .stack (0 )
539- parsed_st = _extract_stack_trace_information_from_stack (st , is_internal )
563+ st : Union [List [FrameInfo ], Generator [FrameInfo ]] = (
564+ getattr (task , "__pw_stack__" , None ) or self .get_frame_info ()
565+ )
566+ parsed_st = _extract_stack_trace_information_from_stack (
567+ st , is_internal , self .needs_full_stack_trace ()
568+ )
540569 self ._api_zone .set (parsed_st )
541570 try :
542571 return cb ()
@@ -567,7 +596,9 @@ class ParsedStackTrace(TypedDict):
567596
568597
569598def _extract_stack_trace_information_from_stack (
570- st : List [inspect .FrameInfo ], is_internal : bool
599+ st : Union [List [FrameInfo ], Generator [FrameInfo ]],
600+ is_internal : bool ,
601+ needs_full_stack : bool ,
571602) -> ParsedStackTrace :
572603 playwright_module_path = str (Path (playwright .__file__ ).parents [0 ])
573604 last_internal_api_name = ""
@@ -596,6 +627,9 @@ def _extract_stack_trace_information_from_stack(
596627 "function" : method_name ,
597628 }
598629 )
630+
631+ if not needs_full_stack :
632+ break
599633 if is_playwright_internal :
600634 last_internal_api_name = method_name
601635 elif last_internal_api_name :
0 commit comments