PyInstaller打包Python程序导入exchangelib报zoneinfo属性缺失错误
PyInstaller打包exchangelib依赖导入失败问题
问题背景
开发可定时连接Exchange Server向收件人发送邮件的Python应用,程序运行依赖exchangelib库:
- 直接运行
.py源文件时,无论通过命令行还是Jupyter Notebook启动,均可正常导入exchangelib及全部所需组件,运行无异常 - 使用PyInstaller将程序打包为exe可执行文件后运行,触发导入失败报错
测试复现代码
print("Attempting: import exchangelib") try: import exchangelib print("SUCCESS: import exchangelib") except Exception as expOutput: print("FAILED: import exchangelib") print(expOutput) print("Attempting: from exchangelib import DELEGATE, Account, Credentials, Configuration, Message, Mailbox, FileAttachment, HTMLBody") try: from exchangelib import DELEGATE, Account, Credentials, Configuration, Message, Mailbox, FileAttachment, HTMLBody print("SUCCESS: import DELEGATE, Account, Credentials, Configuration, Message, Mailbox, FileAttachment, HTMLBody") except Exception as expNewOutput: print(expNewOutput)
运行结果对比
直接运行py文件的正常输出
"SUCCESS: import exchangelib" "SUCCESS: import DELEGATE, Account, Credentials, Configuration, Message, Mailbox, FileAttachment, HTMLBody"
打包为exe后的报错输出
Attempting: import exchangelib FAILED: import exchangelib module 'zoneinfo' has no attribute 'ZoneInfoNotFoundError' Attempting: from exchangelib import DELEGATE, Account, Credentials, Configuration, Message, Mailbox, FileAttachment, HTMLBody module 'zoneinfo' has no attribute 'ZoneInfoNotFoundError'
原使用的打包命令
C:\>cd C:\Users\aguler\AppData\Roaming\Python\Python37 C:\Users\aguler\AppData\Roaming\Python\Python37>ProjectEnvironment\Scripts\activate.bat (ProjectEnvironment) C:\Users\aguler\AppData\Roaming\Python\Python37>Scripts\pyinstaller --onefile C:\PyFiles\Email_Troubleshoot\Test_exchangelib.py --paths=C:\Users\aguler\AppData\Roaming\Python\Python37\site-packages\tzdata --paths=C:\Users\aguler\AppData\Roaming\Python\Python37\site-packages\tzdata\zoneinfo --paths=C:\users\aguler\appdata\roaming\python\python37\projectenvironment\lib\site-packages\exchangelib --paths=C:\Users\aguler\AppData\Roaming\Python\Python37\ProjectEnvironment\Lib\site-packages\backports
问题根因
Python3.7无内置zoneinfo模块,exchangelib通过backports.zoneinfo回退包调用时区相关能力;原打包命令中手动添加的多个--paths参数直接指向依赖的子目录,打乱了模块导入层级,且PyInstaller默认无法自动识别backports这类命名空间包的动态导入逻辑,未将完整的backports.zoneinfo相关依赖打包进exe,导致运行时找不到ZoneInfoNotFoundError属性。
解决步骤
- 先删除之前打包生成的
build、dist文件夹,以及同目录下生成的.spec打包配置文件,避免旧配置干扰 - 移除原打包命令中所有指向依赖子目录的
--paths参数,这类参数仅用于添加Python模块搜索的根目录,指向子目录会破坏模块导入的层级关系 - 调整打包命令,显式声明需要收集的隐藏依赖与时区数据,修改后的命令如下(虚拟环境激活状态下执行):
pyinstaller --onefile C:\PyFiles\Email_Troubleshoot\Test_exchangelib.py ^ --hidden-import backports.zoneinfo ^ --hidden-import backports.zoneinfo._common ^ --hidden-import backports.zoneinfo._zoneinfo ^ --collect-all backports.zoneinfo ^ --collect-all tzdata
- 若执行上述命令后仍存在导入报错,可在测试代码的最顶部(所有
exchangelib相关导入之前)添加一行显式导入,强制PyInstaller识别依赖:
from backports.zoneinfo import ZoneInfoNotFoundError
注意:打包完成后可先在命令行中启动生成的exe,确认输出两个SUCCESS提示即为修复完成。
内容的提问来源于stack exchange,提问作者AGuler
相关产品推荐
相关产品推荐

