Merge branch 'master' of github.com:MongoEngine/mongoengine into fix_baselist_marked_changed_bug

This commit is contained in:
Bastien Gérard
2018-12-15 20:36:42 +01:00
57 changed files with 2051 additions and 1062 deletions

View File

@@ -1,4 +1,4 @@
from all_warnings import AllWarnings
from document import *
from queryset import *
from fields import *
from .all_warnings import AllWarnings
from .document import *
from .queryset import *
from .fields import *

View File

@@ -1,13 +1,13 @@
import unittest
from class_methods import *
from delta import *
from dynamic import *
from indexes import *
from inheritance import *
from instance import *
from json_serialisation import *
from validation import *
from .class_methods import *
from .delta import *
from .dynamic import *
from .indexes import *
from .inheritance import *
from .instance import *
from .json_serialisation import *
from .validation import *
if __name__ == '__main__':
unittest.main()

View File

@@ -5,7 +5,7 @@ from mongoengine import *
from mongoengine.queryset import NULLIFY, PULL
from mongoengine.connection import get_db
from tests.utils import needs_mongodb_v26
from tests.utils import requires_mongodb_gte_26
__all__ = ("ClassMethodsTest", )
@@ -66,10 +66,10 @@ class ClassMethodsTest(unittest.TestCase):
"""
collection_name = 'person'
self.Person(name='Test').save()
self.assertTrue(collection_name in self.db.collection_names())
self.assertIn(collection_name, self.db.collection_names())
self.Person.drop_collection()
self.assertFalse(collection_name in self.db.collection_names())
self.assertNotIn(collection_name, self.db.collection_names())
def test_register_delete_rule(self):
"""Ensure that register delete rule adds a delete rule to the document
@@ -188,7 +188,7 @@ class ClassMethodsTest(unittest.TestCase):
self.assertEqual(BlogPostWithTags.compare_indexes(), { 'missing': [], 'extra': [] })
self.assertEqual(BlogPostWithCustomField.compare_indexes(), { 'missing': [], 'extra': [] })
@needs_mongodb_v26
@requires_mongodb_gte_26
def test_compare_indexes_for_text_indexes(self):
""" Ensure that compare_indexes behaves correctly for text indexes """
@@ -340,7 +340,7 @@ class ClassMethodsTest(unittest.TestCase):
meta = {'collection': collection_name}
Person(name="Test User").save()
self.assertTrue(collection_name in self.db.collection_names())
self.assertIn(collection_name, self.db.collection_names())
user_obj = self.db[collection_name].find_one()
self.assertEqual(user_obj['name'], "Test User")
@@ -349,7 +349,7 @@ class ClassMethodsTest(unittest.TestCase):
self.assertEqual(user_obj.name, "Test User")
Person.drop_collection()
self.assertFalse(collection_name in self.db.collection_names())
self.assertNotIn(collection_name, self.db.collection_names())
def test_collection_name_and_primary(self):
"""Ensure that a collection with a specified name may be used.

View File

@@ -694,7 +694,7 @@ class DeltaTest(unittest.TestCase):
organization.employees.append(person)
updates, removals = organization._delta()
self.assertEqual({}, removals)
self.assertTrue('employees' in updates)
self.assertIn('employees', updates)
def test_delta_with_dbref_false(self):
person, organization, employee = self.circular_reference_deltas_2(Document, Document, False)
@@ -709,7 +709,7 @@ class DeltaTest(unittest.TestCase):
organization.employees.append(person)
updates, removals = organization._delta()
self.assertEqual({}, removals)
self.assertTrue('employees' in updates)
self.assertIn('employees', updates)
def test_nested_nested_fields_mark_as_changed(self):
class EmbeddedDoc(EmbeddedDocument):

View File

@@ -174,8 +174,8 @@ class DynamicTest(unittest.TestCase):
Employee.drop_collection()
self.assertTrue('name' in Employee._fields)
self.assertTrue('salary' in Employee._fields)
self.assertIn('name', Employee._fields)
self.assertIn('salary', Employee._fields)
self.assertEqual(Employee._get_collection_name(),
self.Person._get_collection_name())
@@ -189,7 +189,7 @@ class DynamicTest(unittest.TestCase):
self.assertEqual(1, Employee.objects(age=20).count())
joe_bloggs = self.Person.objects.first()
self.assertTrue(isinstance(joe_bloggs, Employee))
self.assertIsInstance(joe_bloggs, Employee)
def test_embedded_dynamic_document(self):
"""Test dynamic embedded documents"""

View File

@@ -1,15 +1,14 @@
# -*- coding: utf-8 -*-
import unittest
import sys
from datetime import datetime
from nose.plugins.skip import SkipTest
from datetime import datetime
from pymongo.errors import OperationFailure
import pymongo
from mongoengine import *
from mongoengine.connection import get_db
from tests.utils import get_mongodb_version, needs_mongodb_v26
from tests.utils import get_mongodb_version, requires_mongodb_gte_26, MONGODB_32, MONGODB_3
__all__ = ("IndexesTest", )
@@ -19,6 +18,7 @@ class IndexesTest(unittest.TestCase):
def setUp(self):
self.connection = connect(db='mongoenginetest')
self.db = get_db()
self.mongodb_version = get_mongodb_version()
class Person(Document):
name = StringField()
@@ -70,7 +70,7 @@ class IndexesTest(unittest.TestCase):
self.assertEqual(len(info), 4)
info = [value['key'] for key, value in info.iteritems()]
for expected in expected_specs:
self.assertTrue(expected['fields'] in info)
self.assertIn(expected['fields'], info)
def _index_test_inheritance(self, InheritFrom):
@@ -102,7 +102,7 @@ class IndexesTest(unittest.TestCase):
self.assertEqual(len(info), 4)
info = [value['key'] for key, value in info.iteritems()]
for expected in expected_specs:
self.assertTrue(expected['fields'] in info)
self.assertIn(expected['fields'], info)
class ExtendedBlogPost(BlogPost):
title = StringField()
@@ -117,7 +117,7 @@ class IndexesTest(unittest.TestCase):
info = ExtendedBlogPost.objects._collection.index_information()
info = [value['key'] for key, value in info.iteritems()]
for expected in expected_specs:
self.assertTrue(expected['fields'] in info)
self.assertIn(expected['fields'], info)
def test_indexes_document_inheritance(self):
"""Ensure that indexes are used when meta[indexes] is specified for
@@ -226,7 +226,7 @@ class IndexesTest(unittest.TestCase):
list(Person.objects)
info = Person.objects._collection.index_information()
info = [value['key'] for key, value in info.iteritems()]
self.assertTrue([('rank.title', 1)] in info)
self.assertIn([('rank.title', 1)], info)
def test_explicit_geo2d_index(self):
"""Ensure that geo2d indexes work when created via meta[indexes]
@@ -246,7 +246,7 @@ class IndexesTest(unittest.TestCase):
Place.ensure_indexes()
info = Place._get_collection().index_information()
info = [value['key'] for key, value in info.iteritems()]
self.assertTrue([('location.point', '2d')] in info)
self.assertIn([('location.point', '2d')], info)
def test_explicit_geo2d_index_embedded(self):
"""Ensure that geo2d indexes work when created via meta[indexes]
@@ -269,7 +269,7 @@ class IndexesTest(unittest.TestCase):
Place.ensure_indexes()
info = Place._get_collection().index_information()
info = [value['key'] for key, value in info.iteritems()]
self.assertTrue([('current.location.point', '2d')] in info)
self.assertIn([('current.location.point', '2d')], info)
def test_explicit_geosphere_index(self):
"""Ensure that geosphere indexes work when created via meta[indexes]
@@ -289,7 +289,7 @@ class IndexesTest(unittest.TestCase):
Place.ensure_indexes()
info = Place._get_collection().index_information()
info = [value['key'] for key, value in info.iteritems()]
self.assertTrue([('location.point', '2dsphere')] in info)
self.assertIn([('location.point', '2dsphere')], info)
def test_explicit_geohaystack_index(self):
"""Ensure that geohaystack indexes work when created via meta[indexes]
@@ -311,7 +311,7 @@ class IndexesTest(unittest.TestCase):
Place.ensure_indexes()
info = Place._get_collection().index_information()
info = [value['key'] for key, value in info.iteritems()]
self.assertTrue([('location.point', 'geoHaystack')] in info)
self.assertIn([('location.point', 'geoHaystack')], info)
def test_create_geohaystack_index(self):
"""Ensure that geohaystack indexes can be created
@@ -323,7 +323,7 @@ class IndexesTest(unittest.TestCase):
Place.create_index({'fields': (')location.point', 'name')}, bucketSize=10)
info = Place._get_collection().index_information()
info = [value['key'] for key, value in info.iteritems()]
self.assertTrue([('location.point', 'geoHaystack'), ('name', 1)] in info)
self.assertIn([('location.point', 'geoHaystack'), ('name', 1)], info)
def test_dictionary_indexes(self):
"""Ensure that indexes are used when meta[indexes] contains
@@ -356,7 +356,7 @@ class IndexesTest(unittest.TestCase):
value.get('unique', False),
value.get('sparse', False))
for key, value in info.iteritems()]
self.assertTrue(([('addDate', -1)], True, True) in info)
self.assertIn(([('addDate', -1)], True, True), info)
BlogPost.drop_collection()
@@ -491,7 +491,7 @@ class IndexesTest(unittest.TestCase):
obj = Test(a=1)
obj.save()
IS_MONGODB_3 = get_mongodb_version()[0] >= 3
IS_MONGODB_3 = get_mongodb_version() >= MONGODB_3
# Need to be explicit about covered indexes as mongoDB doesn't know if
# the documents returned might have more keys in that here.
@@ -541,19 +541,24 @@ class IndexesTest(unittest.TestCase):
[('categories', 1), ('_id', 1)])
def test_hint(self):
MONGO_VER = self.mongodb_version
TAGS_INDEX_NAME = 'tags_1'
class BlogPost(Document):
tags = ListField(StringField())
meta = {
'indexes': [
'tags',
{
'fields': ['tags'],
'name': TAGS_INDEX_NAME
}
],
}
BlogPost.drop_collection()
for i in range(0, 10):
tags = [("tag %i" % n) for n in range(0, i % 2)]
for i in range(10):
tags = [("tag %i" % n) for n in range(i % 2)]
BlogPost(tags=tags).save()
self.assertEqual(BlogPost.objects.count(), 10)
@@ -563,18 +568,18 @@ class IndexesTest(unittest.TestCase):
if pymongo.version != '3.0':
self.assertEqual(BlogPost.objects.hint([('tags', 1)]).count(), 10)
if MONGO_VER == MONGODB_32:
# Mongo32 throws an error if an index exists (i.e `tags` in our case)
# and you use hint on an index name that does not exist
with self.assertRaises(OperationFailure):
BlogPost.objects.hint([('ZZ', 1)]).count()
else:
self.assertEqual(BlogPost.objects.hint([('ZZ', 1)]).count(), 10)
if pymongo.version >= '2.8':
self.assertEqual(BlogPost.objects.hint('tags').count(), 10)
else:
def invalid_index():
BlogPost.objects.hint('tags').next()
self.assertRaises(TypeError, invalid_index)
self.assertEqual(BlogPost.objects.hint(TAGS_INDEX_NAME ).count(), 10)
def invalid_index_2():
return BlogPost.objects.hint(('tags', 1)).next()
self.assertRaises(Exception, invalid_index_2)
with self.assertRaises(Exception):
BlogPost.objects.hint(('tags', 1)).next()
def test_unique(self):
"""Ensure that uniqueness constraints are applied to fields.
@@ -749,7 +754,7 @@ class IndexesTest(unittest.TestCase):
except NotUniqueError:
pass
def test_unique_and_primary(self):
def test_primary_save_duplicate_update_existing_object(self):
"""If you set a field as primary, then unexpected behaviour can occur.
You won't create a duplicate but you will update an existing document.
"""
@@ -803,7 +808,7 @@ class IndexesTest(unittest.TestCase):
info = BlogPost.objects._collection.index_information()
info = [value['key'] for key, value in info.iteritems()]
index_item = [('_id', 1), ('comments.comment_id', 1)]
self.assertTrue(index_item in info)
self.assertIn(index_item, info)
def test_compound_key_embedded(self):
@@ -850,8 +855,8 @@ class IndexesTest(unittest.TestCase):
info = MyDoc.objects._collection.index_information()
info = [value['key'] for key, value in info.iteritems()]
self.assertTrue([('provider_ids.foo', 1)] in info)
self.assertTrue([('provider_ids.bar', 1)] in info)
self.assertIn([('provider_ids.foo', 1)], info)
self.assertIn([('provider_ids.bar', 1)], info)
def test_sparse_compound_indexes(self):
@@ -867,7 +872,7 @@ class IndexesTest(unittest.TestCase):
info['provider_ids.foo_1_provider_ids.bar_1']['key'])
self.assertTrue(info['provider_ids.foo_1_provider_ids.bar_1']['sparse'])
@needs_mongodb_v26
@requires_mongodb_gte_26
def test_text_indexes(self):
class Book(Document):
title = DictField()
@@ -876,9 +881,9 @@ class IndexesTest(unittest.TestCase):
}
indexes = Book.objects._collection.index_information()
self.assertTrue("title_text" in indexes)
self.assertIn("title_text", indexes)
key = indexes["title_text"]["key"]
self.assertTrue(('_fts', 'text') in key)
self.assertIn(('_fts', 'text'), key)
def test_hashed_indexes(self):
@@ -889,8 +894,8 @@ class IndexesTest(unittest.TestCase):
}
indexes = Book.objects._collection.index_information()
self.assertTrue("ref_id_hashed" in indexes)
self.assertTrue(('ref_id', 'hashed') in indexes["ref_id_hashed"]["key"])
self.assertIn("ref_id_hashed", indexes)
self.assertIn(('ref_id', 'hashed'), indexes["ref_id_hashed"]["key"])
def test_indexes_after_database_drop(self):
"""
@@ -1013,7 +1018,7 @@ class IndexesTest(unittest.TestCase):
TestDoc.ensure_indexes()
index_info = TestDoc._get_collection().index_information()
self.assertTrue('shard_1_1__cls_1_txt_1_1' in index_info)
self.assertIn('shard_1_1__cls_1_txt_1_1', index_info)
if __name__ == '__main__':

View File

@@ -2,14 +2,11 @@
import unittest
import warnings
from datetime import datetime
from tests.fixtures import Base
from mongoengine import Document, EmbeddedDocument, connect
from mongoengine import (BooleanField, Document, EmbeddedDocument,
EmbeddedDocumentField, GenericReferenceField,
IntField, ReferenceField, StringField, connect)
from mongoengine.connection import get_db
from mongoengine.fields import (BooleanField, GenericReferenceField,
IntField, StringField)
from tests.fixtures import Base
__all__ = ('InheritanceTest', )
@@ -26,6 +23,27 @@ class InheritanceTest(unittest.TestCase):
continue
self.db.drop_collection(collection)
def test_constructor_cls(self):
# Ensures _cls is properly set during construction
# and when object gets reloaded (prevent regression of #1950)
class EmbedData(EmbeddedDocument):
data = StringField()
meta = {'allow_inheritance': True}
class DataDoc(Document):
name = StringField()
embed = EmbeddedDocumentField(EmbedData)
meta = {'allow_inheritance': True}
test_doc = DataDoc(name='test', embed=EmbedData(data='data'))
assert test_doc._cls == 'DataDoc'
assert test_doc.embed._cls == 'EmbedData'
test_doc.save()
saved_doc = DataDoc.objects.with_id(test_doc.id)
assert test_doc._cls == saved_doc._cls
assert test_doc.embed._cls == saved_doc.embed._cls
test_doc.delete()
def test_superclasses(self):
"""Ensure that the correct list of superclasses is assembled.
"""
@@ -258,9 +276,10 @@ class InheritanceTest(unittest.TestCase):
name = StringField()
# can't inherit because Animal didn't explicitly allow inheritance
with self.assertRaises(ValueError):
with self.assertRaises(ValueError) as cm:
class Dog(Animal):
pass
self.assertIn("Document Animal may not be subclassed", str(cm.exception))
# Check that _cls etc aren't present on simple documents
dog = Animal(name='dog').save()
@@ -268,7 +287,7 @@ class InheritanceTest(unittest.TestCase):
collection = self.db[Animal._get_collection_name()]
obj = collection.find_one()
self.assertFalse('_cls' in obj)
self.assertNotIn('_cls', obj)
def test_cant_turn_off_inheritance_on_subclass(self):
"""Ensure if inheritance is on in a subclass you cant turn it off.
@@ -277,9 +296,10 @@ class InheritanceTest(unittest.TestCase):
name = StringField()
meta = {'allow_inheritance': True}
with self.assertRaises(ValueError):
with self.assertRaises(ValueError) as cm:
class Mammal(Animal):
meta = {'allow_inheritance': False}
self.assertEqual(str(cm.exception), 'Only direct subclasses of Document may set "allow_inheritance" to False')
def test_allow_inheritance_abstract_document(self):
"""Ensure that abstract documents can set inheritance rules and that
@@ -292,13 +312,48 @@ class InheritanceTest(unittest.TestCase):
class Animal(FinalDocument):
name = StringField()
with self.assertRaises(ValueError):
with self.assertRaises(ValueError) as cm:
class Mammal(Animal):
pass
# Check that _cls isn't present in simple documents
doc = Animal(name='dog')
self.assertFalse('_cls' in doc.to_mongo())
self.assertNotIn('_cls', doc.to_mongo())
def test_using_abstract_class_in_reference_field(self):
# Ensures no regression of #1920
class AbstractHuman(Document):
meta = {'abstract': True}
class Dad(AbstractHuman):
name = StringField()
class Home(Document):
dad = ReferenceField(AbstractHuman) # Referencing the abstract class
address = StringField()
dad = Dad(name='5').save()
Home(dad=dad, address='street').save()
home = Home.objects.first()
home.address = 'garbage'
home.save() # Was failing with ValidationError
def test_abstract_class_referencing_self(self):
# Ensures no regression of #1920
class Human(Document):
meta = {'abstract': True}
creator = ReferenceField('self', dbref=True)
class User(Human):
name = StringField()
user = User(name='John').save()
user2 = User(name='Foo', creator=user).save()
user2 = User.objects.with_id(user2.id)
user2.name = 'Bar'
user2.save() # Was failing with ValidationError
def test_abstract_handle_ids_in_metaclass_properly(self):
@@ -358,11 +413,11 @@ class InheritanceTest(unittest.TestCase):
meta = {'abstract': True,
'allow_inheritance': False}
bkk = City(continent='asia')
self.assertEqual(None, bkk.pk)
city = City(continent='asia')
self.assertEqual(None, city.pk)
# TODO: expected error? Shouldn't we create a new error type?
with self.assertRaises(KeyError):
setattr(bkk, 'pk', 1)
setattr(city, 'pk', 1)
def test_allow_inheritance_embedded_document(self):
"""Ensure embedded documents respect inheritance."""
@@ -374,14 +429,14 @@ class InheritanceTest(unittest.TestCase):
pass
doc = Comment(content='test')
self.assertFalse('_cls' in doc.to_mongo())
self.assertNotIn('_cls', doc.to_mongo())
class Comment(EmbeddedDocument):
content = StringField()
meta = {'allow_inheritance': True}
doc = Comment(content='test')
self.assertTrue('_cls' in doc.to_mongo())
self.assertIn('_cls', doc.to_mongo())
def test_document_inheritance(self):
"""Ensure mutliple inheritance of abstract documents
@@ -434,8 +489,8 @@ class InheritanceTest(unittest.TestCase):
for cls in [Animal, Fish, Guppy]:
self.assertEqual(cls._meta[k], v)
self.assertFalse('collection' in Animal._meta)
self.assertFalse('collection' in Mammal._meta)
self.assertNotIn('collection', Animal._meta)
self.assertNotIn('collection', Mammal._meta)
self.assertEqual(Animal._get_collection_name(), None)
self.assertEqual(Mammal._get_collection_name(), None)

View File

@@ -8,9 +8,12 @@ import weakref
from datetime import datetime
from bson import DBRef, ObjectId
from pymongo.errors import DuplicateKeyError
from tests import fixtures
from tests.fixtures import (PickleEmbedded, PickleTest, PickleSignalsTest,
PickleDynamicEmbedded, PickleDynamicTest)
from tests.utils import MongoDBTestCase
from mongoengine import *
from mongoengine.base import get_document, _document_registry
@@ -22,7 +25,7 @@ from mongoengine.queryset import NULLIFY, Q
from mongoengine.context_managers import switch_db, query_counter
from mongoengine import signals
from tests.utils import needs_mongodb_v26
from tests.utils import requires_mongodb_gte_26
TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__),
'../fields/mongoengine.png')
@@ -30,12 +33,9 @@ TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__),
__all__ = ("InstanceTest",)
class InstanceTest(unittest.TestCase):
class InstanceTest(MongoDBTestCase):
def setUp(self):
connect(db='mongoenginetest')
self.db = get_db()
class Job(EmbeddedDocument):
name = StringField()
years = IntField()
@@ -357,7 +357,7 @@ class InstanceTest(unittest.TestCase):
user_son = User.objects._collection.find_one()
self.assertEqual(user_son['_id'], 'test')
self.assertTrue('username' not in user_son['_id'])
self.assertNotIn('username', user_son['_id'])
User.drop_collection()
@@ -370,7 +370,7 @@ class InstanceTest(unittest.TestCase):
user_son = User.objects._collection.find_one()
self.assertEqual(user_son['_id'], 'mongo')
self.assertTrue('username' not in user_son['_id'])
self.assertNotIn('username', user_son['_id'])
def test_document_not_registered(self):
class Place(Document):
@@ -550,21 +550,14 @@ class InstanceTest(unittest.TestCase):
pass
f = Foo()
try:
with self.assertRaises(Foo.DoesNotExist):
f.reload()
except Foo.DoesNotExist:
pass
except Exception:
self.assertFalse("Threw wrong exception")
f.save()
f.delete()
try:
with self.assertRaises(Foo.DoesNotExist):
f.reload()
except Foo.DoesNotExist:
pass
except Exception:
self.assertFalse("Threw wrong exception")
def test_reload_of_non_strict_with_special_field_name(self):
"""Ensures reloading works for documents with meta strict == False."""
@@ -601,10 +594,10 @@ class InstanceTest(unittest.TestCase):
# Length = length(assigned fields + id)
self.assertEqual(len(person), 5)
self.assertTrue('age' in person)
self.assertIn('age', person)
person.age = None
self.assertFalse('age' in person)
self.assertFalse('nationality' in person)
self.assertNotIn('age', person)
self.assertNotIn('nationality', person)
def test_embedded_document_to_mongo(self):
class Person(EmbeddedDocument):
@@ -634,8 +627,8 @@ class InstanceTest(unittest.TestCase):
class Comment(EmbeddedDocument):
content = StringField()
self.assertTrue('content' in Comment._fields)
self.assertFalse('id' in Comment._fields)
self.assertIn('content', Comment._fields)
self.assertNotIn('id', Comment._fields)
def test_embedded_document_instance(self):
"""Ensure that embedded documents can reference parent instance."""
@@ -734,12 +727,12 @@ class InstanceTest(unittest.TestCase):
t = TestDocument(status="draft", pub_date=datetime.now())
try:
with self.assertRaises(ValidationError) as cm:
t.save()
except ValidationError as e:
expect_msg = "Draft entries may not have a publication date."
self.assertTrue(expect_msg in e.message)
self.assertEqual(e.to_dict(), {'__all__': expect_msg})
expected_msg = "Draft entries may not have a publication date."
self.assertIn(expected_msg, cm.exception.message)
self.assertEqual(cm.exception.to_dict(), {'__all__': expected_msg})
t = TestDocument(status="published")
t.save(clean=False)
@@ -773,12 +766,13 @@ class InstanceTest(unittest.TestCase):
TestDocument.drop_collection()
t = TestDocument(doc=TestEmbeddedDocument(x=10, y=25, z=15))
try:
with self.assertRaises(ValidationError) as cm:
t.save()
except ValidationError as e:
expect_msg = "Value of z != x + y"
self.assertTrue(expect_msg in e.message)
self.assertEqual(e.to_dict(), {'doc': {'__all__': expect_msg}})
expected_msg = "Value of z != x + y"
self.assertIn(expected_msg, cm.exception.message)
self.assertEqual(cm.exception.to_dict(), {'doc': {'__all__': expected_msg}})
t = TestDocument(doc=TestEmbeddedDocument(x=10, y=25)).save()
self.assertEqual(t.doc.z, 35)
@@ -846,12 +840,18 @@ class InstanceTest(unittest.TestCase):
self.assertDbEqual([dict(other_doc.to_mongo()), dict(doc.to_mongo())])
@needs_mongodb_v26
@requires_mongodb_gte_26
def test_modify_with_positional_push(self):
class Content(EmbeddedDocument):
keywords = ListField(StringField())
class BlogPost(Document):
tags = ListField(StringField())
content = EmbeddedDocumentField(Content)
post = BlogPost.objects.create(
tags=['python'], content=Content(keywords=['ipsum']))
post = BlogPost.objects.create(tags=['python'])
self.assertEqual(post.tags, ['python'])
post.modify(push__tags__0=['code', 'mongo'])
self.assertEqual(post.tags, ['code', 'mongo', 'python'])
@@ -862,6 +862,16 @@ class InstanceTest(unittest.TestCase):
['code', 'mongo', 'python']
)
self.assertEqual(post.content.keywords, ['ipsum'])
post.modify(push__content__keywords__0=['lorem'])
self.assertEqual(post.content.keywords, ['lorem', 'ipsum'])
# Assert same order of the list items is maintained in the db
self.assertEqual(
BlogPost._get_collection().find_one({'_id': post.pk})['content']['keywords'],
['lorem', 'ipsum']
)
def test_save(self):
"""Ensure that a document may be saved in the database."""
@@ -1428,6 +1438,60 @@ class InstanceTest(unittest.TestCase):
self.assertEqual(person.age, 21)
self.assertEqual(person.active, False)
def test__get_changed_fields_same_ids_reference_field_does_not_enters_infinite_loop(self):
# Refers to Issue #1685
class EmbeddedChildModel(EmbeddedDocument):
id = DictField(primary_key=True)
class ParentModel(Document):
child = EmbeddedDocumentField(
EmbeddedChildModel)
emb = EmbeddedChildModel(id={'1': [1]})
ParentModel(children=emb)._get_changed_fields()
def test__get_changed_fields_same_ids_reference_field_does_not_enters_infinite_loop(self):
class User(Document):
id = IntField(primary_key=True)
name = StringField()
class Message(Document):
id = IntField(primary_key=True)
author = ReferenceField(User)
Message.drop_collection()
# All objects share the same id, but each in a different collection
user = User(id=1, name='user-name').save()
message = Message(id=1, author=user).save()
message.author.name = 'tutu'
self.assertEqual(message._get_changed_fields(), [])
self.assertEqual(user._get_changed_fields(), ['name'])
def test__get_changed_fields_same_ids_embedded(self):
# Refers to Issue #1768
class User(EmbeddedDocument):
id = IntField()
name = StringField()
class Message(Document):
id = IntField(primary_key=True)
author = EmbeddedDocumentField(User)
Message.drop_collection()
# All objects share the same id, but each in a different collection
user = User(id=1, name='user-name')#.save()
message = Message(id=1, author=user).save()
message.author.name = 'tutu'
self.assertEqual(message._get_changed_fields(), ['author.name'])
message.save()
message_fetched = Message.objects.with_id(message.id)
self.assertEqual(message_fetched.author.name, 'tutu')
def test_query_count_when_saving(self):
"""Ensure references don't cause extra fetches when saving"""
class Organization(Document):
@@ -1461,9 +1525,9 @@ class InstanceTest(unittest.TestCase):
user = User.objects.first()
# Even if stored as ObjectId's internally mongoengine uses DBRefs
# As ObjectId's aren't automatically derefenced
self.assertTrue(isinstance(user._data['orgs'][0], DBRef))
self.assertTrue(isinstance(user.orgs[0], Organization))
self.assertTrue(isinstance(user._data['orgs'][0], Organization))
self.assertIsInstance(user._data['orgs'][0], DBRef)
self.assertIsInstance(user.orgs[0], Organization)
self.assertIsInstance(user._data['orgs'][0], Organization)
# Changing a value
with query_counter() as q:
@@ -1843,9 +1907,8 @@ class InstanceTest(unittest.TestCase):
post_obj = BlogPost.objects.first()
# Test laziness
self.assertTrue(isinstance(post_obj._data['author'],
bson.DBRef))
self.assertTrue(isinstance(post_obj.author, self.Person))
self.assertIsInstance(post_obj._data['author'], bson.DBRef)
self.assertIsInstance(post_obj.author, self.Person)
self.assertEqual(post_obj.author.name, 'Test User')
# Ensure that the dereferenced object may be changed and saved
@@ -2251,12 +2314,12 @@ class InstanceTest(unittest.TestCase):
# Make sure docs are properly identified in a list (__eq__ is used
# for the comparison).
all_user_list = list(User.objects.all())
self.assertTrue(u1 in all_user_list)
self.assertTrue(u2 in all_user_list)
self.assertTrue(u3 in all_user_list)
self.assertTrue(u4 not in all_user_list) # New object
self.assertTrue(b1 not in all_user_list) # Other object
self.assertTrue(b2 not in all_user_list) # Other object
self.assertIn(u1, all_user_list)
self.assertIn(u2, all_user_list)
self.assertIn(u3, all_user_list)
self.assertNotIn(u4, all_user_list) # New object
self.assertNotIn(b1, all_user_list) # Other object
self.assertNotIn(b2, all_user_list) # Other object
# Make sure docs can be used as keys in a dict (__hash__ is used
# for hashing the docs).
@@ -2274,10 +2337,10 @@ class InstanceTest(unittest.TestCase):
# Make sure docs are properly identified in a set (__hash__ is used
# for hashing the docs).
all_user_set = set(User.objects.all())
self.assertTrue(u1 in all_user_set)
self.assertTrue(u4 not in all_user_set)
self.assertTrue(b1 not in all_user_list)
self.assertTrue(b2 not in all_user_list)
self.assertIn(u1, all_user_set)
self.assertNotIn(u4, all_user_set)
self.assertNotIn(b1, all_user_list)
self.assertNotIn(b2, all_user_list)
# Make sure duplicate docs aren't accepted in the set
self.assertEqual(len(all_user_set), 3)
@@ -2978,7 +3041,7 @@ class InstanceTest(unittest.TestCase):
Person(name="Harry Potter").save()
person = Person.objects.first()
self.assertTrue('id' in person._data.keys())
self.assertIn('id', person._data.keys())
self.assertEqual(person._data.get('id'), person.id)
def test_complex_nesting_document_and_embedded_document(self):
@@ -3070,36 +3133,36 @@ class InstanceTest(unittest.TestCase):
dbref2 = f._data['test2']
obj2 = f.test2
self.assertTrue(isinstance(dbref2, DBRef))
self.assertTrue(isinstance(obj2, Test2))
self.assertTrue(obj2.id == dbref2.id)
self.assertTrue(obj2 == dbref2)
self.assertTrue(dbref2 == obj2)
self.assertIsInstance(dbref2, DBRef)
self.assertIsInstance(obj2, Test2)
self.assertEqual(obj2.id, dbref2.id)
self.assertEqual(obj2, dbref2)
self.assertEqual(dbref2, obj2)
dbref3 = f._data['test3']
obj3 = f.test3
self.assertTrue(isinstance(dbref3, DBRef))
self.assertTrue(isinstance(obj3, Test3))
self.assertTrue(obj3.id == dbref3.id)
self.assertTrue(obj3 == dbref3)
self.assertTrue(dbref3 == obj3)
self.assertIsInstance(dbref3, DBRef)
self.assertIsInstance(obj3, Test3)
self.assertEqual(obj3.id, dbref3.id)
self.assertEqual(obj3, dbref3)
self.assertEqual(dbref3, obj3)
self.assertTrue(obj2.id == obj3.id)
self.assertTrue(dbref2.id == dbref3.id)
self.assertFalse(dbref2 == dbref3)
self.assertFalse(dbref3 == dbref2)
self.assertTrue(dbref2 != dbref3)
self.assertTrue(dbref3 != dbref2)
self.assertEqual(obj2.id, obj3.id)
self.assertEqual(dbref2.id, dbref3.id)
self.assertNotEqual(dbref2, dbref3)
self.assertNotEqual(dbref3, dbref2)
self.assertNotEqual(dbref2, dbref3)
self.assertNotEqual(dbref3, dbref2)
self.assertFalse(obj2 == dbref3)
self.assertFalse(dbref3 == obj2)
self.assertTrue(obj2 != dbref3)
self.assertTrue(dbref3 != obj2)
self.assertNotEqual(obj2, dbref3)
self.assertNotEqual(dbref3, obj2)
self.assertNotEqual(obj2, dbref3)
self.assertNotEqual(dbref3, obj2)
self.assertFalse(obj3 == dbref2)
self.assertFalse(dbref2 == obj3)
self.assertTrue(obj3 != dbref2)
self.assertTrue(dbref2 != obj3)
self.assertNotEqual(obj3, dbref2)
self.assertNotEqual(dbref2, obj3)
self.assertNotEqual(obj3, dbref2)
self.assertNotEqual(dbref2, obj3)
def test_default_values(self):
class Person(Document):
@@ -3148,6 +3211,64 @@ class InstanceTest(unittest.TestCase):
self.assertEquals(p.id, None)
p.id = "12345" # in case it is not working: "OperationError: Shard Keys are immutable..." will be raised here
def test_from_son_created_False_without_id(self):
class MyPerson(Document):
name = StringField()
MyPerson.objects.delete()
p = MyPerson.from_json('{"name": "a_fancy_name"}', created=False)
self.assertFalse(p._created)
self.assertIsNone(p.id)
p.save()
self.assertIsNotNone(p.id)
saved_p = MyPerson.objects.get(id=p.id)
self.assertEqual(saved_p.name, 'a_fancy_name')
def test_from_son_created_False_with_id(self):
# 1854
class MyPerson(Document):
name = StringField()
MyPerson.objects.delete()
p = MyPerson.from_json('{"_id": "5b85a8b04ec5dc2da388296e", "name": "a_fancy_name"}', created=False)
self.assertFalse(p._created)
self.assertEqual(p._changed_fields, [])
self.assertEqual(p.name, 'a_fancy_name')
self.assertEqual(p.id, ObjectId('5b85a8b04ec5dc2da388296e'))
p.save()
with self.assertRaises(DoesNotExist):
# Since created=False and we gave an id in the json and _changed_fields is empty
# mongoengine assumes that the document exits with that structure already
# and calling .save() didn't save anything
MyPerson.objects.get(id=p.id)
self.assertFalse(p._created)
p.name = 'a new fancy name'
self.assertEqual(p._changed_fields, ['name'])
p.save()
saved_p = MyPerson.objects.get(id=p.id)
self.assertEqual(saved_p.name, p.name)
def test_from_son_created_True_with_an_id(self):
class MyPerson(Document):
name = StringField()
MyPerson.objects.delete()
p = MyPerson.from_json('{"_id": "5b85a8b04ec5dc2da388296e", "name": "a_fancy_name"}', created=True)
self.assertTrue(p._created)
self.assertEqual(p._changed_fields, [])
self.assertEqual(p.name, 'a_fancy_name')
self.assertEqual(p.id, ObjectId('5b85a8b04ec5dc2da388296e'))
p.save()
saved_p = MyPerson.objects.get(id=p.id)
self.assertEqual(saved_p, p)
self.assertEqual(p.name, 'a_fancy_name')
def test_null_field(self):
# 734
class User(Document):
@@ -3221,7 +3342,7 @@ class InstanceTest(unittest.TestCase):
person.update(set__height=2.0)
@needs_mongodb_v26
@requires_mongodb_gte_26
def test_push_with_position(self):
"""Ensure that push with position works properly for an instance."""
class BlogPost(Document):
@@ -3248,6 +3369,23 @@ class InstanceTest(unittest.TestCase):
blog.reload()
self.assertEqual(blog.tags, [["value1", 123]])
def test_accessing_objects_with_indexes_error(self):
insert_result = self.db.company.insert_many([{'name': 'Foo'},
{'name': 'Foo'}]) # Force 2 doc with same name
REF_OID = insert_result.inserted_ids[0]
self.db.user.insert_one({'company': REF_OID}) # Force 2 doc with same name
class Company(Document):
name = StringField(unique=True)
class User(Document):
company = ReferenceField(Company)
# Ensure index creation exception aren't swallowed (#1688)
with self.assertRaises(DuplicateKeyError):
User.objects().select_related()
if __name__ == '__main__':
unittest.main()

View File

@@ -20,16 +20,16 @@ class ValidatorErrorTest(unittest.TestCase):
# 1st level error schema
error.errors = {'1st': ValidationError('bad 1st'), }
self.assertTrue('1st' in error.to_dict())
self.assertIn('1st', error.to_dict())
self.assertEqual(error.to_dict()['1st'], 'bad 1st')
# 2nd level error schema
error.errors = {'1st': ValidationError('bad 1st', errors={
'2nd': ValidationError('bad 2nd'),
})}
self.assertTrue('1st' in error.to_dict())
self.assertTrue(isinstance(error.to_dict()['1st'], dict))
self.assertTrue('2nd' in error.to_dict()['1st'])
self.assertIn('1st', error.to_dict())
self.assertIsInstance(error.to_dict()['1st'], dict)
self.assertIn('2nd', error.to_dict()['1st'])
self.assertEqual(error.to_dict()['1st']['2nd'], 'bad 2nd')
# moar levels
@@ -40,10 +40,10 @@ class ValidatorErrorTest(unittest.TestCase):
}),
}),
})}
self.assertTrue('1st' in error.to_dict())
self.assertTrue('2nd' in error.to_dict()['1st'])
self.assertTrue('3rd' in error.to_dict()['1st']['2nd'])
self.assertTrue('4th' in error.to_dict()['1st']['2nd']['3rd'])
self.assertIn('1st', error.to_dict())
self.assertIn('2nd', error.to_dict()['1st'])
self.assertIn('3rd', error.to_dict()['1st']['2nd'])
self.assertIn('4th', error.to_dict()['1st']['2nd']['3rd'])
self.assertEqual(error.to_dict()['1st']['2nd']['3rd']['4th'],
'Inception')
@@ -58,7 +58,7 @@ class ValidatorErrorTest(unittest.TestCase):
try:
User().validate()
except ValidationError as e:
self.assertTrue("User:None" in e.message)
self.assertIn("User:None", e.message)
self.assertEqual(e.to_dict(), {
'username': 'Field is required',
'name': 'Field is required'})
@@ -68,7 +68,7 @@ class ValidatorErrorTest(unittest.TestCase):
try:
user.save()
except ValidationError as e:
self.assertTrue("User:RossC0" in e.message)
self.assertIn("User:RossC0", e.message)
self.assertEqual(e.to_dict(), {
'name': 'Field is required'})
@@ -116,7 +116,7 @@ class ValidatorErrorTest(unittest.TestCase):
try:
Doc(id="bad").validate()
except ValidationError as e:
self.assertTrue("SubDoc:None" in e.message)
self.assertIn("SubDoc:None", e.message)
self.assertEqual(e.to_dict(), {
"e": {'val': 'OK could not be converted to int'}})
@@ -127,14 +127,14 @@ class ValidatorErrorTest(unittest.TestCase):
doc = Doc.objects.first()
keys = doc._data.keys()
self.assertEqual(2, len(keys))
self.assertTrue('e' in keys)
self.assertTrue('id' in keys)
self.assertIn('e', keys)
self.assertIn('id', keys)
doc.e.val = "OK"
try:
doc.save()
except ValidationError as e:
self.assertTrue("Doc:test" in e.message)
self.assertIn("Doc:test", e.message)
self.assertEqual(e.to_dict(), {
"e": {'val': 'OK could not be converted to int'}})

View File

@@ -1,3 +1,3 @@
from fields import *
from file_tests import *
from geo import *
from .fields import *
from .file_tests import *
from .geo import *

View File

@@ -175,7 +175,7 @@ class FieldTest(MongoDBTestCase):
self.assertEqual(person.name, None)
self.assertEqual(person.age, 30)
self.assertEqual(person.userid, 'test')
self.assertTrue(isinstance(person.created, datetime.datetime))
self.assertIsInstance(person.created, datetime.datetime)
self.assertEqual(person._data['name'], person.name)
self.assertEqual(person._data['age'], person.age)
@@ -186,6 +186,31 @@ class FieldTest(MongoDBTestCase):
data_to_be_saved = sorted(person.to_mongo().keys())
self.assertEqual(data_to_be_saved, ['age', 'created', 'userid'])
def test_default_value_is_not_used_when_changing_value_to_empty_list_for_strict_doc(self):
"""List field with default can be set to the empty list (strict)"""
# Issue #1733
class Doc(Document):
x = ListField(IntField(), default=lambda: [42])
doc = Doc(x=[1]).save()
doc.x = []
doc.save()
reloaded = Doc.objects.get(id=doc.id)
self.assertEqual(reloaded.x, [])
def test_default_value_is_not_used_when_changing_value_to_empty_list_for_dyn_doc(self):
"""List field with default can be set to the empty list (dynamic)"""
# Issue #1733
class Doc(DynamicDocument):
x = ListField(IntField(), default=lambda: [42])
doc = Doc(x=[1]).save()
doc.x = []
doc.y = 2 # Was triggering the bug
doc.save()
reloaded = Doc.objects.get(id=doc.id)
self.assertEqual(reloaded.x, [])
def test_default_values_when_deleting_value(self):
"""Ensure that default field values are used after non-default
values are explicitly deleted.
@@ -211,7 +236,7 @@ class FieldTest(MongoDBTestCase):
self.assertEqual(person.name, None)
self.assertEqual(person.age, 30)
self.assertEqual(person.userid, 'test')
self.assertTrue(isinstance(person.created, datetime.datetime))
self.assertIsInstance(person.created, datetime.datetime)
self.assertNotEqual(person.created, datetime.datetime(2014, 6, 12))
self.assertEqual(person._data['name'], person.name)
@@ -264,12 +289,11 @@ class FieldTest(MongoDBTestCase):
# Retrive data from db and verify it.
ret = HandleNoneFields.objects.all()[0]
self.assertEqual(ret.str_fld, None)
self.assertEqual(ret.int_fld, None)
self.assertEqual(ret.flt_fld, None)
self.assertIsNone(ret.str_fld)
self.assertIsNone(ret.int_fld)
self.assertIsNone(ret.flt_fld)
# Return current time if retrived value is None.
self.assertTrue(isinstance(ret.comp_dt_fld, datetime.datetime))
self.assertIsNone(ret.comp_dt_fld)
def test_not_required_handles_none_from_database(self):
"""Ensure that every field can handle null values from the
@@ -287,7 +311,7 @@ class FieldTest(MongoDBTestCase):
doc.str_fld = u'spam ham egg'
doc.int_fld = 42
doc.flt_fld = 4.2
doc.com_dt_fld = datetime.datetime.utcnow()
doc.comp_dt_fld = datetime.datetime.utcnow()
doc.save()
# Unset all the fields
@@ -302,12 +326,10 @@ class FieldTest(MongoDBTestCase):
# Retrive data from db and verify it.
ret = HandleNoneFields.objects.first()
self.assertEqual(ret.str_fld, None)
self.assertEqual(ret.int_fld, None)
self.assertEqual(ret.flt_fld, None)
# ComplexDateTimeField returns current time if retrived value is None.
self.assertTrue(isinstance(ret.comp_dt_fld, datetime.datetime))
self.assertIsNone(ret.str_fld)
self.assertIsNone(ret.int_fld)
self.assertIsNone(ret.flt_fld)
self.assertIsNone(ret.comp_dt_fld)
# Retrieved object shouldn't pass validation when a re-save is
# attempted.
@@ -428,6 +450,16 @@ class FieldTest(MongoDBTestCase):
scheme_link.url = 'ws://google.com'
scheme_link.validate()
def test_url_allowed_domains(self):
"""Allow underscore in domain names.
"""
class Link(Document):
url = URLField()
link = Link()
link.url = 'https://san_leandro-ca.geebo.com'
link.validate()
def test_int_validation(self):
"""Ensure that invalid values cannot be assigned to int fields.
"""
@@ -611,6 +643,8 @@ class FieldTest(MongoDBTestCase):
self.assertRaises(ValidationError, person.validate)
person.admin = 'Yes'
self.assertRaises(ValidationError, person.validate)
person.admin = 'False'
self.assertRaises(ValidationError, person.validate)
def test_uuid_field_string(self):
"""Test UUID fields storing as String
@@ -928,137 +962,6 @@ class FieldTest(MongoDBTestCase):
logs = LogEntry.objects.filter(date__gte=datetime.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 10)
def test_complexdatetime_storage(self):
"""Tests for complex datetime fields - which can handle
microseconds without rounding.
"""
class LogEntry(Document):
date = ComplexDateTimeField()
date_with_dots = ComplexDateTimeField(separator='.')
LogEntry.drop_collection()
# Post UTC - microseconds are rounded (down) nearest millisecond and
# dropped - with default datetimefields
d1 = datetime.datetime(1970, 1, 1, 0, 0, 1, 999)
log = LogEntry()
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
# Post UTC - microseconds are rounded (down) nearest millisecond - with
# default datetimefields
d1 = datetime.datetime(1970, 1, 1, 0, 0, 1, 9999)
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
# Pre UTC dates microseconds below 1000 are dropped - with default
# datetimefields
d1 = datetime.datetime(1969, 12, 31, 23, 59, 59, 999)
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
# Pre UTC microseconds above 1000 is wonky - with default datetimefields
# log.date has an invalid microsecond value so I can't construct
# a date to compare.
for i in range(1001, 3113, 33):
d1 = datetime.datetime(1969, 12, 31, 23, 59, 59, i)
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
log1 = LogEntry.objects.get(date=d1)
self.assertEqual(log, log1)
# Test string padding
microsecond = map(int, [math.pow(10, x) for x in range(6)])
mm = dd = hh = ii = ss = [1, 10]
for values in itertools.product([2014], mm, dd, hh, ii, ss, microsecond):
stored = LogEntry(date=datetime.datetime(*values)).to_mongo()['date']
self.assertTrue(re.match('^\d{4},\d{2},\d{2},\d{2},\d{2},\d{2},\d{6}$', stored) is not None)
# Test separator
stored = LogEntry(date_with_dots=datetime.datetime(2014, 1, 1)).to_mongo()['date_with_dots']
self.assertTrue(re.match('^\d{4}.\d{2}.\d{2}.\d{2}.\d{2}.\d{2}.\d{6}$', stored) is not None)
def test_complexdatetime_usage(self):
"""Tests for complex datetime fields - which can handle
microseconds without rounding.
"""
class LogEntry(Document):
date = ComplexDateTimeField()
LogEntry.drop_collection()
d1 = datetime.datetime(1950, 1, 1, 0, 0, 1, 999)
log = LogEntry()
log.date = d1
log.save()
log1 = LogEntry.objects.get(date=d1)
self.assertEqual(log, log1)
# create extra 59 log entries for a total of 60
for i in range(1951, 2010):
d = datetime.datetime(i, 1, 1, 0, 0, 1, 999)
LogEntry(date=d).save()
self.assertEqual(LogEntry.objects.count(), 60)
# Test ordering
logs = LogEntry.objects.order_by("date")
i = 0
while i < 59:
self.assertTrue(logs[i].date <= logs[i + 1].date)
i += 1
logs = LogEntry.objects.order_by("-date")
i = 0
while i < 59:
self.assertTrue(logs[i].date >= logs[i + 1].date)
i += 1
# Test searching
logs = LogEntry.objects.filter(date__gte=datetime.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 30)
logs = LogEntry.objects.filter(date__lte=datetime.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 30)
logs = LogEntry.objects.filter(
date__lte=datetime.datetime(2011, 1, 1),
date__gte=datetime.datetime(2000, 1, 1),
)
self.assertEqual(logs.count(), 10)
LogEntry.drop_collection()
# Test microsecond-level ordering/filtering
for microsecond in (99, 999, 9999, 10000):
LogEntry(
date=datetime.datetime(2015, 1, 1, 0, 0, 0, microsecond)
).save()
logs = list(LogEntry.objects.order_by('date'))
for next_idx, log in enumerate(logs[:-1], start=1):
next_log = logs[next_idx]
self.assertTrue(log.date < next_log.date)
logs = list(LogEntry.objects.order_by('-date'))
for next_idx, log in enumerate(logs[:-1], start=1):
next_log = logs[next_idx]
self.assertTrue(log.date > next_log.date)
logs = LogEntry.objects.filter(
date__lte=datetime.datetime(2015, 1, 1, 0, 0, 0, 10000))
self.assertEqual(logs.count(), 4)
def test_list_validation(self):
"""Ensure that a list field only accepts lists with valid elements."""
AccessLevelChoices = (
@@ -1311,7 +1214,7 @@ class FieldTest(MongoDBTestCase):
# aka 'del list[index]'
# aka 'operator.delitem(list, index)'
reset_post()
del post.info[2] # del from middle ('2')
del post.info[2] # del from middle ('2')
self.assertEqual(post.info, ['0', '1', '3', '4', '5'])
post.save()
post.reload()
@@ -1321,7 +1224,7 @@ class FieldTest(MongoDBTestCase):
# aka 'del list[i:j]'
# aka 'operator.delitem(list, slice(i,j))'
reset_post()
del post.info[1:3] # removes '1', '2'
del post.info[1:3] # removes '1', '2'
self.assertEqual(post.info, ['0', '3', '4', '5'])
post.save()
post.reload()
@@ -1736,8 +1639,8 @@ class FieldTest(MongoDBTestCase):
e.save()
e2 = Simple.objects.get(id=e.id)
self.assertTrue(isinstance(e2.mapping[0], StringSetting))
self.assertTrue(isinstance(e2.mapping[1], IntegerSetting))
self.assertIsInstance(e2.mapping[0], StringSetting)
self.assertIsInstance(e2.mapping[1], IntegerSetting)
# Test querying
self.assertEqual(
@@ -1906,8 +1809,8 @@ class FieldTest(MongoDBTestCase):
e.save()
e2 = Simple.objects.get(id=e.id)
self.assertTrue(isinstance(e2.mapping['somestring'], StringSetting))
self.assertTrue(isinstance(e2.mapping['someint'], IntegerSetting))
self.assertIsInstance(e2.mapping['somestring'], StringSetting)
self.assertIsInstance(e2.mapping['someint'], IntegerSetting)
# Test querying
self.assertEqual(
@@ -1950,6 +1853,48 @@ class FieldTest(MongoDBTestCase):
with self.assertRaises(ValueError):
e.update(set__mapping={"somestrings": ["foo", "bar", ]})
def test_dictfield_with_referencefield_complex_nesting_cases(self):
"""Ensure complex nesting inside DictField handles dereferencing of ReferenceField(dbref=True | False)"""
# Relates to Issue #1453
class Doc(Document):
s = StringField()
class Simple(Document):
mapping0 = DictField(ReferenceField(Doc, dbref=True))
mapping1 = DictField(ReferenceField(Doc, dbref=False))
mapping2 = DictField(ListField(ReferenceField(Doc, dbref=True)))
mapping3 = DictField(ListField(ReferenceField(Doc, dbref=False)))
mapping4 = DictField(DictField(field=ReferenceField(Doc, dbref=True)))
mapping5 = DictField(DictField(field=ReferenceField(Doc, dbref=False)))
mapping6 = DictField(ListField(DictField(ReferenceField(Doc, dbref=True))))
mapping7 = DictField(ListField(DictField(ReferenceField(Doc, dbref=False))))
mapping8 = DictField(ListField(DictField(ListField(ReferenceField(Doc, dbref=True)))))
mapping9 = DictField(ListField(DictField(ListField(ReferenceField(Doc, dbref=False)))))
Doc.drop_collection()
Simple.drop_collection()
d = Doc(s='aa').save()
e = Simple()
e.mapping0['someint'] = e.mapping1['someint'] = d
e.mapping2['someint'] = e.mapping3['someint'] = [d]
e.mapping4['someint'] = e.mapping5['someint'] = {'d': d}
e.mapping6['someint'] = e.mapping7['someint'] = [{'d': d}]
e.mapping8['someint'] = e.mapping9['someint'] = [{'d': [d]}]
e.save()
s = Simple.objects.first()
self.assertIsInstance(s.mapping0['someint'], Doc)
self.assertIsInstance(s.mapping1['someint'], Doc)
self.assertIsInstance(s.mapping2['someint'][0], Doc)
self.assertIsInstance(s.mapping3['someint'][0], Doc)
self.assertIsInstance(s.mapping4['someint']['d'], Doc)
self.assertIsInstance(s.mapping5['someint']['d'], Doc)
self.assertIsInstance(s.mapping6['someint'][0]['d'], Doc)
self.assertIsInstance(s.mapping7['someint'][0]['d'], Doc)
self.assertIsInstance(s.mapping8['someint'][0]['d'][0], Doc)
self.assertIsInstance(s.mapping9['someint'][0]['d'][0], Doc)
def test_mapfield(self):
"""Ensure that the MapField handles the declared type."""
class Simple(Document):
@@ -1991,8 +1936,8 @@ class FieldTest(MongoDBTestCase):
e.save()
e2 = Extensible.objects.get(id=e.id)
self.assertTrue(isinstance(e2.mapping['somestring'], StringSetting))
self.assertTrue(isinstance(e2.mapping['someint'], IntegerSetting))
self.assertIsInstance(e2.mapping['somestring'], StringSetting)
self.assertIsInstance(e2.mapping['someint'], IntegerSetting)
with self.assertRaises(ValidationError):
e.mapping['someint'] = 123
@@ -2147,6 +2092,15 @@ class FieldTest(MongoDBTestCase):
]))
self.assertEqual(a.b.c.txt, 'hi')
def test_embedded_document_field_cant_reference_using_a_str_if_it_does_not_exist_yet(self):
raise SkipTest("Using a string reference in an EmbeddedDocumentField does not work if the class isnt registerd yet")
class MyDoc2(Document):
emb = EmbeddedDocumentField('MyDoc')
class MyDoc(EmbeddedDocument):
name = StringField()
def test_embedded_document_validation(self):
"""Ensure that invalid embedded documents cannot be assigned to
embedded document fields.
@@ -2688,7 +2642,7 @@ class FieldTest(MongoDBTestCase):
bm = Bookmark.objects(bookmark_object=post_1).first()
self.assertEqual(bm.bookmark_object, post_1)
self.assertTrue(isinstance(bm.bookmark_object, Post))
self.assertIsInstance(bm.bookmark_object, Post)
bm.bookmark_object = link_1
bm.save()
@@ -2696,7 +2650,7 @@ class FieldTest(MongoDBTestCase):
bm = Bookmark.objects(bookmark_object=link_1).first()
self.assertEqual(bm.bookmark_object, link_1)
self.assertTrue(isinstance(bm.bookmark_object, Link))
self.assertIsInstance(bm.bookmark_object, Link)
def test_generic_reference_list(self):
"""Ensure that a ListField properly dereferences generic references.
@@ -2931,7 +2885,32 @@ class FieldTest(MongoDBTestCase):
doc = Doc.objects.get(ref=DBRef('doc', doc1.pk))
self.assertEqual(doc, doc2)
def test_generic_reference_filter_by_objectid(self):
def test_generic_reference_is_not_tracked_in_parent_doc(self):
"""Ensure that modifications of related documents (through generic reference) don't influence
the owner changed fields (#1934)
"""
class Doc1(Document):
name = StringField()
class Doc2(Document):
ref = GenericReferenceField()
refs = ListField(GenericReferenceField())
Doc1.drop_collection()
Doc2.drop_collection()
doc1 = Doc1(name='garbage1').save()
doc11 = Doc1(name='garbage11').save()
doc2 = Doc2(ref=doc1, refs=[doc11]).save()
doc2.ref.name = 'garbage2'
self.assertEqual(doc2._get_changed_fields(), [])
doc2.refs[0].name = 'garbage3'
self.assertEqual(doc2._get_changed_fields(), [])
self.assertEqual(doc2._delta(), ({}, {}))
def test_generic_reference_field(self):
"""Ensure we can search for a specific generic reference by
providing its DBRef.
"""
@@ -2943,7 +2922,7 @@ class FieldTest(MongoDBTestCase):
doc1 = Doc.objects.create()
doc2 = Doc.objects.create(ref=doc1)
self.assertTrue(isinstance(doc1.pk, ObjectId))
self.assertIsInstance(doc1.pk, ObjectId)
doc = Doc.objects.get(ref=doc1.pk)
self.assertEqual(doc, doc2)
@@ -2967,37 +2946,33 @@ class FieldTest(MongoDBTestCase):
self.assertEqual(MIME_TYPE, attachment_1.content_type)
self.assertEqual(BLOB, six.binary_type(attachment_1.blob))
def test_binary_validation(self):
"""Ensure that invalid values cannot be assigned to binary fields.
def test_binary_validation_succeeds(self):
"""Ensure that valid values can be assigned to binary fields.
"""
class Attachment(Document):
blob = BinaryField()
class AttachmentRequired(Document):
blob = BinaryField(required=True)
class AttachmentSizeLimit(Document):
blob = BinaryField(max_bytes=4)
Attachment.drop_collection()
AttachmentRequired.drop_collection()
AttachmentSizeLimit.drop_collection()
attachment = Attachment()
attachment.validate()
attachment.blob = 2
self.assertRaises(ValidationError, attachment.validate)
attachment_required = AttachmentRequired()
self.assertRaises(ValidationError, attachment_required.validate)
attachment_required.blob = Binary(six.b('\xe6\x00\xc4\xff\x07'))
attachment_required.validate()
attachment_size_limit = AttachmentSizeLimit(
blob=six.b('\xe6\x00\xc4\xff\x07'))
self.assertRaises(ValidationError, attachment_size_limit.validate)
attachment_size_limit.blob = six.b('\xe6\x00\xc4\xff')
attachment_size_limit.validate()
_5_BYTES = six.b('\xe6\x00\xc4\xff\x07')
_4_BYTES = six.b('\xe6\x00\xc4\xff')
self.assertRaises(ValidationError, AttachmentSizeLimit(blob=_5_BYTES).validate)
AttachmentSizeLimit(blob=_4_BYTES).validate()
def test_binary_validation_fails(self):
"""Ensure that invalid values cannot be assigned to binary fields."""
class Attachment(Document):
blob = BinaryField()
for invalid_data in (2, u'Im_a_unicode', ['some_str']):
self.assertRaises(ValidationError, Attachment(blob=invalid_data).validate)
def test_binary_field_primary(self):
class Attachment(Document):
@@ -3546,13 +3521,13 @@ class FieldTest(MongoDBTestCase):
person.save()
person = Person.objects.first()
self.assertTrue(isinstance(person.like, Car))
self.assertIsInstance(person.like, Car)
person.like = Dish(food="arroz", number=15)
person.save()
person = Person.objects.first()
self.assertTrue(isinstance(person.like, Dish))
self.assertIsInstance(person.like, Dish)
def test_generic_embedded_document_choices(self):
"""Ensure you can limit GenericEmbeddedDocument choices."""
@@ -3577,7 +3552,7 @@ class FieldTest(MongoDBTestCase):
person.save()
person = Person.objects.first()
self.assertTrue(isinstance(person.like, Dish))
self.assertIsInstance(person.like, Dish)
def test_generic_list_embedded_document_choices(self):
"""Ensure you can limit GenericEmbeddedDocument choices inside
@@ -3604,7 +3579,7 @@ class FieldTest(MongoDBTestCase):
person.save()
person = Person.objects.first()
self.assertTrue(isinstance(person.likes[0], Dish))
self.assertIsInstance(person.likes[0], Dish)
def test_recursive_validation(self):
"""Ensure that a validation result to_dict is available."""
@@ -3630,18 +3605,17 @@ class FieldTest(MongoDBTestCase):
except ValidationError as error:
# ValidationError.errors property
self.assertTrue(hasattr(error, 'errors'))
self.assertTrue(isinstance(error.errors, dict))
self.assertTrue('comments' in error.errors)
self.assertTrue(1 in error.errors['comments'])
self.assertTrue(isinstance(error.errors['comments'][1]['content'],
ValidationError))
self.assertIsInstance(error.errors, dict)
self.assertIn('comments', error.errors)
self.assertIn(1, error.errors['comments'])
self.assertIsInstance(error.errors['comments'][1]['content'], ValidationError)
# ValidationError.schema property
error_dict = error.to_dict()
self.assertTrue(isinstance(error_dict, dict))
self.assertTrue('comments' in error_dict)
self.assertTrue(1 in error_dict['comments'])
self.assertTrue('content' in error_dict['comments'][1])
self.assertIsInstance(error_dict, dict)
self.assertIn('comments', error_dict)
self.assertIn(1, error_dict['comments'])
self.assertIn('content', error_dict['comments'][1])
self.assertEqual(error_dict['comments'][1]['content'],
u'Field is required')
@@ -3757,7 +3731,7 @@ class FieldTest(MongoDBTestCase):
# Passes regex validation
user = User(email='me@example.com')
self.assertTrue(user.validate() is None)
self.assertIsNone(user.validate())
def test_tuples_as_tuples(self):
"""Ensure that tuples remain tuples when they are inside
@@ -3784,10 +3758,10 @@ class FieldTest(MongoDBTestCase):
doc.items = tuples
doc.save()
x = TestDoc.objects().get()
self.assertTrue(x is not None)
self.assertTrue(len(x.items) == 1)
self.assertTrue(tuple(x.items[0]) in tuples)
self.assertTrue(x.items[0] in tuples)
self.assertIsNotNone(x)
self.assertEqual(len(x.items), 1)
self.assertIn(tuple(x.items[0]), tuples)
self.assertIn(x.items[0], tuples)
def test_dynamic_fields_class(self):
class Doc2(Document):
@@ -3859,7 +3833,7 @@ class FieldTest(MongoDBTestCase):
assert isinstance(doc.field, ToEmbedChild)
assert doc.field == to_embed_child
def test_invalid_dict_value(self):
def test_dict_field_invalid_dict_value(self):
class DictFieldTest(Document):
dictionary = DictField(required=True)
@@ -3873,6 +3847,22 @@ class FieldTest(MongoDBTestCase):
test.dictionary # Just access to test getter
self.assertRaises(ValidationError, test.validate)
def test_dict_field_raises_validation_error_if_wrongly_assign_embedded_doc(self):
class DictFieldTest(Document):
dictionary = DictField(required=True)
DictFieldTest.drop_collection()
class Embedded(EmbeddedDocument):
name = StringField()
embed = Embedded(name='garbage')
doc = DictFieldTest(dictionary=embed)
with self.assertRaises(ValidationError) as ctx_err:
doc.validate()
self.assertIn("'dictionary'", str(ctx_err.exception))
self.assertIn('Only dictionaries may be used in a DictField', str(ctx_err.exception))
def test_cls_field(self):
class Animal(Document):
meta = {'allow_inheritance': True}
@@ -3937,8 +3927,8 @@ class FieldTest(MongoDBTestCase):
doc = TestLongFieldConsideredAsInt64(some_long=42).save()
db = get_db()
self.assertTrue(isinstance(db.test_long_field_considered_as_int64.find()[0]['some_long'], Int64))
self.assertTrue(isinstance(doc.some_long, six.integer_types))
self.assertIsInstance(db.test_long_field_considered_as_int64.find()[0]['some_long'], Int64)
self.assertIsInstance(doc.some_long, six.integer_types)
class EmbeddedDocumentListFieldTestCase(MongoDBTestCase):
@@ -3971,6 +3961,28 @@ class EmbeddedDocumentListFieldTestCase(MongoDBTestCase):
self.Comments(author='user3', message='message1')
]).save()
def test_fails_upon_validate_if_provide_a_doc_instead_of_a_list_of_doc(self):
# Relates to Issue #1464
comment = self.Comments(author='John')
class Title(Document):
content = StringField()
# Test with an embeddedDocument instead of a list(embeddedDocument)
# It's an edge case but it used to fail with a vague error, making it difficult to troubleshoot it
post = self.BlogPost(comments=comment)
with self.assertRaises(ValidationError) as ctx_err:
post.validate()
self.assertIn("'comments'", str(ctx_err.exception))
self.assertIn('Only lists and tuples may be used in a list field', str(ctx_err.exception))
# Test with a Document
post = self.BlogPost(comments=Title(content='garbage'))
with self.assertRaises(ValidationError) as e:
post.validate()
self.assertIn("'comments'", str(ctx_err.exception))
self.assertIn('Only lists and tuples may be used in a list field', str(ctx_err.exception))
def test_no_keyword_filter(self):
"""
Tests the filter method of a List of Embedded Documents
@@ -4388,6 +4400,45 @@ class EmbeddedDocumentListFieldTestCase(MongoDBTestCase):
self.assertEqual(custom_data['a'], CustomData.c_field.custom_data['a'])
class TestEmbeddedDocumentField(MongoDBTestCase):
def test___init___(self):
class MyDoc(EmbeddedDocument):
name = StringField()
field = EmbeddedDocumentField(MyDoc)
self.assertEqual(field.document_type_obj, MyDoc)
field2 = EmbeddedDocumentField('MyDoc')
self.assertEqual(field2.document_type_obj, 'MyDoc')
def test___init___throw_error_if_document_type_is_not_EmbeddedDocument(self):
with self.assertRaises(ValidationError):
EmbeddedDocumentField(dict)
def test_document_type_throw_error_if_not_EmbeddedDocument_subclass(self):
class MyDoc(Document):
name = StringField()
emb = EmbeddedDocumentField('MyDoc')
with self.assertRaises(ValidationError) as ctx:
emb.document_type
self.assertIn('Invalid embedded document class provided to an EmbeddedDocumentField', str(ctx.exception))
def test_embedded_document_field_only_allow_subclasses_of_embedded_document(self):
# Relates to #1661
class MyDoc(Document):
name = StringField()
with self.assertRaises(ValidationError):
class MyFailingDoc(Document):
emb = EmbeddedDocumentField(MyDoc)
with self.assertRaises(ValidationError):
class MyFailingdoc2(Document):
emb = EmbeddedDocumentField('MyDoc')
class CachedReferenceFieldTest(MongoDBTestCase):
def test_cached_reference_field_get_and_save(self):
@@ -4451,7 +4502,7 @@ class CachedReferenceFieldTest(MongoDBTestCase):
ocorrence = Ocorrence.objects(animal__tag='heavy').first()
self.assertEqual(ocorrence.person, "teste")
self.assertTrue(isinstance(ocorrence.animal, Animal))
self.assertIsInstance(ocorrence.animal, Animal)
def test_cached_reference_field_decimal(self):
class PersonAuto(Document):
@@ -4768,7 +4819,7 @@ class CachedReferenceFieldTest(MongoDBTestCase):
animal__tag='heavy',
animal__owner__tp='u').first()
self.assertEqual(ocorrence.person, "teste")
self.assertTrue(isinstance(ocorrence.animal, Animal))
self.assertIsInstance(ocorrence.animal, Animal)
def test_cached_reference_embedded_list_fields(self):
class Owner(EmbeddedDocument):
@@ -4822,7 +4873,7 @@ class CachedReferenceFieldTest(MongoDBTestCase):
animal__tag='heavy',
animal__owner__tags='cool').first()
self.assertEqual(ocorrence.person, "teste 2")
self.assertTrue(isinstance(ocorrence.animal, Animal))
self.assertIsInstance(ocorrence.animal, Animal)
class LazyReferenceFieldTest(MongoDBTestCase):
@@ -5342,5 +5393,180 @@ class GenericLazyReferenceFieldTest(MongoDBTestCase):
check_fields_type(occ)
class ComplexDateTimeFieldTest(MongoDBTestCase):
def test_complexdatetime_storage(self):
"""Tests for complex datetime fields - which can handle
microseconds without rounding.
"""
class LogEntry(Document):
date = ComplexDateTimeField()
date_with_dots = ComplexDateTimeField(separator='.')
LogEntry.drop_collection()
# Post UTC - microseconds are rounded (down) nearest millisecond and
# dropped - with default datetimefields
d1 = datetime.datetime(1970, 1, 1, 0, 0, 1, 999)
log = LogEntry()
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
# Post UTC - microseconds are rounded (down) nearest millisecond - with
# default datetimefields
d1 = datetime.datetime(1970, 1, 1, 0, 0, 1, 9999)
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
# Pre UTC dates microseconds below 1000 are dropped - with default
# datetimefields
d1 = datetime.datetime(1969, 12, 31, 23, 59, 59, 999)
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
# Pre UTC microseconds above 1000 is wonky - with default datetimefields
# log.date has an invalid microsecond value so I can't construct
# a date to compare.
for i in range(1001, 3113, 33):
d1 = datetime.datetime(1969, 12, 31, 23, 59, 59, i)
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
log1 = LogEntry.objects.get(date=d1)
self.assertEqual(log, log1)
# Test string padding
microsecond = map(int, [math.pow(10, x) for x in range(6)])
mm = dd = hh = ii = ss = [1, 10]
for values in itertools.product([2014], mm, dd, hh, ii, ss, microsecond):
stored = LogEntry(date=datetime.datetime(*values)).to_mongo()['date']
self.assertTrue(re.match('^\d{4},\d{2},\d{2},\d{2},\d{2},\d{2},\d{6}$', stored) is not None)
# Test separator
stored = LogEntry(date_with_dots=datetime.datetime(2014, 1, 1)).to_mongo()['date_with_dots']
self.assertTrue(re.match('^\d{4}.\d{2}.\d{2}.\d{2}.\d{2}.\d{2}.\d{6}$', stored) is not None)
def test_complexdatetime_usage(self):
"""Tests for complex datetime fields - which can handle
microseconds without rounding.
"""
class LogEntry(Document):
date = ComplexDateTimeField()
LogEntry.drop_collection()
d1 = datetime.datetime(1950, 1, 1, 0, 0, 1, 999)
log = LogEntry()
log.date = d1
log.save()
log1 = LogEntry.objects.get(date=d1)
self.assertEqual(log, log1)
# create extra 59 log entries for a total of 60
for i in range(1951, 2010):
d = datetime.datetime(i, 1, 1, 0, 0, 1, 999)
LogEntry(date=d).save()
self.assertEqual(LogEntry.objects.count(), 60)
# Test ordering
logs = LogEntry.objects.order_by("date")
i = 0
while i < 59:
self.assertTrue(logs[i].date <= logs[i + 1].date)
i += 1
logs = LogEntry.objects.order_by("-date")
i = 0
while i < 59:
self.assertTrue(logs[i].date >= logs[i + 1].date)
i += 1
# Test searching
logs = LogEntry.objects.filter(date__gte=datetime.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 30)
logs = LogEntry.objects.filter(date__lte=datetime.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 30)
logs = LogEntry.objects.filter(
date__lte=datetime.datetime(2011, 1, 1),
date__gte=datetime.datetime(2000, 1, 1),
)
self.assertEqual(logs.count(), 10)
LogEntry.drop_collection()
# Test microsecond-level ordering/filtering
for microsecond in (99, 999, 9999, 10000):
LogEntry(
date=datetime.datetime(2015, 1, 1, 0, 0, 0, microsecond)
).save()
logs = list(LogEntry.objects.order_by('date'))
for next_idx, log in enumerate(logs[:-1], start=1):
next_log = logs[next_idx]
self.assertTrue(log.date < next_log.date)
logs = list(LogEntry.objects.order_by('-date'))
for next_idx, log in enumerate(logs[:-1], start=1):
next_log = logs[next_idx]
self.assertTrue(log.date > next_log.date)
logs = LogEntry.objects.filter(
date__lte=datetime.datetime(2015, 1, 1, 0, 0, 0, 10000))
self.assertEqual(logs.count(), 4)
def test_no_default_value(self):
class Log(Document):
timestamp = ComplexDateTimeField()
Log.drop_collection()
log = Log()
self.assertIsNone(log.timestamp)
log.save()
fetched_log = Log.objects.with_id(log.id)
self.assertIsNone(fetched_log.timestamp)
def test_default_static_value(self):
NOW = datetime.datetime.utcnow()
class Log(Document):
timestamp = ComplexDateTimeField(default=NOW)
Log.drop_collection()
log = Log()
self.assertEqual(log.timestamp, NOW)
log.save()
fetched_log = Log.objects.with_id(log.id)
self.assertEqual(fetched_log.timestamp, NOW)
def test_default_callable(self):
NOW = datetime.datetime.utcnow()
class Log(Document):
timestamp = ComplexDateTimeField(default=datetime.datetime.utcnow)
Log.drop_collection()
log = Log()
self.assertGreaterEqual(log.timestamp, NOW)
log.save()
fetched_log = Log.objects.with_id(log.id)
self.assertGreaterEqual(fetched_log.timestamp, NOW)
if __name__ == '__main__':
unittest.main()

View File

@@ -53,7 +53,7 @@ class FileTest(MongoDBTestCase):
putfile.save()
result = PutFile.objects.first()
self.assertTrue(putfile == result)
self.assertEqual(putfile, result)
self.assertEqual("%s" % result.the_file, "<GridFSProxy: hello (%s)>" % result.the_file.grid_id)
self.assertEqual(result.the_file.read(), text)
self.assertEqual(result.the_file.content_type, content_type)
@@ -71,7 +71,7 @@ class FileTest(MongoDBTestCase):
putfile.save()
result = PutFile.objects.first()
self.assertTrue(putfile == result)
self.assertEqual(putfile, result)
self.assertEqual(result.the_file.read(), text)
self.assertEqual(result.the_file.content_type, content_type)
result.the_file.delete()
@@ -96,7 +96,7 @@ class FileTest(MongoDBTestCase):
streamfile.save()
result = StreamFile.objects.first()
self.assertTrue(streamfile == result)
self.assertEqual(streamfile, result)
self.assertEqual(result.the_file.read(), text + more_text)
self.assertEqual(result.the_file.content_type, content_type)
result.the_file.seek(0)
@@ -132,7 +132,7 @@ class FileTest(MongoDBTestCase):
streamfile.save()
result = StreamFile.objects.first()
self.assertTrue(streamfile == result)
self.assertEqual(streamfile, result)
self.assertEqual(result.the_file.read(), text + more_text)
# self.assertEqual(result.the_file.content_type, content_type)
result.the_file.seek(0)
@@ -161,7 +161,7 @@ class FileTest(MongoDBTestCase):
setfile.save()
result = SetFile.objects.first()
self.assertTrue(setfile == result)
self.assertEqual(setfile, result)
self.assertEqual(result.the_file.read(), text)
# Try replacing file with new one
@@ -169,7 +169,7 @@ class FileTest(MongoDBTestCase):
result.save()
result = SetFile.objects.first()
self.assertTrue(setfile == result)
self.assertEqual(setfile, result)
self.assertEqual(result.the_file.read(), more_text)
result.the_file.delete()
@@ -231,8 +231,8 @@ class FileTest(MongoDBTestCase):
test_file_dupe = TestFile()
data = test_file_dupe.the_file.read() # Should be None
self.assertTrue(test_file.name != test_file_dupe.name)
self.assertTrue(test_file.the_file.read() != data)
self.assertNotEqual(test_file.name, test_file_dupe.name)
self.assertNotEqual(test_file.the_file.read(), data)
TestFile.drop_collection()
@@ -291,7 +291,7 @@ class FileTest(MongoDBTestCase):
the_file = FileField()
test_file = TestFile()
self.assertFalse(test_file.the_file in [{"test": 1}])
self.assertNotIn(test_file.the_file, [{"test": 1}])
def test_file_disk_space(self):
""" Test disk space usage when we delete/replace a file """

View File

@@ -298,9 +298,9 @@ class GeoFieldTest(unittest.TestCase):
polygon = PolygonField()
geo_indicies = Event._geo_indices()
self.assertTrue({'fields': [('line', '2dsphere')]} in geo_indicies)
self.assertTrue({'fields': [('polygon', '2dsphere')]} in geo_indicies)
self.assertTrue({'fields': [('point', '2dsphere')]} in geo_indicies)
self.assertIn({'fields': [('line', '2dsphere')]}, geo_indicies)
self.assertIn({'fields': [('polygon', '2dsphere')]}, geo_indicies)
self.assertIn({'fields': [('point', '2dsphere')]}, geo_indicies)
def test_indexes_2dsphere_embedded(self):
"""Ensure that indexes are created automatically for GeoPointFields.
@@ -316,9 +316,9 @@ class GeoFieldTest(unittest.TestCase):
venue = EmbeddedDocumentField(Venue)
geo_indicies = Event._geo_indices()
self.assertTrue({'fields': [('venue.line', '2dsphere')]} in geo_indicies)
self.assertTrue({'fields': [('venue.polygon', '2dsphere')]} in geo_indicies)
self.assertTrue({'fields': [('venue.point', '2dsphere')]} in geo_indicies)
self.assertIn({'fields': [('venue.line', '2dsphere')]}, geo_indicies)
self.assertIn({'fields': [('venue.polygon', '2dsphere')]}, geo_indicies)
self.assertIn({'fields': [('venue.point', '2dsphere')]}, geo_indicies)
def test_geo_indexes_recursion(self):
@@ -335,9 +335,9 @@ class GeoFieldTest(unittest.TestCase):
Parent(name='Berlin').save()
info = Parent._get_collection().index_information()
self.assertFalse('location_2d' in info)
self.assertNotIn('location_2d', info)
info = Location._get_collection().index_information()
self.assertTrue('location_2d' in info)
self.assertIn('location_2d', info)
self.assertEqual(len(Parent._geo_indices()), 0)
self.assertEqual(len(Location._geo_indices()), 1)

View File

@@ -1,6 +1,6 @@
from transform import *
from field_list import *
from queryset import *
from visitor import *
from geo import *
from modify import *
from .transform import *
from .field_list import *
from .queryset import *
from .visitor import *
from .geo import *
from .modify import *

View File

@@ -181,7 +181,7 @@ class OnlyExcludeAllTest(unittest.TestCase):
employee.save()
obj = self.Person.objects(id=employee.id).only('age').get()
self.assertTrue(isinstance(obj, Employee))
self.assertIsInstance(obj, Employee)
# Check field names are looked up properly
obj = Employee.objects(id=employee.id).only('salary').get()

View File

@@ -3,7 +3,7 @@ import unittest
from mongoengine import *
from tests.utils import MongoDBTestCase, needs_mongodb_v3
from tests.utils import MongoDBTestCase, requires_mongodb_gte_3
__all__ = ("GeoQueriesTest",)
@@ -72,7 +72,7 @@ class GeoQueriesTest(MongoDBTestCase):
# $minDistance was added in MongoDB v2.6, but continued being buggy
# until v3.0; skip for older versions
@needs_mongodb_v3
@requires_mongodb_gte_3
def test_near_and_min_distance(self):
"""Ensure the "min_distance" operator works alongside the "near"
operator.
@@ -95,9 +95,9 @@ class GeoQueriesTest(MongoDBTestCase):
location__within_distance=point_and_distance)
self.assertEqual(events.count(), 2)
events = list(events)
self.assertTrue(event2 not in events)
self.assertTrue(event1 in events)
self.assertTrue(event3 in events)
self.assertNotIn(event2, events)
self.assertIn(event1, events)
self.assertIn(event3, events)
# find events within 10 degrees of san francisco
point_and_distance = [[-122.415579, 37.7566023], 10]
@@ -245,7 +245,7 @@ class GeoQueriesTest(MongoDBTestCase):
# $minDistance was added in MongoDB v2.6, but continued being buggy
# until v3.0; skip for older versions
@needs_mongodb_v3
@requires_mongodb_gte_3
def test_2dsphere_near_and_min_max_distance(self):
"""Ensure "min_distace" and "max_distance" operators work well
together with the "near" operator in a 2dsphere index.
@@ -285,9 +285,9 @@ class GeoQueriesTest(MongoDBTestCase):
location__geo_within_center=point_and_distance)
self.assertEqual(events.count(), 2)
events = list(events)
self.assertTrue(event2 not in events)
self.assertTrue(event1 in events)
self.assertTrue(event3 in events)
self.assertNotIn(event2, events)
self.assertIn(event1, events)
self.assertIn(event3, events)
def _test_embedded(self, point_field_class):
"""Helper test method ensuring given point field class works
@@ -329,7 +329,7 @@ class GeoQueriesTest(MongoDBTestCase):
self._test_embedded(point_field_class=PointField)
# Needs MongoDB > 2.6.4 https://jira.mongodb.org/browse/SERVER-14039
@needs_mongodb_v3
@requires_mongodb_gte_3
def test_spherical_geospatial_operators(self):
"""Ensure that spherical geospatial queries are working."""
class Point(Document):

View File

@@ -2,7 +2,7 @@ import unittest
from mongoengine import connect, Document, IntField, StringField, ListField
from tests.utils import needs_mongodb_v26
from tests.utils import requires_mongodb_gte_26
__all__ = ("FindAndModifyTest",)
@@ -96,7 +96,7 @@ class FindAndModifyTest(unittest.TestCase):
self.assertEqual(old_doc.to_mongo(), {"_id": 1})
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}])
@needs_mongodb_v26
@requires_mongodb_gte_26
def test_modify_with_push(self):
class BlogPost(Document):
tags = ListField(StringField())

File diff suppressed because it is too large Load Diff

View File

@@ -48,15 +48,15 @@ class TransformTest(unittest.TestCase):
for k, v in (("set", "$set"), ("set_on_insert", "$setOnInsert"), ("push", "$push")):
update = transform.update(DicDoc, **{"%s__dictField__test" % k: doc})
self.assertTrue(isinstance(update[v]["dictField.test"], dict))
self.assertIsInstance(update[v]["dictField.test"], dict)
# Update special cases
update = transform.update(DicDoc, unset__dictField__test=doc)
self.assertEqual(update["$unset"]["dictField.test"], 1)
update = transform.update(DicDoc, pull__dictField__test=doc)
self.assertTrue(isinstance(update["$pull"]["dictField"]["test"], dict))
self.assertIsInstance(update["$pull"]["dictField"]["test"], dict)
update = transform.update(LisDoc, pull__foo__in=['a'])
self.assertEqual(update, {'$pull': {'foo': {'$in': ['a']}}})
@@ -88,17 +88,15 @@ class TransformTest(unittest.TestCase):
post = BlogPost(**data)
post.save()
self.assertTrue('postTitle' in
BlogPost.objects(title=data['title'])._query)
self.assertIn('postTitle', BlogPost.objects(title=data['title'])._query)
self.assertFalse('title' in
BlogPost.objects(title=data['title'])._query)
self.assertEqual(BlogPost.objects(title=data['title']).count(), 1)
self.assertTrue('_id' in BlogPost.objects(pk=post.id)._query)
self.assertIn('_id', BlogPost.objects(pk=post.id)._query)
self.assertEqual(BlogPost.objects(pk=post.id).count(), 1)
self.assertTrue('postComments.commentContent' in
BlogPost.objects(comments__content='test')._query)
self.assertIn('postComments.commentContent', BlogPost.objects(comments__content='test')._query)
self.assertEqual(BlogPost.objects(comments__content='test').count(), 1)
BlogPost.drop_collection()
@@ -116,8 +114,8 @@ class TransformTest(unittest.TestCase):
post = BlogPost(**data)
post.save()
self.assertTrue('_id' in BlogPost.objects(pk=data['title'])._query)
self.assertTrue('_id' in BlogPost.objects(title=data['title'])._query)
self.assertIn('_id', BlogPost.objects(pk=data['title'])._query)
self.assertIn('_id', BlogPost.objects(title=data['title'])._query)
self.assertEqual(BlogPost.objects(pk=data['title']).count(), 1)
BlogPost.drop_collection()
@@ -260,31 +258,31 @@ class TransformTest(unittest.TestCase):
events = Event.objects(location__within=box)
with self.assertRaises(InvalidQueryError):
events.count()
def test_update_pull_for_list_fields(self):
"""
Test added to check pull operation in update for
"""
Test added to check pull operation in update for
EmbeddedDocumentListField which is inside a EmbeddedDocumentField
"""
class Word(EmbeddedDocument):
word = StringField()
index = IntField()
class SubDoc(EmbeddedDocument):
heading = ListField(StringField())
text = EmbeddedDocumentListField(Word)
class MainDoc(Document):
title = StringField()
content = EmbeddedDocumentField(SubDoc)
word = Word(word='abc', index=1)
update = transform.update(MainDoc, pull__content__text=word)
self.assertEqual(update, {'$pull': {'content.text': SON([('word', u'abc'), ('index', 1)])}})
update = transform.update(MainDoc, pull__content__heading='xyz')
self.assertEqual(update, {'$pull': {'content.heading': 'xyz'}})
if __name__ == '__main__':
unittest.main()

View File

@@ -196,7 +196,7 @@ class QTest(unittest.TestCase):
test2 = test.clone()
self.assertEqual(test2.count(), 3)
self.assertFalse(test2 == test)
self.assertNotEqual(test2, test)
test3 = test2.filter(x=6)
self.assertEqual(test3.count(), 1)
@@ -296,6 +296,18 @@ class QTest(unittest.TestCase):
obj = self.Person.objects(Q(name__not=re.compile('^Gui'))).first()
self.assertEqual(obj, None)
def test_q_repr(self):
self.assertEqual(repr(Q()), 'Q(**{})')
self.assertEqual(repr(Q(name='test')), "Q(**{'name': 'test'})")
self.assertEqual(
repr(Q(name='test') & Q(age__gte=18)),
"(Q(**{'name': 'test'}) & Q(**{'age__gte': 18}))")
self.assertEqual(
repr(Q(name='test') | Q(age__gte=18)),
"(Q(**{'name': 'test'}) | Q(**{'age__gte': 18}))")
def test_q_lists(self):
"""Ensure that Q objects query ListFields correctly.
"""

View File

@@ -39,15 +39,15 @@ class ConnectionTest(unittest.TestCase):
connect('mongoenginetest')
conn = get_connection()
self.assertTrue(isinstance(conn, pymongo.mongo_client.MongoClient))
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertTrue(isinstance(db, pymongo.database.Database))
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, 'mongoenginetest')
connect('mongoenginetest2', alias='testdb')
conn = get_connection('testdb')
self.assertTrue(isinstance(conn, pymongo.mongo_client.MongoClient))
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
def test_connect_in_mocking(self):
"""Ensure that the connect() method works properly in mocking.
@@ -59,31 +59,31 @@ class ConnectionTest(unittest.TestCase):
connect('mongoenginetest', host='mongomock://localhost')
conn = get_connection()
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect('mongoenginetest2', host='mongomock://localhost', alias='testdb2')
conn = get_connection('testdb2')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect('mongoenginetest3', host='mongodb://localhost', is_mock=True, alias='testdb3')
conn = get_connection('testdb3')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect('mongoenginetest4', is_mock=True, alias='testdb4')
conn = get_connection('testdb4')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect(host='mongodb://localhost:27017/mongoenginetest5', is_mock=True, alias='testdb5')
conn = get_connection('testdb5')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect(host='mongomock://localhost:27017/mongoenginetest6', alias='testdb6')
conn = get_connection('testdb6')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect(host='mongomock://localhost:27017/mongoenginetest7', is_mock=True, alias='testdb7')
conn = get_connection('testdb7')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
def test_connect_with_host_list(self):
"""Ensure that the connect() method works when host is a list
@@ -97,27 +97,27 @@ class ConnectionTest(unittest.TestCase):
connect(host=['mongomock://localhost'])
conn = get_connection()
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect(host=['mongodb://localhost'], is_mock=True, alias='testdb2')
conn = get_connection('testdb2')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect(host=['localhost'], is_mock=True, alias='testdb3')
conn = get_connection('testdb3')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect(host=['mongomock://localhost:27017', 'mongomock://localhost:27018'], alias='testdb4')
conn = get_connection('testdb4')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect(host=['mongodb://localhost:27017', 'mongodb://localhost:27018'], is_mock=True, alias='testdb5')
conn = get_connection('testdb5')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
connect(host=['localhost:27017', 'localhost:27018'], is_mock=True, alias='testdb6')
conn = get_connection('testdb6')
self.assertTrue(isinstance(conn, mongomock.MongoClient))
self.assertIsInstance(conn, mongomock.MongoClient)
def test_disconnect(self):
"""Ensure that the disconnect() method works properly
@@ -163,10 +163,10 @@ class ConnectionTest(unittest.TestCase):
connect("testdb_uri", host='mongodb://username:password@localhost/mongoenginetest')
conn = get_connection()
self.assertTrue(isinstance(conn, pymongo.mongo_client.MongoClient))
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertTrue(isinstance(db, pymongo.database.Database))
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, 'mongoenginetest')
c.admin.system.users.remove({})
@@ -179,10 +179,10 @@ class ConnectionTest(unittest.TestCase):
connect("mongoenginetest", host='mongodb://localhost/')
conn = get_connection()
self.assertTrue(isinstance(conn, pymongo.mongo_client.MongoClient))
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertTrue(isinstance(db, pymongo.database.Database))
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, 'mongoenginetest')
def test_connect_uri_default_db(self):
@@ -192,10 +192,10 @@ class ConnectionTest(unittest.TestCase):
connect(host='mongodb://localhost/')
conn = get_connection()
self.assertTrue(isinstance(conn, pymongo.mongo_client.MongoClient))
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertTrue(isinstance(db, pymongo.database.Database))
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, 'test')
def test_uri_without_credentials_doesnt_override_conn_settings(self):
@@ -242,7 +242,7 @@ class ConnectionTest(unittest.TestCase):
'mongoenginetest?authSource=admin')
)
db = get_db('test2')
self.assertTrue(isinstance(db, pymongo.database.Database))
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, 'mongoenginetest')
# Clear all users
@@ -255,10 +255,10 @@ class ConnectionTest(unittest.TestCase):
self.assertRaises(MongoEngineConnectionError, get_connection)
conn = get_connection('testdb')
self.assertTrue(isinstance(conn, pymongo.mongo_client.MongoClient))
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
db = get_db('testdb')
self.assertTrue(isinstance(db, pymongo.database.Database))
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, 'mongoenginetest2')
def test_register_connection_defaults(self):
@@ -267,7 +267,7 @@ class ConnectionTest(unittest.TestCase):
register_connection('testdb', 'mongoenginetest', host=None, port=None)
conn = get_connection('testdb')
self.assertTrue(isinstance(conn, pymongo.mongo_client.MongoClient))
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
def test_connection_kwargs(self):
"""Ensure that connection kwargs get passed to pymongo."""
@@ -326,7 +326,7 @@ class ConnectionTest(unittest.TestCase):
if IS_PYMONGO_3:
c = connect(host='mongodb://localhost/test?replicaSet=local-rs')
db = get_db()
self.assertTrue(isinstance(db, pymongo.database.Database))
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, 'test')
else:
# PyMongo < v3.x raises an exception:
@@ -343,7 +343,7 @@ class ConnectionTest(unittest.TestCase):
self.assertEqual(c._MongoClient__options.replica_set_name,
'local-rs')
db = get_db()
self.assertTrue(isinstance(db, pymongo.database.Database))
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, 'test')
else:
# PyMongo < v3.x raises an exception:
@@ -364,6 +364,12 @@ class ConnectionTest(unittest.TestCase):
date_doc = DateDoc.objects.first()
self.assertEqual(d, date_doc.the_date)
def test_read_preference_from_parse(self):
if IS_PYMONGO_3:
from pymongo import ReadPreference
conn = connect(host="mongodb://a1.vpc,a2.vpc,a3.vpc/prod?readPreference=secondaryPreferred")
self.assertEqual(conn.read_preference, ReadPreference.SECONDARY_PREFERRED)
def test_multiple_connection_settings(self):
connect('mongoenginetest', alias='t1', host="localhost")
@@ -371,8 +377,8 @@ class ConnectionTest(unittest.TestCase):
mongo_connections = mongoengine.connection._connections
self.assertEqual(len(mongo_connections.items()), 2)
self.assertTrue('t1' in mongo_connections.keys())
self.assertTrue('t2' in mongo_connections.keys())
self.assertIn('t1', mongo_connections.keys())
self.assertIn('t2', mongo_connections.keys())
if not IS_PYMONGO_3:
self.assertEqual(mongo_connections['t1'].host, 'localhost')
self.assertEqual(mongo_connections['t2'].host, '127.0.0.1')

View File

@@ -89,15 +89,15 @@ class ContextManagersTest(unittest.TestCase):
with no_dereference(Group) as Group:
group = Group.objects.first()
self.assertTrue(all([not isinstance(m, User)
for m in group.members]))
self.assertFalse(isinstance(group.ref, User))
self.assertFalse(isinstance(group.generic, User))
for m in group.members:
self.assertNotIsInstance(m, User)
self.assertNotIsInstance(group.ref, User)
self.assertNotIsInstance(group.generic, User)
self.assertTrue(all([isinstance(m, User)
for m in group.members]))
self.assertTrue(isinstance(group.ref, User))
self.assertTrue(isinstance(group.generic, User))
for m in group.members:
self.assertIsInstance(m, User)
self.assertIsInstance(group.ref, User)
self.assertIsInstance(group.generic, User)
def test_no_dereference_context_manager_dbref(self):
"""Ensure that DBRef items in ListFields aren't dereferenced.
@@ -129,19 +129,17 @@ class ContextManagersTest(unittest.TestCase):
group = Group.objects.first()
self.assertTrue(all([not isinstance(m, User)
for m in group.members]))
self.assertFalse(isinstance(group.ref, User))
self.assertFalse(isinstance(group.generic, User))
self.assertNotIsInstance(group.ref, User)
self.assertNotIsInstance(group.generic, User)
self.assertTrue(all([isinstance(m, User)
for m in group.members]))
self.assertTrue(isinstance(group.ref, User))
self.assertTrue(isinstance(group.generic, User))
self.assertIsInstance(group.ref, User)
self.assertIsInstance(group.generic, User)
def test_no_sub_classes(self):
class A(Document):
x = IntField()
y = IntField()
meta = {'allow_inheritance': True}
class B(A):
@@ -152,29 +150,29 @@ class ContextManagersTest(unittest.TestCase):
A.drop_collection()
A(x=10, y=20).save()
A(x=15, y=30).save()
B(x=20, y=40).save()
B(x=30, y=50).save()
C(x=40, y=60).save()
A(x=10).save()
A(x=15).save()
B(x=20).save()
B(x=30).save()
C(x=40).save()
self.assertEqual(A.objects.count(), 5)
self.assertEqual(B.objects.count(), 3)
self.assertEqual(C.objects.count(), 1)
with no_sub_classes(A) as A:
with no_sub_classes(A):
self.assertEqual(A.objects.count(), 2)
for obj in A.objects:
self.assertEqual(obj.__class__, A)
with no_sub_classes(B) as B:
with no_sub_classes(B):
self.assertEqual(B.objects.count(), 2)
for obj in B.objects:
self.assertEqual(obj.__class__, B)
with no_sub_classes(C) as C:
with no_sub_classes(C):
self.assertEqual(C.objects.count(), 1)
for obj in C.objects:
@@ -185,18 +183,124 @@ class ContextManagersTest(unittest.TestCase):
self.assertEqual(B.objects.count(), 3)
self.assertEqual(C.objects.count(), 1)
def test_no_sub_classes_modification_to_document_class_are_temporary(self):
class A(Document):
x = IntField()
meta = {'allow_inheritance': True}
class B(A):
z = IntField()
self.assertEqual(A._subclasses, ('A', 'A.B'))
with no_sub_classes(A):
self.assertEqual(A._subclasses, ('A',))
self.assertEqual(A._subclasses, ('A', 'A.B'))
self.assertEqual(B._subclasses, ('A.B',))
with no_sub_classes(B):
self.assertEqual(B._subclasses, ('A.B',))
self.assertEqual(B._subclasses, ('A.B',))
def test_no_subclass_context_manager_does_not_swallow_exception(self):
class User(Document):
name = StringField()
with self.assertRaises(TypeError):
with no_sub_classes(User):
raise TypeError()
def test_query_counter_does_not_swallow_exception(self):
with self.assertRaises(TypeError):
with query_counter() as q:
raise TypeError()
def test_query_counter_temporarily_modifies_profiling_level(self):
connect('mongoenginetest')
db = get_db()
initial_profiling_level = db.profiling_level()
try:
NEW_LEVEL = 1
db.set_profiling_level(NEW_LEVEL)
self.assertEqual(db.profiling_level(), NEW_LEVEL)
with query_counter() as q:
self.assertEqual(db.profiling_level(), 2)
self.assertEqual(db.profiling_level(), NEW_LEVEL)
except Exception:
db.set_profiling_level(initial_profiling_level) # Ensures it gets reseted no matter the outcome of the test
raise
def test_query_counter(self):
connect('mongoenginetest')
db = get_db()
db.test.find({})
collection = db.query_counter
collection.drop()
def issue_1_count_query():
collection.find({}).count()
def issue_1_insert_query():
collection.insert_one({'test': 'garbage'})
def issue_1_find_query():
collection.find_one()
counter = 0
with query_counter() as q:
self.assertEqual(q, counter)
self.assertEqual(q, counter) # Ensures previous count query did not get counted
for _ in range(10):
issue_1_insert_query()
counter += 1
self.assertEqual(q, counter)
for _ in range(4):
issue_1_find_query()
counter += 1
self.assertEqual(q, counter)
for _ in range(3):
issue_1_count_query()
counter += 1
self.assertEqual(q, counter)
def test_query_counter_counts_getmore_queries(self):
connect('mongoenginetest')
db = get_db()
collection = db.query_counter
collection.drop()
many_docs = [{'test': 'garbage %s' % i} for i in range(150)]
collection.insert_many(many_docs) # first batch of documents contains 101 documents
with query_counter() as q:
self.assertEqual(0, q)
self.assertEqual(q, 0)
list(collection.find())
self.assertEqual(q, 2) # 1st select + 1 getmore
for i in range(1, 51):
db.test.find({}).count()
def test_query_counter_ignores_particular_queries(self):
connect('mongoenginetest')
db = get_db()
self.assertEqual(50, q)
collection = db.query_counter
collection.insert_many([{'test': 'garbage %s' % i} for i in range(10)])
with query_counter() as q:
self.assertEqual(q, 0)
cursor = collection.find()
self.assertEqual(q, 0) # cursor wasn't opened yet
_ = next(cursor) # opens the cursor and fires the find query
self.assertEqual(q, 1)
cursor.close() # issues a `killcursors` query that is ignored by the context
self.assertEqual(q, 1)
_ = db.system.indexes.find_one() # queries on db.system.indexes are ignored as well
self.assertEqual(q, 1)
if __name__ == '__main__':
unittest.main()

View File

@@ -200,8 +200,8 @@ class FieldTest(unittest.TestCase):
group = Group(author=user, members=[user]).save()
raw_data = Group._get_collection().find_one()
self.assertTrue(isinstance(raw_data['author'], DBRef))
self.assertTrue(isinstance(raw_data['members'][0], DBRef))
self.assertIsInstance(raw_data['author'], DBRef)
self.assertIsInstance(raw_data['members'][0], DBRef)
group = Group.objects.first()
self.assertEqual(group.author, user)
@@ -224,8 +224,8 @@ class FieldTest(unittest.TestCase):
self.assertEqual(group.members, [user])
raw_data = Group._get_collection().find_one()
self.assertTrue(isinstance(raw_data['author'], ObjectId))
self.assertTrue(isinstance(raw_data['members'][0], ObjectId))
self.assertIsInstance(raw_data['author'], ObjectId)
self.assertIsInstance(raw_data['members'][0], ObjectId)
def test_recursive_reference(self):
"""Ensure that ReferenceFields can reference their own documents.
@@ -469,7 +469,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for m in group_obj.members:
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
# Document select_related
with query_counter() as q:
@@ -485,7 +485,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for m in group_obj.members:
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
# Queryset select_related
with query_counter() as q:
@@ -502,7 +502,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for m in group_obj.members:
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
UserA.drop_collection()
UserB.drop_collection()
@@ -560,7 +560,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for m in group_obj.members:
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
# Document select_related
with query_counter() as q:
@@ -576,7 +576,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for m in group_obj.members:
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
# Queryset select_related
with query_counter() as q:
@@ -593,7 +593,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for m in group_obj.members:
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
UserA.drop_collection()
UserB.drop_collection()
@@ -633,7 +633,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 2)
for k, m in group_obj.members.iteritems():
self.assertTrue(isinstance(m, User))
self.assertIsInstance(m, User)
# Document select_related
with query_counter() as q:
@@ -646,7 +646,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 2)
for k, m in group_obj.members.iteritems():
self.assertTrue(isinstance(m, User))
self.assertIsInstance(m, User)
# Queryset select_related
with query_counter() as q:
@@ -660,7 +660,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 2)
for k, m in group_obj.members.iteritems():
self.assertTrue(isinstance(m, User))
self.assertIsInstance(m, User)
User.drop_collection()
Group.drop_collection()
@@ -715,7 +715,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for k, m in group_obj.members.iteritems():
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
# Document select_related
with query_counter() as q:
@@ -731,7 +731,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for k, m in group_obj.members.iteritems():
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
# Queryset select_related
with query_counter() as q:
@@ -748,7 +748,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for k, m in group_obj.members.iteritems():
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
Group.objects.delete()
Group().save()
@@ -806,7 +806,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 2)
for k, m in group_obj.members.iteritems():
self.assertTrue(isinstance(m, UserA))
self.assertIsInstance(m, UserA)
# Document select_related
with query_counter() as q:
@@ -822,7 +822,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 2)
for k, m in group_obj.members.iteritems():
self.assertTrue(isinstance(m, UserA))
self.assertIsInstance(m, UserA)
# Queryset select_related
with query_counter() as q:
@@ -839,7 +839,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 2)
for k, m in group_obj.members.iteritems():
self.assertTrue(isinstance(m, UserA))
self.assertIsInstance(m, UserA)
UserA.drop_collection()
Group.drop_collection()
@@ -894,7 +894,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for k, m in group_obj.members.iteritems():
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
# Document select_related
with query_counter() as q:
@@ -910,7 +910,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for k, m in group_obj.members.iteritems():
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
# Queryset select_related
with query_counter() as q:
@@ -927,7 +927,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(q, 4)
for k, m in group_obj.members.iteritems():
self.assertTrue('User' in m.__class__.__name__)
self.assertIn('User', m.__class__.__name__)
Group.objects.delete()
Group().save()
@@ -1029,7 +1029,6 @@ class FieldTest(unittest.TestCase):
self.assertEqual(type(foo.bar), Bar)
self.assertEqual(type(foo.baz), Baz)
def test_document_reload_reference_integrity(self):
"""
Ensure reloading a document with multiple similar id
@@ -1209,10 +1208,10 @@ class FieldTest(unittest.TestCase):
# Can't use query_counter across databases - so test the _data object
book = Book.objects.first()
self.assertFalse(isinstance(book._data['author'], User))
self.assertNotIsInstance(book._data['author'], User)
book.select_related()
self.assertTrue(isinstance(book._data['author'], User))
self.assertIsInstance(book._data['author'], User)
def test_non_ascii_pk(self):
"""

38
tests/test_utils.py Normal file
View File

@@ -0,0 +1,38 @@
import unittest
import re
from mongoengine.base.utils import LazyRegexCompiler
signal_output = []
class LazyRegexCompilerTest(unittest.TestCase):
def test_lazy_regex_compiler_verify_laziness_of_descriptor(self):
class UserEmail(object):
EMAIL_REGEX = LazyRegexCompiler('@', flags=32)
descriptor = UserEmail.__dict__['EMAIL_REGEX']
self.assertIsNone(descriptor._compiled_regex)
regex = UserEmail.EMAIL_REGEX
self.assertEqual(regex, re.compile('@', flags=32))
self.assertEqual(regex.search('user@domain.com').group(), '@')
user_email = UserEmail()
self.assertIs(user_email.EMAIL_REGEX, UserEmail.EMAIL_REGEX)
def test_lazy_regex_compiler_verify_cannot_set_descriptor_on_instance(self):
class UserEmail(object):
EMAIL_REGEX = LazyRegexCompiler('@')
user_email = UserEmail()
with self.assertRaises(AttributeError):
user_email.EMAIL_REGEX = re.compile('@')
def test_lazy_regex_compiler_verify_can_override_class_attr(self):
class UserEmail(object):
EMAIL_REGEX = LazyRegexCompiler('@')
UserEmail.EMAIL_REGEX = re.compile('cookies')
self.assertEqual(UserEmail.EMAIL_REGEX.search('Cake & cookies').group(), 'cookies')

View File

@@ -7,12 +7,19 @@ from mongoengine.connection import get_db, get_connection
from mongoengine.python_support import IS_PYMONGO_3
MONGO_TEST_DB = 'mongoenginetest'
MONGO_TEST_DB = 'mongoenginetest' # standard name for the test database
# Constant that can be used to compare the version retrieved with
# get_mongodb_version()
MONGODB_26 = (2, 6)
MONGODB_3 = (3,0)
MONGODB_32 = (3, 2)
class MongoDBTestCase(unittest.TestCase):
"""Base class for tests that need a mongodb connection
db is being dropped automatically
It ensures that the db is clean at the beginning and dropped at the end automatically
"""
@classmethod
@@ -27,40 +34,46 @@ class MongoDBTestCase(unittest.TestCase):
def get_mongodb_version():
"""Return the version tuple of the MongoDB server that the default
connection is connected to.
"""
return tuple(get_connection().server_info()['versionArray'])
"""Return the version of the connected mongoDB (first 2 digits)
def _decorated_with_ver_requirement(func, ver_tuple):
:return: tuple(int, int)
"""
version_list = get_connection().server_info()['versionArray'][:2] # e.g: (3, 2)
return tuple(version_list)
def _decorated_with_ver_requirement(func, version):
"""Return a given function decorated with the version requirement
for a particular MongoDB version tuple.
:param version: The version required (tuple(int, int))
"""
def _inner(*args, **kwargs):
mongodb_ver = get_mongodb_version()
if mongodb_ver >= ver_tuple:
MONGODB_V = get_mongodb_version()
if MONGODB_V >= version:
return func(*args, **kwargs)
raise SkipTest('Needs MongoDB v{}+'.format(
'.'.join([str(v) for v in ver_tuple])
))
raise SkipTest('Needs MongoDB v{}+'.format('.'.join(str(n) for n in version)))
_inner.__name__ = func.__name__
_inner.__doc__ = func.__doc__
return _inner
def needs_mongodb_v26(func):
def requires_mongodb_gte_26(func):
"""Raise a SkipTest exception if we're working with MongoDB version
lower than v2.6.
"""
return _decorated_with_ver_requirement(func, (2, 6))
return _decorated_with_ver_requirement(func, MONGODB_26)
def needs_mongodb_v3(func):
def requires_mongodb_gte_3(func):
"""Raise a SkipTest exception if we're working with MongoDB version
lower than v3.0.
"""
return _decorated_with_ver_requirement(func, (3, 0))
return _decorated_with_ver_requirement(func, MONGODB_3)
def skip_pymongo3(f):
"""Raise a SkipTest exception if we're running a test against