There's a (someone else's) multi-file addon with a complex structure of libraries and classes with a bug in a particular class and I'd like to try to fix it. However I never made an addon with several separated files and I don't understand how to reload it properly. At the moment I edit the original .py file and restart Blender which seems like a terrible workflow.

• I really am not sure but you can try to reload the module with the 'importlib' module. Use "import importlib" and then "importlib.reload(module)" – Gorgious Mar 4 '20 at 10:00
• Does F3 > Reload Scripts help? You can also bind the operator to any hotkey... – brockmann Mar 4 '20 at 10:57
• @Gorgious I'll try that, thank you – Sergey Kritskiy Mar 4 '20 at 11:50
• @brockmann this doesn't seem to update the code – Sergey Kritskiy Mar 4 '20 at 11:51
• Does it for me. Is the addon enabled? Also see: blender.stackexchange.com/a/28505/31447 – brockmann Mar 4 '20 at 12:04

Not sure why Reload Scripts didn't work at first for me, maybe I didn't save the correct file or whatnot, anyway, that's a possible way. My issues were however with this method is that

• I have to edit files in Blender addons folder, not in my project folder;
• this reloads all the scripts, on my machine with a lot of addons installed it takes about four seconds and plus after that some addons reset their settings;

In the end I followed this article for creating and debugging multifile addons. Author suggests using a specific setup for the __init__.py file and then provides a Blender script in the second part of the article to update only a specific addon. I've assigned this script to a hotkey and it works much faster than reloading all the scripts.

Here are the final scripts from the article. __init__.py:

bl_info = {
'category': 'All',
'version': (0, 0, 1),
'blender': (2, 80, 0)
}

import sys
import importlib

modulesFullNames = {}
for currentModuleName in modulesNames:
if 'DEBUG_MODE' in sys.argv:
modulesFullNames[currentModuleName] = ('{}'.format(currentModuleName))
else:
modulesFullNames[currentModuleName] = ('{}.{}'.format(__name__, currentModuleName))

for currentModuleFullName in modulesFullNames.values():
if currentModuleFullName in sys.modules:
else:
globals()[currentModuleFullName] = importlib.import_module(currentModuleFullName)
setattr(globals()[currentModuleFullName], 'modulesNames', modulesFullNames)

def register():
for currentModuleName in modulesFullNames.values():
if currentModuleName in sys.modules:
if hasattr(sys.modules[currentModuleName], 'register'):
sys.modules[currentModuleName].register()

def unregister():
for currentModuleName in modulesFullNames.values():
if currentModuleName in sys.modules:
if hasattr(sys.modules[currentModuleName], 'unregister'):
sys.modules[currentModuleName].unregister()

if __name__ == "__main__":
register()


import os
import sys

filesDir = "d:/Python/TestMultifile"

initFile = "__init__.py"

if filesDir not in sys.path:
sys.path.append(filesDir)

file = os.path.join(filesDir, initFile)

if 'DEBUG_MODE' not in sys.argv:
sys.argv.append('DEBUG_MODE')

if 'DEBUG_MODE' in sys.argv:
sys.argv.remove('DEBUG_MODE')


I have found an easiest method. In this example the addon has two modules - main and operator

__init__.py:

bl_info = {
# Your regular bl_info goes here.
}

# This is essential part
if "bpy" in locals():
import importlib
else:
import bpy
from . import main
from . import operator

classes = (

• To keep code "modular" I would recommend each module with classes to register having a register method as above.. eg modules = [main, operator] then in the register method loop the modules and mod.register() IMO making adding another module easier to test and integrate into addon. – batFINGER Jun 9 '20 at 1:42