Polars 用同步连接读数据库,却报 SQLAlchemy 缺少 greenlet
Polars 1.44.2 识别同步 SQLAlchemy 2.1 连接时也会导入 asyncio,缺 greenlet 就失败。区分依赖补齐与 Polars 2 修复,并核对同步读取。
pl.read_database() 接收的是普通 SQLAlchemy 同步连接,堆栈却进入 sqlalchemy.ext.asyncio,最后报缺少 greenlet。如果组合是 Polars 1.44.2 和 SQLAlchemy 2.1,先检查连接类型识别这一层,不必把同步查询重写成异步。
这条路径的错误通常连在一起:
ModuleNotFoundError: No module named 'greenlet'
ImportError: The SQLAlchemy asyncio module requires that the Python 'greenlet' library is installed.
SQLAlchemy 2.1 将 greenlet 放入 sqlalchemy[asyncio] 可选依赖。只做同步访问时,没有安装它本来是允许的;受影响的 Polars 却在判断传入对象是不是 Session 时,无条件导入了 AsyncSession。错误发生在识别连接的过程中,还没有说明 SQL 有问题。
先确认是哪一层需要了异步依赖
核对实际执行程序的解释器、Polars 和 SQLAlchemy 版本,并看完整堆栈里是否经过 ConnectionExecutor._is_alchemy_session。如果业务代码本来就在创建 AsyncEngine,或者另一个库主动导入了 asyncio 扩展,那是实际异步依赖,应按对应组件安装要求处理。
下面是只用同步连接的最小结构,不包含业务表或写入:
import polars as pl
from sqlalchemy import create_engine
engine = create_engine("sqlite:///:memory:")
try:
with engine.connect() as connection:
frame = pl.read_database("SELECT 1 AS x", connection=connection)
print(frame)
finally:
engine.dispose()
这里的 SQLite 内存库用于隔离连接适配行为。生产连接字符串、权限和网络问题应留在后续检查,不能用更改生产数据库来验证一个 Python 导入错误。
两种处理对应不同的依赖约束
Polars 2.0.0 的正式实现已经把异步类型导入放进 try/except ImportError:同步 Session 先识别,异步模块无法加载时返回不匹配,不再阻断同步连接。项目能够采用 Polars 2 时,可沿现有依赖管理流程升级并重新锁定版本;2.0 同时有其他行为变化,应按项目用到的接口检查迁移,不能为这条错误直接覆盖整个环境。
暂时保留旧 Polars 时,可以给已经使用的 SQLAlchemy 声明 asyncio extra,让它带上 greenlet。例如需要保留案例中的 SQLAlchemy 2.1.1,可在相同虚拟环境中使用:
python -m pip install "sqlalchemy[asyncio]==2.1.1"
由 uv、Poetry 或项目锁文件管理依赖时,应修改相应声明并更新锁文件,而不是只在一台机器上额外装包。这个办法补齐旧识别路径要求的依赖,不会把现有同步代码变成异步,也不要求另建 AsyncSession。
不要把导入错误与 MissingGreenlet: greenlet_spawn has not been called 混为一谈。后者常涉及异步 ORM 属性访问时触发隐式 I/O;已经安装 greenlet,也不代表那个问题会消失。
更新后先沿同一同步连接执行只读查询,核对结果列、行数和类型,再覆盖实际使用的数据库驱动。若选择升级修复路径,验收环境应保留“没有安装 asyncio extra”的原始条件;否则新加的依赖会遮住是否真正修好了连接判断。最后确认连接按原生命周期关闭,不能只以导入成功作为数据库读取验收。


