Skip to content

Commit fd109d8

Browse files
committed
Merge branch 'master' of github.com:MongoEngine/mongoengine into geonear_and_collstats_must_come_first_pipeline
2 parents 25d759d + 38df6f1 commit fd109d8

File tree

12 files changed

+93
-87
lines changed

12 files changed

+93
-87
lines changed

docs/apireference.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ Fields
7777
.. autoclass:: mongoengine.fields.EmailField
7878
.. autoclass:: mongoengine.fields.EnumField
7979
.. autoclass:: mongoengine.fields.IntField
80-
.. autoclass:: mongoengine.fields.LongField
8180
.. autoclass:: mongoengine.fields.FloatField
8281
.. autoclass:: mongoengine.fields.DecimalField
8382
.. autoclass:: mongoengine.fields.Decimal128Field

docs/changelog.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@ Changelog
77
Development
88
===========
99
- (Fill this out as you fix issues and develop your features).
10+
- Fix Document.compare_indexes() not working correctly for text indexes on multiple fields #2612
1011
- Add support for transaction through run_in_transaction (kudos to juannyG for this) #2569
1112
Some considerations:
1213
- make sure to read https://www.mongodb.com/docs/manual/core/transactions-in-applications/#callback-api-vs-core-api
1314
- run_in_transaction context manager relies on Pymongo coreAPI, it will retry automatically in case of `UnknownTransactionCommitResult` but not `TransientTransactionError` exceptions
1415
- Using .count() in a transaction will always use Collection.count_document (as estimated_document_count is not supported in transactions)
1516
- Fix use of $geoNear or $collStats in aggregate #2493
16-
- Further to the deprecation warning, remove ability to use an unpacked list to `Queryset.aggregate(*pipeline)`, a plain list must be provided instead `Queryset.aggregate(pipeline)`, as it's closer to pymongo interface
17-
- Further to the deprecation warning, remove `full_response` from `QuerySet.modify` as it wasn't supported with Pymongo 3+
17+
- BREAKING CHANGE: Further to the deprecation warning, remove ability to use an unpacked list to `Queryset.aggregate(*pipeline)`, a plain list must be provided instead `Queryset.aggregate(pipeline)`, as it's closer to pymongo interface
18+
- BREAKING CHANGE: Further to the deprecation warning, remove `full_response` from `QuerySet.modify` as it wasn't supported with Pymongo 3+
1819
- Fixed stacklevel of many warnings (to point places emitting the warning more accurately)
1920
- Add support for collation/hint/comment to delete/update and aggregate #2842
21+
- BREAKING CHANGE: Remove LongField as it's equivalent to IntField since we drop support to Python2 long time ago (User should simply switch to IntField) #2309
22+
- BugFix - Calling .clear on a ListField wasn't being marked as changed (and flushed to db upon .save()) #2858
2023

2124
Changes in 0.29.0
2225
=================

docs/guide/defining-documents.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ are as follows:
8888
* :class:`~mongoengine.fields.ImageField`
8989
* :class:`~mongoengine.fields.IntField`
9090
* :class:`~mongoengine.fields.ListField`
91-
* :class:`~mongoengine.fields.LongField`
9291
* :class:`~mongoengine.fields.MapField`
9392
* :class:`~mongoengine.fields.ObjectIdField`
9493
* :class:`~mongoengine.fields.ReferenceField`

mongoengine/base/datastructures.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ def __setitem__(self, key, value):
177177
remove = mark_as_changed_wrapper(list.remove)
178178
reverse = mark_as_changed_wrapper(list.reverse)
179179
sort = mark_as_changed_wrapper(list.sort)
180+
clear = mark_as_changed_wrapper(list.clear)
180181
__delitem__ = mark_as_changed_wrapper(list.__delitem__)
181182
__iadd__ = mark_as_changed_wrapper(list.__iadd__)
182183
__imul__ = mark_as_changed_wrapper(list.__imul__)

mongoengine/base/utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,13 @@ def __get__(self, instance, owner):
2020

2121
def __set__(self, instance, value):
2222
raise AttributeError("Can not set attribute LazyRegexCompiler")
23+
24+
25+
class NonOrderedList(list):
26+
"""Simple utility class to compare lists without considering order (useful in context of indexes)"""
27+
28+
def __eq__(self, other):
29+
if isinstance(other, list):
30+
# Compare sorted versions of the lists
31+
return sorted(self) == sorted(other)
32+
return False

mongoengine/document.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
TopLevelDocumentMetaclass,
1515
get_document,
1616
)
17+
from mongoengine.base.utils import NonOrderedList
1718
from mongoengine.common import _import_class
1819
from mongoengine.connection import (
1920
DEFAULT_CONNECTION_NAME,
@@ -1043,9 +1044,13 @@ def compare_indexes(cls):
10431044
# Useful for text indexes (but not only)
10441045
index_type = info["key"][0][1]
10451046
text_index_fields = info.get("weights").keys()
1046-
existing.append([(key, index_type) for key in text_index_fields])
1047+
# Use NonOrderedList to avoid order comparison, see #2612
1048+
existing.append(
1049+
NonOrderedList([(key, index_type) for key in text_index_fields])
1050+
)
10471051
else:
10481052
existing.append(info["key"])
1053+
10491054
missing = [index for index in required if index not in existing]
10501055
extra = [index for index in existing if index not in required]
10511056

mongoengine/fields.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import pymongo
1515
from bson import SON, Binary, DBRef, ObjectId
1616
from bson.decimal128 import Decimal128, create_decimal128_context
17-
from bson.int64 import Int64
1817
from pymongo import ReturnDocument
1918

2019
try:
@@ -68,7 +67,6 @@
6867
"URLField",
6968
"EmailField",
7069
"IntField",
71-
"LongField",
7270
"FloatField",
7371
"DecimalField",
7472
"BooleanField",
@@ -367,13 +365,6 @@ def prepare_query_value(self, op, value):
367365
return super().prepare_query_value(op, int(value))
368366

369367

370-
class LongField(IntField):
371-
"""64-bit integer field. (Equivalent to IntField since the support to Python2 was dropped)"""
372-
373-
def to_mongo(self, value):
374-
return Int64(value)
375-
376-
377368
class FloatField(BaseField):
378369
"""Floating point number field."""
379370

tests/document/test_indexes.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class BlogPost(InheritFrom):
6666
for expected in expected_specs:
6767
assert expected["fields"] in info
6868

69+
assert BlogPost.compare_indexes() == {"missing": [], "extra": []}
70+
6971
def _index_test_inheritance(self, InheritFrom):
7072
class BlogPost(InheritFrom):
7173
date = DateTimeField(db_field="addDate", default=datetime.now)
@@ -949,6 +951,8 @@ class MyDoc(Document):
949951
]["key"]
950952
assert info["provider_ids.foo_1_provider_ids.bar_1"]["sparse"]
951953

954+
assert MyDoc.compare_indexes() == {"missing": [], "extra": []}
955+
952956
def test_text_indexes(self):
953957
class Book(Document):
954958
title = DictField()
@@ -968,6 +972,8 @@ class Book(Document):
968972
assert "ref_id_hashed" in indexes
969973
assert ("ref_id", "hashed") in indexes["ref_id_hashed"]["key"]
970974

975+
assert Book.compare_indexes() == {"missing": [], "extra": []}
976+
971977
def test_indexes_after_database_drop(self):
972978
"""
973979
Test to ensure that indexes are not re-created on a collection
@@ -1045,6 +1051,8 @@ class TestChildDoc(TestDoc):
10451051
TestDoc.ensure_indexes()
10461052
TestChildDoc.ensure_indexes()
10471053

1054+
assert TestDoc.compare_indexes() == {"missing": [], "extra": []}
1055+
10481056
index_info = TestDoc._get_collection().index_information()
10491057
for key in index_info:
10501058
del index_info[key][
@@ -1082,9 +1090,34 @@ class TestDoc(Document):
10821090
TestDoc.drop_collection()
10831091
TestDoc.ensure_indexes()
10841092

1093+
assert TestDoc.compare_indexes() == {"missing": [], "extra": []}
1094+
10851095
index_info = TestDoc._get_collection().index_information()
10861096
assert "shard_1_1__cls_1_txt_1_1" in index_info
10871097

1098+
def test_compare_indexes_works_with_compound_text_indexes(self):
1099+
"""The order of the fields in case of text indexes don't matter
1100+
so it's important to ensure that the compare_indexes method works that way
1101+
https://github.com/MongoEngine/mongoengine/issues/2612
1102+
"""
1103+
1104+
class Sample1(Document):
1105+
a = StringField()
1106+
b = StringField()
1107+
1108+
meta = {"indexes": [{"fields": ["$a", "$b"]}]}
1109+
1110+
class Sample2(Document):
1111+
a = StringField()
1112+
b = StringField()
1113+
1114+
meta = {"indexes": [{"fields": ["$b", "$a"]}]}
1115+
1116+
Sample1.drop_collection()
1117+
Sample2.drop_collection()
1118+
assert Sample1.compare_indexes() == {"missing": [], "extra": []}
1119+
assert Sample2.compare_indexes() == {"missing": [], "extra": []}
1120+
10881121

10891122
if __name__ == "__main__":
10901123
unittest.main()

tests/fields/test_int_field.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
from bson import Int64
23

34
from mongoengine import *
45
from tests.utils import MongoDBTestCase
@@ -42,3 +43,25 @@ class TestDocument(Document):
4243

4344
assert 1 == TestDocument.objects(int_fld__ne=None).count()
4445
assert 1 == TestDocument.objects(int_fld__ne=1).count()
46+
47+
def test_int_field_long_field_migration(self):
48+
class DeprecatedLongField(IntField):
49+
"""64-bit integer field. (Equivalent to IntField since the support to Python2 was dropped)"""
50+
51+
def to_mongo(self, value):
52+
return Int64(value)
53+
54+
class TestDocument(Document):
55+
long = DeprecatedLongField()
56+
57+
TestDocument.drop_collection()
58+
TestDocument(long=10).save()
59+
60+
v = TestDocument.objects().first().long
61+
62+
# simulate a migration to IntField
63+
class TestDocument(Document):
64+
long = IntField()
65+
66+
assert TestDocument.objects(long=10).count() == 1
67+
assert TestDocument.objects().first().long == v

tests/fields/test_long_field.py

Lines changed: 0 additions & 69 deletions
This file was deleted.

tests/queryset/test_transform.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@
55

66
from mongoengine import *
77
from mongoengine.queryset import Q, transform
8+
from tests.utils import MongoDBTestCase
89

910

10-
class TestTransform(unittest.TestCase):
11-
def setUp(self):
12-
connect(db="mongoenginetest")
11+
class TestTransform(MongoDBTestCase):
12+
13+
def test_transform_str_datetime(self):
14+
data = {"date": {"$ne": "2015-12-01T00:00:00"}}
15+
assert transform.query(**data) == {"date": {"$ne": "2015-12-01T00:00:00"}}
16+
assert transform.query(date__ne="2015-12-01T00:00:00") == {
17+
"date": {"$ne": "2015-12-01T00:00:00"}
18+
}
1319

1420
def test_transform_query(self):
1521
"""Ensure that the _transform_query function operates correctly."""

tests/test_datastructures.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ def test___iter__(self):
185185
base_list = BaseList(values, instance=None, name="my_name")
186186
assert values == list(base_list)
187187

188-
def test___iter___allow_modification_while_iterating_withou_error(self):
188+
def test___iter___allow_modification_while_iterating_without_error(self):
189189
# regular list allows for this, thus this subclass must comply to that
190190
base_list = BaseList([True, False, True, False], instance=None, name="my_name")
191191
for idx, val in enumerate(base_list):
@@ -365,6 +365,11 @@ def test_sort_calls_with_key(self):
365365
base_list.sort(key=lambda i: str(i))
366366
assert base_list == [1, 11, 2]
367367

368+
def test_clear_calls_mark_as_changed(self):
369+
base_list = self._get_baselist([True, False])
370+
base_list.clear()
371+
assert base_list._instance._changed_fields == ["my_name"]
372+
368373

369374
class TestStrictDict(unittest.TestCase):
370375
def setUp(self):

0 commit comments

Comments
 (0)