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

时间:2018-08-02 22:06:00

标签: python pyinstaller geopandas

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

  • Windows 10
  • PyInstaller 3.3.1
  • Geopandas 0.4

这是源代码:

print("Hello, StackOverflow")
import geopandas as gpd

这是编译后的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

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

Geopandas已正确安装在Python 3.6.3虚拟环境中(通过PIP,我也尝试过0.4和0.3版本),并且在编译之前就可以正常工作(即python application.py成功运行)。 / p>

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

我怀疑可能需要进行一些隐藏的进口。我对PyInstaller来说还很陌生,因此将不胜感激。

2 个答案:

答案 0 :(得分:2)

似乎geopandas正在init上积极加载其数据目录。它包含软件包中pyinstaller会忽略的非python文件,因此,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...

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

“自动”方式是构建一个hook-geopandas.py文件来为您完成此任务。 pyinstaller会在您进行构建时加载这些挂钩,以节省和共享这些技巧。实际上,已经有一个非常不错的shapely依赖文件,它是geopandas依赖项之一,您可以查看here

------编辑--------

我目前还在构建一个依赖于geopandas的项目,并且我意识到由于此issue,截至该日期(2018-08-23),上述修复尚未完成。

在我的run_it.py中,我进行了以下测试,以确保将fionagdal都正确地打包到捆绑软件中:

from osgeo import gdal, ogr, osr
from fiona.ogrext import Iterator, ItemsIterator, KeysIterator
from geopandas import GeoDataFrame

除非您是向导,否则此测试可能会失败。此垫片在我的.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
)

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

答案 1 :(得分:1)

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

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

我在项目中不使用geopandas数据集,因此,我没有在def __str__(self): return '{} - {} ({})'.format(self.pk, self.name, self.pcode) 中注释掉import geopandas.datasets语句,而是手动将它们包含在我的.spec文件中。

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