Custom startup module doesn't execute save_mainfile or save_as_mainfile code

I’m opening Blender from a subprocess.Popen like this:

app_session = subprocess.Popen(
	[
		app_exe,
		'--python-use-system-env'
	],
	env=_envs,
	stdin=subprocess.PIPE,
	stdout=subprocess.PIPE,
	stderr=subprocess.PIPE,
	# shell=True,
	creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
)

In my startup_scipt.py module I check for a file path. If it exists I open that file. If it doesn’t I want to save the file at that path. Like this:

if os.path.exists(os.getenv('OPEN_FILE_PATH')):
	print('Opening file')
else:
	print('Creating a new file')
	bpy.ops.wm.save_mainfile(filepath='path/to/file.blend')

The startup_script.py loads fine, but for some reason the save_mainfile code doesn’t execute. I’ve also tried save_as_mainfile. Is the code running too early? If so is there a way to defer execution? This is a problem with Maya and Houdini so I usually have to defer the code execution until the main UI is built (evalDeferred and hdefereval respectively)

It seems to error out, but I can’t fully read the error (not totally sure how to create a console output when launching Blender from Popen). I’m using this as a hacky solution (it only prints after I close Blender which isn’t ideal):

print(app_session.stdout.readline())  # read the first line
for i in range(10):  # repeat several times to show that it works
	# print('stdin = {}'.format(app_session.stdin, i))  # write input
	app_session.stdin.flush()  # not necessary in this case
	print('stdout = {}'.format(app_session.stdout.readline()))  # read output
	print(app_session.stderr.readline())  # read error

print(app_session.communicate(b"n\n")[0])

This is the only output that looks like something is going wrong, but I’m very new to Blender:
stdout = b"Warning: property 'release_confirm' not found in keymap item 'OperatorProperties'\r\n"

This has kind of turned into a multi-part question:

  • Do I need to defer evaluation when saving at startup? If so, how?
  • How can I see console output when launching Blender from subprocess.Popen

Thanks!

How are you running your startup script? For me this saves a new file:

blender -b --python-expr 'import bpy; bpy.ops.wm.save_mainfile(filepath="doh.blend")

But maybe your are making that call earlier than the --python-expr option runs.

1 Like

Thanks for this, Paul!

With your example it’s working, so this is a nice backup if an eval defer isn’t possible. I was wondering if there was a way I could do the saving from my custom startup script though? That’s how I’m doing it with every other software, so I want to try and maintain consistency across platforms.

Well, as I asked before how are you running your script? Do you pass it on the command-line to blender?

I’m doing this now as a sort of compromise. The startup_script module handles the saving and the launcher.py manages the execution order. I’d like the startup_script to manage both the saving and execution order (via eval defer), but if this is how it has to be done then I guess that’s fine.

launcher.py:

file_manip_func = 'from startup import startup_script; startup_script.launch_mmm()'

app_session = subprocess.Popen(
	[
		app_exe,
		'--python-use-system-env',
		'--python-expr', file_manip_func
	],
	creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
)

I don’t think there is something like a deferred evaluation hook in Blender (although there are various event handlers that might play that role). But the main question would then still be deferred until which moment? Because I still don’t understand what you did before that caused the save call to (maybe) get executed too early.

There is no need to defer execution of save_as_mainfile, It should work immediately.

To print output while Blender is running instead of at the end, the problem in your code may be using both stdout.readline() and stderr.readline(). I think it will block waiting for output from stderr while stdout is actually getting output.

The easiest solution could be passing stderr=subprocess.STDOUT to Popen and only using stdout.readline().

The release_confirm warning is harmless and unrelated to the issue.

1 Like

Sorry for the confusion @PaulMelis. I put the save call inside the startup_script.py NOT as a python expression in the subprocess.Popen cmd args. Like this:

launcher.py

# Set custom user script path
scripts_path = resource.get('resources', 'apps', 'blender', 'scripts')
os.environ['BLENDER_USER_SCRIPTS'] = scripts_path

# Launch Blender
app_session = subprocess.Popen(
	[
		app_exe,
		'--python-use-system-env',
	],
	creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
)

startup_script.py (in BLENDER_USER_SCRIPTS scripts/startup path)

class MyTestPanel(bpy.types.Panel):

	bl_label = 'Test'
	bl_idname = TEST_PANEL_PT_mainPanel'
	bl_space_type = 'VIEW_3D'
	bl_region_type = 'UI'
	bl_category = 'Test Cat'

    #  Save logic <--------------------------------------------------
	if os.path.exists(os.getenv('OPEN_FILE_PATH')):
		print('Opening file')
	else:
		print('Creating a new file')
		bpy.ops.wm.save_mainfile(filepath='path/to/file.blend')

	def draw(self, context):
		layout = self.layout

		row = layout.row()
		# row.label(text='Sample Text', icon='CUBE')
		layout.operator('screen.custom_window')

Hmmm, you’re saving from the creation function of a Panel, which I assume is also registered at some point? I guess that at that point in the blender startup saving to a file might not actually work.

Or maybe the operator context isn’t set up correctly