|  | 
| 10 | 10 | .. changes for IMAP4_SSL by Tino Lange <[email protected]>, March 2002 | 
| 11 | 11 | .. changes for IMAP4_stream by Piers Lauder <[email protected]>, | 
| 12 | 12 |    November 2002 | 
|  | 13 | +.. changes for IMAP4 IDLE by Forest <[email protected]>, August 2024 | 
| 13 | 14 | 
 | 
| 14 | 15 | **Source code:** :source:`Lib/imaplib.py` | 
| 15 | 16 | 
 | 
| @@ -187,7 +188,7 @@ However, the *password* argument to the ``LOGIN`` command is always quoted. If | 
| 187 | 188 | you want to avoid having an argument string quoted (eg: the *flags* argument to | 
| 188 | 189 | ``STORE``) then enclose the string in parentheses (eg: ``r'(\Deleted)'``). | 
| 189 | 190 | 
 | 
| 190 |  | -Each command returns a tuple: ``(type, [data, ...])`` where *type* is usually | 
|  | 191 | +Most commands return a tuple: ``(type, [data, ...])`` where *type* is usually | 
| 191 | 192 | ``'OK'`` or ``'NO'``, and *data* is either the text from the command response, | 
| 192 | 193 | or mandated results from the command. Each *data* is either a ``bytes``, or a | 
| 193 | 194 | tuple. If a tuple, then the first part is the header of the response, and the | 
| @@ -307,6 +308,93 @@ An :class:`IMAP4` instance has the following methods: | 
| 307 | 308 |    of the IMAP4 QUOTA extension defined in rfc2087. | 
| 308 | 309 | 
 | 
| 309 | 310 | 
 | 
|  | 311 | +.. method:: IMAP4.idle(duration=None) | 
|  | 312 | + | 
|  | 313 | +   Return an :class:`!Idler`: an iterable context manager implementing the | 
|  | 314 | +   IMAP4 ``IDLE`` command as defined in :rfc:`2177`. | 
|  | 315 | + | 
|  | 316 | +   The returned object sends the ``IDLE`` command when activated by the | 
|  | 317 | +   :keyword:`with` statement, produces IMAP untagged responses via the | 
|  | 318 | +   :term:`iterator` protocol, and sends ``DONE`` upon context exit. | 
|  | 319 | + | 
|  | 320 | +   All untagged responses that arrive after sending the ``IDLE`` command | 
|  | 321 | +   (including any that arrive before the server acknowledges the command) will | 
|  | 322 | +   be available via iteration. Any leftover responses (those not iterated in | 
|  | 323 | +   the :keyword:`with` context) can be retrieved in the usual way after | 
|  | 324 | +   ``IDLE`` ends, using :meth:`IMAP4.response`. | 
|  | 325 | + | 
|  | 326 | +   Responses are represented as ``(type, [data, ...])`` tuples, as described | 
|  | 327 | +   in :ref:`IMAP4 Objects <imap4-objects>`. | 
|  | 328 | + | 
|  | 329 | +   The *duration* argument sets a maximum duration (in seconds) to keep idling, | 
|  | 330 | +   after which any ongoing iteration will stop. It can be an :class:`int` or | 
|  | 331 | +   :class:`float`, or ``None`` for no time limit. | 
|  | 332 | +   Callers wishing to avoid inactivity timeouts on servers that impose them | 
|  | 333 | +   should keep this at most 29 minutes (1740 seconds). | 
|  | 334 | +   Requires a socket connection; *duration* must be ``None`` on | 
|  | 335 | +   :class:`IMAP4_stream` connections. | 
|  | 336 | + | 
|  | 337 | +   .. code-block:: pycon | 
|  | 338 | +
 | 
|  | 339 | +      >>> with M.idle(duration=29 * 60) as idler: | 
|  | 340 | +      ...     for typ, data in idler: | 
|  | 341 | +      ...         print(typ, data) | 
|  | 342 | +      ... | 
|  | 343 | +      EXISTS [b'1'] | 
|  | 344 | +      RECENT [b'1'] | 
|  | 345 | +
 | 
|  | 346 | +
 | 
|  | 347 | +   .. method:: Idler.burst(interval=0.1) | 
|  | 348 | + | 
|  | 349 | +      Yield a burst of responses no more than *interval* seconds apart | 
|  | 350 | +      (expressed as an :class:`int` or :class:`float`). | 
|  | 351 | + | 
|  | 352 | +      This :term:`generator` is an alternative to iterating one response at a | 
|  | 353 | +      time, intended to aid in efficient batch processing. It retrieves the | 
|  | 354 | +      next response along with any immediately available subsequent responses. | 
|  | 355 | +      (For example, a rapid series of ``EXPUNGE`` responses after a bulk | 
|  | 356 | +      delete.) | 
|  | 357 | + | 
|  | 358 | +      Requires a socket connection; does not work on :class:`IMAP4_stream` | 
|  | 359 | +      connections. | 
|  | 360 | + | 
|  | 361 | +      .. code-block:: pycon | 
|  | 362 | +
 | 
|  | 363 | +         >>> with M.idle() as idler: | 
|  | 364 | +         ...     # get a response and any others following by < 0.1 seconds | 
|  | 365 | +         ...     batch = list(idler.burst()) | 
|  | 366 | +         ...     print(f'processing {len(batch)} responses...') | 
|  | 367 | +         ...     print(batch) | 
|  | 368 | +         ... | 
|  | 369 | +         processing 3 responses... | 
|  | 370 | +         [('EXPUNGE', [b'2']), ('EXPUNGE', [b'1']), ('RECENT', [b'0'])] | 
|  | 371 | +
 | 
|  | 372 | +      .. tip:: | 
|  | 373 | + | 
|  | 374 | +         The ``IDLE`` context's maximum duration, as passed to | 
|  | 375 | +         :meth:`IMAP4.idle`, is respected when waiting for the first response | 
|  | 376 | +         in a burst. Therefore, an expired :class:`!Idler` will cause this | 
|  | 377 | +         generator to return immediately without producing anything. Callers | 
|  | 378 | +         should consider this if using it in a loop. | 
|  | 379 | + | 
|  | 380 | + | 
|  | 381 | +   .. note:: | 
|  | 382 | + | 
|  | 383 | +      The iterator returned by :meth:`IMAP4.idle` is usable only within a | 
|  | 384 | +      :keyword:`with` statement. Before or after that context, unsolicited | 
|  | 385 | +      responses are collected internally whenever a command finishes, and can | 
|  | 386 | +      be retrieved with :meth:`IMAP4.response`. | 
|  | 387 | + | 
|  | 388 | +   .. note:: | 
|  | 389 | + | 
|  | 390 | +      The :class:`!Idler` class name and structure are internal interfaces, | 
|  | 391 | +      subject to change. Calling code can rely on its context management, | 
|  | 392 | +      iteration, and public method to remain stable, but should not subclass, | 
|  | 393 | +      instantiate, compare, or otherwise directly reference the class. | 
|  | 394 | + | 
|  | 395 | +   .. versionadded:: next | 
|  | 396 | + | 
|  | 397 | + | 
| 310 | 398 | .. method:: IMAP4.list([directory[, pattern]]) | 
| 311 | 399 | 
 | 
| 312 | 400 |    List mailbox names in *directory* matching *pattern*.  *directory* defaults to | 
|  | 
0 commit comments