我将 rasterio 捆绑到可执行文件中的方式有问题
Something wrong with how I'm bundling rasterio into an executable
预期行为和实际行为。
我希望使用 rasterio
将脚本编译成使用 pyinstaller
的可执行文件。脚本 运行 在我的 python 环境中运行良好。但是我无法使用 PyInstaller
.
将其冻结为可执行文件
重现问题的步骤。
我有一个名为 workflow_3.py
的脚本,其中包含以下内容:
import rasterio
就是这样。然后我尝试使用 pyinstaller 编译 运行 如下:
(wps_env36) D:202750-002_RA2CE\Basis>pyinstaller workflow_3.py
(wps_env36) D:202750-002_RA2CE\Basis>dist\workflow_3\workflow_3.exe
编译似乎 运行 完成,但是当我 运行 可执行文件时出现以下错误:
(wps_env36) D:202750-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 版本和出处
rasterio版本是1.0.8,来自conda-forge
python 版本是 3.6.6
我有两个版本的pyinstaller
pyinstaller 3.4 py36h7602738_0 conda-forge
PyInstaller 3.5.dev0+b13e6b30b <pip>
第二个是开发版,因为this problem
所以不得不入手
问题
如何使用 PyInstaller
冻结使用 rasterio
的应用程序?
我想出的当前解决方案是使用 glob
包强制 feed hidden-imports
变量包含在 C:\ProgramData\Anaconda2\envs\wps_env36\Lib\sitepackages\rasterio
中的所有模块。在我的规范文件中,我添加了一些 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
一开始就无法看到这些模块。但是它确实暂时解决了这个问题,并且代码编译正常。
我使用 this answer 来避免像 user32882 那样对 rasterio 的安装路径进行硬编码,因此规范文件可以在任何 OS 上运行。其余方法同上:
import pkgutil
import rasterio
# list all rasterio and fiona submodules, to include them in the package
additional_packages = list()
for package in pkgutil.iter_modules(rasterio.__path__, prefix="rasterio."):
additional_packages.append(package.name)
block_cipher = None
a = Analysis(['src\main.py'],
binaries=[],
datas=[],
hiddenimports=additional_packages,
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='myProgram',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='myProgram')
我测试过此方法也适用于 Fiona,它与 PyInstaller 有同样的问题。
预期行为和实际行为。
我希望使用 rasterio
将脚本编译成使用 pyinstaller
的可执行文件。脚本 运行 在我的 python 环境中运行良好。但是我无法使用 PyInstaller
.
重现问题的步骤。
我有一个名为 workflow_3.py
的脚本,其中包含以下内容:
import rasterio
就是这样。然后我尝试使用 pyinstaller 编译 运行 如下:
(wps_env36) D:202750-002_RA2CE\Basis>pyinstaller workflow_3.py
(wps_env36) D:202750-002_RA2CE\Basis>dist\workflow_3\workflow_3.exe
编译似乎 运行 完成,但是当我 运行 可执行文件时出现以下错误:
(wps_env36) D:202750-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 版本和出处
rasterio版本是1.0.8,来自conda-forge python 版本是 3.6.6
我有两个版本的pyinstaller
pyinstaller 3.4 py36h7602738_0 conda-forge
PyInstaller 3.5.dev0+b13e6b30b <pip>
第二个是开发版,因为this problem
所以不得不入手问题
如何使用 PyInstaller
冻结使用 rasterio
的应用程序?
我想出的当前解决方案是使用 glob
包强制 feed hidden-imports
变量包含在 C:\ProgramData\Anaconda2\envs\wps_env36\Lib\sitepackages\rasterio
中的所有模块。在我的规范文件中,我添加了一些 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
一开始就无法看到这些模块。但是它确实暂时解决了这个问题,并且代码编译正常。
我使用 this answer 来避免像 user32882 那样对 rasterio 的安装路径进行硬编码,因此规范文件可以在任何 OS 上运行。其余方法同上:
import pkgutil
import rasterio
# list all rasterio and fiona submodules, to include them in the package
additional_packages = list()
for package in pkgutil.iter_modules(rasterio.__path__, prefix="rasterio."):
additional_packages.append(package.name)
block_cipher = None
a = Analysis(['src\main.py'],
binaries=[],
datas=[],
hiddenimports=additional_packages,
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='myProgram',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='myProgram')
我测试过此方法也适用于 Fiona,它与 PyInstaller 有同样的问题。