Skip to content

Commit 094399b

Browse files
author
Alejandro Casanovas
committed
Fixed negation of groups '()' as reported in #1058
Fixed: Negations are now correctly consumed when used in: open groups, logical operators, functions and iterables.
1 parent 91f5c0d commit 094399b

File tree

1 file changed

+41
-22
lines changed

1 file changed

+41
-22
lines changed

O365/utils/utils.py

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -951,9 +951,12 @@ def _add_filter(self, *filter_data):
951951
self._filters.append(self._chain)
952952
sentence, attrs = filter_data
953953
for i, group in enumerate(self._open_group_flag):
954-
if group is True:
955-
# Open a group
956-
sentence = '(' + sentence
954+
if group is True or group is None:
955+
# Open a group: None Flags a group that is negated
956+
if group is True:
957+
sentence = '(' + sentence
958+
else:
959+
sentence = 'not (' + sentence
957960
self._open_group_flag[i] = False # set to done
958961
self._filters.append([self._attribute, sentence, attrs])
959962
else:
@@ -1006,14 +1009,18 @@ def logical_operator(self, operation, word):
10061009
:rtype: Query
10071010
"""
10081011
word = self._parse_filter_word(word)
1012+
# consume negation
1013+
negation = self._negation
1014+
if negation:
1015+
self._negation = False
10091016
self._add_filter(
1010-
*self._prepare_sentence(self._attribute, operation, word,
1011-
self._negation))
1017+
*self._prepare_sentence(self._attribute, operation, word, negation)
1018+
)
10121019
return self
10131020

10141021
@fluent
10151022
def equals(self, word):
1016-
""" Add a equals check
1023+
""" Add an equals check
10171024
10181025
:param word: word to compare with
10191026
:rtype: Query
@@ -1022,7 +1029,7 @@ def equals(self, word):
10221029

10231030
@fluent
10241031
def unequal(self, word):
1025-
""" Add a unequals check
1032+
""" Add an unequals check
10261033
10271034
:param word: word to compare with
10281035
:rtype: Query
@@ -1080,10 +1087,12 @@ def function(self, function_name, word):
10801087
:rtype: Query
10811088
"""
10821089
word = self._parse_filter_word(word)
1083-
1090+
# consume negation
1091+
negation = self._negation
1092+
if negation:
1093+
self._negation = False
10841094
self._add_filter(
1085-
*self._prepare_function(function_name, self._attribute, word,
1086-
self._negation))
1095+
*self._prepare_function(function_name, self._attribute, word, negation))
10871096
return self
10881097

10891098
@fluent
@@ -1115,7 +1124,7 @@ def endswith(self, word):
11151124

11161125
@fluent
11171126
def iterable(self, iterable_name, *, collection, word, attribute=None, func=None,
1118-
operation=None, negate=False):
1127+
operation=None, negation=False):
11191128
""" Performs a filter with the OData 'iterable_name' keyword
11201129
on the collection
11211130
@@ -1134,7 +1143,7 @@ def iterable(self, iterable_name, *, collection, word, attribute=None, func=None
11341143
the collection
11351144
:param str operation: the logical operation to apply to the attribute
11361145
inside the collection
1137-
:param bool negate: negate the funcion or operation inside the iterable
1146+
:param bool negation: negate the funcion or operation inside the iterable
11381147
:rtype: Query
11391148
"""
11401149

@@ -1157,21 +1166,26 @@ def iterable(self, iterable_name, *, collection, word, attribute=None, func=None
11571166
attribute = 'a/{}'.format(attribute)
11581167

11591168
if func is not None:
1160-
sentence = self._prepare_function(func, attribute, word, negate)
1169+
sentence = self._prepare_function(func, attribute, word, negation)
11611170
else:
1162-
sentence = self._prepare_sentence(attribute, operation, word, negate)
1171+
sentence = self._prepare_sentence(attribute, operation, word, negation)
11631172

11641173
filter_str, attrs = sentence
11651174

1166-
filter_data = '{}/{}(a:{})'.format(collection, iterable_name, filter_str), attrs
1175+
# consume negation
1176+
negation = 'not' if self._negation else ''
1177+
if self._negation:
1178+
self._negation = False
1179+
1180+
filter_data = '{} {}/{}(a:{})'.format(negation, collection, iterable_name, filter_str).strip(), attrs
11671181
self._add_filter(*filter_data)
11681182

11691183
self._attribute = current_att
11701184

11711185
return self
11721186

11731187
@fluent
1174-
def any(self, *, collection, word, attribute=None, func=None, operation=None, negate=False):
1188+
def any(self, *, collection, word, attribute=None, func=None, operation=None, negation=False):
11751189
""" Performs a filter with the OData 'any' keyword on the collection
11761190
11771191
For example:
@@ -1189,16 +1203,16 @@ def any(self, *, collection, word, attribute=None, func=None, operation=None, ne
11891203
inside the collection
11901204
:param str operation: the logical operation to apply to the
11911205
attribute inside the collection
1192-
:param bool negate: negate the funcion or operation inside the iterable
1206+
:param bool negation: negates the funcion or operation inside the iterable
11931207
:rtype: Query
11941208
"""
11951209

11961210
return self.iterable('any', collection=collection, word=word,
11971211
attribute=attribute, func=func, operation=operation,
1198-
negate=negate)
1212+
negation=negation)
11991213

12001214
@fluent
1201-
def all(self, *, collection, word, attribute=None, func=None, operation=None, negate=False):
1215+
def all(self, *, collection, word, attribute=None, func=None, operation=None, negation=False):
12021216
""" Performs a filter with the OData 'all' keyword on the collection
12031217
12041218
For example:
@@ -1216,13 +1230,13 @@ def all(self, *, collection, word, attribute=None, func=None, operation=None, ne
12161230
inside the collection
12171231
:param str operation: the logical operation to apply to the
12181232
attribute inside the collection
1219-
:param bool negate: negate the funcion or operation inside the iterable
1233+
:param bool negation: negate the funcion or operation inside the iterable
12201234
:rtype: Query
12211235
"""
12221236

12231237
return self.iterable('all', collection=collection, word=word,
12241238
attribute=attribute, func=func, operation=operation,
1225-
negate=negate)
1239+
negation=negation)
12261240

12271241
@fluent
12281242
def order_by(self, attribute=None, *, ascending=True):
@@ -1243,7 +1257,12 @@ def order_by(self, attribute=None, *, ascending=True):
12431257

12441258
def open_group(self):
12451259
""" Applies a precedence grouping in the next filters """
1246-
self._open_group_flag.append(True)
1260+
# consume negation
1261+
if self._negation:
1262+
self._negation = False
1263+
self._open_group_flag.append(None) # flag a negated group open with None
1264+
else:
1265+
self._open_group_flag.append(True)
12471266
return self
12481267

12491268
def close_group(self):

0 commit comments

Comments
 (0)