Compare commits
	
		
			1 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 3da37fbf6e | 
| @@ -12,7 +12,7 @@ __all__ = (document.__all__ + fields.__all__ + connection.__all__ + | |||||||
|  |  | ||||||
| __author__ = 'Harry Marr' | __author__ = 'Harry Marr' | ||||||
|  |  | ||||||
| VERSION = (0, 4, 0) | VERSION = (0, 4, 1) | ||||||
|  |  | ||||||
| def get_version(): | def get_version(): | ||||||
|     version = '%s.%s' % (VERSION[0], VERSION[1]) |     version = '%s.%s' % (VERSION[0], VERSION[1]) | ||||||
|   | |||||||
| @@ -2,8 +2,8 @@ from queryset import QuerySet, QuerySetManager | |||||||
| from queryset import DoesNotExist, MultipleObjectsReturned | from queryset import DoesNotExist, MultipleObjectsReturned | ||||||
|  |  | ||||||
| import sys | import sys | ||||||
|  | import bson | ||||||
| import pymongo | import pymongo | ||||||
| import pymongo.objectid |  | ||||||
|  |  | ||||||
|  |  | ||||||
| _document_registry = {} | _document_registry = {} | ||||||
| @@ -21,11 +21,11 @@ class BaseField(object): | |||||||
|     may be added to subclasses of `Document` to define a document's schema. |     may be added to subclasses of `Document` to define a document's schema. | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     # Fields may have _types inserted into indexes by default  |     # Fields may have _types inserted into indexes by default | ||||||
|     _index_with_types = True |     _index_with_types = True | ||||||
|     _geo_index = False |     _geo_index = False | ||||||
|  |  | ||||||
|     def __init__(self, db_field=None, name=None, required=False, default=None,  |     def __init__(self, db_field=None, name=None, required=False, default=None, | ||||||
|                  unique=False, unique_with=None, primary_key=False, |                  unique=False, unique_with=None, primary_key=False, | ||||||
|                  validation=None, choices=None): |                  validation=None, choices=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' | ||||||
| @@ -43,7 +43,7 @@ class BaseField(object): | |||||||
|         self.choices = choices |         self.choices = choices | ||||||
|  |  | ||||||
|     def __get__(self, instance, owner): |     def __get__(self, instance, owner): | ||||||
|         """Descriptor for retrieving a value from a field in a document. Do  |         """Descriptor for retrieving a value from a field in a document. Do | ||||||
|         any necessary conversion between Python and MongoDB types. |         any necessary conversion between Python and MongoDB types. | ||||||
|         """ |         """ | ||||||
|         if instance is None: |         if instance is None: | ||||||
| @@ -111,9 +111,9 @@ class ObjectIdField(BaseField): | |||||||
|         # return unicode(value) |         # return unicode(value) | ||||||
|  |  | ||||||
|     def to_mongo(self, value): |     def to_mongo(self, value): | ||||||
|         if not isinstance(value, pymongo.objectid.ObjectId): |         if not isinstance(value, bson.objectid.ObjectId): | ||||||
|             try: |             try: | ||||||
|                 return pymongo.objectid.ObjectId(unicode(value)) |                 return bson.objectid.ObjectId(unicode(value)) | ||||||
|             except Exception, e: |             except Exception, e: | ||||||
|                 #e.message attribute has been deprecated since Python 2.6 |                 #e.message attribute has been deprecated since Python 2.6 | ||||||
|                 raise ValidationError(unicode(e)) |                 raise ValidationError(unicode(e)) | ||||||
| @@ -124,7 +124,7 @@ class ObjectIdField(BaseField): | |||||||
|  |  | ||||||
|     def validate(self, value): |     def validate(self, value): | ||||||
|         try: |         try: | ||||||
|             pymongo.objectid.ObjectId(unicode(value)) |             bson.objectid.ObjectId(unicode(value)) | ||||||
|         except: |         except: | ||||||
|             raise ValidationError('Invalid Object ID') |             raise ValidationError('Invalid Object ID') | ||||||
|  |  | ||||||
| @@ -153,8 +153,8 @@ class DocumentMetaclass(type): | |||||||
|                 superclasses.update(base._superclasses) |                 superclasses.update(base._superclasses) | ||||||
|  |  | ||||||
|             if hasattr(base, '_meta'): |             if hasattr(base, '_meta'): | ||||||
|                 # Ensure that the Document class may be subclassed -  |                 # Ensure that the Document class may be subclassed - | ||||||
|                 # 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 | ||||||
|                 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' % | ||||||
| @@ -193,12 +193,12 @@ class DocumentMetaclass(type): | |||||||
|  |  | ||||||
|         module = attrs.get('__module__') |         module = attrs.get('__module__') | ||||||
|  |  | ||||||
|         base_excs = tuple(base.DoesNotExist for base in bases  |         base_excs = tuple(base.DoesNotExist for base in bases | ||||||
|                           if hasattr(base, 'DoesNotExist')) or (DoesNotExist,) |                           if hasattr(base, 'DoesNotExist')) or (DoesNotExist,) | ||||||
|         exc = subclass_exception('DoesNotExist', base_excs, module) |         exc = subclass_exception('DoesNotExist', base_excs, module) | ||||||
|         new_class.add_to_class('DoesNotExist', exc) |         new_class.add_to_class('DoesNotExist', exc) | ||||||
|  |  | ||||||
|         base_excs = tuple(base.MultipleObjectsReturned for base in bases  |         base_excs = tuple(base.MultipleObjectsReturned for base in bases | ||||||
|                           if hasattr(base, 'MultipleObjectsReturned')) |                           if hasattr(base, 'MultipleObjectsReturned')) | ||||||
|         base_excs = base_excs or (MultipleObjectsReturned,) |         base_excs = base_excs or (MultipleObjectsReturned,) | ||||||
|         exc = subclass_exception('MultipleObjectsReturned', base_excs, module) |         exc = subclass_exception('MultipleObjectsReturned', base_excs, module) | ||||||
| @@ -220,9 +220,9 @@ class TopLevelDocumentMetaclass(DocumentMetaclass): | |||||||
|  |  | ||||||
|     def __new__(cls, name, bases, attrs): |     def __new__(cls, name, bases, attrs): | ||||||
|         super_new = super(TopLevelDocumentMetaclass, cls).__new__ |         super_new = super(TopLevelDocumentMetaclass, cls).__new__ | ||||||
|         # Classes defined in this package are abstract and should not have  |         # Classes defined in this package are abstract and should not have | ||||||
|         # their own metadata with DB collection, etc. |         # their own metadata with DB collection, etc. | ||||||
|         # __metaclass__ is only set on the class with the __metaclass__  |         # __metaclass__ is only set on the class with the __metaclass__ | ||||||
|         # attribute (i.e. it is not set on subclasses). This differentiates |         # attribute (i.e. it is not set on subclasses). This differentiates | ||||||
|         # 'real' documents from the 'Document' class |         # 'real' documents from the 'Document' class | ||||||
|         if attrs.get('__metaclass__') == TopLevelDocumentMetaclass: |         if attrs.get('__metaclass__') == TopLevelDocumentMetaclass: | ||||||
| @@ -347,7 +347,7 @@ class BaseDocument(object): | |||||||
|         are present. |         are present. | ||||||
|         """ |         """ | ||||||
|         # Get a list of tuples of field names and their current values |         # Get a list of tuples of field names and their current values | ||||||
|         fields = [(field, getattr(self, name))  |         fields = [(field, getattr(self, name)) | ||||||
|                   for name, field in self._fields.items()] |                   for name, field in self._fields.items()] | ||||||
|  |  | ||||||
|         # Ensure that each field is matched to a valid value |         # Ensure that each field is matched to a valid value | ||||||
|   | |||||||
| @@ -40,16 +40,16 @@ class Document(BaseDocument): | |||||||
|     presence of `_cls` and `_types`, set :attr:`allow_inheritance` to |     presence of `_cls` and `_types`, set :attr:`allow_inheritance` to | ||||||
|     ``False`` in the :attr:`meta` dictionary. |     ``False`` in the :attr:`meta` dictionary. | ||||||
|  |  | ||||||
|     A :class:`~mongoengine.Document` may use a **Capped Collection** by  |     A :class:`~mongoengine.Document` may use a **Capped Collection** by | ||||||
|     specifying :attr:`max_documents` and :attr:`max_size` in the :attr:`meta` |     specifying :attr:`max_documents` and :attr:`max_size` in the :attr:`meta` | ||||||
|     dictionary. :attr:`max_documents` is the maximum number of documents that |     dictionary. :attr:`max_documents` is the maximum number of documents that | ||||||
|     is allowed to be stored in the collection, and :attr:`max_size` is the  |     is allowed to be stored in the collection, and :attr:`max_size` is the | ||||||
|     maximum size of the collection in bytes. If :attr:`max_size` is not  |     maximum size of the collection in bytes. If :attr:`max_size` is not | ||||||
|     specified and :attr:`max_documents` is, :attr:`max_size` defaults to  |     specified and :attr:`max_documents` is, :attr:`max_size` defaults to | ||||||
|     10000000 bytes (10MB). |     10000000 bytes (10MB). | ||||||
|  |  | ||||||
|     Indexes may be created by specifying :attr:`indexes` in the :attr:`meta` |     Indexes may be created by specifying :attr:`indexes` in the :attr:`meta` | ||||||
|     dictionary. The value should be a list of field names or tuples of field  |     dictionary. The value should be a list of field names or tuples of field | ||||||
|     names. Index direction may be specified by prefixing the field names with |     names. Index direction may be specified by prefixing the field names with | ||||||
|     a **+** or **-** sign. |     a **+** or **-** sign. | ||||||
|     """ |     """ | ||||||
| @@ -61,11 +61,11 @@ class Document(BaseDocument): | |||||||
|         document already exists, it will be updated, otherwise it will be |         document already exists, it will be updated, otherwise it will be | ||||||
|         created. |         created. | ||||||
|  |  | ||||||
|         If ``safe=True`` and the operation is unsuccessful, an  |         If ``safe=True`` and the operation is unsuccessful, an | ||||||
|         :class:`~mongoengine.OperationError` will be raised. |         :class:`~mongoengine.OperationError` will be raised. | ||||||
|  |  | ||||||
|         :param safe: check if the operation succeeded before returning |         :param safe: check if the operation succeeded before returning | ||||||
|         :param force_insert: only try to create a new document, don't allow  |         :param force_insert: only try to create a new document, don't allow | ||||||
|             updates of existing documents |             updates of existing documents | ||||||
|         :param validate: validates the document; set to ``False`` for skiping |         :param validate: validates the document; set to ``False`` for skiping | ||||||
|         """ |         """ | ||||||
| @@ -123,9 +123,9 @@ class MapReduceDocument(object): | |||||||
|     """A document returned from a map/reduce query. |     """A document returned from a map/reduce query. | ||||||
|  |  | ||||||
|     :param collection: An instance of :class:`~pymongo.Collection` |     :param collection: An instance of :class:`~pymongo.Collection` | ||||||
|     :param key: Document/result key, often an instance of  |     :param key: Document/result key, often an instance of | ||||||
|                 :class:`~pymongo.objectid.ObjectId`. If supplied as  |                 :class:`~bson.objectid.ObjectId`. If supplied as | ||||||
|                 an ``ObjectId`` found in the given ``collection``,  |                 an ``ObjectId`` found in the given ``collection``, | ||||||
|                 the object can be accessed via the ``object`` property. |                 the object can be accessed via the ``object`` property. | ||||||
|     :param value: The result(s) for this key. |     :param value: The result(s) for this key. | ||||||
|  |  | ||||||
| @@ -140,7 +140,7 @@ class MapReduceDocument(object): | |||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def object(self): |     def object(self): | ||||||
|         """Lazy-load the object referenced by ``self.key``. ``self.key``  |         """Lazy-load the object referenced by ``self.key``. ``self.key`` | ||||||
|         should be the ``primary_key``. |         should be the ``primary_key``. | ||||||
|         """ |         """ | ||||||
|         id_field = self._document()._meta['id_field'] |         id_field = self._document()._meta['id_field'] | ||||||
|   | |||||||
| @@ -5,9 +5,9 @@ from operator import itemgetter | |||||||
|  |  | ||||||
| import re | import re | ||||||
| import pymongo | import pymongo | ||||||
| import pymongo.dbref | import bson.dbref | ||||||
| import pymongo.son | import bson.son | ||||||
| import pymongo.binary | import bson.binary | ||||||
| import datetime | import datetime | ||||||
| import decimal | import decimal | ||||||
| import gridfs | import gridfs | ||||||
| @@ -300,13 +300,13 @@ class ListField(BaseField): | |||||||
|  |  | ||||||
|         if isinstance(self.field, ReferenceField): |         if isinstance(self.field, ReferenceField): | ||||||
|             referenced_type = self.field.document_type |             referenced_type = self.field.document_type | ||||||
|             # Get value from document instance if available  |             # Get value from document instance if available | ||||||
|             value_list = instance._data.get(self.name) |             value_list = instance._data.get(self.name) | ||||||
|             if value_list: |             if value_list: | ||||||
|                 deref_list = [] |                 deref_list = [] | ||||||
|                 for value in value_list: |                 for value in value_list: | ||||||
|                     # Dereference DBRefs |                     # Dereference DBRefs | ||||||
|                     if isinstance(value, (pymongo.dbref.DBRef)): |                     if isinstance(value, (bson.dbref.DBRef)): | ||||||
|                         value = _get_db().dereference(value) |                         value = _get_db().dereference(value) | ||||||
|                         deref_list.append(referenced_type._from_son(value)) |                         deref_list.append(referenced_type._from_son(value)) | ||||||
|                     else: |                     else: | ||||||
| @@ -319,7 +319,7 @@ class ListField(BaseField): | |||||||
|                 deref_list = [] |                 deref_list = [] | ||||||
|                 for value in value_list: |                 for value in value_list: | ||||||
|                     # Dereference DBRefs |                     # Dereference DBRefs | ||||||
|                     if isinstance(value, (dict, pymongo.son.SON)): |                     if isinstance(value, (dict, bson.son.SON)): | ||||||
|                         deref_list.append(self.field.dereference(value)) |                         deref_list.append(self.field.dereference(value)) | ||||||
|                     else: |                     else: | ||||||
|                         deref_list.append(value) |                         deref_list.append(value) | ||||||
| @@ -444,7 +444,7 @@ class ReferenceField(BaseField): | |||||||
|         # Get value from document instance if available |         # Get value from document instance if available | ||||||
|         value = instance._data.get(self.name) |         value = instance._data.get(self.name) | ||||||
|         # Dereference DBRefs |         # Dereference DBRefs | ||||||
|         if isinstance(value, (pymongo.dbref.DBRef)): |         if isinstance(value, (bson.dbref.DBRef)): | ||||||
|             value = _get_db().dereference(value) |             value = _get_db().dereference(value) | ||||||
|             if value is not None: |             if value is not None: | ||||||
|                 instance._data[self.name] = self.document_type._from_son(value) |                 instance._data[self.name] = self.document_type._from_son(value) | ||||||
| @@ -466,13 +466,13 @@ class ReferenceField(BaseField): | |||||||
|  |  | ||||||
|         id_ = id_field.to_mongo(id_) |         id_ = id_field.to_mongo(id_) | ||||||
|         collection = self.document_type._meta['collection'] |         collection = self.document_type._meta['collection'] | ||||||
|         return pymongo.dbref.DBRef(collection, id_) |         return bson.dbref.DBRef(collection, id_) | ||||||
|  |  | ||||||
|     def prepare_query_value(self, op, value): |     def prepare_query_value(self, op, value): | ||||||
|         return self.to_mongo(value) |         return self.to_mongo(value) | ||||||
|  |  | ||||||
|     def validate(self, value): |     def validate(self, value): | ||||||
|         assert isinstance(value, (self.document_type, pymongo.dbref.DBRef)) |         assert isinstance(value, (self.document_type, bson.dbref.DBRef)) | ||||||
|  |  | ||||||
|     def lookup_member(self, member_name): |     def lookup_member(self, member_name): | ||||||
|         return self.document_type._fields.get(member_name) |         return self.document_type._fields.get(member_name) | ||||||
| @@ -490,7 +490,7 @@ class GenericReferenceField(BaseField): | |||||||
|             return self |             return self | ||||||
|  |  | ||||||
|         value = instance._data.get(self.name) |         value = instance._data.get(self.name) | ||||||
|         if isinstance(value, (dict, pymongo.son.SON)): |         if isinstance(value, (dict, bson.son.SON)): | ||||||
|             instance._data[self.name] = self.dereference(value) |             instance._data[self.name] = self.dereference(value) | ||||||
|  |  | ||||||
|         return super(GenericReferenceField, self).__get__(instance, owner) |         return super(GenericReferenceField, self).__get__(instance, owner) | ||||||
| @@ -518,7 +518,7 @@ class GenericReferenceField(BaseField): | |||||||
|  |  | ||||||
|         id_ = id_field.to_mongo(id_) |         id_ = id_field.to_mongo(id_) | ||||||
|         collection = document._meta['collection'] |         collection = document._meta['collection'] | ||||||
|         ref = pymongo.dbref.DBRef(collection, id_) |         ref = bson.dbref.DBRef(collection, id_) | ||||||
|         return {'_cls': document.__class__.__name__, '_ref': ref} |         return {'_cls': document.__class__.__name__, '_ref': ref} | ||||||
|  |  | ||||||
|     def prepare_query_value(self, op, value): |     def prepare_query_value(self, op, value): | ||||||
| @@ -534,7 +534,7 @@ class BinaryField(BaseField): | |||||||
|         super(BinaryField, self).__init__(**kwargs) |         super(BinaryField, self).__init__(**kwargs) | ||||||
|  |  | ||||||
|     def to_mongo(self, value): |     def to_mongo(self, value): | ||||||
|         return pymongo.binary.Binary(value) |         return bson.binary.Binary(value) | ||||||
|  |  | ||||||
|     def to_python(self, value): |     def to_python(self, value): | ||||||
|         # Returns str not unicode as this is binary data |         # Returns str not unicode as this is binary data | ||||||
| @@ -603,7 +603,7 @@ class GridFSProxy(object): | |||||||
|         if not self.newfile: |         if not self.newfile: | ||||||
|             self.new_file() |             self.new_file() | ||||||
|             self.grid_id = self.newfile._id |             self.grid_id = self.newfile._id | ||||||
|         self.newfile.writelines(lines)  |         self.newfile.writelines(lines) | ||||||
|  |  | ||||||
|     def read(self): |     def read(self): | ||||||
|         try: |         try: | ||||||
| @@ -680,7 +680,7 @@ class FileField(BaseField): | |||||||
|     def validate(self, value): |     def validate(self, value): | ||||||
|         if value.grid_id is not None: |         if value.grid_id is not None: | ||||||
|             assert isinstance(value, GridFSProxy) |             assert isinstance(value, GridFSProxy) | ||||||
|             assert isinstance(value.grid_id, pymongo.objectid.ObjectId) |             assert isinstance(value.grid_id, bson.objectid.ObjectId) | ||||||
|  |  | ||||||
|  |  | ||||||
| class GeoPointField(BaseField): | class GeoPointField(BaseField): | ||||||
|   | |||||||
| @@ -2,9 +2,9 @@ from connection import _get_db | |||||||
|  |  | ||||||
| import pprint | import pprint | ||||||
| import pymongo | import pymongo | ||||||
| import pymongo.code | import bson.code | ||||||
| import pymongo.dbref | import bson.dbref | ||||||
| import pymongo.objectid | import bson.objectid | ||||||
| import re | import re | ||||||
| import copy | import copy | ||||||
| import itertools | import itertools | ||||||
| @@ -424,7 +424,7 @@ class QuerySet(object): | |||||||
|             } |             } | ||||||
|             if self._loaded_fields: |             if self._loaded_fields: | ||||||
|                 cursor_args['fields'] = self._loaded_fields |                 cursor_args['fields'] = self._loaded_fields | ||||||
|             self._cursor_obj = self._collection.find(self._query,  |             self._cursor_obj = self._collection.find(self._query, | ||||||
|                                                      **cursor_args) |                                                      **cursor_args) | ||||||
|             # Apply where clauses to cursor |             # Apply where clauses to cursor | ||||||
|             if self._where_clause: |             if self._where_clause: | ||||||
| @@ -476,8 +476,8 @@ class QuerySet(object): | |||||||
|         operators = ['ne', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 'mod', |         operators = ['ne', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 'mod', | ||||||
|                      'all', 'size', 'exists', 'not'] |                      'all', 'size', 'exists', 'not'] | ||||||
|         geo_operators = ['within_distance', 'within_box', 'near'] |         geo_operators = ['within_distance', 'within_box', 'near'] | ||||||
|         match_operators = ['contains', 'icontains', 'startswith',  |         match_operators = ['contains', 'icontains', 'startswith', | ||||||
|                            'istartswith', 'endswith', 'iendswith',  |                            'istartswith', 'endswith', 'iendswith', | ||||||
|                            'exact', 'iexact'] |                            'exact', 'iexact'] | ||||||
|  |  | ||||||
|         mongo_query = {} |         mongo_query = {} | ||||||
| @@ -563,8 +563,8 @@ class QuerySet(object): | |||||||
|                                               % self._document._class_name) |                                               % self._document._class_name) | ||||||
|  |  | ||||||
|     def get_or_create(self, *q_objs, **query): |     def get_or_create(self, *q_objs, **query): | ||||||
|         """Retrieve unique object or create, if it doesn't exist. Returns a tuple of  |         """Retrieve unique object or create, if it doesn't exist. Returns a tuple of | ||||||
|         ``(object, created)``, where ``object`` is the retrieved or created object  |         ``(object, created)``, where ``object`` is the retrieved or created object | ||||||
|         and ``created`` is a boolean specifying whether a new object was created. Raises |         and ``created`` is a boolean specifying whether a new object was created. Raises | ||||||
|         :class:`~mongoengine.queryset.MultipleObjectsReturned` or |         :class:`~mongoengine.queryset.MultipleObjectsReturned` or | ||||||
|         `DocumentName.MultipleObjectsReturned` if multiple results are found. |         `DocumentName.MultipleObjectsReturned` if multiple results are found. | ||||||
| @@ -667,8 +667,8 @@ class QuerySet(object): | |||||||
|     def __len__(self): |     def __len__(self): | ||||||
|         return self.count() |         return self.count() | ||||||
|  |  | ||||||
|     def map_reduce(self, map_f, reduce_f, finalize_f=None, limit=None, |     def map_reduce(self, map_f, reduce_f, output, finalize_f=None, limit=None, | ||||||
|                    scope=None, keep_temp=False): |                    scope=None): | ||||||
|         """Perform a map/reduce query using the current query spec |         """Perform a map/reduce query using the current query spec | ||||||
|         and ordering. While ``map_reduce`` respects ``QuerySet`` chaining, |         and ordering. While ``map_reduce`` respects ``QuerySet`` chaining, | ||||||
|         it must be the last call made, as it does not return a maleable |         it must be the last call made, as it does not return a maleable | ||||||
| @@ -678,52 +678,61 @@ class QuerySet(object): | |||||||
|         and :meth:`~mongoengine.tests.QuerySetTest.test_map_advanced` |         and :meth:`~mongoengine.tests.QuerySetTest.test_map_advanced` | ||||||
|         tests in ``tests.queryset.QuerySetTest`` for usage examples. |         tests in ``tests.queryset.QuerySetTest`` for usage examples. | ||||||
|  |  | ||||||
|         :param map_f: map function, as :class:`~pymongo.code.Code` or string |         :param map_f: map function, as :class:`~bson.code.Code` or string | ||||||
|         :param reduce_f: reduce function, as |         :param reduce_f: reduce function, as | ||||||
|                          :class:`~pymongo.code.Code` or string |                          :class:`~bson.code.Code` or string | ||||||
|  |         :param output: output collection name, if set to 'inline' will try to | ||||||
|  |                        use :class:`~pymongo.collection.Collection.inline_map_reduce` | ||||||
|  |                        This can also be a dictionary containing output options | ||||||
|  |                        see: http://docs.mongodb.org/manual/reference/commands/#mapReduce | ||||||
|         :param finalize_f: finalize function, an optional function that |         :param finalize_f: finalize function, an optional function that | ||||||
|                            performs any post-reduction processing. |                            performs any post-reduction processing. | ||||||
|         :param scope: values to insert into map/reduce global scope. Optional. |         :param scope: values to insert into map/reduce global scope. Optional. | ||||||
|         :param limit: number of objects from current query to provide |         :param limit: number of objects from current query to provide | ||||||
|                       to map/reduce method |                       to map/reduce method | ||||||
|         :param keep_temp: keep temporary table (boolean, default ``True``) |  | ||||||
|  |  | ||||||
|         Returns an iterator yielding |         Returns an iterator yielding | ||||||
|         :class:`~mongoengine.document.MapReduceDocument`. |         :class:`~mongoengine.document.MapReduceDocument`. | ||||||
|  |  | ||||||
|         .. note:: Map/Reduce requires server version **>= 1.1.1**. The PyMongo |         .. note:: | ||||||
|            :meth:`~pymongo.collection.Collection.map_reduce` helper requires |  | ||||||
|            PyMongo version **>= 1.2**. |             Map/Reduce changed in server version **>= 1.7.4**. The PyMongo | ||||||
|  |             :meth:`~pymongo.collection.Collection.map_reduce` helper requires | ||||||
|  |             PyMongo version **>= 1.11**. | ||||||
|  |  | ||||||
|  |         .. versionchanged:: 0.5 | ||||||
|  |            - removed ``keep_temp`` keyword argument, which was only relevant | ||||||
|  |              for MongoDB server versions older than 1.7.4 | ||||||
|  |  | ||||||
|         .. versionadded:: 0.3 |         .. versionadded:: 0.3 | ||||||
|         """ |         """ | ||||||
|         from document import MapReduceDocument |         from document import MapReduceDocument | ||||||
|  |  | ||||||
|         if not hasattr(self._collection, "map_reduce"): |         if not hasattr(self._collection, "map_reduce"): | ||||||
|             raise NotImplementedError("Requires MongoDB >= 1.1.1") |             raise NotImplementedError("Requires MongoDB >= 1.7.1") | ||||||
|  |  | ||||||
|         map_f_scope = {} |         map_f_scope = {} | ||||||
|         if isinstance(map_f, pymongo.code.Code): |         if isinstance(map_f, bson.code.Code): | ||||||
|             map_f_scope = map_f.scope |             map_f_scope = map_f.scope | ||||||
|             map_f = unicode(map_f) |             map_f = unicode(map_f) | ||||||
|         map_f = pymongo.code.Code(self._sub_js_fields(map_f), map_f_scope) |         map_f = bson.code.Code(self._sub_js_fields(map_f), map_f_scope) | ||||||
|  |  | ||||||
|         reduce_f_scope = {} |         reduce_f_scope = {} | ||||||
|         if isinstance(reduce_f, pymongo.code.Code): |         if isinstance(reduce_f, bson.code.Code): | ||||||
|             reduce_f_scope = reduce_f.scope |             reduce_f_scope = reduce_f.scope | ||||||
|             reduce_f = unicode(reduce_f) |             reduce_f = unicode(reduce_f) | ||||||
|         reduce_f_code = self._sub_js_fields(reduce_f) |         reduce_f_code = self._sub_js_fields(reduce_f) | ||||||
|         reduce_f = pymongo.code.Code(reduce_f_code, reduce_f_scope) |         reduce_f = bson.code.Code(reduce_f_code, reduce_f_scope) | ||||||
|  |  | ||||||
|         mr_args = {'query': self._query, 'keeptemp': keep_temp} |         mr_args = {'query': self._query} | ||||||
|  |  | ||||||
|         if finalize_f: |         if finalize_f: | ||||||
|             finalize_f_scope = {} |             finalize_f_scope = {} | ||||||
|             if isinstance(finalize_f, pymongo.code.Code): |             if isinstance(finalize_f, bson.code.Code): | ||||||
|                 finalize_f_scope = finalize_f.scope |                 finalize_f_scope = finalize_f.scope | ||||||
|                 finalize_f = unicode(finalize_f) |                 finalize_f = unicode(finalize_f) | ||||||
|             finalize_f_code = self._sub_js_fields(finalize_f) |             finalize_f_code = self._sub_js_fields(finalize_f) | ||||||
|             finalize_f = pymongo.code.Code(finalize_f_code, finalize_f_scope) |             finalize_f = bson.code.Code(finalize_f_code, finalize_f_scope) | ||||||
|             mr_args['finalize'] = finalize_f |             mr_args['finalize'] = finalize_f | ||||||
|  |  | ||||||
|         if scope: |         if scope: | ||||||
| @@ -732,8 +741,16 @@ class QuerySet(object): | |||||||
|         if limit: |         if limit: | ||||||
|             mr_args['limit'] = limit |             mr_args['limit'] = limit | ||||||
|  |  | ||||||
|         results = self._collection.map_reduce(map_f, reduce_f, **mr_args) |         if output == 'inline' and not self._ordering: | ||||||
|         results = results.find() |             map_reduce_function = 'inline_map_reduce' | ||||||
|  |         else: | ||||||
|  |             map_reduce_function = 'map_reduce' | ||||||
|  |             mr_args['out'] = output | ||||||
|  |  | ||||||
|  |         results = getattr(self._collection, map_reduce_function)(map_f, reduce_f, **mr_args) | ||||||
|  |  | ||||||
|  |         if map_reduce_function == 'map_reduce': | ||||||
|  |             results = results.find() | ||||||
|  |  | ||||||
|         if self._ordering: |         if self._ordering: | ||||||
|             results = results.sort(self._ordering) |             results = results.sort(self._ordering) | ||||||
| @@ -777,7 +794,7 @@ class QuerySet(object): | |||||||
|                 self._skip, self._limit = key.start, key.stop |                 self._skip, self._limit = key.start, key.stop | ||||||
|             except IndexError, err: |             except IndexError, err: | ||||||
|                 # PyMongo raises an error if key.start == key.stop, catch it, |                 # PyMongo raises an error if key.start == key.stop, catch it, | ||||||
|                 # bin it, kill it.  |                 # bin it, kill it. | ||||||
|                 start = key.start or 0 |                 start = key.start or 0 | ||||||
|                 if start >= 0 and key.stop >= 0 and key.step is None: |                 if start >= 0 and key.stop >= 0 and key.step is None: | ||||||
|                     if start == key.stop: |                     if start == key.stop: | ||||||
| @@ -933,7 +950,7 @@ class QuerySet(object): | |||||||
|         return mongo_update |         return mongo_update | ||||||
|  |  | ||||||
|     def update(self, safe_update=True, upsert=False, **update): |     def update(self, safe_update=True, upsert=False, **update): | ||||||
|         """Perform an atomic update on the fields matched by the query. When  |         """Perform an atomic update on the fields matched by the query. When | ||||||
|         ``safe_update`` is used, the number of affected documents is returned. |         ``safe_update`` is used, the number of affected documents is returned. | ||||||
|  |  | ||||||
|         :param safe: check if the operation succeeded before returning |         :param safe: check if the operation succeeded before returning | ||||||
| @@ -957,7 +974,7 @@ class QuerySet(object): | |||||||
|             raise OperationError(u'Update failed (%s)' % unicode(err)) |             raise OperationError(u'Update failed (%s)' % unicode(err)) | ||||||
|  |  | ||||||
|     def update_one(self, safe_update=True, upsert=False, **update): |     def update_one(self, safe_update=True, upsert=False, **update): | ||||||
|         """Perform an atomic update on first field matched by the query. When  |         """Perform an atomic update on first field matched by the query. When | ||||||
|         ``safe_update`` is used, the number of affected documents is returned. |         ``safe_update`` is used, the number of affected documents is returned. | ||||||
|  |  | ||||||
|         :param safe: check if the operation succeeded before returning |         :param safe: check if the operation succeeded before returning | ||||||
| @@ -985,8 +1002,8 @@ class QuerySet(object): | |||||||
|         return self |         return self | ||||||
|  |  | ||||||
|     def _sub_js_fields(self, code): |     def _sub_js_fields(self, code): | ||||||
|         """When fields are specified with [~fieldname] syntax, where  |         """When fields are specified with [~fieldname] syntax, where | ||||||
|         *fieldname* is the Python name of a field, *fieldname* will be  |         *fieldname* is the Python name of a field, *fieldname* will be | ||||||
|         substituted for the MongoDB name of the field (specified using the |         substituted for the MongoDB name of the field (specified using the | ||||||
|         :attr:`name` keyword argument in a field's constructor). |         :attr:`name` keyword argument in a field's constructor). | ||||||
|         """ |         """ | ||||||
| @@ -1009,9 +1026,9 @@ class QuerySet(object): | |||||||
|         options specified as keyword arguments. |         options specified as keyword arguments. | ||||||
|  |  | ||||||
|         As fields in MongoEngine may use different names in the database (set |         As fields in MongoEngine may use different names in the database (set | ||||||
|         using the :attr:`db_field` keyword argument to a :class:`Field`  |         using the :attr:`db_field` keyword argument to a :class:`Field` | ||||||
|         constructor), a mechanism exists for replacing MongoEngine field names |         constructor), a mechanism exists for replacing MongoEngine field names | ||||||
|         with the database field names in Javascript code. When accessing a  |         with the database field names in Javascript code. When accessing a | ||||||
|         field, use square-bracket notation, and prefix the MongoEngine field |         field, use square-bracket notation, and prefix the MongoEngine field | ||||||
|         name with a tilde (~). |         name with a tilde (~). | ||||||
|  |  | ||||||
| @@ -1037,7 +1054,7 @@ class QuerySet(object): | |||||||
|             query['$where'] = self._where_clause |             query['$where'] = self._where_clause | ||||||
|  |  | ||||||
|         scope['query'] = query |         scope['query'] = query | ||||||
|         code = pymongo.code.Code(code, scope=scope) |         code = bson.code.Code(code, scope=scope) | ||||||
|  |  | ||||||
|         db = _get_db() |         db = _get_db() | ||||||
|         return db.eval(code, *fields) |         return db.eval(code, *fields) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import unittest | import unittest | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
|  | import bson | ||||||
| import pymongo | import pymongo | ||||||
|  |  | ||||||
| from mongoengine import * | from mongoengine import * | ||||||
| @@ -7,7 +8,7 @@ from mongoengine.connection import _get_db | |||||||
|  |  | ||||||
|  |  | ||||||
| class DocumentTest(unittest.TestCase): | class DocumentTest(unittest.TestCase): | ||||||
|      |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         connect(db='mongoenginetest') |         connect(db='mongoenginetest') | ||||||
|         self.db = _get_db() |         self.db = _get_db() | ||||||
| @@ -38,7 +39,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|             name = name_field |             name = name_field | ||||||
|             age = age_field |             age = age_field | ||||||
|             non_field = True |             non_field = True | ||||||
|          |  | ||||||
|         self.assertEqual(Person._fields['name'], name_field) |         self.assertEqual(Person._fields['name'], name_field) | ||||||
|         self.assertEqual(Person._fields['age'], age_field) |         self.assertEqual(Person._fields['age'], age_field) | ||||||
|         self.assertFalse('non_field' in Person._fields) |         self.assertFalse('non_field' in Person._fields) | ||||||
| @@ -60,7 +61,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|  |  | ||||||
|         mammal_superclasses = {'Animal': Animal} |         mammal_superclasses = {'Animal': Animal} | ||||||
|         self.assertEqual(Mammal._superclasses, mammal_superclasses) |         self.assertEqual(Mammal._superclasses, mammal_superclasses) | ||||||
|          |  | ||||||
|         dog_superclasses = { |         dog_superclasses = { | ||||||
|             'Animal': Animal, |             'Animal': Animal, | ||||||
|             'Animal.Mammal': Mammal, |             'Animal.Mammal': Mammal, | ||||||
| @@ -68,7 +69,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|         self.assertEqual(Dog._superclasses, dog_superclasses) |         self.assertEqual(Dog._superclasses, dog_superclasses) | ||||||
|  |  | ||||||
|     def test_get_subclasses(self): |     def test_get_subclasses(self): | ||||||
|         """Ensure that the correct list of subclasses is retrieved by the  |         """Ensure that the correct list of subclasses is retrieved by the | ||||||
|         _get_subclasses method. |         _get_subclasses method. | ||||||
|         """ |         """ | ||||||
|         class Animal(Document): pass |         class Animal(Document): pass | ||||||
| @@ -78,15 +79,15 @@ class DocumentTest(unittest.TestCase): | |||||||
|         class Dog(Mammal): pass |         class Dog(Mammal): pass | ||||||
|  |  | ||||||
|         mammal_subclasses = { |         mammal_subclasses = { | ||||||
|             'Animal.Mammal.Dog': Dog,  |             'Animal.Mammal.Dog': Dog, | ||||||
|             'Animal.Mammal.Human': Human |             'Animal.Mammal.Human': Human | ||||||
|         } |         } | ||||||
|         self.assertEqual(Mammal._get_subclasses(), mammal_subclasses) |         self.assertEqual(Mammal._get_subclasses(), mammal_subclasses) | ||||||
|          |  | ||||||
|         animal_subclasses = { |         animal_subclasses = { | ||||||
|             'Animal.Fish': Fish, |             'Animal.Fish': Fish, | ||||||
|             'Animal.Mammal': Mammal, |             'Animal.Mammal': Mammal, | ||||||
|             'Animal.Mammal.Dog': Dog,  |             'Animal.Mammal.Dog': Dog, | ||||||
|             'Animal.Mammal.Human': Human |             'Animal.Mammal.Human': Human | ||||||
|         } |         } | ||||||
|         self.assertEqual(Animal._get_subclasses(), animal_subclasses) |         self.assertEqual(Animal._get_subclasses(), animal_subclasses) | ||||||
| @@ -124,7 +125,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|  |  | ||||||
|         self.assertTrue('name' in Employee._fields) |         self.assertTrue('name' in Employee._fields) | ||||||
|         self.assertTrue('salary' in Employee._fields) |         self.assertTrue('salary' in Employee._fields) | ||||||
|         self.assertEqual(Employee._meta['collection'],  |         self.assertEqual(Employee._meta['collection'], | ||||||
|                          self.Person._meta['collection']) |                          self.Person._meta['collection']) | ||||||
|  |  | ||||||
|         # Ensure that MRO error is not raised |         # Ensure that MRO error is not raised | ||||||
| @@ -146,7 +147,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|             class Dog(Animal): |             class Dog(Animal): | ||||||
|                 pass |                 pass | ||||||
|         self.assertRaises(ValueError, create_dog_class) |         self.assertRaises(ValueError, create_dog_class) | ||||||
|          |  | ||||||
|         # Check that _cls etc aren't present on simple documents |         # Check that _cls etc aren't present on simple documents | ||||||
|         dog = Animal(name='dog') |         dog = Animal(name='dog') | ||||||
|         dog.save() |         dog.save() | ||||||
| @@ -161,7 +162,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|             class Employee(self.Person): |             class Employee(self.Person): | ||||||
|                 meta = {'allow_inheritance': False} |                 meta = {'allow_inheritance': False} | ||||||
|         self.assertRaises(ValueError, create_employee_class) |         self.assertRaises(ValueError, create_employee_class) | ||||||
|          |  | ||||||
|         # Test the same for embedded documents |         # Test the same for embedded documents | ||||||
|         class Comment(EmbeddedDocument): |         class Comment(EmbeddedDocument): | ||||||
|             content = StringField() |             content = StringField() | ||||||
| @@ -186,7 +187,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|         class Person(Document): |         class Person(Document): | ||||||
|             name = StringField() |             name = StringField() | ||||||
|             meta = {'collection': collection} |             meta = {'collection': collection} | ||||||
|          |  | ||||||
|         user = Person(name="Test User") |         user = Person(name="Test User") | ||||||
|         user.save() |         user.save() | ||||||
|         self.assertTrue(collection in self.db.collection_names()) |         self.assertTrue(collection in self.db.collection_names()) | ||||||
| @@ -280,7 +281,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|             tags = ListField(StringField()) |             tags = ListField(StringField()) | ||||||
|             meta = { |             meta = { | ||||||
|                 'indexes': [ |                 'indexes': [ | ||||||
|                     '-date',  |                     '-date', | ||||||
|                     'tags', |                     'tags', | ||||||
|                     ('category', '-date') |                     ('category', '-date') | ||||||
|                 ], |                 ], | ||||||
| @@ -296,12 +297,12 @@ class DocumentTest(unittest.TestCase): | |||||||
|         list(BlogPost.objects) |         list(BlogPost.objects) | ||||||
|         info = BlogPost.objects._collection.index_information() |         info = BlogPost.objects._collection.index_information() | ||||||
|         info = [value['key'] for key, value in info.iteritems()] |         info = [value['key'] for key, value in info.iteritems()] | ||||||
|         self.assertTrue([('_types', 1), ('category', 1), ('addDate', -1)]  |         self.assertTrue([('_types', 1), ('category', 1), ('addDate', -1)] | ||||||
|                         in info) |                         in info) | ||||||
|         self.assertTrue([('_types', 1), ('addDate', -1)] in info) |         self.assertTrue([('_types', 1), ('addDate', -1)] in info) | ||||||
|         # tags is a list field so it shouldn't have _types in the index |         # tags is a list field so it shouldn't have _types in the index | ||||||
|         self.assertTrue([('tags', 1)] in info) |         self.assertTrue([('tags', 1)] in info) | ||||||
|          |  | ||||||
|         class ExtendedBlogPost(BlogPost): |         class ExtendedBlogPost(BlogPost): | ||||||
|             title = StringField() |             title = StringField() | ||||||
|             meta = {'indexes': ['title']} |             meta = {'indexes': ['title']} | ||||||
| @@ -311,7 +312,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|         list(ExtendedBlogPost.objects) |         list(ExtendedBlogPost.objects) | ||||||
|         info = ExtendedBlogPost.objects._collection.index_information() |         info = ExtendedBlogPost.objects._collection.index_information() | ||||||
|         info = [value['key'] for key, value in info.iteritems()] |         info = [value['key'] for key, value in info.iteritems()] | ||||||
|         self.assertTrue([('_types', 1), ('category', 1), ('addDate', -1)]  |         self.assertTrue([('_types', 1), ('category', 1), ('addDate', -1)] | ||||||
|                         in info) |                         in info) | ||||||
|         self.assertTrue([('_types', 1), ('addDate', -1)] in info) |         self.assertTrue([('_types', 1), ('addDate', -1)] in info) | ||||||
|         self.assertTrue([('_types', 1), ('title', 1)] in info) |         self.assertTrue([('_types', 1), ('title', 1)] in info) | ||||||
| @@ -380,7 +381,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|  |  | ||||||
|         class EmailUser(User): |         class EmailUser(User): | ||||||
|             email = StringField() |             email = StringField() | ||||||
|          |  | ||||||
|         user = User(username='test', name='test user') |         user = User(username='test', name='test user') | ||||||
|         user.save() |         user.save() | ||||||
|  |  | ||||||
| @@ -391,20 +392,20 @@ class DocumentTest(unittest.TestCase): | |||||||
|         user_son = User.objects._collection.find_one() |         user_son = User.objects._collection.find_one() | ||||||
|         self.assertEqual(user_son['_id'], 'test') |         self.assertEqual(user_son['_id'], 'test') | ||||||
|         self.assertTrue('username' not in user_son['_id']) |         self.assertTrue('username' not in user_son['_id']) | ||||||
|          |  | ||||||
|         User.drop_collection() |         User.drop_collection() | ||||||
|          |  | ||||||
|         user = User(pk='mongo', name='mongo user') |         user = User(pk='mongo', name='mongo user') | ||||||
|         user.save() |         user.save() | ||||||
|          |  | ||||||
|         user_obj = User.objects.first() |         user_obj = User.objects.first() | ||||||
|         self.assertEqual(user_obj.id, 'mongo') |         self.assertEqual(user_obj.id, 'mongo') | ||||||
|         self.assertEqual(user_obj.pk, 'mongo') |         self.assertEqual(user_obj.pk, 'mongo') | ||||||
|          |  | ||||||
|         user_son = User.objects._collection.find_one() |         user_son = User.objects._collection.find_one() | ||||||
|         self.assertEqual(user_son['_id'], 'mongo') |         self.assertEqual(user_son['_id'], 'mongo') | ||||||
|         self.assertTrue('username' not in user_son['_id']) |         self.assertTrue('username' not in user_son['_id']) | ||||||
|          |  | ||||||
|         User.drop_collection() |         User.drop_collection() | ||||||
|  |  | ||||||
|     def test_creation(self): |     def test_creation(self): | ||||||
| @@ -457,18 +458,18 @@ class DocumentTest(unittest.TestCase): | |||||||
|         """ |         """ | ||||||
|         class Comment(EmbeddedDocument): |         class Comment(EmbeddedDocument): | ||||||
|             content = StringField() |             content = StringField() | ||||||
|          |  | ||||||
|         self.assertTrue('content' in Comment._fields) |         self.assertTrue('content' in Comment._fields) | ||||||
|         self.assertFalse('id' in Comment._fields) |         self.assertFalse('id' in Comment._fields) | ||||||
|         self.assertFalse('collection' in Comment._meta) |         self.assertFalse('collection' in Comment._meta) | ||||||
|      |  | ||||||
|     def test_embedded_document_validation(self): |     def test_embedded_document_validation(self): | ||||||
|         """Ensure that embedded documents may be validated. |         """Ensure that embedded documents may be validated. | ||||||
|         """ |         """ | ||||||
|         class Comment(EmbeddedDocument): |         class Comment(EmbeddedDocument): | ||||||
|             date = DateTimeField() |             date = DateTimeField() | ||||||
|             content = StringField(required=True) |             content = StringField(required=True) | ||||||
|          |  | ||||||
|         comment = Comment() |         comment = Comment() | ||||||
|         self.assertRaises(ValidationError, comment.validate) |         self.assertRaises(ValidationError, comment.validate) | ||||||
|  |  | ||||||
| @@ -496,7 +497,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|         # Test skipping validation on save |         # Test skipping validation on save | ||||||
|         class Recipient(Document): |         class Recipient(Document): | ||||||
|             email = EmailField(required=True) |             email = EmailField(required=True) | ||||||
|          |  | ||||||
|         recipient = Recipient(email='root@localhost') |         recipient = Recipient(email='root@localhost') | ||||||
|         self.assertRaises(ValidationError, recipient.save) |         self.assertRaises(ValidationError, recipient.save) | ||||||
|         try: |         try: | ||||||
| @@ -517,19 +518,19 @@ class DocumentTest(unittest.TestCase): | |||||||
|         """Ensure that a document may be saved with a custom _id. |         """Ensure that a document may be saved with a custom _id. | ||||||
|         """ |         """ | ||||||
|         # Create person object and save it to the database |         # Create person object and save it to the database | ||||||
|         person = self.Person(name='Test User', age=30,  |         person = self.Person(name='Test User', age=30, | ||||||
|                              id='497ce96f395f2f052a494fd4') |                              id='497ce96f395f2f052a494fd4') | ||||||
|         person.save() |         person.save() | ||||||
|         # Ensure that the object is in the database with the correct _id |         # Ensure that the object is in the database with the correct _id | ||||||
|         collection = self.db[self.Person._meta['collection']] |         collection = self.db[self.Person._meta['collection']] | ||||||
|         person_obj = collection.find_one({'name': 'Test User'}) |         person_obj = collection.find_one({'name': 'Test User'}) | ||||||
|         self.assertEqual(str(person_obj['_id']), '497ce96f395f2f052a494fd4') |         self.assertEqual(str(person_obj['_id']), '497ce96f395f2f052a494fd4') | ||||||
|          |  | ||||||
|     def test_save_custom_pk(self): |     def test_save_custom_pk(self): | ||||||
|         """Ensure that a document may be saved with a custom _id using pk alias. |         """Ensure that a document may be saved with a custom _id using pk alias. | ||||||
|         """ |         """ | ||||||
|         # Create person object and save it to the database |         # Create person object and save it to the database | ||||||
|         person = self.Person(name='Test User', age=30,  |         person = self.Person(name='Test User', age=30, | ||||||
|                              pk='497ce96f395f2f052a494fd4') |                              pk='497ce96f395f2f052a494fd4') | ||||||
|         person.save() |         person.save() | ||||||
|         # Ensure that the object is in the database with the correct _id |         # Ensure that the object is in the database with the correct _id | ||||||
| @@ -565,7 +566,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|         BlogPost.drop_collection() |         BlogPost.drop_collection() | ||||||
|  |  | ||||||
|     def test_save_embedded_document(self): |     def test_save_embedded_document(self): | ||||||
|         """Ensure that a document with an embedded document field may be  |         """Ensure that a document with an embedded document field may be | ||||||
|         saved in the database. |         saved in the database. | ||||||
|         """ |         """ | ||||||
|         class EmployeeDetails(EmbeddedDocument): |         class EmployeeDetails(EmbeddedDocument): | ||||||
| @@ -591,7 +592,7 @@ class DocumentTest(unittest.TestCase): | |||||||
|     def test_save_reference(self): |     def test_save_reference(self): | ||||||
|         """Ensure that a document reference field may be saved in the database. |         """Ensure that a document reference field may be saved in the database. | ||||||
|         """ |         """ | ||||||
|          |  | ||||||
|         class BlogPost(Document): |         class BlogPost(Document): | ||||||
|             meta = {'collection': 'blogpost_1'} |             meta = {'collection': 'blogpost_1'} | ||||||
|             content = StringField() |             content = StringField() | ||||||
| @@ -610,8 +611,8 @@ class DocumentTest(unittest.TestCase): | |||||||
|         post_obj = BlogPost.objects.first() |         post_obj = BlogPost.objects.first() | ||||||
|  |  | ||||||
|         # Test laziness |         # Test laziness | ||||||
|         self.assertTrue(isinstance(post_obj._data['author'],  |         self.assertTrue(isinstance(post_obj._data['author'], | ||||||
|                                    pymongo.dbref.DBRef)) |                                    bson.dbref.DBRef)) | ||||||
|         self.assertTrue(isinstance(post_obj.author, self.Person)) |         self.assertTrue(isinstance(post_obj.author, self.Person)) | ||||||
|         self.assertEqual(post_obj.author.name, 'Test User') |         self.assertEqual(post_obj.author.name, 'Test User') | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
|  |  | ||||||
| import unittest | import unittest | ||||||
| import pymongo | import pymongo | ||||||
|  | import bson | ||||||
| from datetime import datetime, timedelta | from datetime import datetime, timedelta | ||||||
|  |  | ||||||
| from mongoengine.queryset import (QuerySet, MultipleObjectsReturned, | from mongoengine.queryset import (QuerySet, MultipleObjectsReturned, | ||||||
| @@ -58,7 +59,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         self.assertEqual(len(people), 2) |         self.assertEqual(len(people), 2) | ||||||
|         results = list(people) |         results = list(people) | ||||||
|         self.assertTrue(isinstance(results[0], self.Person)) |         self.assertTrue(isinstance(results[0], self.Person)) | ||||||
|         self.assertTrue(isinstance(results[0].id, (pymongo.objectid.ObjectId, |         self.assertTrue(isinstance(results[0].id, (bson.objectid.ObjectId, | ||||||
|                                                    str, unicode))) |                                                    str, unicode))) | ||||||
|         self.assertEqual(results[0].name, "User A") |         self.assertEqual(results[0].name, "User A") | ||||||
|         self.assertEqual(results[0].age, 20) |         self.assertEqual(results[0].age, 20) | ||||||
| @@ -162,7 +163,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|  |  | ||||||
|         person = self.Person.objects.get(age__lt=30) |         person = self.Person.objects.get(age__lt=30) | ||||||
|         self.assertEqual(person.name, "User A") |         self.assertEqual(person.name, "User A") | ||||||
|          |  | ||||||
|     def test_find_array_position(self): |     def test_find_array_position(self): | ||||||
|         """Ensure that query by array position works. |         """Ensure that query by array position works. | ||||||
|         """ |         """ | ||||||
| @@ -177,7 +178,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|             posts = ListField(EmbeddedDocumentField(Post)) |             posts = ListField(EmbeddedDocumentField(Post)) | ||||||
|  |  | ||||||
|         Blog.drop_collection() |         Blog.drop_collection() | ||||||
|          |  | ||||||
|         Blog.objects.create(tags=['a', 'b']) |         Blog.objects.create(tags=['a', 'b']) | ||||||
|         self.assertEqual(len(Blog.objects(tags__0='a')), 1) |         self.assertEqual(len(Blog.objects(tags__0='a')), 1) | ||||||
|         self.assertEqual(len(Blog.objects(tags__0='b')), 0) |         self.assertEqual(len(Blog.objects(tags__0='b')), 0) | ||||||
| @@ -226,16 +227,16 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         person, created = self.Person.objects.get_or_create(age=30) |         person, created = self.Person.objects.get_or_create(age=30) | ||||||
|         self.assertEqual(person.name, "User B") |         self.assertEqual(person.name, "User B") | ||||||
|         self.assertEqual(created, False) |         self.assertEqual(created, False) | ||||||
|          |  | ||||||
|         person, created = self.Person.objects.get_or_create(age__lt=30) |         person, created = self.Person.objects.get_or_create(age__lt=30) | ||||||
|         self.assertEqual(person.name, "User A") |         self.assertEqual(person.name, "User A") | ||||||
|         self.assertEqual(created, False) |         self.assertEqual(created, False) | ||||||
|          |  | ||||||
|         # Try retrieving when no objects exists - new doc should be created |         # Try retrieving when no objects exists - new doc should be created | ||||||
|         kwargs = dict(age=50, defaults={'name': 'User C'}) |         kwargs = dict(age=50, defaults={'name': 'User C'}) | ||||||
|         person, created = self.Person.objects.get_or_create(**kwargs) |         person, created = self.Person.objects.get_or_create(**kwargs) | ||||||
|         self.assertEqual(created, True) |         self.assertEqual(created, True) | ||||||
|          |  | ||||||
|         person = self.Person.objects.get(age=50) |         person = self.Person.objects.get(age=50) | ||||||
|         self.assertEqual(person.name, "User C") |         self.assertEqual(person.name, "User C") | ||||||
|  |  | ||||||
| @@ -328,7 +329,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         self.assertEqual(obj, person) |         self.assertEqual(obj, person) | ||||||
|         obj = self.Person.objects(Q(name__iexact='gUIDO VAN rOSSU')).first() |         obj = self.Person.objects(Q(name__iexact='gUIDO VAN rOSSU')).first() | ||||||
|         self.assertEqual(obj, None) |         self.assertEqual(obj, None) | ||||||
|          |  | ||||||
|         # Test unsafe expressions |         # Test unsafe expressions | ||||||
|         person = self.Person(name='Guido van Rossum [.\'Geek\']') |         person = self.Person(name='Guido van Rossum [.\'Geek\']') | ||||||
|         person.save() |         person.save() | ||||||
| @@ -559,7 +560,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|  |  | ||||||
|         obj = self.Person.objects(Q(name__not=re.compile('^bob'))).first() |         obj = self.Person.objects(Q(name__not=re.compile('^bob'))).first() | ||||||
|         self.assertEqual(obj, person) |         self.assertEqual(obj, person) | ||||||
|          |  | ||||||
|         obj = self.Person.objects(Q(name__not=re.compile('^Gui'))).first() |         obj = self.Person.objects(Q(name__not=re.compile('^Gui'))).first() | ||||||
|         self.assertEqual(obj, None) |         self.assertEqual(obj, None) | ||||||
|  |  | ||||||
| @@ -631,7 +632,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|  |  | ||||||
|         class BlogPost(Document): |         class BlogPost(Document): | ||||||
|             name = StringField(db_field='doc-name') |             name = StringField(db_field='doc-name') | ||||||
|             comments = ListField(EmbeddedDocumentField(Comment),  |             comments = ListField(EmbeddedDocumentField(Comment), | ||||||
|                                  db_field='cmnts') |                                  db_field='cmnts') | ||||||
|  |  | ||||||
|         BlogPost.drop_collection() |         BlogPost.drop_collection() | ||||||
| @@ -733,7 +734,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         BlogPost.objects.update_one(add_to_set__tags='unique') |         BlogPost.objects.update_one(add_to_set__tags='unique') | ||||||
|         post.reload() |         post.reload() | ||||||
|         self.assertEqual(post.tags.count('unique'), 1) |         self.assertEqual(post.tags.count('unique'), 1) | ||||||
|          |  | ||||||
|         BlogPost.drop_collection() |         BlogPost.drop_collection() | ||||||
|  |  | ||||||
|     def test_update_pull(self): |     def test_update_pull(self): | ||||||
| @@ -802,7 +803,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         # run a map/reduce operation spanning all posts |         # run a map/reduce operation spanning all posts | ||||||
|         results = BlogPost.objects.map_reduce(map_f, reduce_f) |         results = BlogPost.objects.map_reduce(map_f, reduce_f, "myresults") | ||||||
|         results = list(results) |         results = list(results) | ||||||
|         self.assertEqual(len(results), 4) |         self.assertEqual(len(results), 4) | ||||||
|  |  | ||||||
| @@ -813,7 +814,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         self.assertEqual(film.value, 3) |         self.assertEqual(film.value, 3) | ||||||
|  |  | ||||||
|         BlogPost.drop_collection() |         BlogPost.drop_collection() | ||||||
|          |  | ||||||
|     def test_map_reduce_with_custom_object_ids(self): |     def test_map_reduce_with_custom_object_ids(self): | ||||||
|         """Ensure that QuerySet.map_reduce works properly with custom |         """Ensure that QuerySet.map_reduce works properly with custom | ||||||
|         primary keys. |         primary keys. | ||||||
| @@ -822,24 +823,24 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         class BlogPost(Document): |         class BlogPost(Document): | ||||||
|             title = StringField(primary_key=True) |             title = StringField(primary_key=True) | ||||||
|             tags = ListField(StringField()) |             tags = ListField(StringField()) | ||||||
|          |  | ||||||
|         post1 = BlogPost(title="Post #1", tags=["mongodb", "mongoengine"]) |         post1 = BlogPost(title="Post #1", tags=["mongodb", "mongoengine"]) | ||||||
|         post2 = BlogPost(title="Post #2", tags=["django", "mongodb"]) |         post2 = BlogPost(title="Post #2", tags=["django", "mongodb"]) | ||||||
|         post3 = BlogPost(title="Post #3", tags=["hitchcock films"]) |         post3 = BlogPost(title="Post #3", tags=["hitchcock films"]) | ||||||
|          |  | ||||||
|         post1.save() |         post1.save() | ||||||
|         post2.save() |         post2.save() | ||||||
|         post3.save() |         post3.save() | ||||||
|          |  | ||||||
|         self.assertEqual(BlogPost._fields['title'].db_field, '_id') |         self.assertEqual(BlogPost._fields['title'].db_field, '_id') | ||||||
|         self.assertEqual(BlogPost._meta['id_field'], 'title') |         self.assertEqual(BlogPost._meta['id_field'], 'title') | ||||||
|          |  | ||||||
|         map_f = """ |         map_f = """ | ||||||
|             function() { |             function() { | ||||||
|                 emit(this._id, 1); |                 emit(this._id, 1); | ||||||
|             } |             } | ||||||
|         """ |         """ | ||||||
|          |  | ||||||
|         # reduce to a list of tag ids and counts |         # reduce to a list of tag ids and counts | ||||||
|         reduce_f = """ |         reduce_f = """ | ||||||
|             function(key, values) { |             function(key, values) { | ||||||
| @@ -850,10 +851,10 @@ class QuerySetTest(unittest.TestCase): | |||||||
|                 return total; |                 return total; | ||||||
|             } |             } | ||||||
|         """ |         """ | ||||||
|          |  | ||||||
|         results = BlogPost.objects.map_reduce(map_f, reduce_f) |         results = BlogPost.objects.map_reduce(map_f, reduce_f, "myresults") | ||||||
|         results = list(results) |         results = list(results) | ||||||
|          |  | ||||||
|         self.assertEqual(results[0].object, post1) |         self.assertEqual(results[0].object, post1) | ||||||
|         self.assertEqual(results[1].object, post2) |         self.assertEqual(results[1].object, post2) | ||||||
|         self.assertEqual(results[2].object, post3) |         self.assertEqual(results[2].object, post3) | ||||||
| @@ -943,7 +944,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|  |  | ||||||
|         finalize_f = """ |         finalize_f = """ | ||||||
|             function(key, value) { |             function(key, value) { | ||||||
|                 // f(sec_since_epoch,y,z) =  |                 // f(sec_since_epoch,y,z) = | ||||||
|                 //                    log10(z) + ((y*sec_since_epoch) / 45000) |                 //                    log10(z) + ((y*sec_since_epoch) / 45000) | ||||||
|                 z_10 = Math.log(value.z) / Math.log(10); |                 z_10 = Math.log(value.z) / Math.log(10); | ||||||
|                 weight = z_10 + ((value.y * value.t_s) / 45000); |                 weight = z_10 + ((value.y * value.t_s) / 45000); | ||||||
| @@ -962,6 +963,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         results = Link.objects.order_by("-value") |         results = Link.objects.order_by("-value") | ||||||
|         results = results.map_reduce(map_f, |         results = results.map_reduce(map_f, | ||||||
|                                      reduce_f, |                                      reduce_f, | ||||||
|  |                                      "myresults", | ||||||
|                                      finalize_f=finalize_f, |                                      finalize_f=finalize_f, | ||||||
|                                      scope=scope) |                                      scope=scope) | ||||||
|         results = list(results) |         results = list(results) | ||||||
| @@ -1289,12 +1291,12 @@ class QuerySetTest(unittest.TestCase): | |||||||
|             title = StringField() |             title = StringField() | ||||||
|             date = DateTimeField() |             date = DateTimeField() | ||||||
|             location = GeoPointField() |             location = GeoPointField() | ||||||
|              |  | ||||||
|             def __unicode__(self): |             def __unicode__(self): | ||||||
|                 return self.title |                 return self.title | ||||||
|              |  | ||||||
|         Event.drop_collection() |         Event.drop_collection() | ||||||
|          |  | ||||||
|         event1 = Event(title="Coltrane Motion @ Double Door", |         event1 = Event(title="Coltrane Motion @ Double Door", | ||||||
|                        date=datetime.now() - timedelta(days=1), |                        date=datetime.now() - timedelta(days=1), | ||||||
|                        location=[41.909889, -87.677137]) |                        location=[41.909889, -87.677137]) | ||||||
| @@ -1304,7 +1306,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         event3 = Event(title="Coltrane Motion @ Empty Bottle", |         event3 = Event(title="Coltrane Motion @ Empty Bottle", | ||||||
|                        date=datetime.now(), |                        date=datetime.now(), | ||||||
|                        location=[41.900474, -87.686638]) |                        location=[41.900474, -87.686638]) | ||||||
|                         |  | ||||||
|         event1.save() |         event1.save() | ||||||
|         event2.save() |         event2.save() | ||||||
|         event3.save() |         event3.save() | ||||||
| @@ -1324,24 +1326,24 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         self.assertTrue(event2 not in events) |         self.assertTrue(event2 not in events) | ||||||
|         self.assertTrue(event1 in events) |         self.assertTrue(event1 in events) | ||||||
|         self.assertTrue(event3 in events) |         self.assertTrue(event3 in events) | ||||||
|          |  | ||||||
|         # ensure ordering is respected by "near" |         # ensure ordering is respected by "near" | ||||||
|         events = Event.objects(location__near=[41.9120459, -87.67892]) |         events = Event.objects(location__near=[41.9120459, -87.67892]) | ||||||
|         events = events.order_by("-date") |         events = events.order_by("-date") | ||||||
|         self.assertEqual(events.count(), 3) |         self.assertEqual(events.count(), 3) | ||||||
|         self.assertEqual(list(events), [event3, event1, event2]) |         self.assertEqual(list(events), [event3, event1, event2]) | ||||||
|          |  | ||||||
|         # find events around san francisco |         # find events around san francisco | ||||||
|         point_and_distance = [[37.7566023, -122.415579], 10] |         point_and_distance = [[37.7566023, -122.415579], 10] | ||||||
|         events = Event.objects(location__within_distance=point_and_distance) |         events = Event.objects(location__within_distance=point_and_distance) | ||||||
|         self.assertEqual(events.count(), 1) |         self.assertEqual(events.count(), 1) | ||||||
|         self.assertEqual(events[0], event2) |         self.assertEqual(events[0], event2) | ||||||
|          |  | ||||||
|         # find events within 1 mile of greenpoint, broolyn, nyc, ny |         # find events within 1 mile of greenpoint, broolyn, nyc, ny | ||||||
|         point_and_distance = [[40.7237134, -73.9509714], 1] |         point_and_distance = [[40.7237134, -73.9509714], 1] | ||||||
|         events = Event.objects(location__within_distance=point_and_distance) |         events = Event.objects(location__within_distance=point_and_distance) | ||||||
|         self.assertEqual(events.count(), 0) |         self.assertEqual(events.count(), 0) | ||||||
|          |  | ||||||
|         # ensure ordering is respected by "within_distance" |         # ensure ordering is respected by "within_distance" | ||||||
|         point_and_distance = [[41.9120459, -87.67892], 10] |         point_and_distance = [[41.9120459, -87.67892], 10] | ||||||
|         events = Event.objects(location__within_distance=point_and_distance) |         events = Event.objects(location__within_distance=point_and_distance) | ||||||
| @@ -1354,7 +1356,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         events = Event.objects(location__within_box=box) |         events = Event.objects(location__within_box=box) | ||||||
|         self.assertEqual(events.count(), 1) |         self.assertEqual(events.count(), 1) | ||||||
|         self.assertEqual(events[0].id, event2.id) |         self.assertEqual(events[0].id, event2.id) | ||||||
|          |  | ||||||
|         Event.drop_collection() |         Event.drop_collection() | ||||||
|  |  | ||||||
|     def test_custom_querysets(self): |     def test_custom_querysets(self): | ||||||
| @@ -1398,7 +1400,7 @@ class QTest(unittest.TestCase): | |||||||
|  |  | ||||||
|         query = {'age': {'$gte': 18}, 'name': 'test'} |         query = {'age': {'$gte': 18}, 'name': 'test'} | ||||||
|         self.assertEqual((q1 & q2 & q3 & q4 & q5).to_query(Person), query) |         self.assertEqual((q1 & q2 & q3 & q4 & q5).to_query(Person), query) | ||||||
|      |  | ||||||
|     def test_q_with_dbref(self): |     def test_q_with_dbref(self): | ||||||
|         """Ensure Q objects handle DBRefs correctly""" |         """Ensure Q objects handle DBRefs correctly""" | ||||||
|         connect(db='mongoenginetest') |         connect(db='mongoenginetest') | ||||||
| @@ -1440,7 +1442,7 @@ class QTest(unittest.TestCase): | |||||||
|         query = Q(x__lt=100) & Q(y__ne='NotMyString') |         query = Q(x__lt=100) & Q(y__ne='NotMyString') | ||||||
|         query &= Q(y__in=['a', 'b', 'c']) & Q(x__gt=-100) |         query &= Q(y__in=['a', 'b', 'c']) & Q(x__gt=-100) | ||||||
|         mongo_query = { |         mongo_query = { | ||||||
|             'x': {'$lt': 100, '$gt': -100},  |             'x': {'$lt': 100, '$gt': -100}, | ||||||
|             'y': {'$ne': 'NotMyString', '$in': ['a', 'b', 'c']}, |             'y': {'$ne': 'NotMyString', '$in': ['a', 'b', 'c']}, | ||||||
|         } |         } | ||||||
|         self.assertEqual(query.to_query(TestDoc), mongo_query) |         self.assertEqual(query.to_query(TestDoc), mongo_query) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user