How does the undo operation work?

I have a for loop that each time it will move or rotate several objects randomly, if some conditions not satisfied, it will undo all operations.

for obj in group_obj.objects:
move_rotate(obj, T, T_0)

accessableArea(obj)

new_c = total_cost(group_obj)
if i == 0:
old_c = c_0
if Metropolis(old_c, new_c):
old_c = new_c
else:
for i in range(len(group_obj.objects)):
bpy.ops.ed.undo()


This is move & rotate function

def move_rotate(object, T, T_0):
"""
Description:move and rotate object randomly

"""
if len(object.name.split("_")) < 3:

std = math.sqrt(T/10)
m = np.random.normal(0, std, 1)
if np.random.randint(2):
object.location.x += m
else:
object.location.y += m
# rootate
std = math.pi * (T/T_0)
r = np.random.normal(0, std, 1)
object.rotation_euler.z += r


It will report this error

RuntimeError: Operator bpy.ops.ed.undo.poll() failed, context is incorrect


Another question is, it seems blneder considered all operations down by script as one operation, Each time I run over the script press undo the sence will return to origin instead of last step.

while T > T_F:
for i in range(num):
count = 0
for obj in group.objects:
bpy.ops.ed.undo_push()
# repeat move&rotate until it won't cross the wall
while True:

move_rotate(obj, T, T_0)

if check_if_cross_wall(obj):
bpy.ops.ed.undo()
continue

break

count += 1
accessableArea(obj)

new_c = total_cost(group)
if i == 0:
old_c = c_0
if Metropolis(old_c, new_c):
old_c = new_c
else:
bpy.ops.ed.undo()

T = T * alpha


move & rotate function keep it as is.

report StructRNA of type Object has been removed.

• Run bpy.ops.ed.undo_push() before you do some action.
– X Y
Commented Jul 9, 2022 at 2:48
• That's because Run Script operation is a bpy.ops operation in itself so the undo would reverse everything done by the Run Script action. You can see this action as Run Script under menu Edit > Undo History Commented Jul 9, 2022 at 3:17
• So this would push current state into stack and if I need reverse to a history state just need to use bpy.ops.ed.undo_history(i)? Commented Jul 9, 2022 at 3:49
• If no restore point to get backwards, It will cause the Error: Operator bpy.ops.ed.undo.poll() failed, context is incorrect
– X Y
Commented Jul 9, 2022 at 22:17
• when you access the object, for example: obj = bpy.context.object, and then if you run bpy.ops.ed.undo(), obj is invalid. So you need get the object again.
– X Y
Commented Jul 10, 2022 at 10:24

Create a Restore point

import bpy

# make sure it has a active object
bpy.context.object.location.x += 1

bpy.ops.ed.undo_push(message = "Restore point 1")

bpy.context.object.location.x += 2

bpy.ops.ed.undo_push(message = "Restore point 2")

# restore part, use interface or run bpy.ops
def UNDO():
try:
bpy.ops.ed.undo()
print("success")
except:
print("fail")

# undo 1 step
UNDO()
# because click to run script also create a store point
# so, Restore point 2 is gone!


Fix ReferenceError

import bpy

def UNDO():
try:
bpy.ops.ed.undo()
print("success")
except:
print("fail")

bpy.ops.ed.undo_push(message = "Restore point 1")
obj = bpy.data.objects["Cube"]
obj.location.x += 1

UNDO()
print(obj) # obj cannot be used anymore (after undo)
# so need get the object again
obj = bpy.data.objects["Cube"]
print(obj.name)

• I made some changes to make it more suitable for my needs, but there are some other mistakes appeared. Commented Jul 10, 2022 at 7:26
• See the updated section for details. Commented Jul 10, 2022 at 7:45