Python 3.14.1 加载 SQLAlchemy dataclass 模型报 KeyError: created_by
Python 3.14.1 在加载 SQLAlchemy dataclass 继承模型时可能因延迟注解缺键而失败,定位类创建阶段并升级到修复后的解释器。
应用升级 Python 补丁版本后,还没连接数据库就在定义 ORM 子类时退出,堆栈从 SQLAlchemy 进入 dataclasses.py、inspect.signature()、annotationlib.py,最后报 KeyError: 'created_by'。若字段来自带 declared_attr 的 dataclass mixin,并且模型有进一步继承,应检查 Python 3.14.1 的注解处理回归。
明确出现过的环境是 SQLAlchemy 2.0.44 与 Python 3.14.1。相关标准库修复已进入 Python 3.14.2;这不是整个 3.14 系列都必须退回旧版的问题,也不是数据库里少了一列。
看堆栈发生在哪个阶段
以下是能体现该类继承关系的模型定义,不需要创建数据库或执行 SQL:
from sqlalchemy import ForeignKey
from sqlalchemy.orm import (
DeclarativeBase, Mapped, MappedAsDataclass,
declared_attr, mapped_column, relationship,
)
class Base(MappedAsDataclass, DeclarativeBase):
pass
class User(Base):
__tablename__ = "user_account"
id: Mapped[int] = mapped_column(init=False, primary_key=True)
name: Mapped[str]
class CreatedByMixin(MappedAsDataclass, kw_only=True):
created_by_fk: Mapped[int] = mapped_column(
ForeignKey("user_account.id"), init=False,
)
@declared_attr
@classmethod
def created_by(cls) -> Mapped[User]:
return relationship(foreign_keys=[cls.created_by_fk])
class Item(CreatedByMixin, Base, kw_only=True):
__tablename__ = "item"
id: Mapped[int] = mapped_column(init=False, primary_key=True)
description: Mapped[str]
class SpecialItem(Item, kw_only=True):
__tablename__ = "special_item"
id: Mapped[int] = mapped_column(
ForeignKey("item.id"), init=False, primary_key=True,
)
special_description: Mapped[str]
这一分支的错误发生在 SpecialItem 类创建期间。若实际报错是 SQL 查询中的未定义列、non-default argument follows default argument,或实例化时缺少必填参数,应沿各自的堆栈处理,不能直接套用这个版本结论。
字段存在,注解却在稍后读取时缺了
SQLAlchemy 的映射注解与标准 dataclass 所需的注解不同。生成 dataclass 时,它会临时提供转换后的字段注解,再恢复原来的注解状态。来自 mixin 的声明属性可能参与生成构造函数,却不在恢复后的当前类注解字典中。
Python 3.14.1 在为生成的 dataclass 构造函数处理延迟注解时,存在“字段一定能从相应注解字典取到”的假设。进一步定义子类、检查构造签名时,就可能因缺少该键而失败。Python 3.14.2 对这类动态场景跳过无法取到的注解,避免该 KeyError。
移除 kw_only=True、给模型补一个 docstring,或把 created_by 随手改成默认 None,都不能作为可靠修复。它们还可能改变构造接口或关系含义。
换到修复后的解释器,保留模型的真实接口
先在实际服务、测试进程和镜像中记录 Python 及 SQLAlchemy 版本,确认没有编辑器使用新解释器、worker 仍使用旧镜像的情况。选择兼容项目且包含修复的 Python 3.14.2 或后续维护版本,在隔离环境中恢复锁定依赖,再检查模型导入。
SQLAlchemy 后续也改进了 dataclass 注解的临时替换与恢复逻辑,但这不构成继续支持该 Python 3.14.1 故障组合的理由。不要手工删除 __dataclass_fields__、修改 __annotations__ 或复制标准库函数来绕过启动错误。
模型能导入后,继续检查实际使用的子类构造方式、created_by 关系赋值、序列化和签名读取工具。尤其是接口文档生成、依赖注入或运行时类型检查也会读取注解,不能只用“进程没退出”判断完成。该故障发生在映射定义阶段,修复它本身不需要更改数据库表结构。


