mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Bonsai - make undo errors visible to user
In theory there are possible undo errors, when some step wasn't registered in undo system and undo then won't be able to undo change from IFC. The problem is, those errors could be very dangerous but they occur in background, undetected by users, they're only visible as console traceback. After this commit we'll try to detect them and set `last_error`, which will show usual Bonsai error panel in Properties. @theoryshaw just in case, as you will probably find this kind of error 😁 Example traceback user might see in system console (or in their error report from "Copy Error Message"). ``` last_error: Undo transaction operations: - {'action': 'create', 'value': {'id': 1560, 'type': 'IfcGrid', 'GlobalId': '05Y8D_Ja12HfiEbmc$D3WN', 'OwnerHistory': None, 'Name': None, 'Description': None, 'ObjectType': None, 'ObjectPlacement': None, 'Representation': None, 'UAxes': None, 'VAxes': None, 'WAxes': None, 'PredefinedType': None}} - {'action': 'edit', 'id': 1560, 'index': 2, 'old': None, 'new': 'Grid'} - {'action': 'edit', 'id': 1221, 'index': 4, 'old': ({'id': 1297}, {'id': 1247}, {'id': 1220}, {'id': 1272}), 'new': ({'id': 1272}, {'id': 1247}, {'id': 1220}, {'id': 1560}, {'id': 1297})} - {'action': 'create', 'value': {'id': 1561, 'type': 'IfcCartesianPoint', 'Coordinates': (0.0, 0.0, 0.0)}} - {'action': 'create', 'value': {'id': 1562, 'type': 'IfcDirection', 'DirectionRatios': (0.0, 0.0, 1.0)}} - {'action': 'create', 'value': {'id': 1563, 'type': 'IfcDirection', 'DirectionRatios': (1.0, 0.0, 0.0)}} - {'action': 'create', 'value': {'id': 1564, 'type': 'IfcAxis2Placement3D', 'Location': {'id': 1561}, 'Axis': {'id': 1562}, 'RefDirection': {'id': 1563}}} - {'action': 'create', 'value': {'id': 1565, 'type': 'IfcLocalPlacement', 'PlacementRelTo': None, 'RelativePlacement': {'id': 1564}}} - {'action': 'edit', 'id': 1565, 'index': 0, 'old': None, 'new': {'id': 66}} - {'action': 'edit', 'id': 1560, 'index': 5, 'old': None, 'new': {'id': 1565}} - {'action': 'create', 'value': {'id': 1566, 'type': 'IfcGridAxis', 'AxisTag': 'A', 'AxisCurve': None, 'SameSense': True}} - {'action': 'edit', 'id': 1560, 'index': 7, 'old': None, 'new': ({'id': 1566},)} - {'action': 'create', 'value': {'id': 1567, 'type': 'IfcCartesianPoint', 'Coordinates': (-2.0, 0.0)}} - {'action': 'create', 'value': {'id': 1568, 'type': 'IfcCartesianPoint', 'Coordinates': (22.0, 0.0)}} - {'action': 'create', 'value': {'id': 1569, 'type': 'IfcPolyline', 'Points': ({'id': 1567}, {'id': 1568})}} - {'action': 'edit', 'id': 1566, 'index': 1, 'old': None, 'new': {'id': 1569}} - {'action': 'create', 'value': {'id': 1570, 'type': 'IfcGridAxis', 'AxisTag': 'B', 'AxisCurve': None, 'SameSense': True}} - {'action': 'edit', 'id': 1560, 'index': 7, 'old': ({'id': 1566},), 'new': ({'id': 1566}, {'id': 1570})} - {'action': 'create', 'value': {'id': 1571, 'type': 'IfcCartesianPoint', 'Coordinates': (-2.0, 10.0)}} - {'action': 'create', 'value': {'id': 1572, 'type': 'IfcCartesianPoint', 'Coordinates': (22.0, 10.0)}} - {'action': 'create', 'value': {'id': 1573, 'type': 'IfcPolyline', 'Points': ({'id': 1571}, {'id': 1572})}} - {'action': 'edit', 'id': 1570, 'index': 1, 'old': None, 'new': {'id': 1573}} - {'action': 'create', 'value': {'id': 1574, 'type': 'IfcGridAxis', 'AxisTag': 'C', 'AxisCurve': None, 'SameSense': True}} - {'action': 'edit', 'id': 1560, 'index': 7, 'old': ({'id': 1566}, {'id': 1570}), 'new': ({'id': 1566}, {'id': 1570}, {'id': 1574})} - {'action': 'create', 'value': {'id': 1575, 'type': 'IfcCartesianPoint', 'Coordinates': (-2.0, 20.0)}} - {'action': 'create', 'value': {'id': 1576, 'type': 'IfcCartesianPoint', 'Coordinates': (22.0, 20.0)}} - {'action': 'create', 'value': {'id': 1577, 'type': 'IfcPolyline', 'Points': ({'id': 1575}, {'id': 1576})}} - {'action': 'edit', 'id': 1574, 'index': 1, 'old': None, 'new': {'id': 1577}} - {'action': 'create', 'value': {'id': 1578, 'type': 'IfcGridAxis', 'AxisTag': '01', 'AxisCurve': None, 'SameSense': True}} - {'action': 'edit', 'id': 1560, 'index': 8, 'old': None, 'new': ({'id': 1578},)} - {'action': 'create', 'value': {'id': 1579, 'type': 'IfcCartesianPoint', 'Coordinates': (0.0, -2.0)}} - {'action': 'create', 'value': {'id': 1580, 'type': 'IfcCartesianPoint', 'Coordinates': (0.0, 22.0)}} - {'action': 'create', 'value': {'id': 1581, 'type': 'IfcPolyline', 'Points': ({'id': 1579}, {'id': 1580})}} - {'action': 'edit', 'id': 1578, 'index': 1, 'old': None, 'new': {'id': 1581}} - {'action': 'create', 'value': {'id': 1582, 'type': 'IfcGridAxis', 'AxisTag': '02', 'AxisCurve': None, 'SameSense': True}} - {'action': 'edit', 'id': 1560, 'index': 8, 'old': ({'id': 1578},), 'new': ({'id': 1578}, {'id': 1582})} - {'action': 'create', 'value': {'id': 1583, 'type': 'IfcCartesianPoint', 'Coordinates': (10.0, -2.0)}} - {'action': 'create', 'value': {'id': 1584, 'type': 'IfcCartesianPoint', 'Coordinates': (10.0, 22.0)}} - {'action': 'create', 'value': {'id': 1585, 'type': 'IfcPolyline', 'Points': ({'id': 1583}, {'id': 1584})}} - {'action': 'edit', 'id': 1582, 'index': 1, 'old': None, 'new': {'id': 1585}} - {'action': 'create', 'value': {'id': 1586, 'type': 'IfcGridAxis', 'AxisTag': '03', 'AxisCurve': None, 'SameSense': True}} - {'action': 'edit', 'id': 1560, 'index': 8, 'old': ({'id': 1578}, {'id': 1582}), 'new': ({'id': 1578}, {'id': 1582}, {'id': 1586})} - {'action': 'create', 'value': {'id': 1587, 'type': 'IfcCartesianPoint', 'Coordinates': (20.0, -2.0)}} - {'action': 'create', 'value': {'id': 1588, 'type': 'IfcCartesianPoint', 'Coordinates': (20.0, 22.0)}} - {'action': 'create', 'value': {'id': 1589, 'type': 'IfcPolyline', 'Points': ({'id': 1587}, {'id': 1588})}} - {'action': 'edit', 'id': 1586, 'index': 1, 'old': None, 'new': {'id': 1589}} Traceback (most recent call last): File "C:\Users\Andrej\AppData\Roaming\Blender Foundation\Blender\4.4\extensions\.local\lib\python3.11\site-packages\ifcopenshell\file.py", line 352, in undo transaction.rollback() File "C:\Users\Andrej\AppData\Roaming\Blender Foundation\Blender\4.4\extensions\.local\lib\python3.11\site-packages\ifcopenshell\file.py", line 167, in rollback element = self.file.by_id(operation["id"]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Andrej\AppData\Roaming\Blender Foundation\Blender\4.4\extensions\.local\lib\python3.11\site-packages\ifcopenshell\file.py", line 510, in by_id return self[id] ~~~~^^^^ File "C:\Users\Andrej\AppData\Roaming\Blender Foundation\Blender\4.4\extensions\.local\lib\python3.11\site-packages\ifcopenshell\file.py", line 497, in __getitem__ return entity_instance(self.wrapped_data.by_id(key), self) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Andrej\AppData\Roaming\Blender Foundation\Blender\4.4\extensions\.local\lib\python3.11\site-packages\ifcopenshell\ifcopenshell_wrapper.py", line 8884, in by_id return _ifcopenshell_wrapper.file_by_id(self, id) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RuntimeError: Instance #1565 not found The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\Users\Andrej\AppData\Roaming\Blender Foundation\Blender\4.4\extensions\.local\lib\python3.11\site-packages\bonsai\bim\ifc.py", line 426, in callback tool.Ifc.get().undo() File "C:\Users\Andrej\AppData\Roaming\Blender Foundation\Blender\4.4\extensions\.local\lib\python3.11\site-packages\ifcopenshell\file.py", line 354, in undo raise UndoSystemError("Error during transaction undo.", transaction) from e ifcopenshell.file.UndoSystemError: Error during transaction undo. ```
This commit is contained in:
@@ -31,9 +31,10 @@ import ifcopenshell.ifcopenshell_wrapper
|
||||
import bonsai
|
||||
import bonsai.bim.handler
|
||||
import bonsai.tool as tool
|
||||
from ifcopenshell.file import UndoSystemError
|
||||
from pathlib import Path
|
||||
from bonsai.tool.brick import BrickStore
|
||||
from typing import Set, Union, Optional, TypedDict, Callable, NotRequired
|
||||
from typing import Set, Union, Optional, TypedDict, Callable, NotRequired, Literal
|
||||
|
||||
|
||||
IFC_CONNECTED_TYPE = Union[bpy.types.Material, bpy.types.Object]
|
||||
@@ -417,6 +418,32 @@ class IfcStore:
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.ifc_definition_id = 0
|
||||
|
||||
@staticmethod
|
||||
def get_ifc_file_undo_callback(callback_type: Literal["UNDO", "REDO"]):
|
||||
def callback(_) -> None:
|
||||
try:
|
||||
if callback_type == "UNDO":
|
||||
tool.Ifc.get().undo()
|
||||
else:
|
||||
tool.Ifc.get().redo()
|
||||
except Exception as e:
|
||||
# Persistent callbacks errors are not visible from UI and we set `last_error`
|
||||
# to make it visible.
|
||||
error_msg = ""
|
||||
# In theory it should always be UndoSystemError, but just to be safe.
|
||||
if isinstance(e, UndoSystemError):
|
||||
error_msg += "Undo transaction operations:\n"
|
||||
transaction = e.transaction
|
||||
for operation in transaction.operations:
|
||||
error_msg += f"- {str(operation)}\n"
|
||||
# Show it in system console too, not just in last message.
|
||||
print(error_msg)
|
||||
error_msg += traceback.format_exc()
|
||||
bonsai.last_error = error_msg
|
||||
raise
|
||||
|
||||
return callback
|
||||
|
||||
@staticmethod
|
||||
def execute_ifc_operator(
|
||||
operator: tool.Ifc.Operator,
|
||||
@@ -446,7 +473,9 @@ class IfcStore:
|
||||
if tool.Ifc.get():
|
||||
tool.Ifc.get().end_transaction()
|
||||
IfcStore.add_transaction_operation(
|
||||
operator, rollback=lambda d: tool.Ifc.get().undo(), commit=lambda d: tool.Ifc.get().redo()
|
||||
operator,
|
||||
rollback=IfcStore.get_ifc_file_undo_callback("UNDO"),
|
||||
commit=IfcStore.get_ifc_file_undo_callback("REDO"),
|
||||
)
|
||||
if BrickStore.graph is not None: # `if BrickStore.graph` by itself takes ages.
|
||||
BrickStore.end_transaction()
|
||||
|
||||
Reference in New Issue
Block a user