How can I ensure an info message is displayed before a subprocess
call in Blender? When executing a script from the 3D Viewport using F3 and running the operator, the "Processing... Please wait" message does not appear until after the subprocess completes. Instead, only the "Process complete!" message is shown at the end. It seems that any info or print text before a timer or subprocess
routine does not display until after the operation finishes even though it was called before the subprocess
call.
import bpy
import subprocess
class SimpleOperator(bpy.types.Operator):
bl_idname = "object.simple_operator"
bl_label = "Simple Operator"
@classmethod
def poll(cls, context):
return True
def execute(self, context):
self.report({'INFO'}, "Processing... Please wait") # Does not get displayed
command = ["powershell", "-Command", "Start-Sleep -Seconds 2; Write-Output 'Completed long-running task'"]
result = subprocess.run(command, capture_output=True, text=True, shell=True, check=True)
output = result.stdout
self.report({'INFO'}, "Process complete!")
return {'FINISHED'}
def register():
bpy.utils.register_class(SimpleOperator)
def unregister():
bpy.utils.unregister_class(SimpleOperator)
if __name__ == "__main__":
register()
I need to implement this because my operator performs background installation tasks. To keep the user informed, I want to display a message indicating that the installation is in progress and that they should wait. I plan to achieve this using a straightforward message with self.report({'INFO'}, "info")
to keep it as simple as possible.
Workaround using a timer:
I tried a workaround using a popup using bpy.app.timers.register
but this will only work for simple operator examples like this one:
import bpy
import subprocess
class SimpleOperator(bpy.types.Operator):
bl_idname = "object.simple_operator"
bl_label = "Simple Operator"
def execute(self, context):
context.window_manager.popup_menu(lambda self, context: self.layout.label(text="Installation in progress... Please wait."), title="Info", icon='INFO')
bpy.app.timers.register(self.execute_command, first_interval=0.1)
return {'FINISHED'}
def execute_command(self):
command = ["powershell", "-Command", "Start-Sleep -Seconds 5; Write-Output 'Completed long-running task'"]
result = subprocess.run(command, capture_output=True, text=True, check=True)
print("Command output:", result.stdout)
print("Command error:", result.stderr)
def register():
bpy.utils.register_class(SimpleOperator)
def unregister():
bpy.utils.unregister_class(SimpleOperator)
if __name__ == "__main__":
register()
But it will not work for more complex operator examples like:
class OperatorInstallBase(bpy.types.Operator):
bl_options = {'INTERNAL'}
def get_script_path(self):
raise NotImplementedError("Subclasses must implement this method")
def run_script(self, script_path, *args):
command = ["powershell", "-File", script_path]
result = subprocess.run(command, capture_output=True, text=True, check=True)
return result.stdout
def execute_script(self):
script_path = self.get_script_path()
output = self.run_script(script_path)
# process output
def execute(self, context):
context.window_manager.popup_menu(lambda self, context: self.layout.label(text="Installation in progress... Please wait."), title="Info", icon='INFO')
context.view_layer.update()
bpy.app.timers.register(self.execute_script, first_interval=0.1)
return {'FINISHED'}
where you get errors like:
Traceback (most recent call last):
File "C:\Users\harry\AppData\Roaming\Blender Foundation\Blender\4.0\scripts\addons\blender_web_pro\operators\installation\operator_install_base.py", line 39, in execute_script
script_path = self.get_script_path()
File "c:\Program Files\Blender Foundation\Blender 4.0\4.0\scripts\modules\bpy_types.py", line 898, in __getattribute__
properties = StructRNA.path_resolve(self, "properties")
ReferenceError: StructRNA of type WEB_OT_OperatorInstallX has been removed