使用PyInstaller打包含Geopandas的PyQT5地理空间GUI应用时Fiona模块循环导入错误的解决求助
这个AttributeError: partially initialized module 'fiona' has no attribute '_loading'是PyInstaller打包Geopandas相关应用时的典型问题,本质是Fiona的动态模块加载机制在打包后被破坏,加上循环导入触发导致的。结合你的场景,我给你几个针对性的解决思路:
1. 补充Fiona的关键内部隐式依赖
你的spec文件里已经加了fiona,但PyInstaller的静态分析没法捕获Fiona的内部动态导入模块,需要手动补充到hidden_imports里:
hidden_imports = [ 'fiona', 'fiona._loading', 'fiona.ogrext', 'fiona._shim', 'gdal', 'shapely', 'shapely.geometry', 'pyproj', 'rtree', 'geopandas.datasets', 'pytest', 'pandas._libs.tslibs.timedeltas', ]
这里新增的fiona._loading和fiona.ogrext是Fiona初始化时必须的核心模块,之前的缺失直接导致了循环导入报错。
2. 包含Fiona的GDAL配置文件
Fiona依赖GDAL的配置数据,打包时这些文件不会被自动包含,需要手动添加到datas中。找到你Anaconda环境里的Fiona安装路径(比如D:\Anaconda\envs\ox\Lib\site-packages\fiona),把里面的gdal_data目录和.cfg配置文件加进去:
datas=[ ('input', 'input'), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\branca\\*.json","branca"), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\branca\\templates","templates"), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\folium\\templates","templates"), # 新增Fiona相关数据 ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\fiona\\gdal_data", "fiona/gdal_data"), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\fiona\\*.cfg", "fiona"), ]
3. 尝试开启noarchive选项
把spec文件里的noarchive=False改成noarchive=True,这个选项会让PyInstaller不把所有模块打包成单个归档文件,而是保留原有的文件结构,能有效避免很多动态导入和循环初始化的问题:
a = Analysis(['main.py'], # ... 其他参数保持不变 noarchive=True)
4. 检查并升级依赖版本
旧版本的Fiona和Geopandas在PyInstaller打包时更容易出现兼容性问题,建议你升级到稳定版本:
pip install --upgrade fiona geopandas pyinstaller
推荐版本:Fiona >= 1.8.21,Geopandas >= 0.12.0,PyInstaller >= 5.0。
修改后的完整Spec文件示例
block_cipher = None hidden_imports = [ 'fiona', 'fiona._loading', 'fiona.ogrext', 'fiona._shim', 'gdal', 'shapely', 'shapely.geometry', 'pyproj', 'rtree', 'geopandas.datasets', 'pytest', 'pandas._libs.tslibs.timedeltas', ] a = Analysis(['main.py'], pathex=['D:\\CrowdSourcingV2'], binaries=[], datas=[ ('input', 'input'), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\branca\\*.json","branca"), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\branca\\templates","templates"), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\folium\\templates","templates"), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\fiona\\gdal_data", "fiona/gdal_data"), ("D:\\Anaconda\\envs\\ox\\Lib\\site-packages\\fiona\\*.cfg", "fiona"), ], hiddenimports=hidden_imports, hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=True) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='Crowdsourcing Tool', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=True, disable_windowed_traceback=False, target_arch=None, codesign_identity=None, entitlements_file=None )
按照上面的步骤修改后,重新运行pyinstaller your_spec_file.spec,应该就能解决这个循环导入的问题了。
内容的提问来源于stack exchange,提问作者Magnum Python 93'

