When my Python application frozen with PyInstaller attempts to import Geopandas, it stops working.
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.
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.