Fixed register_delete_rule inheritance issue
This commit is contained in:
		| @@ -140,8 +140,31 @@ class DocumentMetaclass(type): | |||||||
|                 base._subclasses += (_cls,) |                 base._subclasses += (_cls,) | ||||||
|             base._types = base._subclasses   # TODO depreciate _types |             base._types = base._subclasses   # TODO depreciate _types | ||||||
|  |  | ||||||
|         # Handle delete rules |  | ||||||
|         Document, EmbeddedDocument, DictField = cls._import_classes() |         Document, EmbeddedDocument, DictField = cls._import_classes() | ||||||
|  |  | ||||||
|  |         if issubclass(new_class, Document): | ||||||
|  |             new_class._collection = None | ||||||
|  |  | ||||||
|  |         # Add class to the _document_registry | ||||||
|  |         _document_registry[new_class._class_name] = new_class | ||||||
|  |  | ||||||
|  |         # In Python 2, User-defined methods objects have special read-only | ||||||
|  |         # attributes 'im_func' and 'im_self' which contain the function obj | ||||||
|  |         # and class instance object respectively.  With Python 3 these special | ||||||
|  |         # attributes have been replaced by __func__ and __self__.  The Blinker | ||||||
|  |         # module continues to use im_func and im_self, so the code below | ||||||
|  |         # copies __func__ into im_func and __self__ into im_self for | ||||||
|  |         # classmethod objects in Document derived classes. | ||||||
|  |         if PY3: | ||||||
|  |             for key, val in new_class.__dict__.items(): | ||||||
|  |                 if isinstance(val, classmethod): | ||||||
|  |                     f = val.__get__(new_class) | ||||||
|  |                     if hasattr(f, '__func__') and not hasattr(f, 'im_func'): | ||||||
|  |                         f.__dict__.update({'im_func': getattr(f, '__func__')}) | ||||||
|  |                     if hasattr(f, '__self__') and not hasattr(f, 'im_self'): | ||||||
|  |                         f.__dict__.update({'im_self': getattr(f, '__self__')}) | ||||||
|  |  | ||||||
|  |         # Handle delete rules | ||||||
|         for field in new_class._fields.itervalues(): |         for field in new_class._fields.itervalues(): | ||||||
|             f = field |             f = field | ||||||
|             f.owner_document = new_class |             f.owner_document = new_class | ||||||
| @@ -172,28 +195,6 @@ class DocumentMetaclass(type): | |||||||
|                        "field name" % field.name) |                        "field name" % field.name) | ||||||
|                 raise InvalidDocumentError(msg) |                 raise InvalidDocumentError(msg) | ||||||
|  |  | ||||||
|         if issubclass(new_class, Document): |  | ||||||
|             new_class._collection = None |  | ||||||
|  |  | ||||||
|         # Add class to the _document_registry |  | ||||||
|         _document_registry[new_class._class_name] = new_class |  | ||||||
|  |  | ||||||
|         # In Python 2, User-defined methods objects have special read-only |  | ||||||
|         # attributes 'im_func' and 'im_self' which contain the function obj |  | ||||||
|         # and class instance object respectively.  With Python 3 these special |  | ||||||
|         # attributes have been replaced by __func__ and __self__.  The Blinker |  | ||||||
|         # module continues to use im_func and im_self, so the code below |  | ||||||
|         # copies __func__ into im_func and __self__ into im_self for |  | ||||||
|         # classmethod objects in Document derived classes. |  | ||||||
|         if PY3: |  | ||||||
|             for key, val in new_class.__dict__.items(): |  | ||||||
|                 if isinstance(val, classmethod): |  | ||||||
|                     f = val.__get__(new_class) |  | ||||||
|                     if hasattr(f, '__func__') and not hasattr(f, 'im_func'): |  | ||||||
|                         f.__dict__.update({'im_func': getattr(f, '__func__')}) |  | ||||||
|                     if hasattr(f, '__self__') and not hasattr(f, 'im_self'): |  | ||||||
|                         f.__dict__.update({'im_self': getattr(f, '__self__')}) |  | ||||||
|  |  | ||||||
|         return new_class |         return new_class | ||||||
|  |  | ||||||
|     def add_to_class(self, name, value): |     def add_to_class(self, name, value): | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import unittest | |||||||
|  |  | ||||||
| from mongoengine import * | from mongoengine import * | ||||||
|  |  | ||||||
| from mongoengine.queryset import NULLIFY | from mongoengine.queryset import NULLIFY, PULL | ||||||
| from mongoengine.connection import get_db | from mongoengine.connection import get_db | ||||||
|  |  | ||||||
| __all__ = ("ClassMethodsTest", ) | __all__ = ("ClassMethodsTest", ) | ||||||
| @@ -85,6 +85,25 @@ class ClassMethodsTest(unittest.TestCase): | |||||||
|         self.assertEqual(self.Person._meta['delete_rules'], |         self.assertEqual(self.Person._meta['delete_rules'], | ||||||
|                          {(Job, 'employee'): NULLIFY}) |                          {(Job, 'employee'): NULLIFY}) | ||||||
|  |  | ||||||
|  |     def test_register_delete_rule_inherited(self): | ||||||
|  |  | ||||||
|  |         class Vaccine(Document): | ||||||
|  |             name = StringField(required=True) | ||||||
|  |  | ||||||
|  |             meta = {"indexes": ["name"]} | ||||||
|  |  | ||||||
|  |         class Animal(Document): | ||||||
|  |             family = StringField(required=True) | ||||||
|  |             vaccine_made = ListField(ReferenceField("Vaccine", reverse_delete_rule=PULL)) | ||||||
|  |  | ||||||
|  |             meta = {"allow_inheritance": True, "indexes": ["family"]} | ||||||
|  |  | ||||||
|  |         class Cat(Animal): | ||||||
|  |             name = StringField(required=True) | ||||||
|  |  | ||||||
|  |         self.assertEqual(Vaccine._meta['delete_rules'][(Animal, 'vaccine_made')], PULL) | ||||||
|  |         self.assertEqual(Vaccine._meta['delete_rules'][(Cat, 'vaccine_made')], PULL) | ||||||
|  |  | ||||||
|     def test_collection_naming(self): |     def test_collection_naming(self): | ||||||
|         """Ensure that a collection with a specified name may be used. |         """Ensure that a collection with a specified name may be used. | ||||||
|         """ |         """ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user