I have a code that has dynamic module import calls using importlib.import_module and uses Python3.9.10.
The code structure is as below
`main.py
.\Main_dependency
|__ test_calling_script.py
.\Test
|__ test1.py
|__ test2.py
:
|__ testN.py`
My dynamic import is like this where prm.TestName
is a function within the test<n>.py
test_module = getattr(import_module(f'Test.{prm.TestFile}'), prm.TestName)
The code works fine when running through terminal/IDE.
I have converted this into a standalone .exe using pyinstaller and am able to run it (which is where my question is). To make the .exe work, I have specified each dynamic import file path in the hidden import variable of pyinstaller .spec file.
I have some other dynamic imports as well which is bound to make my .spec file messy. Is there a more efficient/clean way to implement the same?
I have tried adding the Test directory in pathex
of .spec file since it is supposed to make pyinstaller add it as a path to search for imports based on the official documentation
pathex: a list of paths to search for imports (like using PYTHONPATH), including paths given by the --paths option.
However, this is not behaving as I expected. Only adding the Test
path under pathex runs into NoModuleFoundError for the dynamically imported modules.
Answering my own question. I found out a simple solution to this using the collect_modules from PyInstaller
To include all files within a directory import the collect_modules and store all modules under a variable like so
from PyInstaller.utils.hooks import collect_submodules
hiddenimports_DUT_Config = collect_submodules('DUT_Config')
All that is left is to assign the hiddenimports_DUT_Config
variable to hidden_imports
in Analysis section of the .spec file.
If there are multiple folders to be included i.e folder_1 and folder_2,
from PyInstaller.utils.hooks import collect_submodules
hiddenimports_1 = collect_submodules(<folder_1)
hiddenimports_2 = collect_submodules(<folder_2)
all_hidden_imports = hiddenimports_1 + hiddenimports_2
a = Analysis(
['main.py'],
pathex=['folder_1', 'folder_2''],
binaries=[],
datas=[],
hiddenimports=all_hidden_imports,