Skip to content

Commit deba719

Browse files
Merge branch 'main' into bitfields
2 parents 1d125ab + 0ee9619 commit deba719

33 files changed

+565
-211
lines changed

Doc/conf.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,18 @@
249249
# bpo-40204: Disable warnings on Sphinx 2 syntax of the C domain since the
250250
# documentation is built with -W (warnings treated as errors).
251251
c_warn_on_allowed_pre_v3 = False
252+
253+
# Fix '!' not working with C domain when pre_v3 is enabled
254+
import sphinx
255+
256+
if sphinx.version_info[:2] < (5, 3):
257+
from sphinx.domains.c import CXRefRole
258+
259+
original_run = CXRefRole.run
260+
261+
def new_run(self):
262+
if self.disabled:
263+
return super(CXRefRole, self).run()
264+
return original_run(self)
265+
266+
CXRefRole.run = new_run

Doc/howto/logging-cookbook.rst

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3428,6 +3428,82 @@ the above handler, you'd pass structured data using something like this::
34283428
i = 1
34293429
logger.debug('Message %d', i, extra=extra)
34303430

3431+
How to treat a logger like an output stream
3432+
-------------------------------------------
3433+
3434+
Sometimes, you need to interface to a third-party API which expects a file-like
3435+
object to write to, but you want to direct the API's output to a logger. You
3436+
can do this using a class which wraps a logger with a file-like API.
3437+
Here's a short script illustrating such a class:
3438+
3439+
.. code-block:: python
3440+
3441+
import logging
3442+
3443+
class LoggerWriter:
3444+
def __init__(self, logger, level):
3445+
self.logger = logger
3446+
self.level = level
3447+
3448+
def write(self, message):
3449+
if message != '\n': # avoid printing bare newlines, if you like
3450+
self.logger.log(self.level, message)
3451+
3452+
def flush(self):
3453+
# doesn't actually do anything, but might be expected of a file-like
3454+
# object - so optional depending on your situation
3455+
pass
3456+
3457+
def close(self):
3458+
# doesn't actually do anything, but might be expected of a file-like
3459+
# object - so optional depending on your situation. You might want
3460+
# to set a flag so that later calls to write raise an exception
3461+
pass
3462+
3463+
def main():
3464+
logging.basicConfig(level=logging.DEBUG)
3465+
logger = logging.getLogger('demo')
3466+
info_fp = LoggerWriter(logger, logging.INFO)
3467+
debug_fp = LoggerWriter(logger, logging.DEBUG)
3468+
print('An INFO message', file=info_fp)
3469+
print('A DEBUG message', file=debug_fp)
3470+
3471+
if __name__ == "__main__":
3472+
main()
3473+
3474+
When this script is run, it prints
3475+
3476+
.. code-block:: text
3477+
3478+
INFO:demo:An INFO message
3479+
DEBUG:demo:A DEBUG message
3480+
3481+
You could also use ``LoggerWriter`` to redirect ``sys.stdout`` and
3482+
``sys.stderr`` by doing something like this:
3483+
3484+
.. code-block:: python
3485+
3486+
import sys
3487+
3488+
sys.stdout = LoggerWriter(logger, logging.INFO)
3489+
sys.stderr = LoggerWriter(logger, logging.WARNING)
3490+
3491+
You should do this *after* configuring logging for your needs. In the above
3492+
example, the :func:`~logging.basicConfig` call does this (using the
3493+
``sys.stderr`` value *before* it is overwritten by a ``LoggerWriter``
3494+
instance). Then, you'd get this kind of result:
3495+
3496+
.. code-block:: pycon
3497+
3498+
>>> print('Foo')
3499+
INFO:demo:Foo
3500+
>>> print('Bar', file=sys.stderr)
3501+
WARNING:demo:Bar
3502+
>>>
3503+
3504+
Of course, these above examples show output according to the format used by
3505+
:func:`~logging.basicConfig`, but you can use a different formatter when you
3506+
configure logging.
34313507

34323508
.. patterns-to-avoid:
34333509

Doc/library/ast.rst

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,20 +1991,28 @@ and classes for traversing abstract syntax trees:
19911991

19921992
.. function:: literal_eval(node_or_string)
19931993

1994-
Safely evaluate an expression node or a string containing a Python literal or
1994+
Evaluate an expression node or a string containing only a Python literal or
19951995
container display. The string or node provided may only consist of the
19961996
following Python literal structures: strings, bytes, numbers, tuples, lists,
19971997
dicts, sets, booleans, ``None`` and ``Ellipsis``.
19981998

1999-
This can be used for safely evaluating strings containing Python values from
2000-
untrusted sources without the need to parse the values oneself. It is not
2001-
capable of evaluating arbitrarily complex expressions, for example involving
2002-
operators or indexing.
1999+
This can be used for evaluating strings containing Python values without the
2000+
need to parse the values oneself. It is not capable of evaluating
2001+
arbitrarily complex expressions, for example involving operators or
2002+
indexing.
2003+
2004+
This function had been documented as "safe" in the past without defining
2005+
what that meant. That was misleading. This is specifically designed not to
2006+
execute Python code, unlike the more general :func:`eval`. There is no
2007+
namespace, no name lookups, or ability to call out. But it is not free from
2008+
attack: A relatively small input can lead to memory exhaustion or to C stack
2009+
exhaustion, crashing the process. There is also the possibility for
2010+
excessive CPU consumption denial of service on some inputs. Calling it on
2011+
untrusted data is thus not recommended.
20032012

20042013
.. warning::
2005-
It is possible to crash the Python interpreter with a
2006-
sufficiently large/complex string due to stack depth limitations
2007-
in Python's AST compiler.
2014+
It is possible to crash the Python interpreter due to stack depth
2015+
limitations in Python's AST compiler.
20082016

20092017
It can raise :exc:`ValueError`, :exc:`TypeError`, :exc:`SyntaxError`,
20102018
:exc:`MemoryError` and :exc:`RecursionError` depending on the malformed

Doc/library/asyncio-future.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ Future Object
8585

8686
Future is an :term:`awaitable` object. Coroutines can await on
8787
Future objects until they either have a result or an exception
88-
set, or until they are cancelled.
88+
set, or until they are cancelled. A Future can be awaited multiple
89+
times and the result is same.
8990

9091
Typically Futures are used to enable low-level
9192
callback-based code (e.g. in protocols implemented using asyncio

Doc/library/asyncio-task.rst

Lines changed: 128 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,13 @@ perform clean-up logic. In case :exc:`asyncio.CancelledError`
294294
is explicitly caught, it should generally be propagated when
295295
clean-up is complete. Most code can safely ignore :exc:`asyncio.CancelledError`.
296296

297-
Important asyncio components, like :class:`asyncio.TaskGroup` and the
298-
:func:`asyncio.timeout` context manager, are implemented using cancellation
299-
internally and might misbehave if a coroutine swallows
300-
:exc:`asyncio.CancelledError`.
297+
The asyncio components that enable structured concurrency, like
298+
:class:`asyncio.TaskGroup` and :func:`asyncio.timeout`,
299+
are implemented using cancellation internally and might misbehave if
300+
a coroutine swallows :exc:`asyncio.CancelledError`. Similarly, user code
301+
should not call :meth:`uncancel <asyncio.Task.uncancel>`.
301302

303+
.. _taskgroups:
302304

303305
Task Groups
304306
===========
@@ -1003,76 +1005,6 @@ Task Object
10031005
Deprecation warning is emitted if *loop* is not specified
10041006
and there is no running event loop.
10051007

1006-
.. method:: cancel(msg=None)
1007-
1008-
Request the Task to be cancelled.
1009-
1010-
This arranges for a :exc:`CancelledError` exception to be thrown
1011-
into the wrapped coroutine on the next cycle of the event loop.
1012-
1013-
The coroutine then has a chance to clean up or even deny the
1014-
request by suppressing the exception with a :keyword:`try` ...
1015-
... ``except CancelledError`` ... :keyword:`finally` block.
1016-
Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does
1017-
not guarantee that the Task will be cancelled, although
1018-
suppressing cancellation completely is not common and is actively
1019-
discouraged.
1020-
1021-
.. versionchanged:: 3.9
1022-
Added the *msg* parameter.
1023-
1024-
.. deprecated-removed:: 3.11 3.14
1025-
*msg* parameter is ambiguous when multiple :meth:`cancel`
1026-
are called with different cancellation messages.
1027-
The argument will be removed.
1028-
1029-
.. _asyncio_example_task_cancel:
1030-
1031-
The following example illustrates how coroutines can intercept
1032-
the cancellation request::
1033-
1034-
async def cancel_me():
1035-
print('cancel_me(): before sleep')
1036-
1037-
try:
1038-
# Wait for 1 hour
1039-
await asyncio.sleep(3600)
1040-
except asyncio.CancelledError:
1041-
print('cancel_me(): cancel sleep')
1042-
raise
1043-
finally:
1044-
print('cancel_me(): after sleep')
1045-
1046-
async def main():
1047-
# Create a "cancel_me" Task
1048-
task = asyncio.create_task(cancel_me())
1049-
1050-
# Wait for 1 second
1051-
await asyncio.sleep(1)
1052-
1053-
task.cancel()
1054-
try:
1055-
await task
1056-
except asyncio.CancelledError:
1057-
print("main(): cancel_me is cancelled now")
1058-
1059-
asyncio.run(main())
1060-
1061-
# Expected output:
1062-
#
1063-
# cancel_me(): before sleep
1064-
# cancel_me(): cancel sleep
1065-
# cancel_me(): after sleep
1066-
# main(): cancel_me is cancelled now
1067-
1068-
.. method:: cancelled()
1069-
1070-
Return ``True`` if the Task is *cancelled*.
1071-
1072-
The Task is *cancelled* when the cancellation was requested with
1073-
:meth:`cancel` and the wrapped coroutine propagated the
1074-
:exc:`CancelledError` exception thrown into it.
1075-
10761008
.. method:: done()
10771009

10781010
Return ``True`` if the Task is *done*.
@@ -1186,3 +1118,125 @@ Task Object
11861118
in the :func:`repr` output of a task object.
11871119

11881120
.. versionadded:: 3.8
1121+
1122+
.. method:: cancel(msg=None)
1123+
1124+
Request the Task to be cancelled.
1125+
1126+
This arranges for a :exc:`CancelledError` exception to be thrown
1127+
into the wrapped coroutine on the next cycle of the event loop.
1128+
1129+
The coroutine then has a chance to clean up or even deny the
1130+
request by suppressing the exception with a :keyword:`try` ...
1131+
... ``except CancelledError`` ... :keyword:`finally` block.
1132+
Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does
1133+
not guarantee that the Task will be cancelled, although
1134+
suppressing cancellation completely is not common and is actively
1135+
discouraged.
1136+
1137+
.. versionchanged:: 3.9
1138+
Added the *msg* parameter.
1139+
1140+
.. deprecated-removed:: 3.11 3.14
1141+
*msg* parameter is ambiguous when multiple :meth:`cancel`
1142+
are called with different cancellation messages.
1143+
The argument will be removed.
1144+
1145+
.. _asyncio_example_task_cancel:
1146+
1147+
The following example illustrates how coroutines can intercept
1148+
the cancellation request::
1149+
1150+
async def cancel_me():
1151+
print('cancel_me(): before sleep')
1152+
1153+
try:
1154+
# Wait for 1 hour
1155+
await asyncio.sleep(3600)
1156+
except asyncio.CancelledError:
1157+
print('cancel_me(): cancel sleep')
1158+
raise
1159+
finally:
1160+
print('cancel_me(): after sleep')
1161+
1162+
async def main():
1163+
# Create a "cancel_me" Task
1164+
task = asyncio.create_task(cancel_me())
1165+
1166+
# Wait for 1 second
1167+
await asyncio.sleep(1)
1168+
1169+
task.cancel()
1170+
try:
1171+
await task
1172+
except asyncio.CancelledError:
1173+
print("main(): cancel_me is cancelled now")
1174+
1175+
asyncio.run(main())
1176+
1177+
# Expected output:
1178+
#
1179+
# cancel_me(): before sleep
1180+
# cancel_me(): cancel sleep
1181+
# cancel_me(): after sleep
1182+
# main(): cancel_me is cancelled now
1183+
1184+
.. method:: cancelled()
1185+
1186+
Return ``True`` if the Task is *cancelled*.
1187+
1188+
The Task is *cancelled* when the cancellation was requested with
1189+
:meth:`cancel` and the wrapped coroutine propagated the
1190+
:exc:`CancelledError` exception thrown into it.
1191+
1192+
.. method:: uncancel()
1193+
1194+
Decrement the count of cancellation requests to this Task.
1195+
1196+
Returns the remaining number of cancellation requests.
1197+
1198+
Note that once execution of a cancelled task completed, further
1199+
calls to :meth:`uncancel` are ineffective.
1200+
1201+
.. versionadded:: 3.11
1202+
1203+
This method is used by asyncio's internals and isn't expected to be
1204+
used by end-user code. In particular, if a Task gets successfully
1205+
uncancelled, this allows for elements of structured concurrency like
1206+
:ref:`taskgroups` and :func:`asyncio.timeout` to continue running,
1207+
isolating cancellation to the respective structured block.
1208+
For example::
1209+
1210+
async def make_request_with_timeout():
1211+
try:
1212+
async with asyncio.timeout(1):
1213+
# Structured block affected by the timeout:
1214+
await make_request()
1215+
await make_another_request()
1216+
except TimeoutError:
1217+
log("There was a timeout")
1218+
# Outer code not affected by the timeout:
1219+
await unrelated_code()
1220+
1221+
While the block with ``make_request()`` and ``make_another_request()``
1222+
might get cancelled due to the timeout, ``unrelated_code()`` should
1223+
continue running even in case of the timeout. This is implemented
1224+
with :meth:`uncancel`. :class:`TaskGroup` context managers use
1225+
:func:`uncancel` in a similar fashion.
1226+
1227+
.. method:: cancelling()
1228+
1229+
Return the number of pending cancellation requests to this Task, i.e.,
1230+
the number of calls to :meth:`cancel` less the number of
1231+
:meth:`uncancel` calls.
1232+
1233+
Note that if this number is greater than zero but the Task is
1234+
still executing, :meth:`cancelled` will still return ``False``.
1235+
This is because this number can be lowered by calling :meth:`uncancel`,
1236+
which can lead to the task not being cancelled after all if the
1237+
cancellation requests go down to zero.
1238+
1239+
This method is used by asyncio's internals and isn't expected to be
1240+
used by end-user code. See :meth:`uncancel` for more details.
1241+
1242+
.. versionadded:: 3.11

Doc/library/email.compat32-message.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Here are the methods of the :class:`Message` class:
8383
Note that this method is provided as a convenience and may not always
8484
format the message the way you want. For example, by default it does
8585
not do the mangling of lines that begin with ``From`` that is
86-
required by the unix mbox format. For more flexibility, instantiate a
86+
required by the Unix mbox format. For more flexibility, instantiate a
8787
:class:`~email.generator.Generator` instance and use its
8888
:meth:`~email.generator.Generator.flatten` method directly. For example::
8989

@@ -125,7 +125,7 @@ Here are the methods of the :class:`Message` class:
125125
Note that this method is provided as a convenience and may not always
126126
format the message the way you want. For example, by default it does
127127
not do the mangling of lines that begin with ``From`` that is
128-
required by the unix mbox format. For more flexibility, instantiate a
128+
required by the Unix mbox format. For more flexibility, instantiate a
129129
:class:`~email.generator.BytesGenerator` instance and use its
130130
:meth:`~email.generator.BytesGenerator.flatten` method directly.
131131
For example::

0 commit comments

Comments
 (0)