The following steps allow a Python module (named module_name
here) outside of an executable created by PyInstaller to be imported and for that module to import modules that were bundled into the executable.
- Add
excludes=['module_name']
to the Analysis object used in the PyInstaller spec. This prevents module_name.py
being bundled into the executable.
- Add
sys.path.append(os.path.dirname(sys.executable))
where module_name
is imported in your application. This allows it to be imported from the directory the executable is in, which is different to the directory that the application will run in (due to being decompressed to a temporary folder). See below for my recommended method of achieving this.
- Make sure any imports performed by the external module are also performed by one of the bundled modules before the external one is imported. The interpreter will not resolve the external module's imports against bundled modules, but will use ones that already exist in
sys.modules
.
In order to set up the paths correctly you can use the following:
if getattr(sys, 'frozen', False):
app_path = os.path.dirname(sys.executable)
sys.path.append(app_path)
else:
app_path = os.path.dirname(os.path.abspath(__file__))
frozen
is only available in generated executables, not when running as a script directly. This snippet will add the executable's location to sys.path
if required as well as giving you easy access to the executable or script's location for use in code.
As an example of the final bullet point, consider the following.
# bundled_module1.py
import external_module
# bundled_module2.py
# module content
# external_module.py
import bundled_module2
This will fail in external_module.py
because the imported module can't be found. However, the following will work:
# bundled_module1.py
import bundled_module2
import external_module
# bundled_module2.py
# module content
# external_module.py
import bundled_module2
This will be fine if there are a limited set of bundled modules that the external one should be able to import. It may get unwieldy for larger sets.
Given that the documentation states that the interpreter will resolve imports against modules bundled into the executable, this feels like a possible bug. Interoperating with modules outside of the executable isn't explicitly called out though.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…