Skip to content

Commit 70f802a

Browse files
committed
Merge remote-tracking branch 'upstream/main' into proc-handle-poc
2 parents fc8c13b + b2f126c commit 70f802a

40 files changed

Lines changed: 507 additions & 438 deletions

Doc/deprecations/pending-removal-in-3.15.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Pending removal in Python 3.15
6060

6161
* :mod:`types`:
6262

63-
* :class:`types.CodeType`: Accessing :attr:`~codeobject.co_lnotab` was
63+
* :class:`types.CodeType`: Accessing :attr:`!codeobject.co_lnotab` was
6464
deprecated in :pep:`626`
6565
since 3.10 and was planned to be removed in 3.12,
6666
but it only got a proper :exc:`DeprecationWarning` in 3.12.

Doc/deprecations/pending-removal-in-future.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ although there is currently no date scheduled for their removal.
4747

4848
* :mod:`codecs`: use :func:`open` instead of :func:`codecs.open`. (:gh:`133038`)
4949

50-
* :attr:`codeobject.co_lnotab`: use the :meth:`codeobject.co_lines` method
50+
* :attr:`!codeobject.co_lnotab`: use the :meth:`codeobject.co_lines` method
5151
instead.
5252

5353
* :mod:`datetime`:

Doc/library/asyncio-task.rst

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,34 @@ and reliable way to wait for all tasks in the group to finish.
355355

356356
Passes on all *kwargs* to :meth:`loop.create_task`
357357

358+
.. method:: cancel()
359+
360+
Cancel the task group. This is a non-exceptional, early exit of the
361+
task group's lifetime -- useful once the group's goal has been met or
362+
its services no longer needed.
363+
364+
:meth:`~asyncio.Task.cancel` will be called on any tasks in the group that
365+
aren't yet done, as well as the parent (body) of the group. The task group
366+
context manager will exit *without* :exc:`asyncio.CancelledError` being raised.
367+
368+
If :meth:`cancel` is called before entering the task group, the group will be
369+
cancelled upon entry. This is useful for patterns where one piece of
370+
code passes an unused :class:`asyncio.TaskGroup` instance to another in order to have
371+
the ability to cancel anything run within the group.
372+
373+
:meth:`cancel` is idempotent and may be called after the task group has
374+
already exited.
375+
376+
Some ways to use :meth:`cancel`:
377+
378+
* call it from the task group body based on some condition or event
379+
* pass the task group instance to child tasks via :meth:`create_task`, allowing a child
380+
task to conditionally cancel the entire entire group
381+
* pass the task group instance or bound :meth:`cancel` method to some other task *before*
382+
opening the task group, allowing remote cancellation
383+
384+
.. versionadded:: next
385+
358386
Example::
359387

360388
async def main():
@@ -366,7 +394,8 @@ Example::
366394
The ``async with`` statement will wait for all tasks in the group to finish.
367395
While waiting, new tasks may still be added to the group
368396
(for example, by passing ``tg`` into one of the coroutines
369-
and calling ``tg.create_task()`` in that coroutine).
397+
and calling ``tg.create_task()`` in that coroutine). There is also opportunity
398+
to short-circuit the entire task group with ``tg.cancel()``, based on some condition.
370399
Once the last task has finished and the ``async with`` block is exited,
371400
no new tasks may be added to the group.
372401

@@ -427,53 +456,6 @@ reported by :meth:`asyncio.Task.cancelling`.
427456
Improved handling of simultaneous internal and external cancellations
428457
and correct preservation of cancellation counts.
429458

430-
Terminating a task group
431-
------------------------
432-
433-
While terminating a task group is not natively supported by the standard
434-
library, termination can be achieved by adding an exception-raising task
435-
to the task group and ignoring the raised exception:
436-
437-
.. code-block:: python
438-
439-
import asyncio
440-
from asyncio import TaskGroup
441-
442-
class TerminateTaskGroup(Exception):
443-
"""Exception raised to terminate a task group."""
444-
445-
async def force_terminate_task_group():
446-
"""Used to force termination of a task group."""
447-
raise TerminateTaskGroup()
448-
449-
async def job(task_id, sleep_time):
450-
print(f'Task {task_id}: start')
451-
await asyncio.sleep(sleep_time)
452-
print(f'Task {task_id}: done')
453-
454-
async def main():
455-
try:
456-
async with TaskGroup() as group:
457-
# spawn some tasks
458-
group.create_task(job(1, 0.5))
459-
group.create_task(job(2, 1.5))
460-
# sleep for 1 second
461-
await asyncio.sleep(1)
462-
# add an exception-raising task to force the group to terminate
463-
group.create_task(force_terminate_task_group())
464-
except* TerminateTaskGroup:
465-
pass
466-
467-
asyncio.run(main())
468-
469-
Expected output:
470-
471-
.. code-block:: text
472-
473-
Task 1: start
474-
Task 2: start
475-
Task 1: done
476-
477459
Sleeping
478460
========
479461

Doc/library/dis.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ operation is being performed, so the intermediate analysis object isn't useful:
400400

401401
.. versionchanged:: 3.10
402402
The :pep:`626` :meth:`~codeobject.co_lines` method is used instead of the
403-
:attr:`~codeobject.co_firstlineno` and :attr:`~codeobject.co_lnotab`
403+
:attr:`~codeobject.co_firstlineno` and :attr:`!codeobject.co_lnotab`
404404
attributes of the :ref:`code object <code-objects>`.
405405

406406
.. versionchanged:: 3.13

Doc/library/inspect.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,6 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
195195
| | | read more :ref:`here |
196196
| | | <inspect-module-co-flags>`|
197197
+-----------------+-------------------+---------------------------+
198-
| | co_lnotab | encoded mapping of line |
199-
| | | numbers to bytecode |
200-
| | | indices |
201-
+-----------------+-------------------+---------------------------+
202198
| | co_freevars | tuple of names of free |
203199
| | | variables (referenced via |
204200
| | | a function's closure) |

Doc/library/profiling.sampling.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
--------------
1919

20-
.. image:: tachyon-logo.png
20+
.. image:: ../../Lib/profiling/sampling/_assets/tachyon-logo.png
2121
:alt: Tachyon logo
2222
:align: center
2323
:width: 300px

Doc/library/tachyon-logo.png

-110 KB
Binary file not shown.

Doc/reference/datamodel.rst

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,7 @@ Attribute assignment updates the module's namespace dictionary, e.g.,
926926
single: __doc__ (module attribute)
927927
single: __annotations__ (module attribute)
928928
single: __annotate__ (module attribute)
929+
single: __lazy_modules__ (module attribute)
929930
pair: module; namespace
930931

931932
.. _import-mod-attrs:
@@ -1121,6 +1122,20 @@ the following writable attributes:
11211122

11221123
.. versionadded:: 3.14
11231124

1125+
.. attribute:: module.__lazy_modules__
1126+
1127+
A container (an object implementing :meth:`~object.__contains__`) of fully
1128+
qualified module name strings. When defined
1129+
at module scope, any regular :keyword:`import` statement in that module whose
1130+
target module name appears in this container is treated as a
1131+
:ref:`lazy import <lazy-imports>`, as if the :keyword:`lazy` keyword had
1132+
been used. Imports inside functions, class bodies, or
1133+
:keyword:`try`/:keyword:`except`/:keyword:`finally` blocks are unaffected.
1134+
1135+
See :ref:`lazy-modules-compat` for details and examples.
1136+
1137+
.. versionadded:: 3.15
1138+
11241139
Module dictionaries
11251140
^^^^^^^^^^^^^^^^^^^
11261141

@@ -1461,7 +1476,6 @@ indirectly) to mutable objects.
14611476
single: co_filename (code object attribute)
14621477
single: co_firstlineno (code object attribute)
14631478
single: co_flags (code object attribute)
1464-
single: co_lnotab (code object attribute)
14651479
single: co_name (code object attribute)
14661480
single: co_names (code object attribute)
14671481
single: co_nlocals (code object attribute)
@@ -1534,14 +1548,6 @@ Special read-only attributes
15341548
* - .. attribute:: codeobject.co_firstlineno
15351549
- The line number of the first line of the function
15361550

1537-
* - .. attribute:: codeobject.co_lnotab
1538-
- A string encoding the mapping from :term:`bytecode` offsets to line
1539-
numbers. For details, see the source code of the interpreter.
1540-
1541-
.. deprecated:: 3.12
1542-
This attribute of code objects is deprecated, and may be removed in
1543-
Python 3.15.
1544-
15451551
* - .. attribute:: codeobject.co_stacksize
15461552
- The required stack size of the code object
15471553

Doc/reference/simple_stmts.rst

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,56 @@ See :pep:`810` for the full specification of lazy imports.
920920

921921
.. versionadded:: 3.15
922922

923+
.. _lazy-modules-compat:
924+
925+
Compatibility via ``__lazy_modules__``
926+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
927+
928+
.. index::
929+
single: __lazy_modules__
930+
931+
As an alternative to using the :keyword:`lazy` keyword, a module can opt
932+
into lazy loading for specific imports by defining a module-level
933+
:attr:`~module.__lazy_modules__` variable. When present, it must be a
934+
container of fully qualified module name strings. Any regular (non-``lazy``)
935+
:keyword:`import` statement at module scope whose target appears in
936+
:attr:`!__lazy_modules__` is treated as a lazy import, exactly as if the
937+
:keyword:`lazy` keyword had been used.
938+
939+
This provides a way to enable lazy loading for specific dependencies without
940+
changing individual ``import`` statements. This is useful when supporting
941+
Python versions older than 3.15 while using lazy imports in 3.15+::
942+
943+
__lazy_modules__ = ["json", "pathlib"]
944+
945+
import json # loaded lazily (name is in __lazy_modules__)
946+
import os # loaded eagerly (name not in __lazy_modules__)
947+
948+
import pathlib # loaded lazily
949+
950+
Relative imports are resolved to their absolute name before the lookup, so
951+
:attr:`!__lazy_modules__` must always contain fully qualified module names.
952+
953+
For ``from``-style imports, the relevant name is the module following
954+
``from``, not the names of its members::
955+
956+
# In mypackage/mymodule.py
957+
__lazy_modules__ = ["mypackage", "mypackage.sub.utils"]
958+
959+
from . import helper # loaded lazily: . resolves to mypackage
960+
from .sub.utils import func # loaded lazily: .sub.utils resolves to mypackage.sub.utils
961+
import json # loaded eagerly (not in __lazy_modules__)
962+
963+
Imports inside functions, class bodies, or
964+
:keyword:`try`/:keyword:`except`/:keyword:`finally` blocks are always eager,
965+
regardless of :attr:`!__lazy_modules__`.
966+
967+
Setting ``-X lazy_imports=none`` (or the :envvar:`PYTHON_LAZY_IMPORTS`
968+
environment variable to ``none``) overrides :attr:`!__lazy_modules__` and
969+
forces all imports to be eager.
970+
971+
.. versionadded:: 3.15
972+
923973
.. _future:
924974

925975
Future statements

Doc/tools/removed-ids.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
# Remove from here in 3.16
44
c-api/allocation.html: deprecated-aliases
55
c-api/file.html: deprecated-api
6+
7+
library/asyncio-task.html: terminating-a-task-group

0 commit comments

Comments
 (0)