# Save a file with filename prompt from script?

I'm trying to write a simple script to save without Blender showing the confirmation popup. This works fine if the file already has a name, however, if I call bpy.ops.wm.save_mainfile() and the file has not been previously saved, Blender simply crashes/exits completely.

So is there a way to call save_mainfile() so that it behaves the same at the normal File/Save operation where it will prompt the user for a filename? (Note that calling save_as_mainfile() also crashes Blender.

Here's what I was at least hoping would work:

def execute( self, context ):
if not bpy.data.filepath:
bpy.ops.wm.save_mainfile( ?parameter to prompt for filename? )
else:
bpy.ops.wm.save_mainfile()
self.report( { 'INFO' }, 'File saved.')
return { 'FINISHED' }

• Looking at the docs for save_as_mainfile, I think it attempts to save the file to the specified path. Based on the fact that no path is provided in your code, it is probably trying to save to some default location it does not have write permission for. Your script needs to obtain a location and obtain permission to write to that location to use save_as_mainfile. However, it is weird your blender version crashes - mine logs an error to the system console. – GiantCowFilms Jul 13 '18 at 1:04
• I'm mostly interested in having a way to get the same default behavior of it prompting the user for a filename by passing in a parameter of some sort. I'll update the question to reflect this and remove the call to save_as_mainfile. – Ziflin Jul 13 '18 at 1:59

To fix your issue, simply pass the value 'INVOKE_AREA' into save_mainfile, bpy.ops.wm.save_mainfile('INVOKE_AREA'). This will open a file selector if the file is not saved, otherwise it will bring up a prompt that confirms the user wishes to save over the file. If you want to avoid the confirm dialog, you will need to call save_mainfile without 'INVOKE AREA'.
Passing 'INVOKE AREA' defines the operator context, which allows save_mainfile to bring up the file selector.
• Can also add to layout layout.operator_context = 'INVOKE_AREA' see this answer – batFINGER Jul 13 '18 at 13:34
• Thank you! Passing in INVOKE_DEFAULT appears to work also, but apparently when I tried that the first time I forgot to re-import my add-on. It works perfectly now, so thanks! – Ziflin Jul 13 '18 at 17:04