-
Notifications
You must be signed in to change notification settings - Fork 258
Description
Describe the bug
When a custom base class is used which inherits from beanie.Document
, the base class gets modified when init_beanie()
is called. This leads to bugs later on if init_beanie()
is called again with a different model that inherits from the same class.
Usually I try to avoid calling init_beanie()
multiple times, but I was writing a tutorial in a Python notebook and there I ran into this issue...
To Reproduce
from beanie import Document, init_beanie
from pymongo import AsyncMongoClient
async def test_inheritance_bug():
client = AsyncMongoClient("mongodb://root:secret@localhost:27017")
database = client.get_database("test")
class A(Document):
a: str | None = None
await init_beanie(database=database, document_models=[A])
a = A(a="foo")
assert a.id is None
class B(Document):
b: str | None = None
await init_beanie(database=database, document_models=[B])
b = B(b="bar")
assert b.id is None
class MyDocument(Document):
pass
class A2(MyDocument):
a: str | None = None
await init_beanie(database=database, document_models=[A2])
a2 = A2(a="foo")
assert a2.id is None
class B2(MyDocument):
b: str | None = None
await init_beanie(database=database, document_models=[B2])
b2 = B2(b="bar")
# THIS FAILS: B2(id='_id', revision_id='revision_id', b='bar')
assert b2.id is None
Expected behavior
It should be possible to call init_beanie()
multiple times during the runtime of an application without things breaking (even if it's not best practice). In this case, things are breaking
Additional context
When init_beanie
is called with MyDocument
for the first time, two new fields are assigned to the MyDocument
type: id: ExpressionField = '_id'
and revision_id: ExpressionField = 'revision_id'
. This causes subsequent failures, since now every new instance of the model has '_id'
as object id, which is invalid.
The issue does not come up if you declare B2
before you call init_beanie
, even if you don't add B2
to the document_models
. In any case, this is not a viable workaround for me, since I need to be able to declare new models later on in my jupyter notebook.