Glue Python Shell 升 3.9 后 import pg 报 ModuleNotFoundError:PyGreSQL 预装消失的解法与 C 扩展 wheel 编译配方
内容性质:解决方案(solution)。基于中国区真实 Glue Python Shell 2.0/Python 3.9 环境实测。编译配方部分对任何"链接系统库的 C 扩展"通用。可指导客户。
概述
Glue Python Shell 作业从 Python 3.6 升级到 3.9 后,代码中 import pg(PyGreSQL 库)报错:
File ".../pygresql_redshift_common.py", line 1, in <module> import pg
ModuleNotFoundError: No module named 'pg'
一句话结论:Python 3.6 运行时预装了 PyGreSQL 5.0.6,Python 3.9 的 analytics 库集把它移除了(改为预装 psycopg2 2.9.3 与 redshift-connector 2.0.907)。3.6 时代 import pg 靠的是预装库这个隐式依赖,升级后依赖消失,需要客户自带或改代码。
值得注意的是,官方文档"Python shell 作业提供自有库"一节的 redshift_module 示例代码正是 import pg 的写法——照该示例写的历史代码在 3.9 下都会踩到这个问题。
根因确认方法
官方文档的预装库对照表(Python 3.6 列 vs Python 3.9 analytics 列):
https://docs.amazonaws.cn/glue/latest/dg/add-job-python.html#python-shell-supported-library
关键行:
| 库 | Python 3.6 | Python 3.9 (analytics) |
|---|---|---|
| PyGreSQL | 5.0.6 | (无) |
| psycopg2 | (无) | 2.9.3 |
| redshift-connector | (无) | 2.0.907 |
只要代码 import pg / import pgdb 且作业从 3.6 升上来,即可断定是本问题。
解法一(长期推荐):改用 3.9 预装驱动
把连接逻辑从 pg 迁到预装的 redshift_connector(Amazon 官方 Redshift 驱动)或 psycopg2,之后不需要自带任何 wheel。以 redshift_connector 为例:
# 原 PyGreSQL 写法
import pg
conn = pg.connect(dbname="host=%s port=%s dbname=%s user=%s password=%s" % (...))
res = conn.query("select ...") # 直接返回结果
# 迁移后(DB-API 2.0 风格)
import redshift_connector
conn = redshift_connector.connect(host=host, port=int(port), database=db_name,
user=user, password=password)
cursor = conn.cursor()
cursor.execute("select ...")
res = cursor.fetchall() # execute + fetch 两步
迁移注意点(客户最易踩):
port必须是 int——Glue 作业参数取出来是字符串,直接传会报错;- PyGreSQL 的
conn.query()直接返回结果,DB-API 需要cursor.execute()+fetchall(); - DB-API 默认不自动提交事务,有写入需
conn.commit()或conn.autocommit = True(PyGreSQL 经典接口没有这层)。
解法二:自带 PyGreSQL wheel(不改代码)
为什么不能直接 pip 下载
PyPI 上 PyGreSQL 所有版本都只发布 Windows wheel(win32/win_amd64)与源码包,没有任何 Linux wheel(可查任一版本的 Files 页,如 https://pypi.org/project/PyGreSQL/5.2.5/#files )。它是 C 扩展、链接 libpq,Linux 环境必须从源码编译——纯内网客户自己装不上,需要编译交付。
版本怎么选
| 版本 | 判定 | 原因 |
|---|---|---|
| 5.0.6(3.6 预装同款) | ❌ | 官方支持最高到 Python 3.7,无 cp39 支持 |
| 5.2.5 | ✅ | 5.2.x 起正式支持 3.9;5.2.5 是 5.x 最后一版,完整保留经典 pg/pgdb 双接口,客户代码零修改 |
| 6.x | ❌ | API 有破坏性调整,客户代码要改(要改代码不如直接走解法一) |
编译配方(manylinux2014 容器,实测一次成功)
docker run --rm -v $PWD/pgbuild:/io quay.io/pypa/manylinux2014_x86_64 bash -c '
yum install -y postgresql-devel # libpq 头文件
/opt/python/cp39-cp39/bin/pip wheel PyGreSQL==5.2.5 --no-deps -w /io/raw
auditwheel repair /io/raw/*.whl -w /io/fixed'
产物:pygresql-5.2.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl(约 3.7 MB)。
配方要点(通用于其他链接系统库的 C 扩展):
auditwheel repair是关键——把 wheel 动态链接的系统库(本例 libpq 及其依赖 .so)复制进 wheel 并改 rpath,目标环境无需装 postgresql 客户端;- 基线选 manylinux2014(glibc 2.17):Glue Python Shell 3.9 运行时是 Amazon Linux 2 / glibc 2.26,2.17 基线一定兼容。不要在 glibc > 2.26 的系统(如 AL2023)上裸编译;
- manylinux2014 官方镜像内置 cp39(
/opt/python/cp39-cp39/),不要用 Glue 官方 Docker 镜像(其 Python 版本与 Python Shell 全不匹配); - PyGreSQL 的 sdist 无 Python 依赖声明,产出 wheel 无
Requires-Dist,纯内网 pip 安装零联网,无需做剥依赖处理(对比 s3fs 等有依赖声明的包)。 - 宿主机若是 RHEL9 系(docker 实为 podman),挂载卷需加
:z做 SELinux relabel,否则容器内写挂载目录报 PermissionError。
真实环境验证结果
GlueVersion 2.0 + PythonVersion 3.9 + library-set=analytics + --extra-py-files 挂该 wheel,探测作业 SUCCEEDED:
Successfully installed pygresql-5.2.5,全程无 pip 联网(日志无Collecting/ 大写Downloading);import pg/import pgdb正常,pg.version = 5.2.5,pg.DB、pg.connect等经典接口齐全;- 对不可达地址
pg.connect()返回干净的 libpq 网络错误(could not connect to server),证明捆绑的 .so 加载正常、无 ABI 问题。
客户侧使用:wheel 上传自己的 S3 → 追加进 --extra-py-files(英文逗号分隔)→ 其余配置不变。
关键判断点
- 作业运行成功但
import报 ModuleNotFoundError,除了"egg 被 3.9 静默忽略"这个常见原因外,还要想到预装库集变化——对照官方预装表看该库是否只在 3.6 列存在。 - 客户问"为什么不用原来的 5.0.6":PyPI Files 页即是证据(5.0.6 预编译包最高 cp37;5.2.2 起才有 cp39)。
- 给客户交付前必须在真实 Glue 环境实测(探测作业跑 import + 连接冒烟),本地 venv 装得上不代表 Glue 装得上。
参考
- Python shell 预装库对照表:https://docs.amazonaws.cn/glue/latest/dg/add-job-python.html#python-shell-supported-library
- PyGreSQL PyPI Files(各版本发布文件):https://pypi.org/project/PyGreSQL/#history
- redshift-connector 文档:https://docs.amazonaws.cn/redshift/latest/mgmt/python-connect.html
- auditwheel:https://github.com/pypa/auditwheel
- 相关 KB:《确定 Glue Python Shell 真实运行时并离线打包 wheel》《Glue Python Shell 纯内网环境离线安装 Python 库的机制与实践》《Glue Python Shell 从 Python 3.6 迁移到 3.9:库依赖不兼容的排查与处理》