Hello
When writing a multi-module plugin, it can be tricky to implement a hot reload function that will automatically reload modules when we enabled/disable the plugin
Of course we can always shut down blender and restart but well… that’s annoying
Initially it seems that the “standard method” is by using importlibs.reload()
But this method can cause issues as if the modules we want to reload contains other modules, those modules are not reloaded recursively, so depending on the exact code you can wind up in a rather broken state
Which was my case these last 24hs, i was stuck on an import reload similar to the link above
i had constant value error where sub properties straight up refuse tor register after an importlib.reload()
(yes i know, i should prolly have a better global/local space and module organisation to avoid such i guess? but it’s quite a hard fix when un-experienced)
But why bother to do all this? Why do we need them at first place? well that’s because plugins modules are still loaded in the python interpreter after disabling operation.
if we inspect sys.modules
we can still see traces of our plugin that we just disabled.
And why so? That’s the root of our hot-reload problem isn’t it?
Therefore i just corrected this behavior in my main __init__.unregister()
function that clean up all traces of my plugin in sys.modules
In other words, whenever you use an import
statement, the first thing Python does is check if the dictionary that sys.modules
references already has an entry for that module and proceed with the next step (binding names in the current namespace) without loading the module first. If you delete entries from sys.modules
, then Python won’t find the already-loaded module and loads again.
In the example below, this hotreload implementation is working fine
Why is this not a more popular solution? is there something I’m missing perhaps?
def cleanse_modules():
"""search for your plugin modules in blender python sys.modules and remove them"""
import sys
all_modules = sys.modules
all_modules = dict(sorted(all_modules.items(),key= lambda x:x[0])) #sort them
for k,v in all_modules.items():
if k.startswith(__name__):
del sys.modules[k]
return None
def register():
for m in main_modules:
m.register()
return
def unregister():
for m in reversed(main_modules):
m.unregister()
cleanse_modules()
return