使用py2exe编译依赖Google Cloud Python API的脚本后出现ImportError求助
我之前也踩过py2exe打包Google Cloud API脚本的坑,这种ImportError大多是因为Google Cloud库的动态导入特性或者依赖的额外文件没被正确打包导致的,给你几个针对性的解决思路:
py2exe的静态依赖分析经常抓不到Google Cloud库中动态导入的子模块,毕竟很多Google Cloud组件是按需加载的。你可以在setup.py里明确列出所有用到的Google Cloud模块,确保它们被打包进去:
from distutils.core import setup import py2exe setup( console=['你的脚本文件名.py'], options={ 'py2exe': { # 先把核心的Google Cloud包列进去 'packages': ['google.cloud', 'google.auth', 'googleapiclient', 'google.api_core'], # 再加上你实际用到的具体子模块,比如用了存储就加google.cloud.storage 'includes': ['google.cloud.storage', 'google.cloud.bigquery'] } } )
记得把里面的模块替换成你脚本实际依赖的部分,别漏了。
Google Cloud的不少模块会依赖.proto协议文件、配置模板或者证书相关的文件,这些文件py2exe默认不会自动打包。你需要手动把它们包含进去:
- 第一种方法:找到你Python环境下的
google目录,把里面的protobuf文件夹(包含.proto文件)、credentials相关文件夹,以及你脚本用到的服务账号JSON文件,复制到生成的dist文件夹对应的路径下。 - 第二种方法:在
setup.py里用data_files参数自动打包这些文件,比如:
import os from distutils.core import setup import py2exe # 自动收集Google Cloud的proto文件 google_root = os.path.dirname(__import__('google').__file__) proto_files = [] for root, _, files in os.walk(os.path.join(google_root, 'protobuf')): for file in files: if file.endswith('.proto'): # 保持相对路径结构,这样exe运行时能找到 target_dir = root.replace(google_root, 'google/protobuf') proto_files.append((target_dir, [os.path.join(root, file)])) setup( console=['你的脚本文件名.py'], data_files=proto_files, options={ 'py2exe': { 'packages': ['google.cloud'] } } )
如果Google Cloud库用了importlib之类的方式动态导入子模块,py2exe根本检测不到。这时候你可以在主脚本的开头手动导入这些可能被动态加载的模块,让py2exe能识别到它们:
# 在脚本最顶部添加这些导入,不需要实际使用,只是让py2exe打包时包含它们 import google.cloud.storage import google.cloud.bigquery import google.auth.transport.requests import google.api_core.retry
别只看笼统的ImportError提示,一定要仔细看错误信息里具体缺失的模块名,比如如果提示No module named 'google.api_core.operations_v1',就把这个模块加到setup.py的includes里。
另外,你可以用py2exe的 verbose模式查看打包过程,看看哪些模块被跳过了:
python setup.py py2exe -v
有时候是版本兼容性问题,旧版py2exe对新版Google Cloud库的支持不够好。先把py2exe和Google Cloud相关库都升级到最新版试试:
pip install --upgrade py2exe pip install --upgrade google-cloud-storage google-cloud-bigquery google-auth google-api-core
内容的提问来源于stack exchange,提问作者Yusuf Siddiqui

