@@ -77,3 +77,46 @@ cdef class _RWLock:
7777 self ._lock.unlock_write()
7878 else :
7979 self ._lock.unlock_write_with(second_lock._lock)
80+
81+
82+ def trace (test_function ):
83+ """ Compiled test trace helper.
84+ """
85+ import sys
86+ from functools import partial, wraps
87+ from threading import get_ident as get_thread_id
88+
89+ _print = sys.stdout.write
90+ sysmon = sys.monitoring
91+ tool_id = sysmon.DEBUGGER_ID
92+
93+ print_lock: cython.pymutex
94+
95+ test_function_startline = test_function.__code__.co_firstlineno
96+
97+ def trace_event (event , code , instruction_offset , *arg ):
98+ filename: str = code.co_filename
99+ if ' test_' in filename and code.co_firstlineno < test_function_startline:
100+ return sysmon.DISABLE
101+ if ' lock' not in filename and ' etree' not in filename:
102+ return sysmon.DISABLE
103+
104+ message = f" [{get_thread_id() & 0xffffffff:08x}] {event:6} {code.co_name}\n "
105+ with print_lock:
106+ _print(message)
107+
108+ @ wraps (test_function)
109+ def method (*args ):
110+ sysmon.use_tool_id(tool_id, " tracer" )
111+ sysmon.set_events(tool_id, sysmon.events.PY_START | sysmon.events.PY_RETURN)
112+
113+ sysmon.register_callback(
114+ tool_id, sysmon.events.PY_START, partial(trace_event, ' call' ))
115+ sysmon.register_callback(
116+ tool_id, sysmon.events.PY_RETURN, partial(trace_event, ' return' ))
117+
118+ test_function(* args)
119+
120+ sysmon.clear_tool_id(tool_id)
121+
122+ return method
0 commit comments