You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pytest使用前置fixture运行后自定义Frozen描述符失效问题排查

问题根因

这个问题的核心原因是你使用的ORM(从start_mappers/clear_mappers逻辑判断为SQLAlchemy这类数据映射器ORM)在启动映射时,会直接覆盖Patient类上你预定义的first_name、email类属性,替换为ORM自带的属性描述符(如SQLAlchemy的InstrumentedAttribute),你自己实现的Frozen描述符被直接替换失效,赋值时自然不会触发你写的只读校验逻辑。
手动实例化时没有启动ORM映射,描述符正常生效,所以可以正常抛出错误。只要session fixture先执行触发了start_mappers,后续所有使用Patient类的测试都会继承被ORM修改后的类属性,导致只读校验失效。

额外提示:你原有Frozen描述符的错误提示存在逻辑问题,显示的是赋值内容的类型名而非属性名,用户无法从报错判断是哪个属性触发了只读限制,后续优化时可以改为返回属性名self.storage_name。

可行解决方案

方案1:改用__setattr__实现只读校验,避免被ORM覆盖

这种方案在实例层面拦截所有属性赋值,优先级高于类属性的描述符,不会被ORM的映射操作影响,兼容性最好:

class Patient:
    # 定义只读属性列表
    _READONLY_ATTRS = {"first_name", "email"}

    def __init__(self, first_name: str, email: str, phone: str, age: int, gender: str, last_name="", weekly_meals: WeeklyMeals = None, nutrition_plan: NutritionPlan = None) -> None:
        self.first_name = first_name
        self.last_name = last_name
        self.email = email
        self.phone = phone
        self.age = age
        self.gender = gender
        self.weekly_meals = weekly_meals
        self.nutrition_plan = nutrition_plan
        self.receipt_line_mapping = dict()
        self.meals = list()

    def __setattr__(self, key, value):
        # 已存在的只读属性禁止修改,初始化阶段允许正常赋值
        if key in self._READONLY_ATTRS and key in self.__dict__:
            raise AttributeError(f'readonly attribute {key}')
        super().__setattr__(key, value)

方案2:在ORM映射配置中保留自定义描述符

如果你使用的是SQLAlchemy,可以在列定义时指定descriptor参数,明确使用你自己的Frozen描述符,避免被ORM默认逻辑覆盖:

# ORM映射定义示例
from sqlalchemy.orm import mapper, Column, String
from your_module import Patient

first_name_col = Column(String)
email_col = Column(String)

mapper(
    Patient,
    patient_table_def,
    properties={
        "first_name": first_name_col.with_descriptor(Frozen()),
        "email": email_col.with_descriptor(Frozen())
    }
)

方案3:测试隔离,拆分单元测试与集成测试

不需要ORM参与的纯领域模型单元测试不要依赖session fixture,也不要触发start_mappers逻辑,避免ORM修改你的原始模型类。可以用pytest的标记把测试分成单元测试、集成测试两类,分开执行避免互相影响。

内容的提问来源于stack exchange,提问作者Joaquim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 08:45:04