statsmodels
is one of the complex modules for PyInstaller and that is because it depends on some other modules that they would mess the PyInstaller import graph. My solution might not look optimized but would do the job.
hidden-imports
would only tell PyInstaller to look for that module but sometimes it can't trace module dependencies (like DLLs, external py files, etc.). so for statsmodels
it won't help.
The overall procedure is to first tell PyInstaller to don't trace statsmodels
with exclude-module
and feed the module manually to the final executable.
Also, we need to bundle some modules like (numpy
, pandas
, etc) with Tree
class.
I'm using Python 3.7.4 with latest PyInstaller 3.5.
Suppose below example taken from official docs.
import numpy as np
import statsmodels.api as sm
import statsmodels.formula.api as smf
dat = sm.datasets.get_rdataset("Guerry", "HistData").data
results = smf.ols('Lottery ~ Literacy + np.log(Pop1831)', data=dat).fit()
print(results.summary())
Use below spec file (I'm using Python's venv called env
next to the script)
# -*- mode: python -*-
block_cipher = None
a = Analysis(['script.py'],
pathex=['<root_project_path>'],
binaries=[],
datas=[],
hiddenimports=['six', 'fractions', 'csv', 'pytz', 'timeit'],
hookspath=[],
runtime_hooks=[],
excludes=['statsmodels'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
a.datas += Tree("./env/Lib/site-packages/statsmodels", prefix="statsmodels")
a.datas += Tree("./env/Lib/site-packages/numpy", prefix="numpy")
a.datas += Tree("./env/Lib/site-packages/pandas", prefix="pandas")
a.datas += Tree("./env/Lib/site-packages/scipy", prefix="scipy")
a.datas += Tree("./env/Lib/site-packages/dateutil", prefix="dateutil")
a.datas += Tree("./env/Lib/site-packages/patsy", prefix="patsy")
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='script',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
runtime_tmpdir=None,
console=True )
And finally generate your executable with:
pyinstaller script.spec