Что-то не так с тем, как я упаковываю растерио в исполняемый файл - PullRequest
0 голосов
/ 05 ноября 2018

Ожидаемое поведение и реальное поведение.

Я ожидал скомпилировать скрипт, используя rasterio, в исполняемый файл, используя pyinstaller. Скрипт прекрасно работает в моей среде Python. Однако я не могу заморозить его в исполняемый файл, используя PyInstaller.

Действия по воспроизведению проблемы.

У меня есть скрипт с именем workflow_3.py, который содержит следующее:

import rasterio

Вот и все. Я попытался скомпилировать, а затем запустить его с помощью pyinstaller следующим образом:

(wps_env36) D:\11202750-002_RA2CE\Basis>pyinstaller workflow_3.py (wps_env36) D:\11202750-002_RA2CE\Basis>dist\workflow_3\workflow_3.exe

Компиляция, кажется, запускается до конца, однако, когда я запускаю исполняемый файл, я получаю следующую ошибку:

(wps_env36) D:\11202750-002_RA2CE\Basis>dist\workflow_3\workflow_3.exe
Traceback (most recent call last):
  File "workflow_3.py", line 1, in <module>
    import rasterio
  File "c:\programdata\anaconda2\envs\wps_env36\lib\site-packages\PyInstaller\loader\pyimod03_i
mporters.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\rasterio\__init__.py", line 23, in <module>
  File "rasterio\_base.pyx", line 1, in init rasterio._base
ModuleNotFoundError: No module named 'rasterio._shim'
[17536] Failed to execute script workflow_3

Попытка решить проблему

Я изменил файл спецификации, явно добавив 'rasterio._shim' в список, содержащийся в переменной hidden-imports. Тогда я побежал pyinstaller workflow_3.spec. Это вызвало другие ModuleNotFoundError для таких модулей, как control .py, crs.py и vrt.py.

Добавление их к hidden-imports успешно устраняет ModuleNotFoundError для этого конкретного пакета, но он все еще ищет другие пакеты, которые содержатся в C:\ProgramData\Anaconda2\envs\wps_env36\Lib\site-packages\rasterio. В этом каталоге около 40 модулей. Кажется чрезмерным добавлять каждое имя файла в этом каталоге в переменную hidden-imports. На самом деле я даже не знаю, сработает ли это.

Поэтому я также попытался добавить весь каталог в мою переменную pathex, чтобы она могла расширять PYTHONPATH вместе с ней. Однако это вызывает еще одну проблему:

File "c:\programdata\anaconda2\envs\wps_env36\lib\traceback.py", line 5, in <module> File "c:\programdata\anaconda2\envs\wps_env36\lib\linecache.py", line 11, in <module> File "c:\programdata\anaconda2\envs\wps_env36\lib\tokenize.py", line 27, in <module> ImportError: cannot import name 'open' pre-safe-import-module hook failed, needs fixing.

Операционная система

Windows 7

Версия Rasterio и происхождение

Версия растерио - 1.0.8, от conda-forge Версия Python 3.6.6

У меня есть две версии pyinstaller

pyinstaller               3.4              py36h7602738_0    conda-forge
PyInstaller               3.5.dev0+b13e6b30b           <pip>

Вторая - это версия для разработки, которую мне пришлось получить из-за этой проблемы

Вопрос

Как мне использовать PyInstaller, чтобы заморозить приложение, которое использует rasterio?

1 Ответ

0 голосов
/ 06 ноября 2018

Текущее решение, которое я придумал, - принудительная подача hidden-imports переменной всех модулей, содержащихся в C:\ProgramData\Anaconda2\envs\wps_env36\Lib\sitepackages\rasterio, с использованием пакета glob. В моем spec-файле я добавил код Python для этого:

# -*- mode: python -*-

block_cipher = None
import glob, os
rasterio_imports_paths = glob.glob(r'C:\ProgramData\Anaconda2\envs\wps_env36\Lib\site-packages\rasterio\*.py')
rasterio_imports = ['rasterio._shim']

for item in rasterio_imports_paths:
    current_module_filename = os.path.split(item)[-1]
    current_module_filename = 'rasterio.'+current_module_filename.replace('.py', '')
    rasterio_imports.append(current_module_filename)

a = Analysis(['workflow_3.py'],
             pathex=['D:\\11202750-002_RA2CE\\Basis'],
             binaries=[],
             datas=[],
             hiddenimports=rasterio_imports,
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='workflow_3',
          debug=True,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='workflow_3')

К сожалению, это не объясняет, почему pyinstaller не смог увидеть эти модули в первую очередь. Однако это на мгновение решает эту проблему, и код прекрасно компилируется.

...