I also ran into issues with the “standard” way to reload addons in the past. My vscode extension (which I don’t have the time to support anymore unfortunately…) uses the approach you describe here. It seems to work well in practice, at least I did not have any issues with it.
One thing I find is it’s easier if your addon is all in one file. I have seen addons split across, say, half a dozen files with only a few hundred lines in each, and I feel this is excessive. I see no big deal with a single addon file being, say, a few thousand lines in size – it’s still faster to load than multiple split files that total to the same size
And this way, Blender can reload the addon more reliably without quitting.
Simplified version of cleanse module function, works great so far tested on multiple projects
def cleanse_modules():
"""search for your plugin modules in blender python sys.modules and remove them"""
for module_name in sorted(sys.modules.keys()):
if module_name.startswith(__name__):
del sys.modules[module_name]
Carreful, modules in sys might not be in the correct order, it might create dependencies issues when deleting them, i remember i had issues… that’s why i sorted them in the more “complex” function
The moral of the story is, there is no fully reliable way to dynamically reload a module in Python. importlib.reload() is the least bad way, since that updates the module object in place, but
names which have disappeared from the module will not be deleted.
references of the form frommoduleimportname will not have those name references updated.
Seems like the first point is a bug that could be fixed, but the second one is a pretty fundamental consequence of the design of Python itself: every name is a variable, and every form of name definition (including import statements) is just another kind of variable assignment.
My caveman solution: Restart Blender and recover the session.
I put this in an operator and bound it to F5, so I can restart Blender quickly with one button press.
Of course you lose all addon state that’s not saved in properties, but for me it achieves the goal to continue from where I was with updated addon code. E.g. reproduce a bug, fix it, press F5 to load the new code, test again to confirm the fix is working.
I have to admit I was wrong,
messing with sys.modules is not a good idea,
it can cause crashes and makes blender test suite fail (if you get your plugin added to Blender),
a better solution might be to use importlib.reload
I have been using sys modules my self for a long time too,
the problem is that messing with sys.modules is basically undefined behavior,
and it fails the blender test suite, there are so many things wrong about it,
also a bit more info, it seems the “correct” way to modify sys.modules is already provided by
bpy.utils.register_submodule_factory
# Snippet
def unregister():
from sys import modules
for mod in reversed(submodules):
mod.unregister()
name = mod.__name__
delattr(module, name.partition(".")[2])
del modules[name]
submodules.clear()
return register, unregister
Ok my bad, i was deleting the modules twice one with my own code and one time with blender’s helper function, good to know that blender’s helper function already does this