Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when using statsmodels with pyinstaller

I'm having problems with PyInstaller and statsmodels. When I run the executable I got the error ImportError: No module named 'statsmodels.__init__.tools', when I run the code directly with Python everything works normally.

I have tried this solution.

It works for the tools module, but I got another error: __init__._version

I have try to add the statsmodels,statsmodels.__init__ and statsmodels.__init__._version, but it didn't work either.

like image 635
rafaelncarvalho Avatar asked Jun 28 '19 16:06

rafaelncarvalho


1 Answers

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
like image 87
Masoud Rahimi Avatar answered Nov 06 '22 17:11

Masoud Rahimi