You seem to misunderstand how operators work. If there's supposed to be a props dialog, it is displayed before the operator execution. More specifically, in the invoke phase:
poll(cls, context) -> invoke(self, context, event) -> execute(self, context)
The poll classmethod of an operator is used to determine if the context allows the operator to run at all. If the context is not suitable (wrong area type, no object selected, ...), it needs to return False
. You won't be able to run this operator until there's a valid context (not only from a button, but also spacebar menu and Python console). Operators in panels (=buttons) will be grayed out if polling fails.
What happens next depends on the execution context. If you run an operator from spacebar menu or by a button click, it will be usually INVOKE_DEFAULT
and thus call invoke()
of the operator. Notable about this method is, that an event object is passed to it. You need to return the result of wm.invoke_props_dialog(self)
in invoke()
to make the dialog work. It will open the dialog and wait for user input. If the user clicks outside the dialog, the operator will be aborted. If he/she clicks on OK, execute()
will be called.
The execute()
method of an operator contains the actual code of the operation. It is immediately executed if the execution context is DEFAULT_EXECUTE
, which is the case for scripts and the Python console by default. There is usually no point in invoking the operator to get user input prior to the actual operation, and it's sometimes not even possible because of an incorrect context (an invocation from the Python console would run invoke()
in the Python console, but a 3D View might be required). You would need to pass custom context along the execution context, like this:
bpy.ops.your.operator({'area': my_area}, 'INVOKE_DEFAULT')
Your operator does not define invoke()
, therefore execute()
is called immediately. The scene parameters are changed, but then you call the props dialog. It can't be used here and does crash for that reason. It is not supported to display a dialog after an action (operators supporting undo can display something in the redo panel, but that's about it).
class SceneSettings(bpy.types.Operator):
bl_idname = "wm.scene_settings"
bl_label = "Scene Settings Set Up"
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self, width=175, height=50)
def execute(self, context):
scene = context.scene
scene.unit_settings.system = 'METRIC'
scene.unit_settings.scale_length = 0.5
return {'FINISHED'}
A more appropriate way to inform the user is to use self.report()
:
import bpy
class SceneSettings(bpy.types.Operator):
bl_idname = "wm.scene_settings"
bl_label = "Scene Settings Set Up"
def execute(self, context):
scene = context.scene
scene.unit_settings.system = 'METRIC'
scene.unit_settings.scale_length = 0.5
self.report({'INFO'}, "Applied scene settings.")
return {'FINISHED'}
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
Run this code in the Text Editor, then search for the operator in the 3D View spacebar menu.

self.report(...)
you if you really want to inform the user. BTW: Do you know that you can modify thestartup.blend
? You can activate the metric system there once and it will be used as default for all new files you create. $\endgroup$self.report({'INFO'}, "Message")
will display between the render engine dropdown and the version info, as long as the operator is executed in the context of the 3D View (button in T- or N-toolshelf or spacebar menu). $\endgroup$