@@ -2,10 +2,10 @@ use std::sync::Mutex;
22
33use bitflags:: bitflags;
44use pyo3:: {
5- exceptions:: PyRuntimeError ,
5+ exceptions:: { PyRuntimeError , PyTypeError } ,
6+ ffi,
67 prelude:: * ,
78 types:: { PyModule , PyTuple } ,
8- ffi,
99} ;
1010
1111bitflags ! {
@@ -33,7 +33,9 @@ pub enum Event {
3333/// about.
3434pub trait Tracer : Send {
3535 /// Return the set of events the tracer wants to receive.
36- fn interest ( & self ) -> EventMask { EventMask :: empty ( ) }
36+ fn interest ( & self ) -> EventMask {
37+ EventMask :: empty ( )
38+ }
3739
3840 /// Called on Python function calls.
3941 fn on_call ( & mut self , _py : Python < ' _ > , _frame : * mut ffi:: PyFrameObject ) { }
@@ -83,7 +85,21 @@ pub fn install_tracer(py: Python<'_>, tracer: Box<dyn Tracer>) -> PyResult<()> {
8385 return Err ( PyRuntimeError :: new_err ( "tracer already installed" ) ) ;
8486 }
8587 let monitoring = py. import ( "sys" ) ?. getattr ( "monitoring" ) ?;
86- let tool_id: u8 = monitoring. call_method1 ( "use_tool_id" , ( "codetracer" , ) ) ?. extract ( ) ?;
88+ // `use_tool_id` changed its signature between Python versions.
89+ // Try calling it with the newer single-argument form first and fall back to
90+ // the older two-argument variant if that fails with a `TypeError`.
91+ const FALLBACK_ID : u8 = 5 ;
92+ let tool_id: u8 = match monitoring. call_method1 ( "use_tool_id" , ( "codetracer" , ) ) {
93+ Ok ( obj) => obj. extract ( ) ?,
94+ Err ( err) => {
95+ if err. is_instance_of :: < PyTypeError > ( py) {
96+ monitoring. call_method1 ( "use_tool_id" , ( FALLBACK_ID , "codetracer" ) ) ?;
97+ FALLBACK_ID
98+ } else {
99+ return Err ( err) ;
100+ }
101+ }
102+ } ;
87103 let events = monitoring. getattr ( "events" ) ?;
88104 let module = PyModule :: new ( py, "_codetracer_callbacks" ) ?;
89105
@@ -102,9 +118,21 @@ pub fn install_tracer(py: Python<'_>, tracer: Box<dyn Tracer>) -> PyResult<()> {
102118 monitoring. call_method ( "register_callback" , ( tool_id, ev, & cb) , None ) ?;
103119 callbacks. push ( cb. unbind ( ) ) ;
104120 }
105- monitoring. call_method ( "set_events" , ( tool_id, mask. bits ( ) , mask. bits ( ) ) , None ) ?;
121+ if let Err ( err) =
122+ monitoring. call_method ( "set_events" , ( tool_id, mask. bits ( ) , mask. bits ( ) ) , None )
123+ {
124+ if err. is_instance_of :: < PyTypeError > ( py) {
125+ monitoring. call_method1 ( "set_events" , ( tool_id, mask. bits ( ) ) ) ?;
126+ } else {
127+ return Err ( err) ;
128+ }
129+ }
106130
107- * guard = Some ( Global { dispatcher : Dispatcher :: new ( tracer) , tool_id, callbacks } ) ;
131+ * guard = Some ( Global {
132+ dispatcher : Dispatcher :: new ( tracer) ,
133+ tool_id,
134+ callbacks,
135+ } ) ;
108136 Ok ( ( ) )
109137}
110138
@@ -122,7 +150,17 @@ pub fn uninstall_tracer(py: Python<'_>) -> PyResult<()> {
122150 let ev = events. getattr ( "LINE" ) ?;
123151 monitoring. call_method ( "register_callback" , ( global. tool_id , ev, py. None ( ) ) , None ) ?;
124152 }
125- monitoring. call_method ( "set_events" , ( global. tool_id , 0u32 , global. dispatcher . mask . bits ( ) ) , None ) ?;
153+ if let Err ( err) = monitoring. call_method (
154+ "set_events" ,
155+ ( global. tool_id , 0u32 , global. dispatcher . mask . bits ( ) ) ,
156+ None ,
157+ ) {
158+ if err. is_instance_of :: < PyTypeError > ( py) {
159+ monitoring. call_method1 ( "set_events" , ( global. tool_id , 0u32 ) ) ?;
160+ } else {
161+ return Err ( err) ;
162+ }
163+ }
126164 monitoring. call_method1 ( "free_tool_id" , ( global. tool_id , ) ) ?;
127165 }
128166 Ok ( ( ) )
@@ -146,4 +184,3 @@ fn callback_line(py: Python<'_>, args: &Bound<'_, PyTuple>) -> PyResult<()> {
146184 }
147185 Ok ( ( ) )
148186}
149-
0 commit comments