Changeset 223:0cc6ebc4c1bd

Show
Ignore:
Timestamp:
18/04/11 23:34:14 (13 months ago)
Author:
Menno Smits <menno@…>
Branch:
default
Message:

Changed IDLE support to use select instead of polling

Also made the idle live test a bit more robust when run against slower
servers.

Files:
2 modified

Legend:

Unmodified
Added
Removed
  • imapclient/imapclient.py

    r221 r223  
    66import response_lexer 
    77from operator import itemgetter 
     8import select 
    89import socket 
    9 import time 
    1010import warnings 
    1111 
     
    112112            port = default_port 
    113113 
     114        self.use_uid = use_uid 
     115        self.ssl = ssl 
     116        self.folder_encode = True 
    114117        self._imap = ImapClass(host, port) 
    115         self.use_uid = use_uid 
    116         self.folder_encode = True 
    117118        self._idle_tag = None 
    118119 
     
    341342        By default, this method will block until an IDLE response is 
    342343        received. If timeout is provided, the call will block for at 
    343         most this number of seconds (approximately) while waiting for 
    344         an IDLE response. 
     344        most this number of seconds while waiting for an IDLE response. 
    345345 
    346346        The return value is a list of received IDLE responses. These 
     
    348348        example: 
    349349 
    350         [(1, 'EXISTS'), 
    351          ('OK', 'Still here'),  
    352          (1, 'FETCH', ('FLAGS', ('\NotJunk',))),  
    353          (0, 'EXPUNGE')] 
    354  
    355         An attempt is made to group responses that were sent together 
    356         by the server by waiting for a little longer after the first 
    357         IDLE response is received. 
    358         """ 
    359         timeouts = 0 
    360         resps = [] 
    361         start_t = time.time() 
    362  
    363         def blocking_done(): 
    364             # Wait for one timed out read to try group IDLE responses 
    365             # that were sent together 
    366             return resps and timeouts > 1 
    367  
    368         if timeout is None: 
    369             done = blocking_done 
    370         else: 
    371             def done(): 
    372                 return blocking_done() or (time.time() - start_t >= timeout) 
    373          
     350        [('OK', 'Still here'), 
     351         (1, 'EXISTS'), 
     352         (1, 'FETCH', ('FLAGS', ('\\NotJunk',)))] 
     353        """ 
    374354        # make the socket non-blocking so the timeout can be 
    375355        # implemented for this call 
    376         self._imap.sock.settimeout(0.1)    
     356        if self.ssl: 
     357            sock = self._imap.sslobj 
     358        else: 
     359            sock = self._imap.sock 
     360        sock.setblocking(0) 
    377361        try: 
    378             while not done(): 
    379                 try: 
    380                     line = self._imap._get_line() 
    381                 except socket.timeout: 
    382                     timeouts += 1 
    383                 else: 
    384                     resps.append(_parse_idle_response(line)) 
     362            resps = [] 
     363            rs, _, _ = select.select([sock], [], [], timeout) 
     364            if rs: 
     365                while True: 
     366                    try: 
     367                        line = self._imap._get_line() 
     368                    except (socket.timeout, socket.error): 
     369                        break 
     370                    else: 
     371                        resps.append(_parse_idle_response(line)) 
    385372            return resps 
    386373        finally: 
    387             self._imap.sock.settimeout(None) 
     374            sock.setblocking(1) 
    388375 
    389376    def idle_done(self): 
  • livetest.py

    r220 r223  
    1010import sys 
    1111import time 
    12 import threading 
    1312from datetime import datetime 
    1413from ConfigParser import SafeConfigParser, NoOptionError 
     
    466465 
    467466            # Check for the idle data 
    468             responses = self.client.idle_check(timeout=1) 
     467            responses = self.client.idle_check(timeout=5) 
    469468            text, more_responses = self.client.idle_done() 
    470469            self.assertIn((1, 'EXISTS'), responses) 
    471             self.assertIn('idle', text.lower())      
    472             self.assertIsInstance(more_responses, list) 
    473              
     470            self.assertTrue(isinstance(text, str)) 
     471            self.assertGreater(len(text), 0) 
     472            self.assertTrue(isinstance(more_responses, list)) 
     473 
     474            # Check for IDLE data returned by idle_done() 
    474475            self.client.idle() 
     476            client2.select_folder('INBOX') 
    475477            client2.append('INBOX', SIMPLE_MESSAGE) 
    476             time.sleep(1) 
     478            time.sleep(2)    # Allow some time for the IDLE response to be sent 
    477479 
    478480            text, responses = self.client.idle_done() 
    479481            self.assertIn((2, 'EXISTS'), responses) 
    480             self.assertIn('idle', text.lower())      
     482            self.assertTrue(isinstance(text, str)) 
     483            self.assertGreater(len(text), 0) 
     484 
    481485 
    482486    return LiveTest