Changeset 239:86b79856cb3d

Show
Ignore:
Timestamp:
06/11/10 18:29:11 (19 months ago)
Author:
Menno Smits <menno@…>
Branch:
default
Message:

much documentation progress made

Files:
2 modified

Legend:

Unmodified
Added
Removed
  • doc-src/index.rst

    r237 r239  
    1212Introduction 
    1313------------ 
    14 XXX 
     14A Pythonic, easy-to-use IMAP client class. 
     15 
     16Unlike imaplib, arguments and returns values are Pythonic and readily 
     17usable. Exceptions are raised when problems occur (no error checking 
     18of return values is required). 
    1519 
    1620A Simple Example 
    1721---------------- 
    1822.. literalinclude:: ../imapclient/examples/example.py 
     23 
     24XXX include some simple output 
    1925 
    2026IMAPClient Class Reference 
  • imapclient/imapclient.py

    r156 r239  
    3232 
    3333class IMAPClient(object): 
     34    #XXX concepts to cover: UIDs, message lists, folder encoding, exceptions 
    3435    """ 
    35     A Pythonic, easy-to-use IMAP client class. 
    36  
    37     Unlike imaplib, arguments and returns values are Pythonic and readily 
    38     usable. Exceptions are raised when problems occur (no error checking of 
    39     return values is required). 
    40  
    4136    Message unique identifiers (UID) can be used with any call. The use_uid 
    4237    argument to the constructor and the use_uid attribute control whether UIDs 
     
    9893    
    9994    def login(self, username, password): 
    100         """Perform a simple login 
     95        """Login using *username* and *password*, returning the 
     96        server response. 
    10197        """ 
    10298        typ, data = self._imap.login(username, password) 
     
    106102 
    107103    def logout(self): 
    108         """Perform a logout 
     104        """Logout, returning the server response. 
    109105        """ 
    110106        typ, data = self._imap.logout() 
     
    114110 
    115111    def capabilities(self): 
    116         """Returns the server capability list 
     112        """Returns the server capability list. 
    117113        """ 
    118114        return self._imap.capabilities 
     
    120116 
    121117    def has_capability(self, capability): 
    122         """Checks if the server has the given capability. 
    123  
    124         @param capability: capability to test (eg 'SORT') 
     118        """Return True if the server has the *capability* specified. 
    125119        """ 
    126120        # FIXME: this will not detect capabilities that are backwards 
     
    135129 
    136130    def get_folder_delimiter(self): 
    137         """Determine the folder separator used by the IMAP server. 
    138  
    139         @return: The folder separator. 
    140         @rtype: string 
     131        """Return the folder separator used by the IMAP server (eg. "/"). 
    141132        """ 
    142133        typ, data = self._imap.namespace() 
     
    150141 
    151142    def list_folders(self, directory="", pattern="*"): 
    152         """Get a listing of folders on the server. 
    153  
    154         The default behaviour (no args) will list all folders for the logged in 
    155         user. 
    156  
    157         @param directory: The base directory to look for folders from. 
    158         @param pattern: A pattern to match against folder names. Only folder 
    159             names matching this pattern will be returned. Wildcards accepted. 
    160         @return: A list of (flags, delim, folder_name). Each folder name will 
    161             be either a string or a unicode string (if the folder on the 
    162             server required decoding). If the folder_encode attribute is 
    163             False, no decoding will be performed and only ordinary strings 
    164             will be returned. 
     143        """Get a listing of folders on the server as a list of 
     144        ``(flags, delimiter, name)`` tuples. 
     145 
     146        Calling list_folders with no arguments will list all 
     147        folders. 
     148 
     149        Specifying *directory* will limit returned folders to that 
     150        base directory. Specifying *pattern* will limit returned 
     151        folders to those with matching names. Wildcards (``*`` and 
     152        ``?``) are supported in *pattern*. 
     153 
     154        #XXX check wildcard facts 
     155 
     156        Each folder name will be either a string or a unicode string 
     157        (if the folder on the server required decoding). If the 
     158        folder_encode attribute is False, no decoding will be 
     159        performed and only ordinary strings will be returned. 
     160 
     161        #XXX check the above is still true 
    165162        """ 
    166163        return self._do_list('LIST', directory, pattern) 
    167164 
    168165    def xlist_folders(self, directory="", pattern="*"): 
    169         """A gmail-specific IMAP extension. 
    170          
    171         This method returns special flags for each folder and a localized name 
    172         for certain folders (eg, the name of the 'inbox' may be localized as the 
    173         flags can be used to determine the actual inbox, even if the name has 
    174         been localized.  It is the responsibility of the caller to either check 
    175         for 'XLIST' in the server capabilites, or to handle the error if the 
    176         server doesn't support this externsion. 
    177  
    178         @param directory: The base directory to look for folders from. 
    179         @param pattern: A pattern to match against folder names. Only folder 
    180             names matching this pattern will be returned. Wildcards accepted. 
    181         @return: A list of (flags, delim, folder_name). As per the return of 
    182             list_folders(). 
     166        """Execute the XLIST command, returning``(flags, delimiter, 
     167        name)`` tuples. 
     168 
     169        This method returns special flags for each folder and a 
     170        localized name for certain folders (e.g. the name of the 
     171        'inbox' may be localized and the flags can be used to 
     172        determine the actual inbox, even if the name has been 
     173        localized. 
     174 
     175        XXX example response 
     176                                             
     177        This is a Gmail-specific IMAP extension. It is the 
     178        responsibility of the caller to either check for 'XLIST' in 
     179        the server capabilites, or to handle the error if the server 
     180        doesn't support this externsion. 
     181 
     182        The *directory* and *pattern* arguments are as per 
     183        list_folders(). 
    183184        """ 
    184185        return self._do_list('XLIST', directory, pattern) 
    185186 
    186187    def list_sub_folders(self, directory="", pattern="*"): 
    187         """Get a listing of subscribed folders on the server. 
    188  
    189         The default behaviour (no args) will list all subscribed folders for the 
    190         logged in user. 
    191  
    192         @param directory: The base directory to look for folders from. 
    193         @param pattern: A pattern to match against folder names. Only folder 
    194             names matching this pattern will be returned. Wildcards accepted. 
    195         @return: A list of (flags, delim, folder_name). As per the return of 
    196             list_folders(). 
     188        """Return a list of subscribed folders on the server as 
     189        ``(flags, delimiter, name)`` tuples. 
     190 
     191        The default behaviour will list all subscribed folders. The 
     192        *directory* and *pattern* arguments are as per list_folders(). 
    197193        """ 
    198194        return self._do_list('LSUB', directory, pattern) 
     
    258254 
    259255    def folder_status(self, folder, what=None): 
    260         """Requests the status from folder. 
    261  
    262         @param folder: The folder name. 
    263         @param what: A sequence of status items to query. Defaults to 
    264             ('MESSAGES', 'RECENT', 'UIDNEXT', 'UIDVALIDITY', 'UNSEEN'). 
    265         @return: Dictionary of the status items for the folder. The keys match 
    266             the items specified in the what parameter. 
    267         @rtype: dict 
     256        """Return the status of *folder*. 
     257 
     258        *what* should be a sequence of status items to query. This 
     259        defaults to ``('MESSAGES', 'RECENT', 'UIDNEXT', 'UIDVALIDITY', 
     260        'UNSEEN')``. 
     261 
     262        Returns a dictionary of the status items for the folder with 
     263        keys matching *what*. 
    268264        """ 
    269265        if what is None: 
     
    290286 
    291287    def close_folder(self): 
    292         """Close the currently selected folder. 
    293  
    294         @return: Server response. 
     288        """Close the currently selected folder, returning the server 
     289        response string. 
    295290        """ 
    296291        typ, data = self._imap.close() 
     
    298293        return data[0] 
    299294 
    300  
    301295    def create_folder(self, folder): 
    302         """Create a new folder on the server. 
    303  
    304         @param folder: The folder name. 
    305         @return: Server response. 
     296        """Create *folder* on the server returning the server response string. 
    306297        """ 
    307298        typ, data = self._imap.create(self._encode_folder_name(folder)) 
     
    309300        return data[0] 
    310301 
    311  
    312302    def delete_folder(self, folder): 
    313         """Delete a new folder on the server. 
    314  
    315         @param folder: Folder name to delete. 
    316         @return: Server response. 
     303        """Delete *folder* on the server returning the server response string. 
    317304        """ 
    318305        typ, data = self._imap.delete(self._encode_folder_name(folder)) 
     
    320307        return data[0] 
    321308 
    322  
    323309    def folder_exists(self, folder): 
    324         """Determine if a folder exists on the server. 
    325  
    326         @param folder: Full folder name to look for. 
    327         @return: True if the folder exists. False otherwise. 
     310        """Return True if *folder* exists on the server. 
    328311        """ 
    329312        typ, data = self._imap.list('', self._encode_folder_name(folder)) 
     
    332315        return len(data) == 1 and data[0] != None 
    333316 
    334  
    335317    def subscribe_folder(self, folder): 
    336         """Subscribe to a folder. 
    337  
    338         @param folder: Folder name to subscribe to. 
    339         @return: Server response message. 
     318        """Subscribe to *folder*, returning the server response string. 
    340319        """ 
    341320        typ, data = self._imap.subscribe(self._encode_folder_name(folder)) 
     
    343322        return data 
    344323 
    345  
    346324    def unsubscribe_folder(self, folder): 
    347         """Unsubscribe a folder. 
    348  
    349         @param folder: Folder name to unsubscribe. 
    350         @return: Server response message. 
     325        """Unsubscribe to *folder*, returning the server response string. 
    351326        """ 
    352327        typ, data = self._imap.unsubscribe(self._encode_folder_name(folder)) 
     
    354329        return data 
    355330 
    356  
    357331    def search(self, criteria='ALL', charset=None): 
     332        """Return a list of messages ids matching *criteria*. 
     333 
     334        XXX more detail 
     335        """ 
    358336        if not criteria: 
    359337            raise ValueError('no criteria specified') 
     
    380358 
    381359    def sort(self, sort_criteria, criteria='ALL', charset='UTF-8' ): 
    382         """Returns a list of messages sorted by sort_criteria. 
     360        """Return a list of message ids sorted by *sort_criteria* and 
     361        optionally filtered by *criteria*. 
     362 
     363        The *critera* are as per search().   
    383364 
    384365        Note that this is an extension to the IMAP4: 
    385366        http://www.ietf.org/internet-drafts/draft-ietf-imapext-sort-19.txt 
     367 
     368        XXX needs more detail 
     369        XXX explain charset 
    386370        """ 
    387371        if not criteria: 
     
    409393 
    410394    def get_flags(self, messages): 
    411         """Return the flags set for messages 
    412  
    413         @param messages: Message IDs to check flags for 
    414         @return: As for add_f 
    415             { msgid1: [flag1, flag2, ... ], } 
     395        """Returns the flags set for each message in *messages* as a 
     396        dictionary structured like this: 
     397          ``{ msgid1: [flag1, flag2, ... ], }``. 
    416398        """ 
    417399        response = self.fetch(messages, ['FLAGS']) 
     
    420402 
    421403    def add_flags(self, messages, flags): 
    422         """Add one or more flags to messages 
    423  
    424         @param messages: Message IDs to add flags to 
    425         @param flags: Sequence of flags to add 
    426         @return: The flags set for each message ID as a dictionary 
    427             { msgid1: [flag1, flag2, ... ], } 
     404        """Add *flags* to *messages*. 
     405 
     406        *flags* should be a sequence of strings. Returns the flags set 
     407         for each modified message (see *get_flags*). 
    428408        """ 
    429409        return self._store('+FLAGS', messages, flags) 
     
    431411 
    432412    def remove_flags(self, messages, flags): 
    433         """Remove one or more flags from messages 
    434  
    435         @param messages: Message IDs to remove flags from 
    436         @param flags: Sequence of flags to remove 
    437         @return: As for get_flags. 
     413        """Remove one or more *flags* from *messages*. 
     414 
     415        *flags* should be a sequence of strings. Returns the flags set 
     416         for each modified message (see *get_flags*). 
    438417        """ 
    439418        return self._store('-FLAGS', messages, flags) 
     
    441420 
    442421    def set_flags(self, messages, flags): 
    443         """Set the flags for messages 
    444  
    445         @param messages: Message IDs to set flags for 
    446         @param flags: Sequence of flags to set 
    447         @return: As for get_flags. 
     422        """Set the *flags* for *messages*. 
     423 
     424        *flags* should be a sequence of strings. Returns the flags set 
     425         for each modified message (see *get_flags*). 
    448426        """ 
    449427        return self._store('FLAGS', messages, flags) 
     
    451429 
    452430    def delete_messages(self, messages): 
    453         """Short-hand method for deleting one or more messages 
    454  
    455         @param messages: Message IDs to mark for deletion. 
    456         @return: Same as for get_flags. 
     431        """Delete one or more *messages* from the currently selected 
     432        folder. 
     433 
     434        Returns the flags set for each modified message (see 
     435        *get_flags*). 
    457436        """ 
    458437        return self.add_flags(messages, DELETED) 
     
    489468        return parse_fetch_response(data) 
    490469 
    491  
    492470    def append(self, folder, msg, flags=(), msg_time=None): 
    493         """Append a message to a folder 
    494  
    495         @param folder: Folder name to append to. 
    496         @param msg: Message body as a string. 
    497         @param flags: Sequnce of message flags to set. If not specified no 
    498             flags will be set. 
    499         @param msg_time: Optional date and time to set for the message. The 
    500             server will set a time if it isn't specified. If msg_time contains 
    501             timezone information (tzinfo), this will be honoured. Otherwise the 
    502             local machine's time zone sent to the server. 
    503         @type msg_time: datetime.datetime 
    504         @return: The append response returned by the server. 
    505         @rtype: str 
     471        """Append a message to *folder*. 
     472 
     473        *msg* should be a string contains the full message including 
     474        headers. 
     475 
     476        *flags* should be a sequence of message flags to set. If not 
     477        specified no flags will be set. 
     478 
     479        *msg_time* is an optional datetime instance specifying the 
     480        date and time to set on the message. The server will set a 
     481        time if it isn't specified. If *msg_time* contains timezone 
     482        information (tzinfo), this will be honoured. Otherwise the 
     483        local machine's time zone sent to the server. 
     484 
     485        Returns the APPEND response as returned by the server. 
    506486        """ 
    507487        if msg_time: 
     
    518498        return data[0] 
    519499 
    520  
    521500    def copy(self, messages, folder): 
    522         """Copy one or more messages from the current folder to another folder 
    523  
    524         @param messages: Message IDs to fetch. 
    525         @param folder: Folder name to append to. 
    526         @return: The COPY command response message returned by the 
    527           server. 
     501        """Copy one or more messages from the current folder to 
     502        *folder*. Returns the COPY response string returned by the 
     503        server. 
    528504        """ 
    529505        msg_list = messages_to_str(messages) 
     
    537513        return data[0] 
    538514 
    539  
    540515    def expunge(self): 
     516        """Remove any messaages from the server that have the \Deleted 
     517        flag set. 
     518 
     519        XXX check if this is just for the current folder 
     520        """ 
    541521        typ, data = self._imap.expunge() 
    542522        self._checkok('expunge', typ, data) 
    543523        #TODO: expunge response 
    544524 
    545  
    546525    def getacl(self, folder): 
    547         """Get the ACL for a folder 
    548  
    549         @param folder: Folder name to get the ACL for. 
    550         @return: A list of (who, acl) tuples 
     526        """Returns a list of ``(who, acl)`` tuples describing the 
     527        access controls for *folder*. 
    551528        """ 
    552529        typ, data = self._imap.getacl(folder) 
     
    561538        return out 
    562539 
    563  
    564540    def setacl(self, folder, who, what): 
    565         """Set an ACL for a folder 
    566  
    567         @param folder: Folder name to set an ACL for. 
    568         @param who: User or group ID for the ACL. 
    569         @param what: A string describing the ACL. Set to '' to remove an ACL. 
    570         @return: Server response string. 
     541        """Set an ACL (*what*) for user (*who*) for a folder. 
     542 
     543        Set *what* to an empty string to remove an ACL. Returns the 
     544        server response string. 
    571545        """ 
    572546        typ, data = self._imap.setacl(folder, who, what) 
     
    574548        return data[0] 
    575549 
    576  
    577550    def _check_resp(self, expected, command, typ, data): 
    578551        """Check command responses for errors. 
    579552 
    580         @raise: Error if a command failed. 
     553        Raises IMAPClient.Error if the command fails. 
    581554        """ 
    582555        if typ != expected: 
    583556            raise self.Error('%s failed: %r' % (command, data[0])) 
    584557 
    585  
    586558    def _checkok(self, command, typ, data): 
    587559        self._check_resp('OK', command, typ, data) 
    588560 
    589  
    590561    def _checkbye(self, command, typ, data): 
    591562        self._check_resp('BYE', command, typ, data) 
    592563 
    593  
    594564    def _store(self, cmd, messages, flags): 
    595         """Worker function for flag manipulation functions 
    596  
    597         @param cmd: STORE command to use (eg. '+FLAGS') 
    598         @param messages: Sequence of message IDs 
    599         @param flags: Sequence of flags to set. 
    600         @return: The flags set for each message ID as a dictionary 
    601             { msgid1: [flag1, flag2, ... ], } 
     565        """Worker function for the various flag manipulation methods. 
     566 
     567        *cmd* is the STORE command to use (eg. '+FLAGS'). 
    602568        """ 
    603569        if not messages: 
     
    614580 
    615581        return self._flatten_dict(parse_fetch_response((data))) 
    616  
    617582 
    618583    def _flatten_dict(self, fetch_dict): 
     
    626591            return imap_utf7.decode(name) 
    627592        return name 
    628  
    629593 
    630594    def _encode_folder_name(self, name): 
     
    644608 
    645609def messages_to_str(messages): 
    646     """Convert a sequence of messages ids or a single message id into an 
    647     message ID list for use with IMAP commands. 
    648  
    649     @param messages: A sequence of messages IDs or a single message ID. 
    650         (eg. [1,4,5,7,8]) 
    651     @return: Message list string (eg. "1,4,5,6,8") 
     610    """Convert a sequence of messages ids or a single integer message id 
     611    into an id list string for use with IMAP commands 
    652612    """ 
    653613    if isinstance(messages, (str, int, long)): 
     
    659619 
    660620def seq_to_parenlist(flags): 
    661     """Convert a sequence into parenthised list for use with IMAP commands 
    662  
    663     @param flags: Sequence to process (eg. ['abc', 'def']) 
    664     @return: IMAP parenthenised list (eg. '(abc def)') 
     621    """Convert a sequence of strings into parenthised list string for 
     622    use with IMAP commands. 
    665623    """ 
    666624    if isinstance(flags, str): 
     
    672630 
    673631def datetime_to_imap(dt): 
    674     """Convert a datetime instance to a IMAP datetime string 
    675  
    676     If timezone information is missing the current system timezone is used. 
     632    """Convert a datetime instance to a IMAP datetime string. 
     633 
     634    If timezone information is missing the current system 
     635    timezone is used. 
    677636    """ 
    678637    if not dt.tzinfo: