Skip to content

Instantly share code, notes, and snippets.

@tin2tin
Created January 16, 2025 10:45
Show Gist options
  • Save tin2tin/d4b55d0ca0bffad86ef053db31f5db06 to your computer and use it in GitHub Desktop.
Save tin2tin/d4b55d0ca0bffad86ef053db31f5db06 to your computer and use it in GitHub Desktop.
Threading
import bpy
import subprocess
import threading
import re
# Function to parse progress from subprocess output
def parse_progress(line):
"""
Parses progress information from a line of output.
Example format: '23/100 [===> ] 23%' or similar.
Adjust regex as needed for your specific progress format.
"""
match = re.search(r"(\d+)/(\d+)", line)
if match:
current = int(match.group(1))
total = int(match.group(2))
progress = current / total
return progress
return None
# Function to handle subprocess output
def process_output(stdout, stderr):
"""
Reads the subprocess output and updates Blender's system bar progress.
"""
wm = bpy.context.window_manager
wm.progress_begin(0, 1) # Start progress (min=0, max=1)
try:
for line in iter(stdout.readline, b""):
line = line.decode().strip()
print(line) # Print to Blender's console for debugging
# Try to parse progress from the line
progress = parse_progress(line)
if progress is not None:
wm.progress_update(progress) # Update Blender progress bar
# Process stderr if needed
if stderr:
for line in iter(stderr.readline, b""):
print("Error:", line.decode().strip())
finally:
wm.progress_end() # End progress
# Function to run any subprocess command in a thread
def run_subprocess_in_thread(command, **kwargs):
"""
Run a subprocess command in a separate thread.
Args:
command (list or str): The command to run (list for arguments).
**kwargs: Additional keyword arguments to pass to subprocess.Popen.
"""
def task():
# Run the subprocess
try:
process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True, # Ensure text output (Python 3.6+)
**kwargs,
)
process_output(process.stdout, process.stderr)
except Exception as e:
print(f"Subprocess Error: {e}")
# Run the task in a separate thread
thread = threading.Thread(target=task)
thread.start()
# Add a button in the UI to trigger the subprocess
class RunSubprocessOperator(bpy.types.Operator):
"""Run Subprocess Example"""
bl_idname = "wm.run_subprocess_example"
bl_label = "Run Subprocess Example"
def execute(self, context):
# Replace with your actual subprocess command
# Example: Simulating progress (Linux/macOS: 'seq', Windows: 'for /L')
# This command simulates a progress bar-like output
run_subprocess_in_thread(["python", "-c", """
import time
for i in range(1, 24):
print(f'{i}/23 [{"="*i:<23}] {i*100//23}%')
time.sleep(0.5)
"""])
return {'FINISHED'}
# Register the operator and add to the UI
def menu_func(self, context):
self.layout.operator(RunSubprocessOperator.bl_idname)
def register():
bpy.utils.register_class(RunSubprocessOperator)
bpy.types.TOPBAR_MT_file.append(menu_func)
def unregister():
bpy.utils.unregister_class(RunSubprocessOperator)
bpy.types.TOPBAR_MT_file.remove(menu_func)
# Enable the script to run in Blender
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment