Skip to content

Commit a3e2ea3

Browse files
committed
Added uncaught exception handler
1 parent cfd9f40 commit a3e2ea3

5 files changed

Lines changed: 62 additions & 90 deletions

File tree

hkb_editor/gui/beh_editor.py

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,6 @@ def _do_load_from_file(self, file_path: str):
277277
self._set_menus_enabled(True)
278278

279279
dpg.focus_item(f"{self.tag}_roots_filter")
280-
except Exception as e:
281-
details = traceback.format_exception_only(e)
282-
self.logger.error(
283-
f"Loading behavior failed: {details[0]}\nSee log for details!"
284-
)
285-
raise e
286280
finally:
287281
dpg.delete_item(loading_screen)
288282

@@ -328,7 +322,7 @@ def _locate_witchy(self) -> str:
328322
title="Locate WitchyBND.exe", filetypes={"WitchyBND": "WitchyBND.exe"}
329323
)
330324
if not witchy_exe:
331-
self.logger.error("WitchyBND is required for repacking behavior")
325+
raise RuntimeError("WitchyBND is required for repacking behavior")
332326

333327
self.config.witchy_exe = witchy_exe
334328
self.config.save()
@@ -341,7 +335,7 @@ def _locate_hklib(self) -> str:
341335
title="Locate HKLib.exe", filetypes={"HKLib": "HKLib.CLI.exe"}
342336
)
343337
if not hklib_exe:
344-
self.logger.error("HKLib is required for repacking behavior")
338+
raise RuntimeError("HKLib is required for repacking behavior")
345339

346340
self.config.hklib_exe = hklib_exe
347341
self.config.save()
@@ -362,13 +356,9 @@ def _reload_character(self) -> None:
362356
game_config = detect_game_config()
363357
self.chr_reloader = ChrReloader(game_config)
364358
else:
365-
self.logger.error("ChrReloader is not available")
366-
return
359+
raise RuntimeError("ChrReloader is not available")
367360

368361
self.chr_reloader.reload_character(chr)
369-
except Exception as e:
370-
self.logger.error(f"Reloading {chr} failed: {e}")
371-
self.chr_reloader = None
372362
finally:
373363
dpg.delete_item(loading)
374364
self._busy = False
@@ -2163,25 +2153,22 @@ def load_bone_names(self) -> None:
21632153
if not file_path:
21642154
return
21652155

2166-
try:
2167-
self.logger.info("Loading bone names from %s", file_path)
2156+
self.logger.info("Loading bone names from %s", file_path)
21682157

2169-
bones = load_skeleton_bones(file_path)
2170-
self.loaded_skeleton_path = file_path
2158+
bones = load_skeleton_bones(file_path)
2159+
self.loaded_skeleton_path = file_path
21712160

2172-
boneweights_type_id = self.beh.type_registry.find_first_type_by_name(
2173-
"hkbBoneWeightArray"
2174-
)
2175-
basepath = "boneWeights"
2176-
aliases = AliasMap()
2161+
boneweights_type_id = self.beh.type_registry.find_first_type_by_name(
2162+
"hkbBoneWeightArray"
2163+
)
2164+
basepath = "boneWeights"
2165+
aliases = AliasMap()
21772166

2178-
for idx, bone in enumerate(bones):
2179-
aliases.add(bone, f"{basepath}:{idx}", boneweights_type_id, None)
2167+
for idx, bone in enumerate(bones):
2168+
aliases.add(bone, f"{basepath}:{idx}", boneweights_type_id, None)
21802169

2181-
# Insert left so that these aliases take priority
2182-
self.alias_manager.aliases.insert(0, aliases)
2183-
except ValueError as e:
2184-
self.logger.error("Loading bone names failed: %s", e, exc_info=True)
2170+
# Insert left so that these aliases take priority
2171+
self.alias_manager.aliases.insert(0, aliases)
21852172

21862173
def open_fix_common_problems_dialog(self):
21872174
tag = f"{self.tag}_fix_common_problems"

hkb_editor/gui/widgets/attributes_widget.py

Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,43 +1139,39 @@ def _update_attribute(
11391139
self._on_value_changed(sender, handler, (old_value, new_value))
11401140

11411141
if sender and dpg.does_item_exist(sender):
1142-
try:
1143-
todo = [sender]
1144-
while todo:
1145-
widget = todo.pop()
1146-
if not dpg.does_item_exist(widget):
1147-
continue
1148-
1149-
dpg_type = dpg.get_item_type(widget)
1150-
if (
1151-
dpg_type
1152-
in (
1153-
"mvAppItemType::mvInputText",
1154-
"mvAppItemType::mvInputInt",
1155-
"mvAppItemType::mvInputFloat",
1156-
"mvAppItemType::mvInputDouble",
1157-
"mvAppItemType::mvCheckbox",
1158-
"mvAppItemType::mvCombo",
1159-
)
1160-
and dpg.is_item_visible(widget)
1161-
and "bindable_attribute" not in dpg.get_item_alias(widget)
1162-
):
1163-
if dpg_type == "mvAppItemType::mvCombo":
1164-
items: list[str] = dpg.get_item_configuration(widget)[
1165-
"items"
1166-
]
1167-
if isinstance(ui_repr, int):
1168-
ui_repr = items[ui_repr]
1169-
else:
1170-
ui_repr = items.index(str(ui_repr))
1171-
1172-
dpg.set_value(widget, ui_repr)
1173-
break
1174-
else:
1175-
todo.extend(dpg.get_item_children(widget, 1))
1176-
except Exception as e:
1177-
self.logger.error(f"dpg.set_value failed: {e}")
1178-
raise e
1142+
todo = [sender]
1143+
while todo:
1144+
widget = todo.pop()
1145+
if not dpg.does_item_exist(widget):
1146+
continue
1147+
1148+
dpg_type = dpg.get_item_type(widget)
1149+
if (
1150+
dpg_type
1151+
in (
1152+
"mvAppItemType::mvInputText",
1153+
"mvAppItemType::mvInputInt",
1154+
"mvAppItemType::mvInputFloat",
1155+
"mvAppItemType::mvInputDouble",
1156+
"mvAppItemType::mvCheckbox",
1157+
"mvAppItemType::mvCombo",
1158+
)
1159+
and dpg.is_item_visible(widget)
1160+
and "bindable_attribute" not in dpg.get_item_alias(widget)
1161+
):
1162+
if dpg_type == "mvAppItemType::mvCombo":
1163+
items: list[str] = dpg.get_item_configuration(widget)[
1164+
"items"
1165+
]
1166+
if isinstance(ui_repr, int):
1167+
ui_repr = items[ui_repr]
1168+
else:
1169+
ui_repr = items.index(str(ui_repr))
1170+
1171+
dpg.set_value(widget, ui_repr)
1172+
break
1173+
else:
1174+
todo.extend(dpg.get_item_children(widget, 1))
11791175

11801176
def _cut_value(self, sender: str, app_data: Any, user_data: Any) -> None:
11811177
# deselect the selectable
@@ -1185,13 +1181,7 @@ def _cut_value(self, sender: str, app_data: Any, user_data: Any) -> None:
11851181
widget = self._selected_attribute_info.widget
11861182
val = dpg.get_value(widget)
11871183

1188-
try:
1189-
pyperclip.copy(str(val))
1190-
except pyperclip.PyperclipException as e:
1191-
self.logger.error("Cut value failed: %s", e)
1192-
# Not nice, but clearing the value without having copied it is worse
1193-
return
1194-
1184+
pyperclip.copy(str(val))
11951185
default_val = type(val)()
11961186
self._update_attribute(widget, default_val, attribute)
11971187

@@ -1241,13 +1231,10 @@ def _paste_value(self, sender: str) -> None:
12411231
new_value = data
12421232

12431233
# Let the handler handle the rest
1244-
try:
1245-
self._update_attribute(widget, new_value, attribute)
1234+
self._update_attribute(widget, new_value, attribute)
12461235

1247-
if isinstance(attribute, HkbPointer) and self._on_graph_changed:
1248-
self._on_graph_changed()
1249-
except Exception as e:
1250-
self.logger.error(f"Paste value to {path} failed: {e}")
1236+
if isinstance(attribute, HkbPointer) and self._on_graph_changed:
1237+
self._on_graph_changed()
12511238

12521239
def _move_array_item(self, sender: str, offset: int) -> None:
12531240
# deselect the selectable

hkb_editor/gui/workflows/apply_template.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,8 @@ def on_okay() -> None:
134134

135135
# Undo any changes that might have already happened
136136
if prev_undo != behavior.top_undo_id():
137-
try:
138-
behavior.undo()
139-
logger.warning("All recorded changes undone")
140-
except Exception as e:
141-
logger.error(f"Some of the changes the failed template made could not be undone: {e}")
137+
behavior.undo()
138+
logger.warning("All recorded changes undone")
142139

143140
else:
144141
logger.info(f"Template '{template._title}' finished successfully")

hkb_editor/gui/workflows/clone_hierarchy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ def import_hierarchy(
227227
def resolve_root_path(root_path: list[str]) -> HkbPointer:
228228
try:
229229
target_obj = behavior.resolve_unique_object_path(root_path[:-1])
230-
except Exception:
231-
logger.error(f"Failed to resolve root path {root_path}", exc_info=True)
230+
except Exception as e:
231+
logger.error(f"Failed to resolve root path {root_path}", exc_info=e)
232232
return None
233233

234234
# Check if the last path component went into a pointer array. If so, append

main.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ def main():
2424
)
2525
_logger = logging.getLogger(__name__)
2626

27-
# TODO use this and remove redundant logging
28-
# def handle_uncaught(exc_type, exc_value, exc_traceback):
29-
# sys.__excepthook__(exc_type, exc_value, exc_traceback)
30-
# _logger.error(str(exc_value))
27+
# Handle uncaught exceptions
28+
def handle_uncaught(exc_type, exc_value, exc_traceback):
29+
if exc_type is not KeyboardInterrupt:
30+
_logger.error(str(exc_value), exc_info=exc_value)
31+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
3132

32-
# sys.excepthook = handle_uncaught
33+
sys.excepthook = handle_uncaught
3334

3435
# Check for clipboard support, will print instructions if it fails
3536
try:

0 commit comments

Comments
 (0)