detect when EmbeddedDocumentListField receives an EmbeddedDocument instance instead of a list. It is a common mistake and the error wasn't meaningful (was fired from _from_son)

(relates to #1464)
This commit is contained in:
Bastien Gérard 2018-09-04 22:25:53 +02:00
parent 032ace40d1
commit 193656e71b
2 changed files with 45 additions and 2 deletions

View File

@ -313,11 +313,16 @@ class ComplexBaseField(BaseField):
if hasattr(value, 'to_python'):
return value.to_python()
BaseDocument = _import_class('BaseDocument')
if isinstance(value, BaseDocument):
# Something is wrong, return the value as it is
return value
is_list = False
if not hasattr(value, 'items'):
try:
is_list = True
value = {k: v for k, v in enumerate(value)}
value = {idx: v for idx, v in enumerate(value)}
except TypeError: # Not iterable return the value
return value

View File

@ -3868,7 +3868,7 @@ class FieldTest(MongoDBTestCase):
assert isinstance(doc.field, ToEmbedChild)
assert doc.field == to_embed_child
def test_invalid_dict_value(self):
def test_dict_field_invalid_dict_value(self):
class DictFieldTest(Document):
dictionary = DictField(required=True)
@ -3882,6 +3882,22 @@ class FieldTest(MongoDBTestCase):
test.dictionary # Just access to test getter
self.assertRaises(ValidationError, test.validate)
def test_dict_field_raises_validation_error_if_wrongly_assign_embedded_doc(self):
class DictFieldTest(Document):
dictionary = DictField(required=True)
DictFieldTest.drop_collection()
class Embedded(EmbeddedDocument):
name = StringField()
embed = Embedded(name='garbage')
doc = DictFieldTest(dictionary=embed)
with self.assertRaises(ValidationError) as ctx_err:
doc.validate()
self.assertIn("'dictionary'", str(ctx_err.exception))
self.assertIn('Only dictionaries may be used in a DictField', str(ctx_err.exception))
def test_cls_field(self):
class Animal(Document):
meta = {'allow_inheritance': True}
@ -3980,6 +3996,28 @@ class EmbeddedDocumentListFieldTestCase(MongoDBTestCase):
self.Comments(author='user3', message='message1')
]).save()
def test_fails_upon_validate_if_provide_a_doc_instead_of_a_list_of_doc(self):
# Relates to Issue #1464
comment = self.Comments(author='John')
class Title(Document):
content = StringField()
# Test with an embeddedDocument instead of a list(embeddedDocument)
# It's an edge case but it used to fail with a vague error, making it difficult to troubleshoot it
post = self.BlogPost(comments=comment)
with self.assertRaises(ValidationError) as ctx_err:
post.validate()
self.assertIn("'comments'", str(ctx_err.exception))
self.assertIn('Only lists and tuples may be used in a list field', str(ctx_err.exception))
# Test with a Document
post = self.BlogPost(comments=Title(content='garbage'))
with self.assertRaises(ValidationError) as e:
post.validate()
self.assertIn("'comments'", str(ctx_err.exception))
self.assertIn('Only lists and tuples may be used in a list field', str(ctx_err.exception))
def test_no_keyword_filter(self):
"""
Tests the filter method of a List of Embedded Documents