使用pytest monkeypatch打补丁Pydantic BaseModel方法时触发ValueError
解决Pydantic BaseModel实例用monkeypatch打补丁失败的问题
问题原因
Pydantic的BaseModel重写了__setattr__方法,会严格校验要设置的属性是否是模型定义的字段。你要补丁的intro是实例方法而非模型字段,直接用monkeypatch.setattr(p, 'intro', ...)会触发Pydantic的字段检查,抛出ValueError: "Person" object has no field "intro"错误。
解决方案
方案1:给类而非实例打补丁
直接修改Person类的intro方法,避开实例的字段检查,同时注意补丁函数要接收self参数(因为是实例方法):
from pydantic import BaseModel class Person(BaseModel): name: str age: int def intro(self) -> str: return f"I am {self.name}, {self.age} years old." def test_person_intro(monkeypatch): p = Person(name='Joe', age=20) # 给Person类的intro方法打补丁 monkeypatch.setattr(Person, 'intro', lambda self: 'patched intro') assert p.intro() == 'patched intro'
方案2:直接操作实例的__dict__绕过检查
通过修改实例的__dict__属性设置方法,绕过Pydantic的__setattr__校验,同样要保证补丁函数接收self:
from pydantic import BaseModel class Person(BaseModel): name: str age: int def intro(self) -> str: return f"I am {self.name}, {self.age} years old." def test_person_intro(monkeypatch): p = Person(name='Joe', age=20) # 直接修改实例的__dict__ monkeypatch.setattr(p.__dict__, 'intro', lambda self: 'patched intro') assert p.intro() == 'patched intro'
注意点
你原来写的lambda: 'patched intro'没有接收self参数,调用p.intro()时Python会自动把实例作为第一个参数传入,会导致参数不匹配报错,所以补丁函数必须加上self参数。
内容的提问来源于stack exchange,提问作者valcapp
相关产品推荐
相关产品推荐

