From 8bf5370b6cdac97e00b314d6cd57016494a25873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Mon, 28 Oct 2019 22:05:13 +0100 Subject: [PATCH 1/2] Improve error message from InvalidDocumentError whenever an embedded document has a bad shape (e.g due to migration) --- docs/changelog.rst | 1 + mongoengine/base/document.py | 9 +++++++-- tests/document/test_instance.py | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 5422f113..a717b837 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -15,6 +15,7 @@ Development - If you catch/use ``MongoEngineConnectionError`` in your code, you'll have to rename it. - BREAKING CHANGE: Positional arguments when instantiating a document are no longer supported. #2103 - From now on keyword arguments (e.g. ``Doc(field_name=value)``) are required. +- Improve error message related to InvalidDocumentError #2180 - Fix updating/modifying/deleting/reloading a document that's sharded by a field with ``db_field`` specified. #2125 - ``ListField`` now accepts an optional ``max_length`` parameter. #2110 - The codebase is now formatted using ``black``. #2109 diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index a962a82b..a967436a 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -732,7 +732,10 @@ class BaseDocument(object): only_fields = [] if son and not isinstance(son, dict): - raise ValueError("The source SON object needs to be of type 'dict'") + raise ValueError( + "The source SON object needs to be of type 'dict' but a '%s' was found" + % type(son) + ) # Get the class name from the document, falling back to the given # class if unavailable @@ -770,7 +773,9 @@ class BaseDocument(object): errors_dict[field_name] = e if errors_dict: - errors = "\n".join(["%s - %s" % (k, v) for k, v in errors_dict.items()]) + errors = "\n".join( + ["Field '%s' - %s" % (k, v) for k, v in errors_dict.items()] + ) msg = "Invalid data to create a `%s` instance.\n%s" % ( cls._class_name, errors, diff --git a/tests/document/test_instance.py b/tests/document/test_instance.py index 9b4a16e5..60e5313d 100644 --- a/tests/document/test_instance.py +++ b/tests/document/test_instance.py @@ -3656,6 +3656,29 @@ class TestInstance(MongoDBTestCase): with self.assertRaises(DuplicateKeyError): User.objects().select_related() + def test_embedded_document_failed_while_loading_instance_when_it_is_not_a_dict( + self + ): + class LightSaber(EmbeddedDocument): + color = StringField() + + class Jedi(Document): + light_saber = EmbeddedDocumentField(LightSaber) + + coll = Jedi._get_collection() + Jedi(light_saber=LightSaber(color="red")).save() + _ = list(Jedi.objects) # Ensure a proper document loads without errors + + # Forces a document with a wrong shape (may occur in case of migration) + coll.insert_one({"light_saber": "I_should_be_a_dict"}) + + with self.assertRaises(InvalidDocumentError) as cm: + list(Jedi.objects) + self.assertEqual( + str(cm.exception), + "Invalid data to create a `Jedi` instance.\nField 'light_saber' - The source SON object needs to be of type 'dict' but a '' was found", + ) + class ObjectKeyTestCase(MongoDBTestCase): def test_object_key_simple_document(self): From 54ca7bf09fa70a4fba3d83d8fc77090cddaaae67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Mon, 28 Oct 2019 22:38:21 +0100 Subject: [PATCH 2/2] fix associated test to avoid discrepencies btw py2 and py3 --- tests/document/test_instance.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/document/test_instance.py b/tests/document/test_instance.py index 60e5313d..7a868d29 100644 --- a/tests/document/test_instance.py +++ b/tests/document/test_instance.py @@ -3670,13 +3670,16 @@ class TestInstance(MongoDBTestCase): _ = list(Jedi.objects) # Ensure a proper document loads without errors # Forces a document with a wrong shape (may occur in case of migration) - coll.insert_one({"light_saber": "I_should_be_a_dict"}) + value = u"I_should_be_a_dict" + coll.insert_one({"light_saber": value}) with self.assertRaises(InvalidDocumentError) as cm: list(Jedi.objects) + self.assertEqual( str(cm.exception), - "Invalid data to create a `Jedi` instance.\nField 'light_saber' - The source SON object needs to be of type 'dict' but a '' was found", + "Invalid data to create a `Jedi` instance.\nField 'light_saber' - The source SON object needs to be of type 'dict' but a '%s' was found" + % type(value), )