Skip to content

Instantly share code, notes, and snippets.

@Jerakin
Last active December 2, 2021 19:34
Show Gist options
  • Save Jerakin/45b2742b0227f8a43d76a298d9a54f03 to your computer and use it in GitHub Desktop.
Save Jerakin/45b2742b0227f8a43d76a298d9a54f03 to your computer and use it in GitHub Desktop.
Ugly patched version of Blenders unregister tool function that I can't get to work
class ToolNotRegisteredError(Exception):
"""Adding special exception to be able to only catch this special exception"""
pass
def unregister_tool(tool_cls):
space_type = tool_cls.bl_space_type
context_mode = tool_cls.bl_context_mode
from bl_ui.space_toolsystem_common import (
ToolSelectPanelHelper,
ToolDef,
)
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
if cls is None:
raise Exception("Space type %r has no toolbar" % space_type)
tools = cls._tools[context_mode]
def get_tool_def(tool_list, bl_idname):
for definition in tool_list:
if definition is None:
continue
if isinstance(definition, ToolDef):
if definition.idname == bl_idname:
return definition, definition
else:
for child_definition in definition:
if child_definition.idname == bl_idname:
return definition, child_definition
return None, None
if hasattr(tool_cls, "_bl_tool"):
_tool_def = tool_def = tool_cls._bl_tool
else:
_tool_def, tool_def = get_tool_def(tools, tool_cls.bl_idname)
if not tool_def:
raise ToolNotRegisteredError("bpy.utils.unregister_tool: could not find %r (may not be registered)" % tool_cls.bl_idname)
try:
i = tools.index(_tool_def)
except ValueError:
i = -1
def tool_list_clean(tool_list):
# Trim separators.
while tool_list and tool_list[-1] is None:
del tool_list[-1]
while tool_list and tool_list[0] is None:
del tool_list[0]
# Remove duplicate separators.
for i in range(len(tool_list) - 1, -1, -1):
is_none = tool_list[i] is None
if is_none and prev_is_none:
del tool_list[i]
prev_is_none = is_none
changed = False
if i != -1:
del tools[i]
tool_list_clean(tools)
changed = True
if not changed:
for i, item in enumerate(tools):
if isinstance(item, tuple):
try:
j = item.index(tool_def)
except ValueError:
j = -1
if j != -1:
item_clean = list(item)
del item_clean[j]
tool_list_clean(item_clean)
if item_clean:
tools[i] = tuple(item_clean)
else:
del tools[i]
tool_list_clean(tools)
del item_clean
# tuple(sub_item for sub_item in items if sub_item is not tool_def)
changed = True
break
if not changed:
raise Exception("Unable to remove %r" % tool_cls)
if hasattr(tool_cls, "_bl_tool"):
del tool_cls._bl_tool
keymap_data = tool_def.keymap
if keymap_data is not None:
from bpy import context
wm = context.window_manager
keyconfigs = wm.keyconfigs
for kc in (keyconfigs.default, keyconfigs.addon):
km = kc.keymaps.get(keymap_data[0])
if km is None:
print("Warning keymap %r not found in %r!" % (keymap_data[0], kc.name))
else:
kc.keymaps.remove(km)

The template Ui Tools Simple, throws an exception if ran multiple times in a row.
Exception: Tool 'my_template.my_circle_select' already exists!

And if you try to unregister it before registering it throws a different error. AttributeError: type object 'MyTool' has no attribute '_bl_tool'

This "patch" fixes this error but you will have to unregistering before registering your tool first.

This does seem to be a bug in blender. This is the line it crashes on https://github.com/blender/blender/blob/aec56e562a2799ea764671206f7b3b889b69829d/release/scripts/modules/bpy/utils/__init__.py#L954 The register_tool function is adding that to the class instance at https://github.com/blender/blender/blob/aec56e562a2799ea764671206f7b3b889b69829d/release/scripts/modules/bpy/utils/__init__.py#L872 If it is added to the class instance it makes sense that it isn't there on the uninstantiated class.
I wonder if the bpy.utils.register_class (so for a class and not tool) is calling the corresponding unregister function within it self not to get a "Already registed error" when running from the text editor.

import bpy
from bpy.types import WorkSpaceTool
class MyTool(WorkSpaceTool):
pass
if __name__ == "__main__":
try:
unregister_tool(MyTool)
except ToolNotRegisteredError:
pass
bpy.utils.register_tool(MyTool)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment