Changeset 90:5ac3ccadb5fc for imapclient/imapclient.py
- Timestamp:
- 18/12/09 17:17:30 (2 years ago)
- Branch:
- default
- Files:
-
- 1 modified
-
imapclient/imapclient.py (modified) (46 diffs)
Legend:
- Unmodified
- Added
- Removed
-
imapclient/imapclient.py
r87 r90 25 25 26 26 class IMAPClient(object): 27 '''27 """ 28 28 A Pythonic, easy-to-use IMAP client class. 29 29 … … 57 57 These are aliases for the imaplib.IMAP4 exceptions of the same name. Socket 58 58 errors may also be raised in the case of network errors. 59 '''59 """ 60 60 61 61 Error = imaplib.IMAP4.error … … 69 69 70 70 def __init__(self, host, port=None, use_uid=True, ssl=False): 71 '''Initialise object instance and connect to the remote IMAP server.71 """Initialise object instance and connect to the remote IMAP server. 72 72 73 73 @param host: The IMAP server address/hostname to connect to. … … 75 75 @param use_uid: Should message UIDs be used (default is True). 76 76 @param ssl: Make an SSL connection (default is False) 77 '''77 """ 78 78 if ssl: 79 79 ImapClass = imaplib.IMAP4_SSL … … 92 92 93 93 def login(self, username, password): 94 '''Perform a simple login95 '''94 """Perform a simple login 95 """ 96 96 typ, data = self._imap.login(username, password) 97 97 self._checkok('login', typ, data) … … 100 100 101 101 def logout(self): 102 '''Perform a logout103 '''102 """Perform a logout 103 """ 104 104 typ, data = self._imap.logout() 105 105 self._checkbye('logout', typ, data) … … 108 108 109 109 def capabilities(self): 110 '''Returns the server capability list111 '''110 """Returns the server capability list 111 """ 112 112 return self._imap.capabilities 113 113 114 114 115 115 def has_capability(self, capability): 116 '''Checks if the server has the given capability.116 """Checks if the server has the given capability. 117 117 118 118 @param capability: capability to test (eg 'SORT') 119 '''119 """ 120 120 # FIXME: this will not detect capabilities that are backwards 121 121 # compatible with the current level. For instance the SORT … … 129 129 130 130 def get_folder_delimiter(self): 131 '''Determine the folder separator used by the IMAP server.131 """Determine the folder separator used by the IMAP server. 132 132 133 133 @return: The folder separator. 134 134 @rtype: string 135 '''135 """ 136 136 typ, data = self._imap.namespace() 137 137 self._checkok('namespace', typ, data) … … 145 145 146 146 def list_folders(self, directory="", pattern="*"): 147 '''Get a listing of folders on the server.147 """Get a listing of folders on the server. 148 148 149 149 The default behaviour (no args) will list all folders for the logged in … … 157 157 decoding). If the folder_encode attribute is False, no decoding 158 158 will be performed and only ordinary strings will be returned. 159 '''159 """ 160 160 typ, data = self._imap.list(directory, pattern) 161 161 self._checkok('list', typ, data) … … 177 177 178 178 def list_sub_folders(self, directory="", pattern="*"): 179 '''Get a listing of subscribed folders on the server.179 """Get a listing of subscribed folders on the server. 180 180 181 181 The default behaviour (no args) will list all subscribed folders for the … … 186 186 names matching this pattern will be returned. Wildcards accepted. 187 187 @return: A list of folder names. As per the return of list_folders(). 188 '''188 """ 189 189 typ, data = self._imap.lsub(directory, pattern) 190 190 self._checkok('lsub', typ, data) … … 200 200 201 201 def select_folder(self, folder): 202 '''Select the current folder on the server. Future calls to methods202 """Select the current folder on the server. Future calls to methods 203 203 such as search and fetch will act on the selected folder. 204 204 … … 206 206 @return: Number of messages in the folder. 207 207 @rtype: long int 208 '''208 """ 209 209 typ, data = self._imap.select(self._encode_folder_name(folder)) 210 210 self._checkok('select', typ, data) … … 213 213 214 214 def folder_status(self, folder, what=None): 215 '''Requests the status from folder.215 """Requests the status from folder. 216 216 217 217 @param folder: The folder name. … … 221 221 the items specified in the what parameter. 222 222 @rtype: dict 223 '''223 """ 224 224 if what is None: 225 225 what = ('MESSAGES', 'RECENT', 'UIDNEXT', 'UIDVALIDITY', 'UNSEEN') … … 245 245 246 246 def close_folder(self): 247 '''Close the currently selected folder.247 """Close the currently selected folder. 248 248 249 249 @return: Server response. 250 '''250 """ 251 251 typ, data = self._imap.close() 252 252 self._checkok('close', typ, data) … … 255 255 256 256 def create_folder(self, folder): 257 '''Create a new folder on the server.257 """Create a new folder on the server. 258 258 259 259 @param folder: The folder name. 260 260 @return: Server response. 261 '''261 """ 262 262 typ, data = self._imap.create(self._encode_folder_name(folder)) 263 263 self._checkok('create', typ, data) … … 266 266 267 267 def delete_folder(self, folder): 268 '''Delete a new folder on the server.268 """Delete a new folder on the server. 269 269 270 270 @param folder: Folder name to delete. 271 271 @return: Server response. 272 '''272 """ 273 273 typ, data = self._imap.delete(self._encode_folder_name(folder)) 274 274 self._checkok('delete', typ, data) … … 277 277 278 278 def folder_exists(self, folder): 279 '''Determine if a folder exists on the server.279 """Determine if a folder exists on the server. 280 280 281 281 @param folder: Full folder name to look for. 282 282 @return: True if the folder exists. False otherwise. 283 '''283 """ 284 284 typ, data = self._imap.list('', self._encode_folder_name(folder)) 285 285 self._checkok('list', typ, data) … … 288 288 289 289 def subscribe_folder(self, folder): 290 '''Subscribe to a folder.290 """Subscribe to a folder. 291 291 292 292 @param folder: Folder name to subscribe to. 293 293 @return: Server response message. 294 '''294 """ 295 295 typ, data = self._imap.subscribe(self._encode_folder_name(folder)) 296 296 self._checkok('subscribe', typ, data) … … 299 299 300 300 def unsubscribe_folder(self, folder): 301 '''Unsubscribe a folder.301 """Unsubscribe a folder. 302 302 303 303 @param folder: Folder name to unsubscribe. 304 304 @return: Server response message. 305 '''305 """ 306 306 typ, data = self._imap.unsubscribe(self._encode_folder_name(folder)) 307 307 self._checkok('unsubscribe', typ, data) … … 332 332 333 333 def sort(self, sort_criteria, criteria='ALL', charset='UTF-8' ): 334 '''Returns a list of messages sorted by sort_criteria.334 """Returns a list of messages sorted by sort_criteria. 335 335 336 336 Note that this is an extension to the IMAP4: 337 337 http://www.ietf.org/internet-drafts/draft-ietf-imapext-sort-19.txt 338 '''338 """ 339 339 if not criteria: 340 340 raise ValueError('no criteria specified') … … 361 361 362 362 def get_flags(self, messages): 363 '''Return the flags set for messages363 """Return the flags set for messages 364 364 365 365 @param messages: Message IDs to check flags for 366 366 @return: As for add_f 367 367 { msgid1: [flag1, flag2, ... ], } 368 '''368 """ 369 369 response = self.fetch(messages, ['FLAGS']) 370 370 return self._flatten_dict(response) … … 372 372 373 373 def add_flags(self, messages, flags): 374 '''Add one or more flags to messages374 """Add one or more flags to messages 375 375 376 376 @param messages: Message IDs to add flags to … … 378 378 @return: The flags set for each message ID as a dictionary 379 379 { msgid1: [flag1, flag2, ... ], } 380 '''380 """ 381 381 return self._store('+FLAGS', messages, flags) 382 382 383 383 384 384 def remove_flags(self, messages, flags): 385 '''Remove one or more flags from messages385 """Remove one or more flags from messages 386 386 387 387 @param messages: Message IDs to remove flags from 388 388 @param flags: Sequence of flags to remove 389 389 @return: As for get_flags. 390 '''390 """ 391 391 return self._store('-FLAGS', messages, flags) 392 392 393 393 394 394 def set_flags(self, messages, flags): 395 '''Set the flags for messages395 """Set the flags for messages 396 396 397 397 @param messages: Message IDs to set flags for 398 398 @param flags: Sequence of flags to set 399 399 @return: As for get_flags. 400 '''400 """ 401 401 return self._store('FLAGS', messages, flags) 402 402 403 403 404 404 def delete_messages(self, messages): 405 '''Short-hand method for deleting one or more messages405 """Short-hand method for deleting one or more messages 406 406 407 407 @param messages: Message IDs to mark for deletion. 408 408 @return: Same as for get_flags. 409 '''409 """ 410 410 return self.add_flags(messages, DELETED) 411 411 412 412 413 413 def fetch(self, messages, parts): 414 '''Retrieve selected data items for one or more messages.414 """Retrieve selected data items for one or more messages. 415 415 416 416 @param messages: Message IDs to fetch. … … 420 420 INTERNALDATE parts will be returned as datetime objects converted 421 421 to the local machine's time zone. 422 '''422 """ 423 423 if not messages: 424 424 return {} … … 438 438 439 439 def append(self, folder, msg, flags=(), msg_time=None): 440 '''Append a message to a folder440 """Append a message to a folder 441 441 442 442 @param folder: Folder name to append to. … … 451 451 @return: The append response returned by the server. 452 452 @rtype: str 453 '''453 """ 454 454 if msg_time: 455 455 time_val = '"%s"' % datetime_to_imap(msg_time) … … 473 473 474 474 def getacl(self, folder): 475 '''Get the ACL for a folder475 """Get the ACL for a folder 476 476 477 477 @param folder: Folder name to get the ACL for. 478 478 @return: A list of (who, acl) tuples 479 '''479 """ 480 480 typ, data = self._imap.getacl(folder) 481 481 self._checkok('getacl', typ, data) … … 491 491 492 492 def setacl(self, folder, who, what): 493 '''Set an ACL for a folder493 """Set an ACL for a folder 494 494 495 495 @param folder: Folder name to set an ACL for. … … 497 497 @param what: A string describing the ACL. Set to '' to remove an ACL. 498 498 @return: Server response string. 499 '''499 """ 500 500 typ, data = self._imap.setacl(folder, who, what) 501 501 self._checkok('setacl', typ, data) … … 504 504 505 505 def _check_resp(self, expected, command, typ, data): 506 '''Check command responses for errors.506 """Check command responses for errors. 507 507 508 508 @raise: Error if a command failed. 509 '''509 """ 510 510 if typ != expected: 511 511 raise self.Error('%s failed: %r' % (command, data[0])) … … 521 521 522 522 def _store(self, cmd, messages, flags): 523 '''Worker function for flag manipulation functions523 """Worker function for flag manipulation functions 524 524 525 525 @param cmd: STORE command to use (eg. '+FLAGS') … … 528 528 @return: The flags set for each message ID as a dictionary 529 529 { msgid1: [flag1, flag2, ... ], } 530 '''530 """ 531 531 if not messages: 532 532 return {} … … 563 563 564 564 class FetchParser(object): 565 '''565 """ 566 566 Parse an IMAP FETCH response and convert the return values to useful Python 567 567 values. 568 '''568 """ 569 569 570 570 def parse(self, response): … … 634 634 635 635 def do_INTERNALDATE(self, arg): 636 '''Process an INTERNALDATE response636 """Process an INTERNALDATE response 637 637 638 638 @param arg: A quoted IMAP INTERNALDATE string 639 639 (eg. " 9-Feb-2007 17:08:08 +0000") 640 640 @return: datetime.datetime instance for the given time (in UTC) 641 '''641 """ 642 642 arg = 'INTERNALDATE "%s"' % arg 643 643 mo = imaplib.InternalDate.match(arg) … … 669 669 670 670 class FetchTokeniser(object): 671 '''671 """ 672 672 General response tokenizer and converter 673 '''673 """ 674 674 675 675 QUOTED_STRING = '(?:".*?")' … … 691 691 692 692 def process_pairs(self, s): 693 '''Break up and convert a string of FETCH response pairs693 """Break up and convert a string of FETCH response pairs 694 694 695 695 @param s: FETCH response string eg. "FOO 12 BAH (1 abc def "foo bar")" 696 696 @return: Tokenised and converted input return as (name, data) pairs. 697 '''697 """ 698 698 out = [] 699 699 for m in strict_finditer(self.PAIR_RE, s): … … 703 703 704 704 def process_list(self, s): 705 '''Break up and convert a string of data items705 """Break up and convert a string of data items 706 706 707 707 @param s: FETCH response string eg. "(1 abc def "foo bar")" 708 708 @return: A list of converted items. 709 '''709 """ 710 710 if s == '': 711 711 return [] … … 731 731 732 732 class Literal(object): 733 '''733 """ 734 734 Simple class to represent a literal token in the fetch response 735 735 (eg. "{21}") 736 '''736 """ 737 737 738 738 def __init__(self, length): … … 747 747 748 748 def strict_finditer(regex, s): 749 '''Like re.finditer except the regex must match from exactly where the749 """Like re.finditer except the regex must match from exactly where the 750 750 previous match ended and all the entire input must be matched. 751 '''751 """ 752 752 i = 0 753 753 matched = False … … 767 767 768 768 def messages_to_str(messages): 769 '''Convert a sequence of messages ids or a single message id into an769 """Convert a sequence of messages ids or a single message id into an 770 770 message ID list for use with IMAP commands. 771 771 … … 773 773 (eg. [1,4,5,7,8]) 774 774 @return: Message list string (eg. "1,4,5,6,8") 775 '''775 """ 776 776 if isinstance(messages, (str, int, long)): 777 777 messages = (messages,) … … 782 782 783 783 def seq_to_parenlist(flags): 784 '''Convert a sequence into parenthised list for use with IMAP commands784 """Convert a sequence into parenthised list for use with IMAP commands 785 785 786 786 @param flags: Sequence to process (eg. ['abc', 'def']) 787 787 @return: IMAP parenthenised list (eg. '(abc def)') 788 '''788 """ 789 789 if isinstance(flags, str): 790 790 flags = (flags,) … … 795 795 796 796 def datetime_to_imap(dt): 797 '''Convert a datetime instance to a IMAP datetime string797 """Convert a datetime instance to a IMAP datetime string 798 798 799 799 If timezone information is missing the current system timezone is used. 800 '''800 """ 801 801 if not dt.tzinfo: 802 802 dt = dt.replace(tzinfo=FixedOffset.for_system())
