Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 24 additions & 25 deletions Doc/howto/a-conceptual-overview-of-asyncio.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ model of how :mod:`asyncio` fundamentally works, helping you understand the
how and why behind the recommended patterns.

You might be curious about some key :mod:`!asyncio` concepts.
You'll be comfortably able to answer these questions by the end of this
article:
By the end of this article, you'll be able to comfortably answer these questions:

- What's happening behind the scenes when an object is awaited?
- How does :mod:`!asyncio` differentiate between a task which doesn't need
CPU-time (such as a network request or file read) as opposed to a task that
CPU time (such as a network request or file read) as opposed to a task that
does (such as computing n-factorial)?
- How to write an asynchronous variant of an operation, such as
an async sleep or database request.
Expand All @@ -35,7 +34,7 @@ A conceptual overview part 1: the high-level
--------------------------------------------

In part 1, we'll cover the main, high-level building blocks of :mod:`!asyncio`:
the event loop, coroutine functions, coroutine objects, tasks and ``await``.
the event loop, coroutine functions, coroutine objects, tasks, and ``await``.

==========
Event Loop
Expand All @@ -56,7 +55,7 @@ Once it pauses or completes, it returns control to the event loop.
The event loop will then select another job from its pool and invoke it.
You can *roughly* think of the collection of jobs as a queue: jobs are added and
then processed one at a time, generally (but not always) in order.
This process repeats indefinitely with the event loop cycling endlessly
This process repeats indefinitely, with the event loop cycling endlessly
onwards.
If there are no more jobs pending execution, the event loop is smart enough to
rest and avoid needlessly wasting CPU cycles, and will come back when there's
Expand Down Expand Up @@ -276,7 +275,7 @@ in this case, a call to resume ``plant_a_tree()``.

Generally speaking, when the awaited task finishes (``dig_the_hole_task``),
the original task or coroutine (``plant_a_tree()``) is added back to the event
loops to-do list to be resumed.
loop's to-do list to be resumed.

This is a basic, yet reliable mental model.
In practice, the control handoffs are slightly more complex, but not by much.
Expand Down Expand Up @@ -310,7 +309,7 @@ Consider this program::
The first statement in the coroutine ``main()`` creates ``task_b`` and schedules
it for execution via the event loop.
Then, ``coro_a()`` is repeatedly awaited. Control never cedes to the
event loop which is why we see the output of all three ``coro_a()``
event loop, which is why we see the output of all three ``coro_a()``
invocations before ``coro_b()``'s output:

.. code-block:: none
Expand Down Expand Up @@ -338,8 +337,8 @@ This behavior of ``await coroutine`` can trip a lot of people up!
That example highlights how using only ``await coroutine`` could
unintentionally hog control from other tasks and effectively stall the event
loop.
:func:`asyncio.run` can help you detect such occurences via the
``debug=True`` flag which accordingly enables
:func:`asyncio.run` can help you detect such occurrences via the
``debug=True`` flag, which enables
:ref:`debug mode <asyncio-debug-mode>`.
Among other things, it will log any coroutines that monopolize execution for
100ms or longer.
Expand All @@ -348,8 +347,8 @@ The design intentionally trades off some conceptual clarity around usage of
``await`` for improved performance.
Each time a task is awaited, control needs to be passed all the way up the
call stack to the event loop.
That might sound minor, but in a large program with many ``await``'s and a deep
callstack that overhead can add up to a meaningful performance drag.
That might sound minor, but in a large program with many ``await`` statements and a deep
call stack, that overhead can add up to a meaningful performance drag.

------------------------------------------------
A conceptual overview part 2: the nuts and bolts
Expand All @@ -372,7 +371,7 @@ resume a coroutine.
If the coroutine was paused and is now being resumed, the argument ``arg``
will be sent in as the return value of the ``yield`` statement which originally
paused it.
If the coroutine is being used for the first time (as opposed to being resumed)
If the coroutine is being used for the first time (as opposed to being resumed),
``arg`` must be ``None``.

.. code-block::
Expand Down Expand Up @@ -403,14 +402,14 @@ If the coroutine is being used for the first time (as opposed to being resumed)
returned_value = e.value
print(f"Coroutine main() finished and provided value: {returned_value}.")

:ref:`yield <yieldexpr>`, like usual, pauses execution and returns control
:ref:`yield <yieldexpr>`, as usual, pauses execution and returns control
to the caller.
In the example above, the ``yield``, on line 3, is called by
``... = await rock`` on line 11.
More broadly speaking, ``await`` calls the :meth:`~object.__await__` method of
the given object.
``await`` also does one more very special thing: it propagates (or "passes
along") any ``yield``\ s it receives up the call-chain.
along") any ``yield``\ s it receives up the call chain.
In this case, that's back to ``... = coroutine.send(None)`` on line 16.

The coroutine is resumed via the ``coroutine.send(42)`` call on line 21.
Expand Down Expand Up @@ -462,12 +461,12 @@ computation's status and result.
The term is a nod to the idea of something still to come or not yet happened,
and the object is a way to keep an eye on that something.

A future has a few important attributes. One is its state which can be either
"pending", "cancelled" or "done".
A future has a few important attributes. One is its state, which can be either
"pending", "cancelled", or "done".
Another is its result, which is set when the state transitions to done.
Unlike a coroutine, a future does not represent the actual computation to be
done; instead, it represents the status and result of that computation, kind of
like a status light (red, yellow or green) or indicator.
like a status light (red, yellow, or green) or indicator.

:class:`asyncio.Task` subclasses :class:`asyncio.Future` in order to gain
these various capabilities.
Expand All @@ -490,8 +489,8 @@ We'll go through an example of how you could leverage a future to create your
own variant of asynchronous sleep (``async_sleep``) which mimics
:func:`asyncio.sleep`.

This snippet registers a few tasks with the event loop and then awaits a
coroutine wrapped in a task: ``async_sleep(3)``.
This snippet registers a few tasks with the event loop and then awaits the task
created by ``asyncio.create_task``, which wraps the ``async_sleep(3)`` coroutine.
We want that task to finish only after three seconds have elapsed, but without
preventing other tasks from running.

Expand Down Expand Up @@ -540,8 +539,8 @@ will monitor how much time has elapsed and, accordingly, call
# Block until the future is marked as done.
await future

Below, we'll use a rather bare object, ``YieldToEventLoop()``, to ``yield``
from ``__await__`` in order to cede control to the event loop.
Below, we use a rather bare ``YieldToEventLoop()`` object to ``yield``
from its ``__await__`` method, ceding control to the event loop.
This is effectively the same as calling ``asyncio.sleep(0)``, but this approach
offers more clarity, not to mention it's somewhat cheating to use
``asyncio.sleep`` when showcasing how to implement it!
Expand All @@ -552,13 +551,13 @@ The ``watcher_task``, which runs the coroutine ``_sleep_watcher(...)``, will
be invoked once per full cycle of the event loop.
On each resumption, it'll check the time and if not enough has elapsed, then
it'll pause once again and hand control back to the event loop.
Eventually, enough time will have elapsed, and ``_sleep_watcher(...)`` will
mark the future as done, and then itself finish too by breaking out of the
Once enough time has elapsed, ``_sleep_watcher(...)``
marks the future as done and completes by exiting its
infinite ``while`` loop.
Given this helper task is only invoked once per cycle of the event loop,
you'd be correct to note that this asynchronous sleep will sleep *at least*
three seconds, rather than exactly three seconds.
Note this is also of true of ``asyncio.sleep``.
Note this is also true of ``asyncio.sleep``.

::

Expand Down Expand Up @@ -601,6 +600,6 @@ For reference, you could implement it without futures, like so::
else:
await YieldToEventLoop()

But, that's all for now. Hopefully you're ready to more confidently dive into
But that's all for now. Hopefully you're ready to more confidently dive into
some async programming or check out advanced topics in the
:mod:`rest of the documentation <asyncio>`.
2 changes: 1 addition & 1 deletion Doc/library/cmath.rst
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ Constants
.. data:: nan

A floating-point "not a number" (NaN) value. Equivalent to
``float('nan')``.
``float('nan')``. See also :data:`math.nan`.

.. versionadded:: 3.6

Expand Down
3 changes: 2 additions & 1 deletion Doc/library/http.rst
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ equal to the constant name (i.e. ``http.HTTPStatus.OK`` is also available as

.. versionchanged:: 3.13
Implemented RFC9110 naming for status constants. Old constant names are preserved for
backwards compatibility.
backwards compatibility: ``413 REQUEST_ENTITY_TOO_LARGE``, ``414 REQUEST_URI_TOO_LONG``,
``416 REQUESTED_RANGE_NOT_SATISFIABLE`` and ``422 UNPROCESSABLE_ENTITY``.

HTTP status category
--------------------
Expand Down
28 changes: 24 additions & 4 deletions Doc/library/pyexpat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,10 @@ XMLParser Objects
Calling ``SetReparseDeferralEnabled(True)`` allows re-enabling reparse
deferral.

Note that :meth:`SetReparseDeferralEnabled` has been backported to some
prior releases of CPython as a security fix. Check for availability of
:meth:`SetReparseDeferralEnabled` using :func:`hasattr` if used in code
running across a variety of Python versions.
:meth:`!SetReparseDeferralEnabled`
has been backported to some prior releases of CPython as a security fix.
Check for availability using :func:`hasattr` if used in code running
across a variety of Python versions.

.. versionadded:: 3.13

Expand Down Expand Up @@ -257,6 +257,11 @@ against some common XML vulnerabilities.
The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset`
should not be used as they may have no special meaning.

:meth:`!SetBillionLaughsAttackProtectionActivationThreshold`
has been backported to some prior releases of CPython as a security fix.
Check for availability using :func:`hasattr` if used in code running
across a variety of Python versions.

.. note::

Activation thresholds below 4 MiB are known to break support for DITA 1.3
Expand Down Expand Up @@ -288,6 +293,11 @@ against some common XML vulnerabilities.
The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset`
should not be used as they may have no special meaning.

:meth:`!SetBillionLaughsAttackProtectionMaximumAmplification`
has been backported to some prior releases of CPython as a security fix.
Check for availability using :func:`hasattr` if used in code running
across a variety of Python versions.

.. note::

The maximum amplification factor is only considered if the threshold
Expand All @@ -309,6 +319,11 @@ against some common XML vulnerabilities.
The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset`
should not be used as they may have no special meaning.

:meth:`!SetAllocTrackerActivationThreshold`
has been backported to some prior releases of CPython as a security fix.
Check for availability using :func:`hasattr` if used in code running
across a variety of Python versions.

.. versionadded:: next

.. method:: xmlparser.SetAllocTrackerMaximumAmplification(max_factor, /)
Expand All @@ -334,6 +349,11 @@ against some common XML vulnerabilities.
The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset`
should not be used as they may have no special meaning.

:meth:`!SetAllocTrackerMaximumAmplification`
has been backported to some prior releases of CPython as a security fix.
Check for availability using :func:`hasattr` if used in code running
across a variety of Python versions.

.. note::

The maximum amplification factor is only considered if the threshold
Expand Down
62 changes: 46 additions & 16 deletions Doc/library/smtplib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).

An :class:`SMTP_SSL` instance behaves exactly the same as instances of
:class:`SMTP`. :class:`SMTP_SSL` should be used for situations where SSL is
required from the beginning of the connection and using :meth:`starttls` is
not appropriate. If *host* is not specified, the local host is used. If
required from the beginning of the connection and using :meth:`~SMTP.starttls`
is not appropriate. If *host* is not specified, the local host is used. If
*port* is zero, the standard SMTP-over-SSL port (465) is used. The optional
arguments *local_hostname*, *timeout* and *source_address* have the same
meaning as they do in the :class:`SMTP` class. *context*, also optional,
Expand Down Expand Up @@ -112,7 +112,7 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).

The LMTP protocol, which is very similar to ESMTP, is heavily based on the
standard SMTP client. It's common to use Unix sockets for LMTP, so our
:meth:`connect` method must support that as well as a regular host:port
:meth:`~SMTP.connect` method must support that as well as a regular host:port
server. The optional arguments *local_hostname* and *source_address* have the
same meaning as they do in the :class:`SMTP` class. To specify a Unix
socket, you must use an absolute path for *host*, starting with a '/'.
Expand Down Expand Up @@ -147,9 +147,15 @@ A nice selection of exceptions is defined as well:
.. exception:: SMTPResponseException

Base class for all exceptions that include an SMTP error code. These exceptions
are generated in some instances when the SMTP server returns an error code. The
error code is stored in the :attr:`smtp_code` attribute of the error, and the
:attr:`smtp_error` attribute is set to the error message.
are generated in some instances when the SMTP server returns an error code.

.. attribute:: smtp_code

The error code.

.. attribute:: smtp_error

The error message.


.. exception:: SMTPSenderRefused
Expand All @@ -161,9 +167,13 @@ A nice selection of exceptions is defined as well:

.. exception:: SMTPRecipientsRefused

All recipient addresses refused. The errors for each recipient are accessible
through the attribute :attr:`recipients`, which is a dictionary of exactly the
same sort as :meth:`SMTP.sendmail` returns.
All recipient addresses refused.

.. attribute:: recipients

A dictionary of exactly the same sort as returned
by :meth:`SMTP.sendmail` containing the errors for
each recipient.


.. exception:: SMTPDataError
Expand Down Expand Up @@ -213,7 +223,6 @@ SMTP Objects

An :class:`SMTP` instance has the following methods:


.. method:: SMTP.set_debuglevel(level)

Set the debug output level. A value of 1 or ``True`` for *level* results in
Expand Down Expand Up @@ -417,7 +426,7 @@ An :class:`SMTP` instance has the following methods:

.. versionchanged:: 3.4
The method now supports hostname check with
:attr:`SSLContext.check_hostname` and *Server Name Indicator* (see
:attr:`ssl.SSLContext.check_hostname` and *Server Name Indicator* (see
:const:`~ssl.HAS_SNI`).

.. versionchanged:: 3.5
Expand All @@ -435,7 +444,7 @@ An :class:`SMTP` instance has the following methods:
ESMTP options (such as ``DSN`` commands) that should be used with all ``RCPT``
commands can be passed as *rcpt_options*. (If you need to use different ESMTP
options to different recipients you have to use the low-level methods such as
:meth:`mail`, :meth:`rcpt` and :meth:`data` to send the message.)
:meth:`!mail`, :meth:`!rcpt` and :meth:`!data` to send the message.)

.. note::

Expand Down Expand Up @@ -467,10 +476,7 @@ An :class:`SMTP` instance has the following methods:
This method may raise the following exceptions:

:exc:`SMTPRecipientsRefused`
All recipients were refused. Nobody got the mail. The :attr:`recipients`
attribute of the exception object is a dictionary with information about the
refused recipients (like the one returned when at least one recipient was
accepted).
All recipients were refused. Nobody got the mail.

:exc:`SMTPHeloError`
The server didn't reply properly to the ``HELO`` greeting.
Expand Down Expand Up @@ -546,6 +552,30 @@ Low-level methods corresponding to the standard SMTP/ESMTP commands ``HELP``,
Normally these do not need to be called directly, so they are not documented
here. For details, consult the module code.

Additionally, an SMTP instance has the following attributes:


.. attribute:: SMTP.helo_resp

The response to the ``HELO`` command, see :meth:`helo`.


.. attribute:: SMTP.ehlo_resp

The response to the ``EHLO`` command, see :meth:`ehlo`.


.. attribute:: SMTP.does_esmtp

A boolean value indicating whether the server supports ESMTP, see
:meth:`ehlo`.


.. attribute:: SMTP.esmtp_features

A dictionary of the names of SMTP service extensions supported by the server,
see :meth:`ehlo`.


.. _smtp-example:

Expand Down
4 changes: 2 additions & 2 deletions Doc/library/time.rst
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ Functions

The result has the following attributes:

- *adjustable*: ``True`` if the clock can be changed automatically (e.g. by
a NTP daemon) or manually by the system administrator, ``False`` otherwise
- *adjustable*: ``True`` if the clock can be set to jump forward or backward
in time, ``False`` otherwise. Does not refer to gradual NTP rate adjustments.
- *implementation*: The name of the underlying C function used to get
the clock value. Refer to :ref:`time-clock-id-constants` for possible values.
- *monotonic*: ``True`` if the clock cannot go backward,
Expand Down
Loading
Loading