Using Blender's filebrowser with Python

Every now and then an addon requires that the user selects a spe­cif­ic file or path. Sure, you could just give users a sim­ple string input and let them copy/paste into it but how much cool­er would it be to let them pick a file from the filebrowser?

Luckily Blender pro­vides a handy class that does almost every­thing for us.

Meet ImportHelper

Importhelper is a mix-in class found in the bpy_extras sub­mod­ule. It includes an invoke() func­tion that calls the file­brows­er and a few helper func­tions used in Blender’s importer addons. To use it all we have to do is extend it in our oper­a­tor. Let’s start by import­ing both ImportHelper and Operator.

from bpy_extras.io_utils import ImportHelper
from bpy.types import Operator

Now we can go ahead and cre­ate the operator:

class OT_TestOpenFilebrowser(Operator, ImportHelper):

    bl_idname = "test.open_filebrowser"
    bl_label = "Open the file browser (yay)"

    def execute(self, context):
        """Do something with the selected file(s)."""

        return {'FINISHED'}

Yup, that’s it. Our new oper­a­tor already has an invoke() func­tion that calls the file­brows­er and when a user selects a file, it stores the file’s path in self.filepath. Note that this is a reg­u­lar StringProperty inside ImportHelper that we inher­it­ed when we sub­classed it.


To fil­ter the types of files shown to the user we have to add a filter_glob prop­er­ty to our class. This is a StringProperty with the list of exten­sions we want to show. Each exten­sion is writ­ten in wild­card style and is sep­a­rat­ed by a semi-colon. Note that strings longer that 255 could be cut (since that’s the inter­nal buffer size). 

filter_glob: StringProperty(
    default='*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp',
    options={'HIDDEN'}
)

Also keep in mind that users can dis­able fil­ter­ing in the UI and select any kind of file. You might want to reject a file or do some­thing dif­fer­ent depend­ing on the exten­sion you receive. You can take care of that with good old spli­text().

filename, extension = os.path.splitext(self.filepath)

And what about adding set­tings to the file­brows­er screen? All you have to do is add prop­er­ties to the oper­a­tor as usu­al and they will show up in the browser.

    some_boolean: BoolProperty(
            name='Do a thing',
            description='Do a thing with the file you\'ve selected',
            default=True,
            )

Final code

import bpy
import os

from bpy.props import StringProperty, BoolProperty
from bpy_extras.io_utils import ImportHelper
from bpy.types import Operator


class OT_TestOpenFilebrowser(Operator, ImportHelper):

    bl_idname = "test.open_filebrowser"
    bl_label = "Open the file browser (yay)"
    
    filter_glob: StringProperty(
        default='*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp',
        options={'HIDDEN'}
    )
    
    some_boolean: BoolProperty(
        name='Do a thing',
        description='Do a thing with the file you\'ve selected',
        default=True,
    )

    def execute(self, context):
        """Do something with the selected file(s)."""

        filename, extension = os.path.splitext(self.filepath)
        
        print('Selected file:', self.filepath)
        print('File name:', filename)
        print('File extension:', extension)
        print('Some Boolean:', self.some_boolean)
        
        return {'FINISHED'}


def register():
    bpy.utils.register_class(OT_TestOpenFilebrowser)


def unregister():
    bpy.utils.unregister_class(OT_TestOpenFilebrowser)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.test.open_filebrowser('INVOKE_DEFAULT')

There’s also an ExportHelper class that includes some util­i­ties to check for exist­ing files and set­ting a default unti­tled file­name in the browser. 

Did I miss some­thing? Let me know in the comments!

All the posts you can read
TutorialsBlender, Python03.04.2020



17 Comments

  1. Vnny(4 years ago)

    script worked fine, but I still cant build a blender script with a but­ton for import file and one for export file! I just cant seem to get but­tons to work for me to open any­thing oth­er than blenders inten­tions, like “render.render” ! 5 days now and still cant get my head around it, but this is by far the best site vis­it­ed, nice and clean look­ing easy to follow.

    1. Diego Gangl(4 years ago)

      Hi Vnny, thanks for the com­ments! If you want to cre­ate cus­tom but­tons; you need to cre­ate, and reg­is­ter, your own oper­a­tors and then add them to a pan­el as but­tons (I assume that’s what you mean by Blender’s intentions).

  2. David John Hawley(4 years ago)

    One thing I can’t fig­ure out is how to get the result of the file dia­log back.
    I want to get a file­name in order to do some­thing, let’s call it ActualOperation(myObject), where myObject is an ElementTree.
    The exam­ples all show the oper­a­tion using the filepath to do ActualOperation, but as argu­ments are passsed in as prop­er­ties, and only sim­ple types are allowed, that is not possible.
    So I want to do the obvi­ous, which is get the filepath back from the file dia­log somehow.

  3. danig(3 years ago)

    Hi Diego,
    thanks for all the use­ful blog posts! 

    I try to make the Load but­ton only avail­able when a spec­i­fy file type is select­ed like a .exe but could not find out how that works. Do you know if this is pos­si­ble? and if so could you share some insights?

    1. Diego Gangl(3 years ago)

      Hi! As far as I know you can’t affect the but­tons in the file­brows­er while it’s open. What you can do is to fil­ter the files so only the ones you want to allow are vis­i­ble. Check out the ‘filter_glob‘ prop­er­ty I men­tion in the post for this. Just replace ‘*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp’ for ‘*.exe;’, or the for­mats you want to enable.

      Cheers o/

  4. Harold(3 years ago)

    Hi Diego,
    Thanks for this tutorial.

    I’m using the ExportHelper class to export 3D objects. The func­tion­al­i­ty works fine. However, I want to add an addi­tion­al fea­ture to the class. I want the file­name exten­sion, “filename_ext”, to change depend­ing on the user selec­tion. For exam­ple, if the user selects the item “Animation” from the EnumProperty, then the “filename_ext” is set to a dif­fer­ent extension. 

    Is this pos­si­ble? if so, how would you do it?

    Here is a code snip­pet for your reference.

    # ExportHelper mix­in class uses this

    filename_ext = “.xml”

    filter_glob = StringProperty(
    default=”*.xml”,
    options={‘HIDDEN’},
    maxlen=255, # Max inter­nal buffer length, longer would be clamped.
    )

    dataTypeToExport = EnumProperty(
    name=“Export Type”,
    description=“Choose data to export”,
    items=((‘Mesh’, “Mesh Data Only”, “Export Mesh Data only”),
    (‘Animation’, “Animation Data Only”, “Export Animation Data only”),
    (‘NavMesh’, “Navigation Data”, “Export NavMesh Data only”)),
    default=‘Mesh’,
    )

    1. Diego Gangl(3 years ago)

      Hey Harold,

      I haven’t test­ed this, but it should be pos­si­ble to change these val­ues before show­ing the file brows­er. You would have to over­ride the invoke() func­tion and set those val­ues before ‘context.window_manager.fileselect_add(self)‘. Basically copy and paste the invoke func­tion in the ExportHelper class in [BLENDER DIR]/scripts/modules/bpy_extras/io_utils.py. Then you can change
      the prop­er­ties like ‘self.filename_ext = ‘.txt’‘.

  5. Hal(2 years ago)

    I used this as an exam­ple, set it up, and it works per­fect­ly — so, nat­u­ral­ly I found a ques­tion about this.

    I found that when I exit by click­ing “Cancel” or by press­ing ESC, I still get a full path name as a select­ed file from the dia­log. How can I find out if the user can­celled and did­n’t want to select a file?

    1. Diego Gangl(2 years ago)

      Hi, nev­er used this myself but there is a “can­cel” call­back that you can over­ride in oper­a­tor class­es: https://docs.blender.org/api/current/bpy.types.Operator.html#bpy.types.Operator.cancel

      1. Hal(2 years ago)

        It took me a while, play­ing around, to get this worked out. I was using the basic for­mat from your UIList demo and had the NewItem() func­tion called from the UIList to add a file name to a list. NewItem() called the OT_OpenFileBrowser.execute() func­tion. Then I had code that read the file­name and print­ed it out in NewItem(), but since I was using the same file over and over, I did­n’t real­ize it was­n’t work­ing. The exe­cute() func­tion does not return to the call­ing func­tion. (It is SO hard to get used to things like this in the Blender API!)

        So here’s what seems to hap­pen, and an answer to my question:

        When you call exe­cute() in the OpenFileBrowser oper­a­tor, it does not return to the call­ing func­tion, so don’t try to find a way to call, then read the file­name, and do some­thing you anoth­er func­tion or class. Instead, put all you want to do with the file name you get in the exe­cute() func­tion. So if you want to load the file, store the name, just check res­o­lu­tion in the file, or any­thing, that has to be in the exe­cute() func­tion in OpenFileBrowser.

        Now here’s the part that sur­prised me. When you call exe­cute() and the brows­er pops up, if it’s can­celled, that’s it. Nothing more in exe­cute() is done. So if there’s noth­ing you need to do if they can­cel pick­ing a file, just put the code in exe­cute() that you need if a file is picked and if no file is picked, it won’t be run.

        I can see over­rid­ing the can­cel func­tion — thanks, because I’ll remem­ber that, but in this case, I’m lucky I don’t need to do any­thing if it’s cancelled.

        Thanks for the tuto­ri­als, this is the 2nd in just a cou­ple weeks that’s been a big help, and thank you for help­ing with ques­tions in the com­ments as well!

      2. Diego Gangl(2 years ago)

        No prob­lem!
        Yup, oper­a­tors always return a set with a sin­gle string (with only a few pos­si­ble val­ues). It’s best to keep what­ev­er log­ic you can out­side the op class, or as classmethods.

  6. Peter(2 years ago)

    This is awe­some! I’m writ­ing a script that auto-loads all image tex­tures from a sin­gle fold­er — how can I alter this to allow selec­tion of direc­to­ries? Currently if you hit “Okay” on a direc­to­ry it just opens that direc­to­ry in the file brows­er… Thanks!

    1. Diego Gangl(2 years ago)

      Hi, I’m not sure how this can be done (if at all) on the oper­a­tor side. With prop­er­ties you can set the sub­type to “DIR_PATH” and it will select direc­to­ries, so if you have a string prop­er­ty to store the selec­tion you can use that.

  7. Carlos(2 years ago)

    Hi Diego!
    Do you know if there is any way to open the OS file­brows­er from the python api?
    Thanks!!

    1. Diego Gangl(2 years ago)

      Hi! Sorry for the delay, depends on the OS but gen­er­al­ly you want to call the file­brows­er using subprocess.run(). On lin­ux you can use ‘xdg-open’, on win­dows use ‘explor­er’.
      Cheers,

  8. rc(1 year ago)

    Hi,

    I test­ed this and it works, but there is a prob­lem: even if I select mul­ti­ple files, only the last one gets print­ed. I am on Blender 3.2, not sure if it matters?
    Any idea why?

  9. JOE MORRIS(6 months ago)

    How would I add instruc­tions in the right hand pane of the file brows­er that comes up…just text
    like…“please choose path to save ren­dered image”

Leave a Reply

Your email address will not be published.