无法使用 PyInstaller 可执行文件导入 Geopandas - 尽管在虚拟环境中运行良好

Jos*_*ska 3 python pyinstaller geopandas

当我的 Python 应用程序被 PyInstaller 冻结时尝​​试导入 Geopandas,它停止工作。

  • 视窗 10
  • PyInstaller 3.3.1
  • 大熊猫 0.4

这是源代码:

print("Hello, StackOverflow")
import geopandas as gpd
Run Code Online (Sandbox Code Playgroud)

这是编译后的 EXE 的控制台输出结果:

Hello, StackOverflow
Traceback (most recent call last):
  File "application.py", line 3, in <module>
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "d:\documents\projecttwo\publish\harv_venv1\env\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\geopandas\__init__.py", line 9, in <module>
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "d:\documents\projecttwo\publish\harv_venv1\env\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\geopandas\datasets\__init__.py", line 7, in <module>
StopIteration
[6764] Failed to execute script application
Run Code Online (Sandbox Code Playgroud)

当我尝试导入 Geopandas 是更复杂的应用程序时,这种行为是一致的,并且控制台输出是恒定的。

Geopandas 已正确安装在 Python 3.6.3 虚拟环境中(通过 PIP,我也尝试过 0.4 和 0.3 版)并且在编译之前python application.py运行良好(即成功运行)。

我尝试从不同来源(例如 Gohlke 的轮子)安装 geopandas 和 pyinstaller,结果相同。我还尝试从头开始创建一个全新的虚拟环境,从 Gohlke 安装 Fiona,从 pip 安装 geopandas。

我怀疑可能需要进行一些隐藏的导入。我对 PyInstaller 还很陌生,所以任何帮助将不胜感激。

aor*_*orr 6

看起来geopandas正在 init 上积极加载他们的数据目录。它包含在您的包中被忽略的非 python 文件pyinstaller,因此为了geopandas在加载时找到它们,必须显式打包它们。

“手动”过程花了我一段时间才弄清楚,我正在使用它conda作为我的包管理器(如果你不是,这些编辑仍然应该对你有帮助)。为了使其正常工作,我们需要修改第一次.spec运行时构建的文件:pyinstaller

# -*- mode: python -*-

import os
from PyInstaller.utils.hooks import collect_data_files # this is very helpful
env_path = os.environ['CONDA_PREFIX']
dlls = os.path.join(env_path, 'DLLs')
bins = os.path.join(env_path, 'Library', 'bin')

paths = [
    os.getcwd(),
    env_path,
    dlls,
    bins,
]

# these binary paths might be different on your installation. 
# modify as needed. 
# caveat emptor
binaries = [
    (os.path.join(bins,'geos.dll'), ''),
    (os.path.join(bins,'geos_c.dll'), ''),
    (os.path.join(bins,'spatialindex_c-64.dll'), ''),
    (os.path.join(bins,'spatialindex-64.dll'),''),
]

hidden_imports = [
    'ctypes',
    'ctypes.util',
    'fiona',
    'gdal',
    'geos',
    'shapely',
    'shapely.geometry',
    'pyproj',
    'rtree',
    'geopandas.datasets',
    'pytest',
    'pandas._libs.tslibs.timedeltas',
]

# other fancy pyinstaller stuff...

a = Analysis(['run_it.py'],
         pathex=paths, # add all your paths
         binaries=binaries, # add the dlls you may need
         datas=collect_data_files('geopandas', subdir='datasets'), #this is the important bit for your particular error message
         hiddenimports=hidden_imports, # double tap
         hookspath=[],
         runtime_hooks=[],
         excludes=excludes,
         win_no_prefer_redirects=False,
         win_private_assemblies=False,
         cipher=block_cipher)
# remaining fancy pyinstaller stuff...
Run Code Online (Sandbox Code Playgroud)

这应该会收集丢失的数据目录并将其放在可执行文件可以找到的位置。

“自动”方式是构建一个hook-geopandas.py为您执行此操作的文件。pyinstaller当您构建时加载这些钩子作为保存和共享这些技巧的一种方式。事实上,已经有一个非常好的挂钩文件shapely(依赖项之一),您可以在此处geopandas查看。

- - - 编辑 - - - -

我目前也在构建一个依赖于的项目,geopandas并且我意识到由于这个问题,截至目前(2018-08-23)上述修复还不完整。

在我的 run_it.py 中,我包含了以下测试以确保fiona全部gdal正确打包到捆绑包中:

from osgeo import gdal, ogr, osr
from fiona.ogrext import Iterator, ItemsIterator, KeysIterator
from geopandas import GeoDataFrame
Run Code Online (Sandbox Code Playgroud)

除非你是巫师,否则这个测试可能会失败。这个垫片在我的 .spec 文件中对我有用:

_osgeo_pyds = collect_data_files('osgeo', include_py_files=True)

osgeo_pyds = []
for p, lib in _osgeo_pyds:
    if '.pyd' in p:
        osgeo_pyds.append((p, ''))

binaries = osgeo_pyds + [
    # your other binaries
]

a = Analysis(
    # include your kwargs
)
Run Code Online (Sandbox Code Playgroud)

我希望这有助于使这个答案更加完整,并且您的捆绑应用程序可以按预期完成地理空间工作。


小智 5

我收到了同样的错误,并以与上面的 aorr 不同的方式解决了它。

该错误是由于 pyinstaller 找不到包中包含的 geopandas 数据集而引起的,因为它们是 .shp 文件。

我没有在我的项目中使用的数据集geopandas / S的如此,而不是手动,包括他们在我的.spec文件我只是注释掉import geopandas.datasets的语句:File "site-packages\geopandas\__init__.py", line 9, in <module>

这正确编译并为我的程序提供了预期的输出。