Cannot import Geopandas with PyInstaller executable - despite running fine in the virtual env

前端 未结 2 1291
独厮守ぢ
独厮守ぢ 2021-01-06 17:52

When my Python application frozen with PyInstaller attempts to import Geopandas, it stops working.

  • Windows 10
  • PyInstaller 3.3.1
  • Geopandas 0.
相关标签:
2条回答
  • 2021-01-06 18:27

    looks like geopandas is aggressively loading their data directory on init. It contains non-python files that are ignored by pyinstaller in your package, so for geopandas to find them when you load it, they must be packaged explicitly.

    The "manual" process took me a while to figure out, and I'm using conda as my package manager (if you're not, these edits should still help you). To get this working we need to modify the .spec file that was built when you ran pyinstaller the first time:

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

    That should collect your missing data directory and put it where your executable can find it.

    The "auto" way would be to build a hook-geopandas.py file that does this for you. pyinstaller loads these hooks when you build as a way of saving and sharing these tricks. In fact, there's already a very nice hook file for shapely, one of geopandas dependencies, that you can review here.

    ------EDIT--------

    I am also currently building a project that depends on geopandas and I realized that the fix above is incomplete as of this date (2018-08-23) because of this issue.

    In my run_it.py i have included the following test to ensure fiona and gdal are all packaged up correctly into the bundle:

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

    This test will probably fail for you unless you're a wizard. This shim worked for me in my .spec file:

    _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
    )
    

    I hope this helps make this answer more complete, and your bundled app do it's geospatial things as expected.

    0 讨论(0)
  • 2021-01-06 18:46

    I received this same error and solved it differently to aorr above.

    The error was caused because the geopandas datasets included in the package aren't found by pyinstaller because they are .shp files.

    I don't use the geopandas datasets in my project/s so instead of manually including them in my .spec file I just commented out the import geopandas.datasets statement from: File "site-packages\geopandas\__init__.py", line 9, in <module>.

    This compiled properly and gave me the expected outputs for my program.

    0 讨论(0)
提交回复
热议问题