Added FutureWarning for inherited classes not declaring allow_inheritance

Refs #437
This commit is contained in:
Ross Lawley 2012-03-05 11:25:13 +00:00
parent b7d0d8f0cc
commit 6ecdc7b59d
7 changed files with 52 additions and 8 deletions

View File

@ -5,6 +5,7 @@ Changelog
Changes in 0.6 Changes in 0.6
============== ==============
- Added FutureWarning to inherited classes not declaring 'allow_inheritance' as the default will change in 0.7
- Added support for covered indexes when inheritance is off - Added support for covered indexes when inheritance is off
- No longer always upsert on save for items with a '_id' - No longer always upsert on save for items with a '_id'
- Error raised if update doesn't have an operation - Error raised if update doesn't have an operation

View File

@ -1,3 +1,5 @@
import warnings
from queryset import QuerySet, QuerySetManager from queryset import QuerySet, QuerySetManager
from queryset import DoesNotExist, MultipleObjectsReturned from queryset import DoesNotExist, MultipleObjectsReturned
from queryset import DO_NOTHING from queryset import DO_NOTHING
@ -116,7 +118,6 @@ class BaseField(object):
validation=None, choices=None, verbose_name=None, help_text=None): validation=None, choices=None, verbose_name=None, help_text=None):
self.db_field = (db_field or name) if not primary_key else '_id' self.db_field = (db_field or name) if not primary_key else '_id'
if name: if name:
import warnings
msg = "Fields' 'name' attribute deprecated in favour of 'db_field'" msg = "Fields' 'name' attribute deprecated in favour of 'db_field'"
warnings.warn(msg, DeprecationWarning) warnings.warn(msg, DeprecationWarning)
self.name = None self.name = None
@ -471,7 +472,6 @@ class DocumentMetaclass(type):
"""Metaclass for all documents. """Metaclass for all documents.
""" """
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
def _get_mixin_fields(base): def _get_mixin_fields(base):
attrs = {} attrs = {}
@ -512,6 +512,13 @@ class DocumentMetaclass(type):
# inheritance may be disabled to remove dependency on # inheritance may be disabled to remove dependency on
# additional fields _cls and _types # additional fields _cls and _types
class_name.append(base._class_name) class_name.append(base._class_name)
if not base._meta.get('allow_inheritance_defined', True):
warnings.warn(
"%s uses inheritance, the default for allow_inheritance "
"is changing to off by default. Please add it to the "
"document meta." % name,
FutureWarning
)
if base._meta.get('allow_inheritance', True) == False: if base._meta.get('allow_inheritance', True) == False:
raise ValueError('Document %s may not be subclassed' % raise ValueError('Document %s may not be subclassed' %
base.__name__) base.__name__)
@ -673,6 +680,10 @@ class TopLevelDocumentMetaclass(DocumentMetaclass):
'delete_rules': {}, 'delete_rules': {},
'allow_inheritance': True 'allow_inheritance': True
} }
allow_inheritance_defined = ('allow_inheritance' in base_meta or
'allow_inheritance'in attrs.get('meta', {}))
meta['allow_inheritance_defined'] = allow_inheritance_defined
meta.update(base_meta) meta.update(base_meta)
# Apply document-defined meta options # Apply document-defined meta options

View File

@ -39,7 +39,7 @@ setup(name='mongoengine',
author='Harry Marr', author='Harry Marr',
author_email='harry.marr@{nospam}gmail.com', author_email='harry.marr@{nospam}gmail.com',
maintainer="Ross Lawley", maintainer="Ross Lawley",
maintainer_email="ross.lawley@gmail.com", maintainer_email="ross.lawley@{nospam}gmail.com",
url='http://mongoengine.org/', url='http://mongoengine.org/',
license='MIT', license='MIT',
include_package_data=True, include_package_data=True,

View File

@ -23,11 +23,32 @@ class DocumentTest(unittest.TestCase):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
age = IntField() age = IntField()
meta = {'allow_inheritance': True}
self.Person = Person self.Person = Person
def tearDown(self): def tearDown(self):
self.Person.drop_collection() self.Person.drop_collection()
def test_future_warning(self):
"""Add FutureWarning for future allow_inhertiance default change.
"""
with warnings.catch_warnings(True) as errors:
class SimpleBase(Document):
a = IntField()
class InheritedClass(SimpleBase):
b = IntField()
InheritedClass()
self.assertEquals(len(errors), 1)
warning = errors[0]
self.assertEquals(FutureWarning, warning.category)
self.assertTrue("InheritedClass" in warning.message.message)
def test_drop_collection(self): def test_drop_collection(self):
"""Ensure that the collection may be dropped from the database. """Ensure that the collection may be dropped from the database.
""" """
@ -145,7 +166,8 @@ class DocumentTest(unittest.TestCase):
def test_get_superclasses(self): def test_get_superclasses(self):
"""Ensure that the correct list of superclasses is assembled. """Ensure that the correct list of superclasses is assembled.
""" """
class Animal(Document): pass class Animal(Document):
meta = {'allow_inheritance': True}
class Fish(Animal): pass class Fish(Animal): pass
class Mammal(Animal): pass class Mammal(Animal): pass
class Human(Mammal): pass class Human(Mammal): pass
@ -194,7 +216,8 @@ class DocumentTest(unittest.TestCase):
def test_polymorphic_queries(self): def test_polymorphic_queries(self):
"""Ensure that the correct subclasses are returned from a query""" """Ensure that the correct subclasses are returned from a query"""
class Animal(Document): pass class Animal(Document):
meta = {'allow_inheritance': True}
class Fish(Animal): pass class Fish(Animal): pass
class Mammal(Animal): pass class Mammal(Animal): pass
class Human(Mammal): pass class Human(Mammal): pass
@ -223,7 +246,8 @@ class DocumentTest(unittest.TestCase):
"""Ensure that the correct subclasses are returned from a query when """Ensure that the correct subclasses are returned from a query when
using references / generic references using references / generic references
""" """
class Animal(Document): pass class Animal(Document):
meta = {'allow_inheritance': True}
class Fish(Animal): pass class Fish(Animal): pass
class Mammal(Animal): pass class Mammal(Animal): pass
class Human(Mammal): pass class Human(Mammal): pass
@ -302,7 +326,8 @@ class DocumentTest(unittest.TestCase):
self.Person._get_collection_name()) self.Person._get_collection_name())
# Ensure that MRO error is not raised # Ensure that MRO error is not raised
class A(Document): pass class A(Document):
meta = {'allow_inheritance': True}
class B(A): pass class B(A): pass
class C(B): pass class C(B): pass
@ -597,6 +622,7 @@ class DocumentTest(unittest.TestCase):
'tags', 'tags',
('category', '-date') ('category', '-date')
], ],
'allow_inheritance': True
} }
BlogPost.drop_collection() BlogPost.drop_collection()
@ -996,6 +1022,8 @@ class DocumentTest(unittest.TestCase):
username = StringField(primary_key=True) username = StringField(primary_key=True)
name = StringField() name = StringField()
meta = {'allow_inheritance': True}
User.drop_collection() User.drop_collection()
self.assertEqual(User._fields['username'].db_field, '_id') self.assertEqual(User._fields['username'].db_field, '_id')
@ -1045,6 +1073,8 @@ class DocumentTest(unittest.TestCase):
class Place(Document): class Place(Document):
name = StringField() name = StringField()
meta = {'allow_inheritance': True}
class NicePlace(Place): class NicePlace(Place):
pass pass

View File

@ -12,6 +12,7 @@ class DynamicDocTest(unittest.TestCase):
class Person(DynamicDocument): class Person(DynamicDocument):
name = StringField() name = StringField()
meta = {'allow_inheritance': True}
Person.drop_collection() Person.drop_collection()

View File

@ -20,4 +20,4 @@ class Mixin(object):
class Base(Document): class Base(Document):
pass meta = {'allow_inheritance': True}

View File

@ -20,6 +20,7 @@ class QuerySetTest(unittest.TestCase):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
age = IntField() age = IntField()
meta = {'allow_inheritance': True}
self.Person = Person self.Person = Person
def test_initialisation(self): def test_initialisation(self):