How to execute an external py-file with a button

I have here a script I am working on: (to load and execute a py-script with buttons in a panel).

import bpy
import os

class Test(bpy.types.Panel):
“”“Creates a Panel in the scene context of the properties editor”""
bl_label = “Testing”
bl_idname = “SCENE_PT_Testing”
bl_space_type = ‘PROPERTIES’
bl_region_type = ‘WINDOW’
bl_context = “scene”

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

    layout.operator("Load and execute script a", text="Script a")
    layout.operator("Load and execute script b", text="Script b")

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

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

if name == “main”:
register()

The layout.operator command is in pseudo-code. Can I put a command in there to load and execute an external script (which simple with some boring data and commands, no functions or classes), or do I have to make a function somewhere (def) or another class ?

(Just starting with python).

Welcome to Python, Peetie!

When you call layout.operator(…) you need to give it the name of a registered operator. In Blender, custom operators are implemented as Python classes, so yes, you’ll have to create another class in your Python file. In the Blender text editor if you go to Templates > Python > Operator Simple, it will bring up the skeleton of a basic operator. You can copy the class definition into your Python file along with your Panel class. The bl_idname you give your operator is what you pass to layout.operator, so that it knows what code to call when the button is pressed. Whatever you write into the execute method of your operator is the code that’s executed when you press the button.

Note that right now your register_class call is referring to GlobalShaders, but it should be referring to Test (the class name of your Panel). You have to have a second register_class call that registers your custom operator as well.

You’ve chosen a challenge that might be more complex than it initially appears because loading files, executing arbitrary code, and interacting with the operating system are all Python programming tasks that don’t have much to do with 3D… they’re general purpose programming tasks, and fairly advanced ones at that.

There’s two basic approaches to executing a Python script from a running Python process. You can create a subprocess to run the script, or you can treat the script as a string and “exec” it inside the process that’s running your operator.

The following code should create a new Blender process in the background and execute a python file—but I haven’t tested it, so please excuse my errors. Check out the Python subprocess module’s documentation.

import bpy
import os
import subprocess

subprocess.call([
    bpy.app.binary_path,
    '--background', '-noaudio', '-nojoystick',
    os.path.abspath(bpy.data.filepath), # the current .blend file
    '--python',
    os.path.abspath(python_script_filepath)
    ])

The other strategy is to “exec” the code as a string. It behaves approximately like you typed the contents of the file wherever the exec function is called, which would probably be in the middle of your operator’s execute method.

with open('python_script_file.py', 'r') as scriptfile:
    script_text = scriptfile.read()
exec(script_text)

Hope some of this helps!

1 Like

Hi @joeycarr

Thanks for the short tutorial.
Strang a bit that it is so difficult: I want to have a button, and when some-one presses on it, it does what I already made. (Is button pressed: do that, finish). But it is the way it is.
I will dive a bit more into python which I really need to do to finish my addon:

There you see the script that generates a colour palette and settings for a shader. I can run the script and it works. I will find out with help from your info how I can make it more userfriendly (making an addon of it).

Regards, Peetie

This saved my life, using exec and using global and local scopes dictionaries

specifically inside the operator execute function:

filename = os.path.join(folder, "ExternalScript.py")
exec(compile(open(filename).read(), filename, 'exec'), globals()) 

The most important part is the globals() thing
now you can call anything of the external script on the same execute function.

1 Like

This doesn’t seem to work in blender 2.91.

Is there something I need to import to use exec in blender? I know the exec works in py37 outside of blender, but it doesn’t work inside of blender.