Объедините CEFpython в PyInstaller с параметром --onefile

У меня есть приложение, в котором у меня было два исполняемых файла: Flask-SocketIO-Server и браузер CefPython. Я связал два исполняемых файла с PyInstaller. Flask-Server с параметром --onefile и cefpython с параметром --onedir, потому что я не смог сделать это с параметром --onefile. Теперь я решил иметь только исполняемый файл для обоих кодов (Flask и CEFpython), поэтому на моем фляжном сервере есть код для запуска графического пользовательского интерфейса CEF:

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)

Код работает нормально, но когда я пытаюсь связать этот код с PyInstaller с параметром --onefile, сгенерированный исполняемый файл не работает, что вызывает некоторые зависимости CEF. Вот ошибки при запуске Pyinstaller:

Запуск Flask-SocketIO в производственном режиме Запуск графического интерфейса пользователя ... Инициализация сервера [wxpython.py] CEF Python 57.1 [wxpython.py] Python 2.7.14 64bit [wxpython.py] wxPython 4.0.1 msw (phoenix) [0727 / 125110.576: ОШИБКА: main_delegate.cc (684)] Не удалось загрузить пакет локали для en-US [0727 / 125110.576: ОШИБКА: main_delegate.cc (691)] Не удалось загрузить cef.pak [0727 / 125110.578: ОШИБКА: main_delegate.cc (708)] Не удалось загрузить cef_100_percent.pak [0727 / 125110.582: ОШИБКА: main_delegate.cc (717)] Не удалось загрузить cef_200_percent.pak [0727 / 125110.582: ОШИБКА: main_delegate.cc (726)] Не удалось загрузить cefak_extensions. [0727 / 125110.648: ОШИБКА: content_client.cc (269)] Нет ресурсов данных для идентификатора 20418 [0727 / 125110.648: ОШИБКА: content_client.cc (269)] Нет ресурсов данных для идентификатора 20419 [0727 / 125110.650: ОШИБКА: content_client .cc (269)] Нет доступных ресурсов данных для идентификатора 20420 [0727 / 125110.655: ОШИБКА: content_client.cc (269)] Нет ресурсов данных для идентификатора 20421 [0727 / 125110.656: ОШИБКА : content_client.cc (269)] Нет доступных ресурсов данных для идентификатора 20422 [0727 / 125110.656: ОШИБКА: content_client.cc (269)] Нет ресурсов данных для идентификатора 20417 [0727 / 125110.680: ОШИБКА: extension_system.cc (72)] Не удалось проанализировать манифест расширения. C: \ Users \ Ricardo \ AppData \ Local \ Temp_MEI95 ~ 1 \ display_react.py: 118: wxPyDeprecationWarning: вызов устаревшего элемента EmptyIcon. Используйте вместо этого: class: Icon

Вот файл .spec, который я использую:

# -*- 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 )

РЕДАКТИРОВАТЬ: РЕШЕНО

Благодаря @cztomczak у меня все заработало. Проблема была не в PyInstaller, а в том, что wxpython.py искал локаль, ресурсы и материалы подпроцесса. Хотя все файлы находились в каталоге «temp / dir / _MEIxxx», wxpython искал эти файлы в каталоге исполняемого файла. Итак, способ, которым я должен сообщить код для поиска этих файлов во временном каталоге, был следующим:

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}

Мне пришлось это сделать, потому что имя созданной папки на temp (_MEIxxxx) всегда меняется. И, вероятно, у меня будут проблемы в будущем, потому что, если приложение выйдет из строя, папка _MEIxx не будет удалена, и если я попытаюсь повторно запустить исполняемый файл, этот фрагмент кода будет иметь две папки _MEI и, возможно, не будет работать вообще до тех пор, пока кто-нибудь почистит временный каталог.

Итак, возобновляем ... Чтобы связать приложение в один файл: - Вставьте файл hook-cefpython3.py (доступный в пакете) в Python27 / envs / libs / site-package / Pyinstaller / hooks - Запустите Pyinstaller с параметрами --onefile - Сообщите коду cefpython, где находятся локаль, ресурс и подпроцесс (locale_dir_path, resource_dir_path, browser_subprocess_path)


person Ricardo Goncalves    schedule 27.07.2018    source источник


Ответы (2)


Я предполагаю, что у вас возникли ошибки, потому что ваш файл спецификации не включал все необходимые двоичные файлы CEF. Существует официальный пример pyinstaller, который вы можете использовать и изменять для использования параметра --onefile: https://github.com/cztomczak/cefpython/blob/master/examples/pyinstaller/README-pyinstaller.md

person Czarek Tomczak    schedule 27.07.2018
comment
ну, я попытался запустить пример pyinstaller, и он выдает ошибку: «AssertionError: Missing cefpython3 Cython modules», когда pyinstaller обращается к hook-cefpython3.py. Вы знаете, в чем может быть причина? Большое спасибо за помощь. - person Ricardo Goncalves; 30.07.2018
comment
Похоже, что содержимое пакета cefpython3 в вашей системе было изменено. Там ожидается несколько файлов .pyd. Утверждение здесь: github.com/cztomczak/ cefpython / blob / master / examples / pyinstaller / - person Czarek Tomczak; 30.07.2018
comment
@RicardoGoncalves Проверьте, что установлено в CEFPYTHON3_DIR. - person Czarek Tomczak; 30.07.2018
comment
Большое спасибо! Это было то. CFPYTHON3_DIR был: c: \ xxx \ xxx \ envs \ inst_exe \ scripts \ Lib \ site-packages \ cefpython3 вместо c: \ xxx \ xxx \ envs \ inst_exe \ Lib \ site-packages \ cefpython3. Теперь это работает. Теперь я попытаюсь изменить файл .spec для создания одного исполняемого файла. Еще раз спасибо за помощь и за прекрасный пакет. - person Ricardo Goncalves; 30.07.2018
comment
Я отредактировал файл .spec, чтобы создать один файл. И хотя он успешно сгенерирован, он не запускается из-за той же проблемы: отсутствует пакет локали, cef.pak, cef_100.pak и т. Д. В основном папка локали и файлы .pak. Здесь мой .spec изменен (только часть, которую я изменил, deletec Collect () и отредактировал Exe ()): exe = EXE (pyz, a.scripts, a.binaries, a.zipfiles, a.datas, name = 'cefapp' , debug = DEBUG, strip = False, upx = False, console = DEBUG, icon = .. / resources / wxpython.ico). Я все еще пытаюсь сделать это на вашем примере pyinstaller - person Ricardo Goncalves; 30.07.2018
comment
@RicardoGoncalves Проверить временную папку извлеченного файла pyinstaller при запуске приложения. См. Sys._MEIPASS, установленный pyinstaller. Посмотрите, все ли двоичные файлы находятся там. Если да, попробуйте вручную установить параметры ApplicationSettings.locales_dir_path и resources_dir_path. См. Документы для справки. - person Czarek Tomczak; 30.07.2018
comment
Я попробовал еще пару вещей. Поскольку это единственный исполняемый файл, все данные и двоичные файлы хранятся во временном каталоге (_MIEPASS2), когда я выполняю cefapp.exe. Недостающие файлы находятся в этом временном каталоге (файлы локали и .pak), так что пакетный пакет правильный. Что не так, каталог используется exe для использования двоичных данных. Итак, я сохранил папку локали и файлы .pak в том же каталоге, что и .exe, и теперь никаких ошибок не появляется. В любом случае, он не работает должным образом, потому что окно открыто, но внутри ничего не видно. Так что это все еще не работает ...: / - person Ricardo Goncalves; 30.07.2018
comment
Я пробовал то, что вы сказали, потому что думаю, что это источник проблемы. Однако почему-то locales_dir_path и resources_dir_path вообще не работают, и я не знаю, где код пытается найти ресурсы и локали ... Даже если я запускаю код в обычном режиме (когда я говорю обычно, это без pyinstaller, просто ввод: 'python server.py') - person Ricardo Goncalves; 30.07.2018
comment
Изменить: это произошло из-за '\' вместо '\\'. Я думаю, что теперь он работает. Я выложу решение. Еще раз спасибо! - person Ricardo Goncalves; 30.07.2018
comment
Теперь все решено! Я только что выложил решение! Спасибо! - person Ricardo Goncalves; 31.07.2018
comment
@RicardoGoncalves Вы должны использовать переменные окружения _MEIPASS2 или _MEIPASS для обнаружения временного каталога. Они устанавливаются pyinstaller и доступны в os.environ. Иногда приложение не закрывается правильно, поэтому временный каталог не будет очищен, и ваше решение не сработает. - person Czarek Tomczak; 31.07.2018

У меня была аналогичная проблема, и я обнаружил, что использование переменной окружения _MEIPASS является более элегантным решением.

import cefpython
import os
import sys

if hasattr(sys, '_MEIPASS'):
    # settings when packaged
    settings = {'locales_dir_path': os.path.join(sys._MEIPASS, 'locales'),
                'resources_dir_path': sys._MEIPASS,
                'browser_subprocess_path': os.path.join(sys._MEIPASS, 'subprocess.exe'),
                'log_file': os.path.join(sys._MEIPASS, 'debug.log')}
else:
    # settings when unpackaged
    settings = {}

cefPython.Initialize(settings=settings)
person resident    schedule 25.02.2019