Removing blf draw text on error

I know how to remove it when the user clicks enter or cancels or whatever via

bpy.types.SpaceView3D.draw_handler_remove(self._handle, ‘WINDOW’)

But sometimes in my script it is possible to press the wrong button when in the modal and it causes the code to error out, and then the HUD just stays alive until I close blender.

How can I get around this? Maybe there is a command to clear all drawn text?

There’s no practical way to remove a callback when the handle is lost, but there are countless ways to store a reference.

Store on the operator class. Note: doesn’t survive script reloads.

__class__.handle = ...

Store on module. Note: doesn’t survive script reloads.

globals()['handle'] = ...

Store on bpy or in the driver namespace. Survives script reloads.

bpy._handle = ...
bpy.app.driver_namespace['handle'] = ...

Store in builtins to have it accessible from any scope. Don’t use in release.

__builtins__.handle = ...

Thank you!

Do you know if it is possible to be notified if an handle is lost? The reason I am asking then maybe one can run a timer to do a clean up with a trigger.

Not really. Handles are very basic objects without __weakref__ implementation, so it doesn’t support garbage collecting callbacks.

I mean, if you really really want your handle back, you knew its address, you can use ctypes to cast it into an object. This is usually the quickest way back to your desktop if the object’s been deallocated.

>>> st = bpy.types.SpaceView3D
>>> h = st.draw_handle_add(lambda: print(1), (), "WINDOW", "POST_PIXEL")
>>> h
<capsule object "RNA_HANDLE" at 0x0000014482E21C30>
>>> del h
>>> h
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
NameError: name 'h' is not defined
>>> import ctypes
>>> pyob = ctypes.cast(0x0000014482E21C30, ctypes.py_object)
>>> h = pyob.value
>>> h
<capsule object "RNA_HANDLE" at 0x0000014482E21C30>

>>> st.draw_handler_remove(h, "WINDOW")
>>> 

I’ve been having trouble implementing this in my script so wanted to necro this to see if there are some suggestions:

So first I’m now storing my stuff in bpy like you said:

bpy._handle = bpy.types.SpaceView3D.draw_handler_add(name_of_my_draw_func, args, ‘WINDOW’, ‘POST_PIXEL’)

and then I created a button to remove it in case something goes wrong and it gets stuck:

bpy.types.SpaceView3D.draw_handler_remove(bpy._handle, ‘WINDOW’)

and the logic works when I test it individually but in my script I am storing many draw functions there, different ones for each class I have. When I press the button to remove it the first time it works, but then sooner or later I get something like “this is already removed” even though its still there, taunting me on the screen.

What would be the proper way to handle this situation?