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

Updating an inner dict within a DictField of a DynamicDocument raise an AttributeError #2795

Open
karimelhajoui63 opened this issue Jan 27, 2024 · 1 comment

Comments

@karimelhajoui63
Copy link

Hi,

Details:

I have an issue with the updating of a DictField of a DynamicDocument that sometimes raises an exception.
It seems that there is a bug in mongoengine (more precisely in the _changed_fields) when we try to update a key of an inner dict, within the DictField that is at the top level of the Document.
As far as I dug, it seems to be because the inner dict is considered as a BaseDict, so when it is updated, the inner dict is added to _changed_fields but this inner dict isn't a field of the document, so there is an AttributeError on save() (see traceback below).

One more thing: this seem to be the case only with DynamicDocument and not with Document. And there is also no exception raised when the document came from the database.

Tested on versions:

  • Python 3.10.13
  • MongoEngine 0.27.0
  • PyMongo 4.6.1

Code to reproduce the bug:

from mongoengine import connect, DictField, DynamicDocument

connect("test", host="mongodb://localhost:27018/test")

class ExampleModel(DynamicDocument):  # but there is no exception at all with `Document`
    root_dict = DictField(default=None)
    

ExampleModel.objects().delete()  # just in case

example = ExampleModel()
example.root_dict = {"inner_dict":{"key": "value"}}
example.save()  # ✅

if example.root_dict["inner_dict"]["key"]:
    print("'inner_dict' is present in 'example'")

# ------------------

# example.reload()  # <-- with this line uncommented, no exception is raised

example.root_dict["inner_dict"]["key"] = "NEW_value"
try:
    example.save()  # raise "AttributeError" ❌
except AttributeError as exc:
    print(exc)
else:
    print("No exception for 'example'")

# ------------------
    
example_from_db = ExampleModel.objects().first()
example_from_db.root_dict["inner_dict"]["key"] = "NEW_value"
try:
    example_from_db.save()  # don't raise any exception ✅
except AttributeError as exc:
    print(exc)
else:
    print("No exception for 'example_from_db'")

Output of this program:

'inner_dict' is present in 'example'
'ExampleModel' object has no attribute 'inner_dict'
No exception for 'example_from_db'

Complete traceback of the error on .save():

Traceback (most recent call last):
  File "/workspaces/bin/personal/mongoengine_dictfield.py", line 23, in <module>
    example.save()
  File "/workspaces/.venv/lib/python3.10/site-packages/mongoengine/document.py", line 429, in save
    object_id, created = self._save_update(
  File "/workspaces/.venv/lib/python3.10/site-packages/mongoengine/document.py", line 545, in _save_update
    update_doc = self._get_update_doc()
  File "/workspaces/.venv/lib/python3.10/site-packages/mongoengine/document.py", line 501, in _get_update_doc
    updates, removals = self._delta()
  File "/workspaces/.venv/lib/python3.10/site-packages/mongoengine/base/document.py", line 746, in _delta
    d = getattr(d, real_path)
AttributeError: 'ExampleModel' object has no attribute 'inner_dict'
@karimelhajoui63
Copy link
Author

Hi,
Who should I tag for this ? @bagerard ?

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

1 participant