I usually can patch methods of normal objects using pytest monkeypatch. However when I try with a pydantic.BaseModel it fails.
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)
monkeypatch.setattr(p, 'intro', lambda: 'patched intro')
assert p.intro() == 'patched intro'
Raises:
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x10f0d3040>
def test_intro(monkeypatch):
p = Person(name='Joe', age=20)
> monkeypatch.setattr(p, 'intro', lambda: 'patched intro')
- - - - - - - - - - - - - - - - - - - - -
> ???
E ValueError: "Person" object has no field "intro"
pydantic/main.py:422: ValueError
2 Answers 2
You could patch the type:
def test_person_intro(monkeypatch):
p = Person(name='Joe', age=20)
monkeypatch.setattr(Person, 'intro', lambda self: 'patched intro')
assert p.intro() == 'patched intro'
Or you could set item in the instance dict:
def test_person_intro(monkeypatch):
p = Person(name='Joe', age=20)
monkeypatch.setitem(p.__dict__, 'intro', lambda: 'patched intro')
assert p.intro() == 'patched intro'
The reason an instance setattr isn't working as usual is that pydantic.BaseModel overrides __setattr__ to only allow a restricted set of names. You will see the same error doing person.intro = "other" as well, it is unrelated to pytest's monkeypatch fixture.
Comments
To simplify from the answer by wim, If wanting to patch manually, this worked for me:
p.__dict__['myattr'] = 'myval'
After this, p.myattr also worked.
Comments
Explore related questions
See similar questions with these tags.