def test_find_folders_with_restriction(self): # Exact match folders = list( FolderCollection(account=self.account, folders=[ self.account.root ]).find_folders(q=Q(name='Top of Information Store'))) self.assertEqual(len(folders), 1, sorted(f.name for f in folders)) # Startswith folders = list( FolderCollection(account=self.account, folders=[ self.account.root ]).find_folders(q=Q(name__startswith='Top of '))) self.assertEqual(len(folders), 1, sorted(f.name for f in folders)) # Wrong case folders = list( FolderCollection(account=self.account, folders=[ self.account.root ]).find_folders(q=Q(name__startswith='top of '))) self.assertEqual(len(folders), 0, sorted(f.name for f in folders)) # Case insensitive folders = list( FolderCollection(account=self.account, folders=[ self.account.root ]).find_folders(q=Q(name__istartswith='top of '))) self.assertEqual(len(folders), 1, sorted(f.name for f in folders))
def test_queryset_copy(self): qs = QuerySet(folder_collection=FolderCollection( account=None, folders=[Inbox(root='XXX')])) qs.q = Q() qs.only_fields = ('a', 'b') qs.order_fields = ('c', 'd') qs.return_format = QuerySet.NONE # Initially, immutable items have the same id() new_qs = qs._copy_self() self.assertNotEqual(id(qs), id(new_qs)) self.assertEqual(id(qs.folder_collection), id(new_qs.folder_collection)) self.assertEqual(id(qs._cache), id(new_qs._cache)) self.assertEqual(qs._cache, new_qs._cache) self.assertNotEqual(id(qs.q), id(new_qs.q)) self.assertEqual(qs.q, new_qs.q) self.assertEqual(id(qs.only_fields), id(new_qs.only_fields)) self.assertEqual(qs.only_fields, new_qs.only_fields) self.assertEqual(id(qs.order_fields), id(new_qs.order_fields)) self.assertEqual(qs.order_fields, new_qs.order_fields) self.assertEqual(id(qs.return_format), id(new_qs.return_format)) self.assertEqual(qs.return_format, new_qs.return_format) # Set the same values, forcing a new id() new_qs.q = Q() new_qs.only_fields = ('a', 'b') new_qs.order_fields = ('c', 'd') new_qs.return_format = QuerySet.NONE self.assertNotEqual(id(qs), id(new_qs)) self.assertEqual(id(qs.folder_collection), id(new_qs.folder_collection)) self.assertEqual(id(qs._cache), id(new_qs._cache)) self.assertEqual(qs._cache, new_qs._cache) self.assertNotEqual(id(qs.q), id(new_qs.q)) self.assertEqual(qs.q, new_qs.q) self.assertEqual(qs.only_fields, new_qs.only_fields) self.assertEqual(qs.order_fields, new_qs.order_fields) self.assertEqual(qs.return_format, new_qs.return_format) # Set the new values, forcing a new id() new_qs.q = Q(foo=5) new_qs.only_fields = ('c', 'd') new_qs.order_fields = ('e', 'f') new_qs.return_format = QuerySet.VALUES self.assertNotEqual(id(qs), id(new_qs)) self.assertEqual(id(qs.folder_collection), id(new_qs.folder_collection)) self.assertEqual(id(qs._cache), id(new_qs._cache)) self.assertEqual(qs._cache, new_qs._cache) self.assertNotEqual(id(qs.q), id(new_qs.q)) self.assertNotEqual(qs.q, new_qs.q) self.assertNotEqual(id(qs.only_fields), id(new_qs.only_fields)) self.assertNotEqual(qs.only_fields, new_qs.only_fields) self.assertNotEqual(id(qs.order_fields), id(new_qs.order_fields)) self.assertNotEqual(qs.order_fields, new_qs.order_fields) self.assertNotEqual(id(qs.return_format), id(new_qs.return_format)) self.assertNotEqual(qs.return_format, new_qs.return_format)
def doStuff(credentials, yardAccount, account, done): # while(True): account.inbox.refresh() yardAccount.inbox.refresh() print("Unread Emails in RNS Queue: " + str(account.inbox.unread_count)) for item in account.inbox.filter(is_read=False, sender="*****@*****.**"): if ("Goods Released" in item.body): release(item.body, driver, account) item.flag = 1 item.is_read = True # else: # print("Unrecognized RNS Message: \n" + item.body) # popUpOK("Unrecognized RNS Message, see inbox or\nconsole window for details",16,top) # item.is_read=True # item.flag=2 # item.flag=1 # item.is_read=True item.save() q = (Q(subject__contains="Back Haul") | Q(subject__icontains="BH ") ) & Q(sender="*****@*****.**") & ~Q(flag=1) for item in yardAccount.inbox.filter(q): updateInfo(item.body, driver, done) # print(item.flag) item.flag = 1 item.save() # sleep(30) # top.after(3000, doStuff()) print("Done\n") top.after(60000, doStuff, credentials, yardAccount, account, done)
def test_q(self): tz = EWSTimeZone.timezone('Europe/Copenhagen') start = tz.localize(EWSDateTime(1950, 9, 26, 8, 0, 0)) end = tz.localize(EWSDateTime(2050, 9, 26, 11, 0, 0)) result = '''\ <m:Restriction xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"> <t:And xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Or> <t:Contains ContainmentMode="Substring" ContainmentComparison="Exact"> <t:FieldURI FieldURI="item:Categories"/> <t:Constant Value="FOO"/> </t:Contains> <t:Contains ContainmentMode="Substring" ContainmentComparison="Exact"> <t:FieldURI FieldURI="item:Categories"/> <t:Constant Value="BAR"/> </t:Contains> </t:Or> <t:IsGreaterThan> <t:FieldURI FieldURI="calendar:End"/> <t:FieldURIOrConstant> <t:Constant Value="1950-09-26T08:00:00+01:00"/> </t:FieldURIOrConstant> </t:IsGreaterThan> <t:IsLessThan> <t:FieldURI FieldURI="calendar:Start"/> <t:FieldURIOrConstant> <t:Constant Value="2050-09-26T11:00:00+01:00"/> </t:FieldURIOrConstant> </t:IsLessThan> </t:And> </m:Restriction>''' q = Q(Q(categories__contains='FOO') | Q(categories__contains='BAR'), start__lt=end, end__gt=start) r = Restriction(q, folders=[Calendar()], applies_to=Restriction.ITEMS) self.assertEqual(str(r), ''.join(l.lstrip() for l in result.split('\n'))) # Test empty Q q = Q() self.assertEqual( q.to_xml(folders=[Calendar()], version=None, applies_to=Restriction.ITEMS), None) with self.assertRaises(ValueError): Restriction(q, folders=[Calendar()], applies_to=Restriction.ITEMS) # Test validation with self.assertRaises(ValueError): Q(datetime_created__range=(1, )) # Must have exactly 2 args with self.assertRaises(ValueError): Q(datetime_created__range=(1, 2, 3)) # Must have exactly 2 args with self.assertRaises(TypeError): Q(datetime_created=Build(15, 1)).clean() # Must be serializable with self.assertRaises(ValueError): Q(datetime_created=EWSDateTime(2017, 1, 1)).clean() # Must be tz-aware date with self.assertRaises(ValueError): Q(categories__contains=[[1, 2], [3, 4] ]).clean() # Must be single value
def test_q_expr(self): self.assertEqual(Q().expr(), None) self.assertEqual((~Q()).expr(), None) self.assertEqual(Q(x=5).expr(), 'x == 5') self.assertEqual((~Q(x=5)).expr(), 'x != 5') q = (Q(b__contains='a', x__contains=5) | Q(~Q(a__contains='c'), f__gt=3, c=6)) & ~Q(y=9, z__contains='b') self.assertEqual( str(q), # str() calls expr() "((b contains 'a' AND x contains 5) OR (NOT a contains 'c' AND c == 6 AND f > 3)) " "AND NOT (y == 9 AND z contains 'b')") self.assertEqual( repr(q), "Q('AND', Q('OR', Q('AND', Q(b contains 'a'), Q(x contains 5)), Q('AND', Q('NOT', Q(a contains 'c')), " "Q(c == 6), Q(f > 3))), Q('NOT', Q('AND', Q(y == 9), Q(z contains 'b'))))" ) # Test simulated IN expression in_q = Q(foo__in=[1, 2, 3]) self.assertEqual(in_q.conn_type, Q.OR) self.assertEqual(len(in_q.children), 3)
def test_q_querystring(self): self.assertEqual(Q('this is a QS').expr(), 'this is a QS') self.assertEqual(Q(Q('this is a QS')), Q('this is a QS')) self.assertEqual(Q(Q(Q(Q('this is a QS')))), Q('this is a QS')) with self.assertRaises(ValueError): Q('this is a QS') & Q(foo='bar') with self.assertRaises(ValueError): Q(5)
def test_q_simplification(self): self.assertEqual(Q(foo='bar') & Q(), Q(foo='bar')) self.assertEqual(Q() & Q(foo='bar'), Q(foo='bar')) self.assertEqual(Q('foo') & Q(), Q('foo')) self.assertEqual(Q() & Q('foo'), Q('foo'))
def test_q_never(self): # Tests Q with conn_type NEVER. This is for cases where the user makes queries that would return an empty # result, but the server does not support this type of query. The only example so far is 'foo__in=[]' which # should always match nothing. self.assertEqual( Q(foo__in=[]), Q(conn_type=Q.NEVER) ) # __in with empty sequence should translate to NEVER self.assertTrue(Q(foo__in=[]).is_never()) # Test the flag self.assertEqual(~Q(foo__in=[]), Q()) # Negation should translate to the no-op self.assertTrue( ~Q(foo__in=[]).is_empty()) # Negation should translate to a no-op # Test in combination with AND and OR self.assertEqual(Q(foo__in=[], bar='baz'), Q(conn_type=Q.NEVER)) # NEVER removes all other args self.assertEqual(Q(foo__in=[]) & Q(bar='baz'), Q(conn_type=Q.NEVER)) # NEVER removes all other args self.assertEqual(Q(foo__in=[]) | Q(bar='baz'), Q(bar='baz')) # OR removes all 'never' args
def test_q_failures(self): with self.assertRaises(ValueError): # Invalid value Q(foo=None).clean(version=Version(build=EXCHANGE_2007))
def test_q_boolean_ops(self): self.assertEqual((Q(foo=5) & Q(foo=6)).conn_type, Q.AND) self.assertEqual((Q(foo=5) | Q(foo=6)).conn_type, Q.OR)
def test_q_inversion(self): version = Version(build=EXCHANGE_2007) account = mock_account(version=version, protocol=mock_protocol( version=version, service_endpoint='example.com')) root = Root(account=account) self.assertEqual((~Q(foo=5)).op, Q.NE) self.assertEqual((~Q(foo__not=5)).op, Q.EQ) self.assertEqual((~Q(foo__lt=5)).op, Q.GTE) self.assertEqual((~Q(foo__lte=5)).op, Q.GT) self.assertEqual((~Q(foo__gt=5)).op, Q.LTE) self.assertEqual((~Q(foo__gte=5)).op, Q.LT) # Test not not Q on a non-leaf self.assertEqual(Q(foo__contains=('bar', 'baz')).conn_type, Q.AND) self.assertEqual((~Q(foo__contains=('bar', 'baz'))).conn_type, Q.NOT) self.assertEqual((~~Q(foo__contains=('bar', 'baz'))).conn_type, Q.AND) self.assertEqual(Q(foo__contains=('bar', 'baz')), ~~Q(foo__contains=('bar', 'baz'))) # Test generated XML of 'Not' statement when there is only one child. Skip 't:And' between 't:Not' and 't:Or'. result = '''\ <m:Restriction xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"> <t:Not xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Or> <t:IsEqualTo> <t:FieldURI FieldURI="item:Subject"/> <t:FieldURIOrConstant> <t:Constant Value="bar"/> </t:FieldURIOrConstant> </t:IsEqualTo> <t:IsEqualTo> <t:FieldURI FieldURI="item:Subject"/> <t:FieldURIOrConstant> <t:Constant Value="baz"/> </t:FieldURIOrConstant> </t:IsEqualTo> </t:Or> </t:Not> </m:Restriction>''' q = ~(Q(subject='bar') | Q(subject='baz')) self.assertEqual( xml_to_str( q.to_xml(folders=[Calendar(root=root)], version=version, applies_to=Restriction.ITEMS)), ''.join(s.lstrip() for s in result.split('\n')))
def test_magic(self): self.assertEqual(str(Q()), 'Q()')
def test_q_failures(self): with self.assertRaises(ValueError): # Invalid value Q(foo=None).clean()
# WARNING: Filtering on the 'body' field is not fully supported by EWS. There seems to be a window # before some internal search index is populated where case-sensitive or case-insensitive filtering # for substrings in the body element incorrectly returns an empty result, and sometimes the result # stays empty. # filter() also supports EWS QueryStrings. Just pass the string to filter(). QueryStrings cannot # be combined with other filters. We make no attempt at validating the syntax of the QueryString # - we just pass the string verbatim to EWS. # # Read more about the QueryString syntax here: # https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/querystring-querystringtype a.inbox.filter('subject:XXX') # filter() also supports Q objects that are modeled after Django Q objects, for building complex # boolean logic search expressions. q = (Q(subject__iexact='foo') | Q(subject__contains='bar')) & ~Q(subject__startswith='baz') a.inbox.filter(q) # In this example, we filter by categories so we only get the items created by us. a.calendar.filter( start__lt=a.default_timezone.localize(EWSDateTime(2019, 1, 1)), end__gt=a.default_timezone.localize(EWSDateTime(2019, 1, 31)), categories__contains=['foo', 'bar'], ) # By default, EWS returns only the master recurring item. If you want recurring calendar # items to be expanded, use calendar.view(start=..., end=...) instead. items = a.calendar.view( start=a.default_timezone.localize(EWSDateTime(2019, 1, 31)), end=a.default_timezone.localize(EWSDateTime(2019, 1, 31)) +