diff --git a/docs/changelog.rst b/docs/changelog.rst index 99081957..bc01a403 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,6 +17,9 @@ Development - If you catch/use ``MongoEngineConnectionError`` in your code, you'll have to rename it. - BREAKING CHANGE: Positional arguments when instantiating a document are no longer supported. #2103 - From now on keyword arguments (e.g. ``Doc(field_name=value)``) are required. +- DEPRECATION: ``Q.empty`` & ``QNode.empty`` are marked as deprecated and will be removed in a next version of MongoEngine. #2210 + - Added ability to check if Q or QNode are empty by parsing them to bool. + - Instead of ``Q(name="John").empty`` use ``not Q(name="John")``. - Improve error message related to InvalidDocumentError #2180 - Fix updating/modifying/deleting/reloading a document that's sharded by a field with ``db_field`` specified. #2125 - ``ListField`` now accepts an optional ``max_length`` parameter. #2110 diff --git a/mongoengine/queryset/visitor.py b/mongoengine/queryset/visitor.py index 058c722a..470839c1 100644 --- a/mongoengine/queryset/visitor.py +++ b/mongoengine/queryset/visitor.py @@ -1,4 +1,5 @@ import copy +import warnings from mongoengine.errors import InvalidQueryError from mongoengine.queryset import transform @@ -108,6 +109,8 @@ class QNode(object): @property def empty(self): + msg = "'empty' property is deprecated in favour of using 'not bool(filter)'" + warnings.warn(msg, DeprecationWarning) return False def __or__(self, other): @@ -137,6 +140,11 @@ class QCombination(QNode): op = " & " if self.operation is self.AND else " | " return "(%s)" % op.join([repr(node) for node in self.children]) + def __bool__(self): + return bool(self.children) + + __nonzero__ = __bool__ # For Py2 support + def accept(self, visitor): for i in range(len(self.children)): if isinstance(self.children[i], QNode): @@ -146,6 +154,8 @@ class QCombination(QNode): @property def empty(self): + msg = "'empty' property is deprecated in favour of using 'not bool(filter)'" + warnings.warn(msg, DeprecationWarning) return not bool(self.children) def __eq__(self, other): @@ -167,12 +177,17 @@ class Q(QNode): def __repr__(self): return "Q(**%s)" % repr(self.query) + def __bool__(self): + return bool(self.query) + + __nonzero__ = __bool__ # For Py2 support + + def __eq__(self, other): + return self.__class__ == other.__class__ and self.query == other.query + def accept(self, visitor): return visitor.visit_query(self) @property def empty(self): return not bool(self.query) - - def __eq__(self, other): - return self.__class__ == other.__class__ and self.query == other.query diff --git a/tests/queryset/test_visitor.py b/tests/queryset/test_visitor.py index afa00839..81e0f253 100644 --- a/tests/queryset/test_visitor.py +++ b/tests/queryset/test_visitor.py @@ -407,6 +407,17 @@ class TestQ(unittest.TestCase): def test_combine_or_both_empty(self): assert Q() | Q() == Q() + def test_q_bool(self): + assert Q(name="John") + assert not Q() + + def test_combine_bool(self): + assert not Q() & Q() + assert Q() & Q(name="John") + assert Q(name="John") & Q() + assert Q() | Q(name="John") + assert Q(name="John") | Q() + if __name__ == "__main__": unittest.main()