1+ import atexit
2+ from weakref import WeakKeyDictionary
13from .enums import AltDSSEvent
24from . import ffi , lib
35
810)
911
1012class EventCallbackManager :
11- _ctx_to_manager = {}
13+ _ctx_to_manager = WeakKeyDictionary ()
1214
1315 def __init__ (self , ctx ):
1416 if ctx in EventCallbackManager ._ctx_to_manager :
@@ -19,6 +21,23 @@ def __init__(self, ctx):
1921 for evt_type in AltDSSEvent :
2022 setattr (self , evt_type .name , [])
2123
24+
25+ def unregister_all (self ):
26+ for evt_type in AltDSSEvent :
27+ handlers = getattr (self , evt_type .name )
28+ if not handlers :
29+ continue
30+
31+ handlers [:] = []
32+ lib .ctx_DSSEvents_UnregisterAlt (
33+ self .ctx ,
34+ evt_type ,
35+ lib .altdss_python_util_callback
36+ )
37+
38+ def __del__ (self ):
39+ self .unregister_all ()
40+
2241 def register_func (self , evt : AltDSSEvent , func ) -> bool :
2342 handlers = getattr (self , AltDSSEvent (evt ).name )
2443 if len (handlers ) == 0 :
@@ -88,4 +107,14 @@ def altdss_python_util_callback(ctx, eventCode: int, step: int, ptr):
88107 lib .ctx_Error_Set_Description (ctx , f"Python callback exception: { ex } " .encode ())
89108
90109
110+ def _remove_callbacks ():
111+ '''
112+ Remove all callbacks at exit. Since the native library may outlive the Python callbacks,
113+ we need to remove the callbacks here to ensure they are not called.
114+ '''
115+ for ctx_mgr in EventCallbackManager ._ctx_to_manager .values ():
116+ ctx_mgr .unregister_all ()
117+
118+ atexit .register (_remove_callbacks )
119+
91120__all__ = ['get_manager_for_ctx' ]
0 commit comments