Using the sys and importlib modules, a function can be written to remove the package and its modules from Python's import cache. This allows for the package to reload its child modules when it is re-imported.
import sys
import importlib
from types import ModuleType
def deep_reload(m: ModuleType):
name = m.__name__ # get the name that is used in sys.modules
name_ext = name + '.' # support finding sub modules or packages
del m
def compare(loaded: str):
return (loaded == name) or loaded.startswith(name_ext)
all_mods = tuple(sys.modules) # prevent changing iterable while iterating over it
sub_mods = filter(compare, all_mods)
for pkg in sub_mods:
del sys.modules[pkg] # remove sub modules and packages from import cache
return importlib.import_module(name)
This code can be extended with a Lock to make it thread-safe as well:
from threading import Lock
sys_mod_lock = Lock() # all accesses to sys.modules must be programmed to acquire this lock first
# this means do not use any builtin import mechanism such as the 'import' statement once the following function is being used
# instead use importlib's import_module function while sys_mod_lock is acquired
def tsafe_reload(m: ModuleType):
with sys_mod_lock:
return deep_reload(m)
Note: these functions come with one of the caveats from the standard library's reload. Any references elsewhere in the program leading to the old package will be maintained and will not be replaced automatically. For that, you can look at globalsub, which can replace all references to an object in the interpreter with a different object (usually for debugging purposes).