I wrote codes about multiple script files, not add-on

Hello friends, this loads multiple python script files outside Blender, you can edit the scripts with PyCharm and just press Alt+P on this single script then the other script files will be reloaded.
It’s embarrassing that my thread always move at the top when I edit, this is my last edit, bye.

  • New method (This is very stable, it’s exactly like the include in C++)
    Blend file: Multiple Scripts.zip (88.7 KB)
  • Old method (Don’t use this because the objects inside the modules are always deleted)
    Blend file: Import Modules (Unstable).zip (133.4 KB)
  • To use one of them, "Don’t forget to extract the zip file, that’s very important", then open the .blend file, and open the System Console to see the output.

Pros for both methods:

  • This is the exact opposite of add-on, the script files are just close to your blend file.
  • You can use an external Python Editor like PyCharm which is the best. You just press Alt+P on this script to run all the scripts. You don’t need to restart Blender after an update, not like an addon.
  • Once you finished scripting, you can close the Text Editor by enabling the check box “Register” then when Blender re-starts, the script is registered automatically. The text name in blender must have an extension ‘.py’.
  • In the future, when you open your blend file and that you have reinstalled Blender, then you don’t have to worry which add-on you should install.
  • In the future, if you accidentally renamed the Scripts folder or move it to another relative location then when you open your blend file, then there is a visible error message box telling that the script files are not found, it’s possible if the register check box is enabled, you always do that when you finished scripting.

Cons for both methods:

  • You must press Alt+P on this script every time you re-run it, I tried to use a keymap but it’s impossible.

Cons for the old method:

  • Don’t support very complex multiple scripts because objects are always unexpectedly deleted.
  • If you want to add a new module, then you must restart Blender.
  • Submodules of ‘main’ cannot have submodules.

New method:

print("--------------------------------------------------")
import bpy

_scripts_folder = "Scripts"
_scripts = (
    "script1.py",
    "script2.py",
    "main.py", # This must be the last
)

####################################################################################################
# Based on 'bpy.types.WindowManager.popup_menu' in Blender 2.83.0 Python API documentation.    
# Search: popup_menu

def error_message_draw(self, context):
    self.layout.label(text=g_error_message)

def error_message(message):
    global g_error_message
    g_error_message = message
    bpy.context.window_manager.popup_menu(error_message_draw, title="Error", icon='ERROR')

####################################################################################################
import os

_dir = os.path.join(os.path.dirname(bpy.data.filepath), _scripts_folder)

for filename in _scripts:
    _script_filepath = os.path.join(_dir, filename)

    # Check if the script file exists, and if it's not checked then you will never know if the script file
    # is not found when this text editor is hidden during first start of blender because you won't see
    # an error message.
    if not os.path.exists(_script_filepath):
        error_message(f'The file "{filename}" is not found, if the project is zipped, then extract it.')
    else:
        exec(open(_script_filepath).read())

Screenshot

Old method:

import bpy

print("--------------------------------------------------")

scripts_folder = "Scripts"
main_str ='main'
submodules_str = (
    'module1',
    'module2',
)

####################################################################################################
def debug_print(text):
    if True:
        print(text)

####################################################################################################
# Based on 'bpy.types.WindowManager.popup_menu' in Blender 2.83.0 Python API documentation.    
# Search: popup_menu

def error_message_draw(self, context):
    self.layout.label(text=bpy.app.driver_namespace['error_message'])

def error_message(message):
    bpy.app.driver_namespace['error_message'] = message
    bpy.context.window_manager.popup_menu(error_message_draw, title="Error", icon='ERROR')

################################################################################################################
# Modified version of: https://blender.stackexchange.com/questions/33603/importing-python-modules-and-text-files
# Importing modules.
#
# NOTE: The reason you must not import all existing modules is you want to have error message if
# a file named 'main.py' is not found for example.

import sys
import os
import importlib

# Must be before
is_first_import = importlib.util.find_spec(main_str) is None

# Must be after
dir = os.path.join(os.path.dirname(bpy.data.filepath), scripts_folder)
if not dir in sys.path:
    sys.path.append(dir)

program = f"import {main_str}"
debug_print(f"")
debug_print(f">>> {program}")
exec(program)

if not is_first_import:
    for name in submodules_str:
        module_filepath = os.path.join(dir, f"{name}.py")
        if not os.path.exists(module_filepath):
            error_message(f"The file '{name}.py' is not found.")
        else:
            program = f"importlib.reload({main_str}.{name})"
            debug_print(f"")
            debug_print(f">>> {program}")
            exec(program)

# Check if the script file exists, and if it's not checked then you will never know if the script file
# is not found when this text editor is hidden during first start of blender because you won't see
# an error message.
module_filepath = os.path.join(dir, f"{main_str}.py")
if not os.path.exists(module_filepath):
    error_message(f"The file '{main_str}.py' is not found.")
else:
    if not is_first_import:
        # this next part forces a reload in case you edit the source after you first start the blender session
        program = f"importlib.reload({main_str})"
        debug_print(f"")
        debug_print(f">>> {program}")
        exec(program)

####################################################################################################

Output:

  • First part is the output of first run.
  • You add EDIT1 in each modules ‘MyModule1’ and ‘MyModule2’.
  • The second part is the output of second run.
  • You add EDIT2 in the module ‘main’.
  • The third part is the output of the third run.
2 Likes