Invalid DB Data now raises an InvalidDocumentError

fixes #2
This commit is contained in:
Ross Lawley 2012-05-01 11:03:23 +01:00
parent 0240a09056
commit d7765511ee
3 changed files with 32 additions and 5 deletions

View File

@ -4,6 +4,8 @@ Changelog
Changes in 0.6.X 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 meta `auto_create_index` so you can disable index creation
- Added write concern options to inserts - Added write concern options to inserts
- Fixed typo in meta for index options - Fixed typo in meta for index options
@ -281,5 +283,3 @@ Changes in v0.1.2
Changes in v0.1.1 Changes in v0.1.1
=================
- Documents may now use capped collections

View File

@ -979,8 +979,8 @@ class BaseDocument(object):
""" """
# get the class name from the document, falling back to the given # get the class name from the document, falling back to the given
# class if unavailable # class if unavailable
class_name = son.get(u'_cls', cls._class_name) class_name = son.get('_cls', cls._class_name)
data = dict((str(key), value) for key, value in son.items()) data = dict(("%s" % key, value) for key, value in son.items())
if '_types' in data: if '_types' in data:
del data['_types'] del data['_types']
@ -993,11 +993,16 @@ class BaseDocument(object):
cls = get_document(class_name) cls = get_document(class_name)
changed_fields = [] changed_fields = []
errors_dict = {}
for field_name, field in cls._fields.items(): for field_name, field in cls._fields.items():
if field.db_field in data: if field.db_field in data:
value = data[field.db_field] value = data[field.db_field]
try:
data[field_name] = (value if value is None data[field_name] = (value if value is None
else field.to_python(value)) else field.to_python(value))
except (AttributeError, ValueError), e:
errors_dict[field_name] = e
elif field.default: elif field.default:
default = field.default default = field.default
if callable(default): if callable(default):
@ -1005,7 +1010,13 @@ class BaseDocument(object):
if isinstance(default, BaseDocument): if isinstance(default, BaseDocument):
changed_fields.append(field_name) 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 = cls(**data)
obj._changed_fields = changed_fields obj._changed_fields = changed_fields
obj._created = False obj._created = False
return obj return obj

View File

@ -2398,6 +2398,22 @@ class DocumentTest(unittest.TestCase):
self.assertRaises(InvalidDocumentError, throw_invalid_document_error) 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): def test_reverse_delete_rule_cascade_and_nullify(self):
"""Ensure that a referenced document is also deleted upon deletion. """Ensure that a referenced document is also deleted upon deletion.
""" """