diff --git a/.install_mongodb_on_travis.sh b/.install_mongodb_on_travis.sh index 6ac2e364..f1073333 100644 --- a/.install_mongodb_on_travis.sh +++ b/.install_mongodb_on_travis.sh @@ -25,8 +25,14 @@ elif [ "$MONGODB" = "3.4" ]; then sudo apt-get update sudo apt-get install mongodb-org-server=3.4.17 # service should be started automatically +elif [ "$MONGODB" = "3.6" ]; then + sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5 + echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.6 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.6.list + sudo apt-get update + sudo apt-get install mongodb-org-server=3.6.12 + # service should be started automatically else - echo "Invalid MongoDB version, expected 2.6, 3.0, 3.2 or 3.4." + echo "Invalid MongoDB version, expected 2.6, 3.0, 3.2, 3.4 or 3.6." exit 1 fi; diff --git a/.travis.yml b/.travis.yml index b943024a..909183c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,8 @@ matrix: env: MONGODB=3.2 PYMONGO=3.x - python: 3.6 env: MONGODB=3.4 PYMONGO=3.x + - python: 3.6 + env: MONGODB=3.6 PYMONGO=3.x before_install: - bash .install_mongodb_on_travis.sh diff --git a/README.rst b/README.rst index 12d9df0e..cb279d2c 100644 --- a/README.rst +++ b/README.rst @@ -26,10 +26,10 @@ an `API reference `_. Supported MongoDB Versions ========================== -MongoEngine is currently tested against MongoDB v2.6, v3.0, v3.2 and v3.4. Future +MongoEngine is currently tested against MongoDB v2.6, v3.0, v3.2, v3.4 and v3.6. Future versions should be supported as well, but aren't actively tested at the moment. Make sure to open an issue or submit a pull request if you experience any -problems with MongoDB v3.4+. +problems with MongoDB v3.6+. Installation ============ diff --git a/docs/changelog.rst b/docs/changelog.rst index b875ffcd..6ac8da93 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,7 @@ Changelog Development =========== +- Add support for MongoDB 3.6 and Python3.7 in travis - Fix querying on List(EmbeddedDocument) subclasses fields #1961 #1492 - Fix querying on (Generic)EmbeddedDocument subclasses fields #475 - expose `mongoengine.connection.disconnect` and `mongoengine.connection.disconnect_all` diff --git a/mongoengine/mongodb_support.py b/mongoengine/mongodb_support.py index 717a3d81..8e414075 100644 --- a/mongoengine/mongodb_support.py +++ b/mongoengine/mongodb_support.py @@ -6,6 +6,7 @@ from mongoengine.connection import get_connection # Constant that can be used to compare the version retrieved with # get_mongodb_version() +MONGODB_36 = (3, 6) MONGODB_34 = (3, 4) MONGODB_32 = (3, 2) MONGODB_3 = (3, 0) diff --git a/tests/queryset/queryset.py b/tests/queryset/queryset.py index 31b1641e..5005f260 100644 --- a/tests/queryset/queryset.py +++ b/tests/queryset/queryset.py @@ -6,7 +6,6 @@ import uuid from decimal import Decimal from bson import DBRef, ObjectId -from nose.plugins.skip import SkipTest import pymongo from pymongo.errors import ConfigurationError from pymongo.read_preferences import ReadPreference @@ -18,7 +17,7 @@ from mongoengine import * from mongoengine.connection import get_connection, get_db from mongoengine.context_managers import query_counter, switch_db from mongoengine.errors import InvalidQueryError -from mongoengine.mongodb_support import get_mongodb_version, MONGODB_32 +from mongoengine.mongodb_support import get_mongodb_version, MONGODB_32, MONGODB_36 from mongoengine.pymongo_support import IS_PYMONGO_3 from mongoengine.queryset import (DoesNotExist, MultipleObjectsReturned, QuerySet, QuerySetManager, queryset_manager) @@ -33,6 +32,12 @@ class db_ops_tracker(query_counter): return list(self.db.system.profile.find(ignore_query)) +def get_key_compat(mongo_ver): + ORDER_BY_KEY = 'sort' if mongo_ver >= MONGODB_32 else '$orderby' + CMD_QUERY_KEY = 'command' if mongo_ver >= MONGODB_36 else 'query' + return ORDER_BY_KEY, CMD_QUERY_KEY + + class QuerySetTest(unittest.TestCase): def setUp(self): @@ -1323,8 +1328,7 @@ class QuerySetTest(unittest.TestCase): """Ensure that the default ordering can be cleared by calling order_by() w/o any arguments. """ - MONGO_VER = self.mongodb_version - ORDER_BY_KEY = 'sort' if MONGO_VER >= MONGODB_32 else '$orderby' + ORDER_BY_KEY, CMD_QUERY_KEY = get_key_compat(self.mongodb_version) class BlogPost(Document): title = StringField() @@ -1341,7 +1345,7 @@ class QuerySetTest(unittest.TestCase): BlogPost.objects.filter(title='whatever').first() self.assertEqual(len(q.get_ops()), 1) self.assertEqual( - q.get_ops()[0]['query'][ORDER_BY_KEY], + q.get_ops()[0][CMD_QUERY_KEY][ORDER_BY_KEY], {'published_date': -1} ) @@ -1349,14 +1353,14 @@ class QuerySetTest(unittest.TestCase): with db_ops_tracker() as q: BlogPost.objects.filter(title='whatever').order_by().first() self.assertEqual(len(q.get_ops()), 1) - self.assertNotIn(ORDER_BY_KEY, q.get_ops()[0]['query']) + self.assertNotIn(ORDER_BY_KEY, q.get_ops()[0][CMD_QUERY_KEY]) # calling an explicit order_by should use a specified sort with db_ops_tracker() as q: BlogPost.objects.filter(title='whatever').order_by('published_date').first() self.assertEqual(len(q.get_ops()), 1) self.assertEqual( - q.get_ops()[0]['query'][ORDER_BY_KEY], + q.get_ops()[0][CMD_QUERY_KEY][ORDER_BY_KEY], {'published_date': 1} ) @@ -1365,13 +1369,12 @@ class QuerySetTest(unittest.TestCase): qs = BlogPost.objects.filter(title='whatever').order_by('published_date') qs.order_by().first() self.assertEqual(len(q.get_ops()), 1) - self.assertNotIn(ORDER_BY_KEY, q.get_ops()[0]['query']) + self.assertNotIn(ORDER_BY_KEY, q.get_ops()[0][CMD_QUERY_KEY]) def test_no_ordering_for_get(self): """ Ensure that Doc.objects.get doesn't use any ordering. """ - MONGO_VER = self.mongodb_version - ORDER_BY_KEY = 'sort' if MONGO_VER == MONGODB_32 else '$orderby' + ORDER_BY_KEY, CMD_QUERY_KEY = get_key_compat(self.mongodb_version) class BlogPost(Document): title = StringField() @@ -1387,13 +1390,13 @@ class QuerySetTest(unittest.TestCase): with db_ops_tracker() as q: BlogPost.objects.get(title='whatever') self.assertEqual(len(q.get_ops()), 1) - self.assertNotIn(ORDER_BY_KEY, q.get_ops()[0]['query']) + self.assertNotIn(ORDER_BY_KEY, q.get_ops()[0][CMD_QUERY_KEY]) # Ordering should be ignored for .get even if we set it explicitly with db_ops_tracker() as q: BlogPost.objects.order_by('-title').get(title='whatever') self.assertEqual(len(q.get_ops()), 1) - self.assertNotIn(ORDER_BY_KEY, q.get_ops()[0]['query']) + self.assertNotIn(ORDER_BY_KEY, q.get_ops()[0][CMD_QUERY_KEY]) def test_find_embedded(self): """Ensure that an embedded document is properly returned from @@ -2532,6 +2535,7 @@ class QuerySetTest(unittest.TestCase): def test_comment(self): """Make sure adding a comment to the query gets added to the query""" MONGO_VER = self.mongodb_version + _, CMD_QUERY_KEY = get_key_compat(MONGO_VER) QUERY_KEY = 'filter' if MONGO_VER >= MONGODB_32 else '$query' COMMENT_KEY = 'comment' if MONGO_VER >= MONGODB_32 else '$comment' @@ -2550,8 +2554,8 @@ class QuerySetTest(unittest.TestCase): ops = q.get_ops() self.assertEqual(len(ops), 2) for op in ops: - self.assertEqual(op['query'][QUERY_KEY], {'age': {'$gte': 18}}) - self.assertEqual(op['query'][COMMENT_KEY], 'looking for an adult') + self.assertEqual(op[CMD_QUERY_KEY][QUERY_KEY], {'age': {'$gte': 18}}) + self.assertEqual(op[CMD_QUERY_KEY][COMMENT_KEY], 'looking for an adult') def test_map_reduce(self): """Ensure map/reduce is both mapping and reducing. @@ -5240,8 +5244,7 @@ class QuerySetTest(unittest.TestCase): self.assertEqual(op['nreturned'], 1) def test_bool_with_ordering(self): - MONGO_VER = self.mongodb_version - ORDER_BY_KEY = 'sort' if MONGO_VER >= MONGODB_32 else '$orderby' + ORDER_BY_KEY, CMD_QUERY_KEY = get_key_compat(self.mongodb_version) class Person(Document): name = StringField() @@ -5260,21 +5263,22 @@ class QuerySetTest(unittest.TestCase): op = q.db.system.profile.find({"ns": {"$ne": "%s.system.indexes" % q.db.name}})[0] - self.assertNotIn(ORDER_BY_KEY, op['query']) + self.assertNotIn(ORDER_BY_KEY, op[CMD_QUERY_KEY]) # Check that normal query uses orderby qs2 = Person.objects.order_by('name') - with query_counter() as p: + with query_counter() as q: for x in qs2: pass - op = p.db.system.profile.find({"ns": + op = q.db.system.profile.find({"ns": {"$ne": "%s.system.indexes" % q.db.name}})[0] - self.assertIn(ORDER_BY_KEY, op['query']) + self.assertIn(ORDER_BY_KEY, op[CMD_QUERY_KEY]) def test_bool_with_ordering_from_meta_dict(self): + ORDER_BY_KEY, CMD_QUERY_KEY = get_key_compat(self.mongodb_version) class Person(Document): name = StringField() @@ -5296,7 +5300,7 @@ class QuerySetTest(unittest.TestCase): op = q.db.system.profile.find({"ns": {"$ne": "%s.system.indexes" % q.db.name}})[0] - self.assertNotIn('$orderby', op['query'], + self.assertNotIn('$orderby', op[CMD_QUERY_KEY], 'BaseQuerySet must remove orderby from meta in boolen test') self.assertEqual(Person.objects.first().name, 'A')