I wrote a script, which imports a .stl file and does stuff with it. Now I want to convert the script into an addon.

Currently the file and directory are hardcoded, which doesnt make much sense in an addon. Now I am looking for 2 possible ways to fix this.

Either I expose where the user can enter the file and directory


I find something like tkinters askopenfile.

  • $\begingroup$ If you have the variable exposed in a ui panel or set some kind of default in the addon preferences, you could set the subtype of the stringproperty to 'FILE_PATH' or 'DIR_PATH' as desired. API subtype (string) – Enumerator in [‘FILE_PATH’, ‘DIR_PATH’, ‘FILE_NAME’, ‘BYTE_STRING’, ‘PASSWORD’, ‘NONE’] $\endgroup$
    – Ratt
    May 16, 2022 at 11:14

2 Answers 2


Below is an addon that you would need to complete with the code you want to execute for each STL you input, but it is a starting point. It includes a panel with a button to invoke the operator, but you could do it with a menu entry, shortcut, or simply from the operator search menu instead.

It relies on the ImportHelper class. This class is not well documented, but the key feature is that it adds an invoke function to your class as well as a couple of members, mainly filepath, that it fills out when it calls the file browser from the invoke function.

Something that's hard to find in the documentation is that ImportHelper calls fileselect_add from invoke and it is fileselect_add that sets

The string properties filepath, filename, directory and a files collection [...] when present in the [invoking] operator

It is the files collection that is used to iterate through the input files.

bl_info = {
    "name" : "Import/Process STL files",
    "description" : "Import multiple STL files and process them",
    "author" : "Marty",
    "version" : (0, 0, 1),
    "blender" : (2, 80, 0),
    "location" : "View3D",
    "warning" : "",
    "support" : "COMMUNITY",
    "doc_url" : "",
    "category" : "3D View"

import bpy
from bpy.types import Operator
from bpy.types import Panel
from bpy.props import StringProperty, CollectionProperty
from bpy_extras.io_utils import ImportHelper
from pathlib import Path

class TLA_OT_stlhandler(Operator, ImportHelper):
    """ Import an STL and do things with it"""
    bl_idname = "import.stlhandler"
    bl_label = "Process STL"
    bl_options = {"REGISTER", "UNDO"}

    filter_glob: StringProperty(

    files: CollectionProperty(type=bpy.types.PropertyGroup)

    def poll(cls, context):
        return context.mode == "OBJECT"

    def execute(self, context):
        directory_path = Path(self.filepath).parent
        for file in self.files:
            bpy.ops.import_mesh.stl(filepath=str(directory_path / file.name))
            print(f'Do Your thing here')
        return {'FINISHED'}

class TLA_PT_sidebar(Panel):
    """Display Process STL"""
    bl_label = "STL"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "TLA"

    def draw(self, context):
        col = self.layout.column(align=True)
        prop = col.operator(TLA_OT_stlhandler.bl_idname)
classes = [

def register():
    for c in classes:

def unregister():
    for c in classes:

if __name__ == '__main__':

you can do it like this:

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(
    some_boolean: BoolProperty(
        name='Do a thing',
        description='Do a thing with the file you\'ve selected',

    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():

def unregister():

if __name__ == "__main__":

    # test call

code from here:



You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .