diff --git a/docs/changelog.rst b/docs/changelog.rst index 5718fd22..a49ed06f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,8 @@ Changelog Changes in 0.6.X ================ +- Invalid data from the DB now raises a InvalidDocumentError +- Cleaned up the Validation Error - docs and code - Added meta `auto_create_index` so you can disable index creation - Added write concern options to inserts - Fixed typo in meta for index options @@ -281,5 +283,3 @@ Changes in v0.1.2 Changes in v0.1.1 -================= -- Documents may now use capped collections diff --git a/mongoengine/base.py b/mongoengine/base.py index 63d2a8f0..b4530c93 100644 --- a/mongoengine/base.py +++ b/mongoengine/base.py @@ -979,8 +979,8 @@ class BaseDocument(object): """ # get the class name from the document, falling back to the given # class if unavailable - class_name = son.get(u'_cls', cls._class_name) - data = dict((str(key), value) for key, value in son.items()) + class_name = son.get('_cls', cls._class_name) + data = dict(("%s" % key, value) for key, value in son.items()) if '_types' in data: del data['_types'] @@ -993,11 +993,16 @@ class BaseDocument(object): cls = get_document(class_name) changed_fields = [] + errors_dict = {} + for field_name, field in cls._fields.items(): if field.db_field in data: value = data[field.db_field] - data[field_name] = (value if value is None + try: + data[field_name] = (value if value is None else field.to_python(value)) + except (AttributeError, ValueError), e: + errors_dict[field_name] = e elif field.default: default = field.default if callable(default): @@ -1005,7 +1010,13 @@ class BaseDocument(object): if isinstance(default, BaseDocument): changed_fields.append(field_name) + if errors_dict: + errors = "\n".join(["%s - %s" % (k, v) for k, v in errors_dict.items()]) + raise InvalidDocumentError(""" +Invalid data to create a `%s` instance.\n%s""".strip() % (cls._class_name, errors)) + obj = cls(**data) + obj._changed_fields = changed_fields obj._created = False return obj diff --git a/tests/document.py b/tests/document.py index 54b0b97a..68fb3a6c 100644 --- a/tests/document.py +++ b/tests/document.py @@ -2398,6 +2398,22 @@ class DocumentTest(unittest.TestCase): self.assertRaises(InvalidDocumentError, throw_invalid_document_error) + def test_invalid_son(self): + """Raise an error if loading invalid data""" + class Occurrence(EmbeddedDocument): + number = IntField() + + class Word(Document): + stem = StringField() + count = IntField(default=1) + forms = ListField(StringField(), default=list) + occurs = ListField(EmbeddedDocumentField(Occurrence), default=list) + + def raise_invalid_document(): + Word._from_son({'stem': [1,2,3], 'forms': 1, 'count': 'one', 'occurs': {"hello": None}}) + + self.assertRaises(InvalidDocumentError, raise_invalid_document) + def test_reverse_delete_rule_cascade_and_nullify(self): """Ensure that a referenced document is also deleted upon deletion. """