I would like to dynamically create and import modules inside an inner __init__.py file, if one or several of a set of indexed submodules doesn't exist.
I have a set of module layers, say;
top_module/
__init__.py
sub_module/
__init__.py
a1/
__init__.py
n1.py
b1/
__init__.py
b1.py
b2/
__init__.py
b2.py
b3/
__init__.py
b3.py
a2/
__init__.py
a2.py
b*/...
a*/...
Where the top_module/__init__.py does a from .sub_module import *.
From within the top_module/sub_module/__init__.py, say I have several of these a* folders that are just indexed iteratively. I know that I can do something like this to iterate importing over an index for those modules that exist;
from importlib import import_module
for a in range(some_max_a):
import_module(f'.a{a}', package='top_module.sub_module')
And that I can do something like this to just ignore modules that don't exist yet;
from importlib import import_module
for a in range(some_max_a):
try:
import_module(f'.a{a}', package='top_module.sub_module')
except ModuleNotFoundError:
pass
What I would like to be able to do is dynamically create and import these modules if they don't exist.
What I have so far is
from importlib import import_module
from sys import modules
from types import ModuleType
PKG = 'top_module.sub_module'
for a in range(some_max_a):
try:
import_module(f'.a{a}', package=PKG)
except ModuleNotFoundError:
modules[f'{PKG}.a{a}'] = ModuleType(f'{PKG}.a{a}')
for b in range(some_max_b):
modules[f'{PKG}.a{a}.b{b}'] = ModuleType(f'{PKG}.a{a}.b{b}')
def function_all_should_have(*args, **kwargs):
raise NotImplementedError
modules[f'{PKG}.a{a}.b{b}'].function_all_should_have = function_all_should_have
import_module(f'{PKG}.a{a}')
I've tried with and without the {PKG} in the import_module call and or the ModuleType call.
If I import the created package, I can see that all the modules that I'm expecting this to create exist in the sys.modules, but trying to access any of them with a call to something like top_module.sub_module.a3.b3.function_all_should_have() yields an error along the lines of
AttributeError: module 'top_module.sub_module' has no attribute 'a3'.
Yet I can see that there is a top_module.sub_module.a3 module along with all the top_module.sub_module.a3.b* modules.
I'm not really sure why the modules would be created and exist in sys.modules but be unreachable after importing.
If there's no easy answer I could just go back to my second example and pass if the modules don't exist, but I would still like to understand what's happening here. The only closest question I could find to this was dynamic module creation.
sys.modulesis the cache used by the import machinery, so I'm not surprised if actual importing is skipped in your hack. It might also matter how you imported the parent module where the error comes from, not sure. A more complete example might help more.