Compare commits

...

6 Commits

Author SHA1 Message Date
Ross Lawley
4defc82192 Version Bump 2012-09-11 15:16:39 +00:00
Ross Lawley
5949970a95 Fixed index inheritance issues
firmed up testcases (MongoEngine/mongoengine#123) (MongoEngine/mongoengine#125)
2012-09-11 15:14:37 +00:00
Ross Lawley
5c6035d636 Updated upgrade docs for BinaryFields 2012-09-11 08:56:32 +00:00
Ross Lawley
a2183e3dcc Reverted EmbeddedDocuments meta handling.
You now can turn off inheritance (MongoEngine/mongoengine#119)
2012-09-07 13:23:46 +01:00
Ross Lawley
99637151b5 Updated version 2012-09-05 10:24:25 +01:00
Ross Lawley
a8e787c120 Update index spec generation so its not destructive (MongoEngine/mongoengine#113) 2012-09-04 14:39:19 +01:00
8 changed files with 136 additions and 21 deletions

View File

@@ -2,6 +2,19 @@
Changelog Changelog
========= =========
Changes in 0.7.4
================
- Fixed index inheritance issues - firmed up testcases (MongoEngine/mongoengine#123) (MongoEngine/mongoengine#125)
Changes in 0.7.3
================
- Reverted EmbeddedDocuments meta handling - now can turn off inheritance (MongoEngine/mongoengine#119)
Changes in 0.7.2
================
- Update index spec generation so its not destructive (MongoEngine/mongoengine#113)
Changes in 0.7.1 Changes in 0.7.1
================= =================
- Fixed index spec inheritance (MongoEngine/mongoengine#111) - Fixed index spec inheritance (MongoEngine/mongoengine#111)

View File

@@ -61,6 +61,13 @@ stored in rather than as string representations. Your code may need to be
updated to handle native types rather than strings keys for the results of updated to handle native types rather than strings keys for the results of
item frequency queries. item frequency queries.
BinaryFields
------------
Binary fields have been updated so that they are native binary types. If you
previously were doing `str` comparisons with binary field values you will have
to update and wrap the value in a `str`.
0.5 to 0.6 0.5 to 0.6
========== ==========

View File

@@ -12,7 +12,7 @@ from signals import *
__all__ = (document.__all__ + fields.__all__ + connection.__all__ + __all__ = (document.__all__ + fields.__all__ + connection.__all__ +
queryset.__all__ + signals.__all__) queryset.__all__ + signals.__all__)
VERSION = (0, 7, 1) VERSION = (0, 7, 4)
def get_version(): def get_version():

View File

@@ -508,6 +508,10 @@ class DocumentMetaclass(type):
attrs['_is_document'] = attrs.get('_is_document', False) attrs['_is_document'] = attrs.get('_is_document', False)
# EmbeddedDocuments could have meta data for inheritance
if 'meta' in attrs:
attrs['_meta'] = attrs.pop('meta')
# Handle document Fields # Handle document Fields
# Merge all fields from subclasses # Merge all fields from subclasses
@@ -571,6 +575,24 @@ class DocumentMetaclass(type):
superclasses[base._class_name] = base superclasses[base._class_name] = base
superclasses.update(base._superclasses) superclasses.update(base._superclasses)
if hasattr(base, '_meta'):
# Warn if allow_inheritance isn't set and prevent
# inheritance of classes where inheritance is set to False
allow_inheritance = base._meta.get('allow_inheritance',
ALLOW_INHERITANCE)
if (not getattr(base, '_is_base_cls', True)
and allow_inheritance is None):
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
)
elif (allow_inheritance == False and
not base._meta.get('abstract')):
raise ValueError('Document %s may not be subclassed' %
base.__name__)
attrs['_class_name'] = '.'.join(reversed(class_name)) attrs['_class_name'] = '.'.join(reversed(class_name))
attrs['_superclasses'] = superclasses attrs['_superclasses'] = superclasses
@@ -745,21 +767,6 @@ class TopLevelDocumentMetaclass(DocumentMetaclass):
if hasattr(base, 'meta'): if hasattr(base, 'meta'):
meta.merge(base.meta) meta.merge(base.meta)
elif hasattr(base, '_meta'): elif hasattr(base, '_meta'):
# Warn if allow_inheritance isn't set and prevent
# inheritance of classes where inheritance is set to False
allow_inheritance = base._meta.get('allow_inheritance',
ALLOW_INHERITANCE)
if not base._is_base_cls and allow_inheritance is None:
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
)
elif (allow_inheritance == False and
not base._meta.get('abstract')):
raise ValueError('Document %s may not be subclassed' %
base.__name__)
meta.merge(base._meta) meta.merge(base._meta)
# Set collection in the meta if its callable # Set collection in the meta if its callable

View File

@@ -25,6 +25,14 @@ class EmbeddedDocument(BaseDocument):
collection. :class:`~mongoengine.EmbeddedDocument`\ s should be used as collection. :class:`~mongoengine.EmbeddedDocument`\ s should be used as
fields on :class:`~mongoengine.Document`\ s through the fields on :class:`~mongoengine.Document`\ s through the
:class:`~mongoengine.EmbeddedDocumentField` field type. :class:`~mongoengine.EmbeddedDocumentField` field type.
A :class:`~mongoengine.EmbeddedDocument` subclass may be itself subclassed,
to create a specialised version of the embedded document that will be
stored in the same collection. To facilitate this behaviour, `_cls` and
`_types` fields are added to documents (hidden though the MongoEngine
interface though). To disable this behaviour and remove the dependence on
the presence of `_cls` and `_types`, set :attr:`allow_inheritance` to
``False`` in the :attr:`meta` dictionary.
""" """
# The __metaclass__ attribute is removed by 2to3 when running with Python3 # The __metaclass__ attribute is removed by 2to3 when running with Python3

View File

@@ -398,6 +398,7 @@ class QuerySet(object):
or a **-** to determine the index ordering or a **-** to determine the index ordering
""" """
index_spec = QuerySet._build_index_spec(self._document, key_or_list) index_spec = QuerySet._build_index_spec(self._document, key_or_list)
index_spec = index_spec.copy()
fields = index_spec.pop('fields') fields = index_spec.pop('fields')
index_spec['drop_dups'] = drop_dups index_spec['drop_dups'] = drop_dups
index_spec['background'] = background index_spec['background'] = background
@@ -472,7 +473,9 @@ class QuerySet(object):
# Ensure document-defined indexes are created # Ensure document-defined indexes are created
if self._document._meta['index_specs']: if self._document._meta['index_specs']:
for spec in self._document._meta['index_specs']: index_spec = self._document._meta['index_specs']
for spec in index_spec:
spec = spec.copy()
fields = spec.pop('fields') fields = spec.pop('fields')
types_indexed = types_indexed or includes_types(fields) types_indexed = types_indexed or includes_types(fields)
opts = index_opts.copy() opts = index_opts.copy()
@@ -498,8 +501,10 @@ class QuerySet(object):
""" """
if isinstance(spec, basestring): if isinstance(spec, basestring):
spec = {'fields': [spec]} spec = {'fields': [spec]}
if isinstance(spec, (list, tuple)): elif isinstance(spec, (list, tuple)):
spec = {'fields': spec} spec = {'fields': list(spec)}
elif isinstance(spec, dict):
spec = dict(spec)
index_list = [] index_list = []
direction = None direction = None

View File

@@ -5,7 +5,7 @@
%define srcname mongoengine %define srcname mongoengine
Name: python-%{srcname} Name: python-%{srcname}
Version: 0.7.1 Version: 0.7.4
Release: 1%{?dist} Release: 1%{?dist}
Summary: A Python Document-Object Mapper for working with MongoDB Summary: A Python Document-Object Mapper for working with MongoDB

View File

@@ -338,7 +338,6 @@ class DocumentTest(unittest.TestCase):
meta = {'allow_inheritance': False} meta = {'allow_inheritance': False}
self.assertRaises(ValueError, create_employee_class) self.assertRaises(ValueError, create_employee_class)
def test_allow_inheritance_abstract_document(self): def test_allow_inheritance_abstract_document(self):
"""Ensure that abstract documents can set inheritance rules and that """Ensure that abstract documents can set inheritance rules and that
_cls and _types will not be used. _cls and _types will not be used.
@@ -366,6 +365,31 @@ class DocumentTest(unittest.TestCase):
Animal.drop_collection() Animal.drop_collection()
def test_allow_inheritance_embedded_document(self):
# Test the same for embedded documents
class Comment(EmbeddedDocument):
content = StringField()
meta = {'allow_inheritance': False}
def create_special_comment():
class SpecialComment(Comment):
pass
self.assertRaises(ValueError, create_special_comment)
comment = Comment(content='test')
self.assertFalse('_cls' in comment.to_mongo())
self.assertFalse('_types' in comment.to_mongo())
class Comment(EmbeddedDocument):
content = StringField()
meta = {'allow_inheritance': True}
comment = Comment(content='test')
self.assertTrue('_cls' in comment.to_mongo())
self.assertTrue('_types' in comment.to_mongo())
def test_document_inheritance(self): def test_document_inheritance(self):
"""Ensure mutliple inheritance of abstract docs works """Ensure mutliple inheritance of abstract docs works
""" """
@@ -396,6 +420,9 @@ class DocumentTest(unittest.TestCase):
'indexes': ['name'] 'indexes': ['name']
} }
self.assertEqual(Animal._meta['index_specs'],
[{'fields': [('_types', 1), ('name', 1)]}])
Animal.drop_collection() Animal.drop_collection()
dog = Animal(name='dog') dog = Animal(name='dog')
@@ -417,6 +444,9 @@ class DocumentTest(unittest.TestCase):
'allow_inheritance': False, 'allow_inheritance': False,
'indexes': ['name'] 'indexes': ['name']
} }
self.assertEqual(Animal._meta['index_specs'],
[{'fields': [('name', 1)]}])
collection.update({}, {"$unset": {"_types": 1, "_cls": 1}}, multi=True) collection.update({}, {"$unset": {"_types": 1, "_cls": 1}}, multi=True)
# Confirm extra data is removed # Confirm extra data is removed
@@ -634,6 +664,12 @@ class DocumentTest(unittest.TestCase):
'allow_inheritance': True 'allow_inheritance': True
} }
self.assertEqual(BlogPost._meta['index_specs'],
[{'fields': [('_types', 1), ('addDate', -1)]},
{'fields': [('tags', 1)]},
{'fields': [('_types', 1), ('category', 1),
('addDate', -1)]}])
BlogPost.drop_collection() BlogPost.drop_collection()
info = BlogPost.objects._collection.index_information() info = BlogPost.objects._collection.index_information()
@@ -657,6 +693,13 @@ class DocumentTest(unittest.TestCase):
title = StringField() title = StringField()
meta = {'indexes': ['title']} meta = {'indexes': ['title']}
self.assertEqual(ExtendedBlogPost._meta['index_specs'],
[{'fields': [('_types', 1), ('addDate', -1)]},
{'fields': [('tags', 1)]},
{'fields': [('_types', 1), ('category', 1),
('addDate', -1)]},
{'fields': [('_types', 1), ('title', 1)]}])
BlogPost.drop_collection() BlogPost.drop_collection()
list(ExtendedBlogPost.objects) list(ExtendedBlogPost.objects)
@@ -687,6 +730,27 @@ class DocumentTest(unittest.TestCase):
description = StringField() description = StringField()
self.assertEqual(A._meta['index_specs'], B._meta['index_specs']) self.assertEqual(A._meta['index_specs'], B._meta['index_specs'])
self.assertEqual([{'fields': [('_types', 1), ('title', 1)]}],
A._meta['index_specs'])
def test_build_index_spec_is_not_destructive(self):
class MyDoc(Document):
keywords = StringField()
meta = {
'indexes': ['keywords'],
'allow_inheritance': False
}
self.assertEqual(MyDoc._meta['index_specs'],
[{'fields': [('keywords', 1)]}])
# Force index creation
MyDoc.objects._ensure_indexes()
self.assertEqual(MyDoc._meta['index_specs'],
[{'fields': [('keywords', 1)]}])
def test_db_field_load(self): def test_db_field_load(self):
"""Ensure we load data correctly """Ensure we load data correctly
@@ -748,6 +812,9 @@ class DocumentTest(unittest.TestCase):
'allow_inheritance': False 'allow_inheritance': False
} }
self.assertEqual([{'fields': [('rank.title', 1)]}],
Person._meta['index_specs'])
Person.drop_collection() Person.drop_collection()
# Indexes are lazy so use list() to perform query # Indexes are lazy so use list() to perform query
@@ -766,6 +833,10 @@ class DocumentTest(unittest.TestCase):
'*location.point', '*location.point',
], ],
} }
self.assertEqual([{'fields': [('location.point', '2d')]}],
Place._meta['index_specs'])
Place.drop_collection() Place.drop_collection()
info = Place.objects._collection.index_information() info = Place.objects._collection.index_information()
@@ -791,6 +862,10 @@ class DocumentTest(unittest.TestCase):
], ],
} }
self.assertEqual([{'fields': [('addDate', -1)], 'unique': True,
'sparse': True, 'types': False}],
BlogPost._meta['index_specs'])
BlogPost.drop_collection() BlogPost.drop_collection()
info = BlogPost.objects._collection.index_information() info = BlogPost.objects._collection.index_information()