I have an app where i had two executables: A Flask-SocketIO-Server and CefPython browser. I bundled the two executables with PyInstaller. The Flask-Server with --onefile option and the cefpython with --onedir option, because i couldnt make it with --onefile. Now i decided to have only executable for both codes (Flask and CEFpython), so my flask server has code to run the CEF graphical user interface:
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'dev':
print "Running Flask-SocketIO on dev mode"
else:
print "Running Flask-SocketIO on production mode"
path = os.getcwd()
gui_path = path + '\\display_react\\display_react.exe'
print 'Running Graphical User Interface...'
thread.start_new_thread(display_react.main, ()) # Baterias
print 'Initializing server'
socketio.run(app, debug=False)
The code works fine, but when i try to bundle this code with PyInstaller with --onefile option, the generated executable doesnt work cause some of CEF dependencies. Here the errors when running Pyinstaller:
Running Flask-SocketIO on production mode Running Graphical User Interface... Initializing server [wxpython.py] CEF Python 57.1 [wxpython.py] Python 2.7.14 64bit [wxpython.py] wxPython 4.0.1 msw (phoenix) [0727/125110.576:ERROR:main_delegate.cc(684)] Could not load locale pak for en-US [0727/125110.576:ERROR:main_delegate.cc(691)] Could not load cef.pak [0727/125110.578:ERROR:main_delegate.cc(708)] Could not load cef_100_percent.pak [0727/125110.582:ERROR:main_delegate.cc(717)] Could not load cef_200_percent.pak [0727/125110.582:ERROR:main_delegate.cc(726)] Could not load cef_extensions.pak [0727/125110.648:ERROR:content_client.cc(269)] No data resource available for id 20418 [0727/125110.648:ERROR:content_client.cc(269)] No data resource available for id 20419 [0727/125110.650:ERROR:content_client.cc(269)] No data resource available for id 20420 [0727/125110.655:ERROR:content_client.cc(269)] No data resource available for id 20421 [0727/125110.656:ERROR:content_client.cc(269)] No data resource available for id 20422 [0727/125110.656:ERROR:content_client.cc(269)] No data resource available for id 20417 [0727/125110.680:ERROR:extension_system.cc(72)] Failed to parse extension manifest. C:\Users\Ricardo\AppData\Local\Temp_MEI95~1\display_react.py:118: wxPyDeprecationWarning: Call to deprecated item EmptyIcon. Use :class:
Icon
instead
Here the .spec file i am using:
# -*- mode: python -*-
block_cipher = None
def get_cefpython_path():
import cefpython3 as cefpython
path = os.path.dirname(cefpython.__file__)
return "%s%s" % (path, os.sep)
cefp = get_cefpython_path()
a = Analysis(['server.py'],
pathex=['C:\\Users\\Ricardo\\addvolt-scanning-tool\\backend'],
binaries=[],
datas=[('PCANBasic.dll', '.'), ('o.ico', '.')], #some dlls i need for flask
hiddenimports=['engineio.async_gevent'], #engineio hidden import for Flask usage
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas + [('locales/en-US.pak', '%s/locales/en-US.pak' % cefp, 'DATA')], # my try to fix that missing dependencies
name='server',
debug=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=True )
EDIT: SOLVED
Thanks to @cztomczak i got this working. The problem was not on PyInstaller, but on the way wxpython.py was looking for the locale, resources and subprocess stuff. Although all files were on the 'temp/dir/_MEIxxx', the wxpython was looking for these files on the directory of the executable. So the way i got to inform the code to look for these files on temp directory was:
dir_temp = tempfile.gettempdir()
files = []
for i in os.listdir(dir_temp):
if os.path.isdir(os.path.join(dir_temp,i)) and '_MEI' in i:
files.append(i)
dir_temp = dir_temp + str(files[0])
dir_temp = os.path.join(dir_temp, str(files[0]))
dir_temp_locale = os.path.join(dir_temp, 'locales')
dir_temp_subprocess = os.path.join(dir_temp_subprocess, 'subprocess.exe')
print dir_temp
dir_temp = dir_temp.replace("\\", "\\\\")
print dir_temp
print dir_temp_locale
dir_temp_locale = dir_temp_locale.replace("\\", "\\\\")
print dir_temp_locale
dir_temp_supbprocess = dir_temp_subprocess.replace("\\", "\\\\")
print dir_temp_subprocess
...
settings = {'auto_zooming': '-2.5', 'locales_dir_path': dir_temp_locale, 'resources_dir_path': dir_temp, 'browser_subprocess_path': dir_temp_subprocess}
i had to do this because the name of the created folder on temp (_MEIxxxx) is always changing. And probably i will have problems in the future because if the App crashes, the _MEIxx folder will not be deleted and if i try to re-run the executable, this piece of code will have two _MEI folders and possibily will not work at all until someone clean the temp directory.
So, resuming... To bundle in onefile the app: - Paste the hook-cefpython3.py (available on the package) on Python27/envs/libs/site-package/Pyinstaller/hooks - Run Pyinstaller with --onefile options - Tell the cefpython code where locale, resource and subprocess are (locale_dir_path, resource_dir_path, browser_subprocess_path)