From 319f1deceb75499dc0c962a0fe8fdd7436f22894 Mon Sep 17 00:00:00 2001 From: Sridhar Sundarraman Date: Sun, 12 Apr 2015 17:28:26 +0300 Subject: [PATCH 1/3] Unit Test to Demonstrate #954 --- tests/document/validation.py | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/document/validation.py b/tests/document/validation.py index 573c2e57..646efddb 100644 --- a/tests/document/validation.py +++ b/tests/document/validation.py @@ -165,6 +165,48 @@ class ValidatorErrorTest(unittest.TestCase): self.assertRaises(ValidationError, lambda: d2.validate()) + def test_parent_reference_in_child_document(self): + """ Test to demonstrate behavior in Issue #954 + """ + class Parent(Document): + meta = {'allow_inheritance': True} + reference = ReferenceField('self') + + class Child(Parent): + pass + + parent = Parent() + parent.save() + + child = Child(reference=parent) + try: + # Saving child should not raise a ValidationError + child.save() + except ValidationError as e: + self.fail("test should not throw validation error. %s" % e.message) + + def test_parent_reference_set_as_attribute_in_child_document_(self): + """ Test to demonstrate behavior (when set as attribute) in Issue #954 + """ + class Parent(Document): + meta = {'allow_inheritance': True} + reference = ReferenceField('self') + + class Child(Parent): + pass + + parent = Parent() + parent.save() + + child = Child() + child.reference = parent + + try: + # Saving the child should not raise a ValidationError + child.save() + except ValidationError as e: + self.fail("test should not throw validation error. %s" % e.message) + if __name__ == '__main__': unittest.main() From 5d6a28954b70fd14b140978040d343d1f2f28982 Mon Sep 17 00:00:00 2001 From: Matthew Ellison Date: Tue, 28 Apr 2015 15:07:22 -0400 Subject: [PATCH 2/3] Reflect Inheritance in Field's 'owner_document' The 'owner_document' property of a Field now reflects the parent field which first contained the Field when a Document in inherited. Fixes #954 Closes #955 --- mongoengine/base/fields.py | 17 ++++++++++++----- mongoengine/base/metaclasses.py | 3 ++- tests/document/validation.py | 26 ++++++++++++-------------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/mongoengine/base/fields.py b/mongoengine/base/fields.py index aa16804e..08fbc9b7 100644 --- a/mongoengine/base/fields.py +++ b/mongoengine/base/fields.py @@ -83,6 +83,7 @@ class BaseField(object): self.help_text = help_text self.null = null self.sparse = sparse + self._owner_document = None # Adjust the appropriate creation counter, and save our local copy. if self.db_field == '_id': @@ -189,6 +190,17 @@ class BaseField(object): self.validate(value, **kwargs) + @property + def owner_document(self): + return self._owner_document + + def _set_owner_document(self, owner_document): + self._owner_document = owner_document + + @owner_document.setter + def owner_document(self, owner_document): + self._set_owner_document(owner_document) + class ComplexBaseField(BaseField): @@ -398,11 +410,6 @@ class ComplexBaseField(BaseField): self.field.owner_document = owner_document self._owner_document = owner_document - def _get_owner_document(self, owner_document): - self._owner_document = owner_document - - owner_document = property(_get_owner_document, _set_owner_document) - class ObjectIdField(BaseField): diff --git a/mongoengine/base/metaclasses.py b/mongoengine/base/metaclasses.py index 48da84f4..7a104da9 100644 --- a/mongoengine/base/metaclasses.py +++ b/mongoengine/base/metaclasses.py @@ -176,7 +176,8 @@ class DocumentMetaclass(type): # Handle delete rules for field in new_class._fields.itervalues(): f = field - f.owner_document = new_class + if f.owner_document is None: + f.owner_document = new_class delete_rule = getattr(f, 'reverse_delete_rule', DO_NOTHING) if isinstance(f, CachedReferenceField): diff --git a/tests/document/validation.py b/tests/document/validation.py index 646efddb..8498a740 100644 --- a/tests/document/validation.py +++ b/tests/document/validation.py @@ -166,7 +166,9 @@ class ValidatorErrorTest(unittest.TestCase): self.assertRaises(ValidationError, lambda: d2.validate()) def test_parent_reference_in_child_document(self): - """ Test to demonstrate behavior in Issue #954 + """ + Test to ensure a ReferenceField can store a reference to a parent + class when inherited. Issue #954. """ class Parent(Document): meta = {'allow_inheritance': True} @@ -179,14 +181,14 @@ class ValidatorErrorTest(unittest.TestCase): parent.save() child = Child(reference=parent) - try: - # Saving child should not raise a ValidationError - child.save() - except ValidationError as e: - self.fail("test should not throw validation error. %s" % e.message) - def test_parent_reference_set_as_attribute_in_child_document_(self): - """ Test to demonstrate behavior (when set as attribute) in Issue #954 + # Saving child should not raise a ValidationError + child.save() + + def test_parent_reference_set_as_attribute_in_child_document(self): + """ + Test to ensure a ReferenceField can store a reference to a parent + class when inherited and when set via attribute. Issue #954. """ class Parent(Document): meta = {'allow_inheritance': True} @@ -201,12 +203,8 @@ class ValidatorErrorTest(unittest.TestCase): child = Child() child.reference = parent - try: - # Saving the child should not raise a ValidationError - child.save() - except ValidationError as e: - self.fail("test should not throw validation error. %s" % e.message) - + # Saving the child should not raise a ValidationError + child.save() if __name__ == '__main__': unittest.main() From f2cbcea6d77e5fd9408aa5ec6c6e6af5c3683f46 Mon Sep 17 00:00:00 2001 From: Matthew Ellison Date: Wed, 29 Apr 2015 14:26:05 -0400 Subject: [PATCH 3/3] Unit Tests for #954 Fail on Exception, not Error --- tests/document/validation.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/document/validation.py b/tests/document/validation.py index 8498a740..ba03366e 100644 --- a/tests/document/validation.py +++ b/tests/document/validation.py @@ -183,7 +183,10 @@ class ValidatorErrorTest(unittest.TestCase): child = Child(reference=parent) # Saving child should not raise a ValidationError - child.save() + try: + child.save() + except ValidationError as e: + self.fail("ValidationError raised: %s" % e.message) def test_parent_reference_set_as_attribute_in_child_document(self): """ @@ -204,7 +207,11 @@ class ValidatorErrorTest(unittest.TestCase): child.reference = parent # Saving the child should not raise a ValidationError - child.save() + try: + child.save() + except ValidationError as e: + self.fail("ValidationError raised: %s" % e.message) + if __name__ == '__main__': unittest.main()