Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Documents with multiple inheritance on top level are not properly initialised #1029

Open
ADR-007 opened this issue Sep 23, 2024 · 1 comment

Comments

@ADR-007
Copy link

ADR-007 commented Sep 23, 2024

Describe the bug

Models that have more than 1 base class on top level are skipped during the initialization, so they cannot be used for any query.

To Reproduce

class CustomBaseDocument(Document):
    my_custom_base_field: int

class Account(
    # any two classes inherited from Document:
    CustomBaseDocument,
    DocumentWithSoftDelete,
):
    name: str


account = Account(name="test", my_custom_base_field=42)
await account.save()
Error
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.venv/lib/python3.12/site-packages/beanie/odm/actions.py:239: in wrapper
    result = await f(
.venv/lib/python3.12/site-packages/beanie/odm/utils/state.py:85: in wrapper
    result = await f(self, *args, **kwargs)
.venv/lib/python3.12/site-packages/beanie/odm/utils/self_validation.py:19: in wrapper
    return await f(self, *args, **kwargs)
.venv/lib/python3.12/site-packages/beanie/odm/documents.py:611: in save
    return await self.update(
.venv/lib/python3.12/site-packages/beanie/odm/actions.py:239: in wrapper
    result = await f(
.venv/lib/python3.12/site-packages/beanie/odm/utils/state.py:85: in wrapper
    result = await f(self, *args, **kwargs)
.venv/lib/python3.12/site-packages/beanie/odm/documents.py:728: in update
    result = await self.find_one(find_query).update(
.venv/lib/python3.12/site-packages/beanie/odm/queries/update.py:351: in __await__
    update_result = yield from self._update().__await__()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <beanie.odm.queries.update.UpdateOne object at 0x1311c6990>

    async def _update(self):
        if not self.bulk_writer:
            if self.response_type == UpdateResponse.UPDATE_RESULT:
                return await self.document_model.get_motor_collection().update_one(
                    self.find_query,
                    self.update_query,
                    session=self.session,
                    **self.pymongo_kwargs,
                )
            else:
>               result = await self.document_model.get_motor_collection().find_one_and_update(
                    self.find_query,
                    self.update_query,
                    session=self.session,
                    return_document=ReturnDocument.BEFORE
                    if self.response_type == UpdateResponse.OLD_DOCUMENT
                    else ReturnDocument.AFTER,
                    **self.pymongo_kwargs,
                )
E               AttributeError: 'NoneType' object has no attribute 'find_one_and_update'

.venv/lib/python3.12/site-packages/beanie/odm/queries/update.py:319: AttributeError

Expected behavior
Document is saved as it happens when there is just a single base class

Additional context

Source of the problem:
beanie/odm/utils/init.py:

    class Initializer:
        ...
        async def init_document(self, cls: Type[Document]) -> Optional[Output]:
            ...
            bases = [b for b in cls.__bases__ if issubclass(b, Document)]
            if len(bases) > 1:
                return None
            ...
@staticxterm
Copy link

Hi, thank you for the report.

How would you know which Document to update? Just this one, the other, all of them? Beanie treats Document classes as their own separate Document instances in the DB, along with the collection they belong to.
Also I'm having trouble to understand which action would you like to be possible / what API. Could you give some usage examples, along with the expected outcome(s)?

You can use Pydantic models (that inherit from BaseModel) for the 'base classes'/models that you have, and then inherit from those for your Document's.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants