Skip to content

Commit dc71241

Browse files
committed
gh-55454: Clarify imaplib idle() docs
- Add example idle response tuples, to make the minor difference from other imaplib response tuples more obvious. - Merge the idle context manager's burst() method docs with the IMAP object's idle() method docs, for easier understanding. - Upgrade the Windows note regarding lack of pipe timeouts to a warning. - Rephrase various things for clarity.
1 parent 572d1e5 commit dc71241

File tree

1 file changed

+65
-78
lines changed

1 file changed

+65
-78
lines changed

Doc/library/imaplib.rst

Lines changed: 65 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -308,22 +308,28 @@ An :class:`IMAP4` instance has the following methods:
308308
of the IMAP4 QUOTA extension defined in rfc2087.
309309

310310

311-
.. method:: IMAP4.idle([dur])
311+
.. method:: IMAP4.idle(dur=None)
312312

313313
Return an iterable context manager implementing the ``IDLE`` command
314314
as defined in :rfc:`2177`.
315315

316-
The optional *dur* argument specifies a maximum duration (in seconds) to
317-
keep idling. It defaults to ``None``, meaning no time limit.
318-
To avoid inactivity timeouts on servers that impose them, callers are
319-
advised to keep this <= 29 minutes. See the note below regarding
316+
The context manager 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+
The *dur* argument sets a maximum duration (in seconds) to keep idling,
321+
after which iteration will stop. It defaults to ``None``, meaning no time
322+
limit. Callers wishing to avoid inactivity timeouts on servers that impose
323+
them should keep this <= 29 minutes.
324+
See the :ref:`warning below <windows-pipe-timeout-warning>` if using
320325
:class:`IMAP4_stream` on Windows.
321326

322-
The context manager sends the ``IDLE`` command upon entry, produces
323-
responses via iteration, and sends ``DONE`` upon exit.
324-
It represents responses as ``(type, datum)`` tuples, rather than the
325-
``(type, [data, ...])`` tuples returned by other methods, because only
326-
one response is represented at a time.
327+
Response tuples produced by the iterator almost exactly match those
328+
returned by other imaplib methods. The difference is that the tuple's
329+
second member is a single response datum, rather than a list of data.
330+
Therefore, in a mailbox where calling ``M.response('EXISTS')`` would
331+
return ``('EXISTS', [b'1'])``, the idle iterator would produce
332+
``('EXISTS', b'1')``.
327333

328334
Example::
329335

@@ -332,22 +338,59 @@ An :class:`IMAP4` instance has the following methods:
332338
typ, datum = response
333339
print(typ, datum)
334340

335-
It is also possible to process a burst of responses all at once instead
336-
of one at a time. See `IDLE Context Manager`_ for details.
341+
('EXISTS', b'1')
342+
('RECENT', b'1')
337343

338-
Responses produced by the iterator will not be returned by
339-
:meth:`IMAP4.response`.
344+
Instead of iterating one response at a time, it is also possible to retrieve
345+
the next response along with any immediately available subsequent responses
346+
(e.g. a rapid series of ``EXPUNGE`` events from a bulk delete). This
347+
batch processing aid is provided by the context's ``burst()``
348+
:term:`generator`:
340349

341-
.. note::
350+
.. method:: idler.burst(interval=0.1)
351+
352+
Yield a burst of responses no more than *interval* seconds apart.
353+
354+
Example::
355+
356+
with M.idle() as idler:
357+
358+
# get the next response and any others following by < 0.1 seconds
359+
batch = list(idler.burst())
360+
361+
print(f'processing {len(batch)} responses...')
362+
print(batch)
363+
364+
processing 3 responses...
365+
[('EXPUNGE', b'2'), ('EXPUNGE', b'1'), ('RECENT', b'0')]
366+
367+
The ``IDLE`` context's maximum duration (the *dur* argument to
368+
:meth:`IMAP4.idle`) is respected when waiting for the first response
369+
in a burst. Therefore, an expired idle context will cause this generator
370+
to return immediately without producing anything. Callers should
371+
consider this if using it in a loop.
372+
373+
374+
.. _windows-pipe-timeout-warning:
375+
376+
.. warning::
342377

343378
Windows :class:`IMAP4_stream` connections have no way to accurately
344-
respect *dur*, since Windows ``select()`` only works on sockets.
345-
However, if the server regularly sends status messages during ``IDLE``,
346-
they will wake our selector and keep iteration from blocking for long.
347-
Dovecot's ``imap_idle_notify_interval`` is two minutes by default.
348-
Assuming that's typical of IMAP servers, subtracting it from the 29
349-
minutes needed to avoid server inactivity timeouts would make 27
350-
minutes a sensible value for *dur* in this situation.
379+
respect the *dur* or *interval* arguments, since Windows ``select()``
380+
only works on sockets.
381+
382+
If the server regularly sends status messages during ``IDLE``, they will
383+
wake our iterator anyway, allowing *dur* to behave roughly as intended,
384+
although usually late. Dovecot's ``imap_idle_notify_interval`` default
385+
setting does this every 2 minutes. Assuming that's typical of IMAP
386+
servers, subtracting it from the 29 minutes needed to avoid server
387+
inactivity timeouts would make 27 minutes a sensible value for *dur* in
388+
this situation.
389+
390+
There is no such fallback for ``burst()``, which will yield endless
391+
responses and block indefinitely for each one. It is therefore advised
392+
not to use ``burst()`` with an :class:`IMAP4_stream` connection on
393+
Windows.
351394

352395

353396
.. method:: IMAP4.list([directory[, pattern]])
@@ -655,62 +698,6 @@ The following attributes are defined on instances of :class:`IMAP4`:
655698
.. versionadded:: 3.5
656699

657700

658-
.. _idle context manager:
659-
660-
IDLE Context Manager
661-
--------------------
662-
663-
The object returned by :meth:`IMAP4.idle` implements the context management
664-
protocol for the :keyword:`with` statement, and the :term:`iterator` protocol
665-
for retrieving untagged responses while the context is active.
666-
It also has the following method:
667-
668-
.. method:: IdleContextManager.burst([interval])
669-
670-
Yield a burst of responses no more than *interval* seconds apart.
671-
672-
This generator retrieves the next response along with any
673-
immediately available subsequent responses (e.g. a rapid series of
674-
``EXPUNGE`` responses after a bulk delete) so they can be efficiently
675-
processed as a batch instead of one at a time.
676-
677-
The optional *interval* argument specifies a time limit (in seconds)
678-
for each response after the first. It defaults to 0.1 seconds.
679-
(The ``IDLE`` context's maximum duration is respected when waiting for the
680-
first response.)
681-
682-
Represents responses as ``(type, datum)`` tuples, just as when
683-
iterating directly on the context manager.
684-
685-
Example::
686-
687-
with M.idle() as idler:
688-
689-
# get the next response and any others following by < 0.1 seconds
690-
batch = list(idler.burst())
691-
692-
print(f'processing {len(batch)} responses...')
693-
for typ, datum in batch:
694-
print(typ, datum)
695-
696-
Produces no responses and returns immediately if the ``IDLE`` context's
697-
maximum duration (the *dur* argument to :meth:`IMAP4.idle`) has elapsed.
698-
Callers should plan accordingly if using this method in a loop.
699-
700-
.. note::
701-
702-
Windows :class:`IMAP4_stream` connections will ignore the *interval*
703-
argument, yielding endless responses and blocking indefinitely for each
704-
one, since Windows ``select()`` only works on sockets. It is therefore
705-
advised not to use this method with an :class:`IMAP4_stream` connection
706-
on Windows.
707-
708-
.. note::
709-
710-
The context manager's type name is not part of its public interface,
711-
and is subject to change.
712-
713-
714701
.. _imap4-example:
715702

716703
IMAP4 Example

0 commit comments

Comments
 (0)