Skip to content

Commit 8a6a432

Browse files
authored
Merge branch 'main' into 3.14-zstd-python-code
2 parents 1d63022 + 08d7687 commit 8a6a432

File tree

12 files changed

+121
-26
lines changed

12 files changed

+121
-26
lines changed

Doc/library/asyncio-eventloop.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ Creating Futures and Tasks
361361

362362
.. versionadded:: 3.5.2
363363

364-
.. method:: loop.create_task(coro, *, name=None, context=None)
364+
.. method:: loop.create_task(coro, *, name=None, context=None, eager_start=None)
365365

366366
Schedule the execution of :ref:`coroutine <coroutine>` *coro*.
367367
Return a :class:`Task` object.
@@ -377,12 +377,20 @@ Creating Futures and Tasks
377377
custom :class:`contextvars.Context` for the *coro* to run in.
378378
The current context copy is created when no *context* is provided.
379379

380+
An optional keyword-only *eager_start* argument allows specifying
381+
if the task should execute eagerly during the call to create_task,
382+
or be scheduled later. If *eager_start* is not passed the mode set
383+
by :meth:`loop.set_task_factory` will be used.
384+
380385
.. versionchanged:: 3.8
381386
Added the *name* parameter.
382387

383388
.. versionchanged:: 3.11
384389
Added the *context* parameter.
385390

391+
.. versionchanged:: next
392+
Added the *eager_start* parameter.
393+
386394
.. method:: loop.set_task_factory(factory)
387395

388396
Set a task factory that will be used by

Include/internal/pycore_magic_number.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ Known values:
276276
Python 3.14a7 3621 (Optimize LOAD_FAST opcodes into LOAD_FAST_BORROW)
277277
Python 3.14a7 3622 (Store annotations in different class dict keys)
278278
Python 3.14a7 3623 (Add BUILD_INTERPOLATION & BUILD_TEMPLATE opcodes)
279+
Python 3.14b1 3624 (Don't optimize LOAD_FAST when local is killed by DELETE_FAST)
279280
280281
Python 3.15 will start with 3650
281282
@@ -288,7 +289,7 @@ PC/launcher.c must also be updated.
288289
289290
*/
290291

291-
#define PYC_MAGIC_NUMBER 3623
292+
#define PYC_MAGIC_NUMBER 3624
292293
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
293294
(little-endian) and then appending b'\r\n'. */
294295
#define PYC_MAGIC_NUMBER_TOKEN \

Lib/asyncio/base_events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ def create_future(self):
459459
return futures.Future(loop=self)
460460

461461
def create_task(self, coro, **kwargs):
462-
"""Schedule a coroutine object.
462+
"""Schedule or begin executing a coroutine object.
463463
464464
Return a task object.
465465
"""

Lib/asyncio/taskgroups.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ async def _aexit(self, et, exc):
179179
exc = None
180180

181181

182-
def create_task(self, coro, *, name=None, context=None):
182+
def create_task(self, coro, **kwargs):
183183
"""Create a new task in this group and return it.
184184
185185
Similar to `asyncio.create_task`.
@@ -193,10 +193,7 @@ def create_task(self, coro, *, name=None, context=None):
193193
if self._aborting:
194194
coro.close()
195195
raise RuntimeError(f"TaskGroup {self!r} is shutting down")
196-
if context is None:
197-
task = self._loop.create_task(coro, name=name)
198-
else:
199-
task = self._loop.create_task(coro, name=name, context=context)
196+
task = self._loop.create_task(coro, **kwargs)
200197

201198
futures.future_add_to_awaited_by(task, self._parent_task)
202199

Lib/asyncio/tasks.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -386,19 +386,13 @@ def __wakeup(self, future):
386386
Task = _CTask = _asyncio.Task
387387

388388

389-
def create_task(coro, *, name=None, context=None):
389+
def create_task(coro, **kwargs):
390390
"""Schedule the execution of a coroutine object in a spawn task.
391391
392392
Return a Task object.
393393
"""
394394
loop = events.get_running_loop()
395-
if context is None:
396-
# Use legacy API if context is not needed
397-
task = loop.create_task(coro, name=name)
398-
else:
399-
task = loop.create_task(coro, name=name, context=context)
400-
401-
return task
395+
return loop.create_task(coro, **kwargs)
402396

403397

404398
# wait() and as_completed() similar to those in PEP 3148.
@@ -1030,9 +1024,9 @@ def create_eager_task_factory(custom_task_constructor):
10301024
used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`.
10311025
"""
10321026

1033-
def factory(loop, coro, *, name=None, context=None):
1027+
def factory(loop, coro, *, eager_start=True, **kwargs):
10341028
return custom_task_constructor(
1035-
coro, loop=loop, name=name, context=context, eager_start=True)
1029+
coro, loop=loop, eager_start=eager_start, **kwargs)
10361030

10371031
return factory
10381032

Lib/test/test_asyncio/test_eager_task_factory.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,24 @@ async def run():
263263

264264
self.run_coro(run())
265265

266+
def test_eager_start_false(self):
267+
name = None
268+
269+
async def asyncfn():
270+
nonlocal name
271+
name = asyncio.current_task().get_name()
272+
273+
async def main():
274+
t = asyncio.get_running_loop().create_task(
275+
asyncfn(), eager_start=False, name="example"
276+
)
277+
self.assertFalse(t.done())
278+
self.assertIsNone(name)
279+
await t
280+
self.assertEqual(name, "example")
281+
282+
self.run_coro(main())
283+
266284

267285
class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase):
268286
Task = tasks._PyTask
@@ -505,5 +523,24 @@ def tearDown(self):
505523
asyncio.current_task = asyncio.tasks.current_task = self._current_task
506524
return super().tearDown()
507525

526+
527+
class DefaultTaskFactoryEagerStart(test_utils.TestCase):
528+
def test_eager_start_true_with_default_factory(self):
529+
name = None
530+
531+
async def asyncfn():
532+
nonlocal name
533+
name = asyncio.current_task().get_name()
534+
535+
async def main():
536+
t = asyncio.get_running_loop().create_task(
537+
asyncfn(), eager_start=True, name="example"
538+
)
539+
self.assertTrue(t.done())
540+
self.assertEqual(name, "example")
541+
await t
542+
543+
asyncio.run(main(), loop_factory=asyncio.EventLoop)
544+
508545
if __name__ == '__main__':
509546
unittest.main()

Lib/test/test_asyncio/test_tasks.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ class BaseTaskTests:
8989
Future = None
9090
all_tasks = None
9191

92-
def new_task(self, loop, coro, name='TestTask', context=None):
93-
return self.__class__.Task(coro, loop=loop, name=name, context=context)
92+
def new_task(self, loop, coro, name='TestTask', context=None, eager_start=None):
93+
return self.__class__.Task(coro, loop=loop, name=name, context=context, eager_start=eager_start)
9494

9595
def new_future(self, loop):
9696
return self.__class__.Future(loop=loop)
@@ -2686,6 +2686,35 @@ async def main():
26862686

26872687
self.assertEqual([None, 1, 2], ret)
26882688

2689+
def test_eager_start_true(self):
2690+
name = None
2691+
2692+
async def asyncfn():
2693+
nonlocal name
2694+
name = self.current_task().get_name()
2695+
2696+
async def main():
2697+
t = self.new_task(coro=asyncfn(), loop=asyncio.get_running_loop(), eager_start=True, name="example")
2698+
self.assertTrue(t.done())
2699+
self.assertEqual(name, "example")
2700+
await t
2701+
2702+
def test_eager_start_false(self):
2703+
name = None
2704+
2705+
async def asyncfn():
2706+
nonlocal name
2707+
name = self.current_task().get_name()
2708+
2709+
async def main():
2710+
t = self.new_task(coro=asyncfn(), loop=asyncio.get_running_loop(), eager_start=False, name="example")
2711+
self.assertFalse(t.done())
2712+
self.assertIsNone(name)
2713+
await t
2714+
self.assertEqual(name, "example")
2715+
2716+
asyncio.run(main(), loop_factory=asyncio.EventLoop)
2717+
26892718
def test_get_coro(self):
26902719
loop = asyncio.new_event_loop()
26912720
coro = coroutine_function()

Lib/test/test_external_inspection.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ def baz():
5959
foo()
6060
6161
def foo():
62-
sock.sendall(b"ready")
63-
time.sleep(1000)
62+
sock.sendall(b"ready"); time.sleep(1000) # same line number
6463
6564
bar()
6665
"""
@@ -96,10 +95,10 @@ def foo():
9695
p.wait(timeout=SHORT_TIMEOUT)
9796

9897
expected_stack_trace = [
99-
("foo", script_name, 15),
98+
("foo", script_name, 14),
10099
("baz", script_name, 11),
101100
("bar", script_name, 9),
102-
("<module>", script_name, 17),
101+
("<module>", script_name, 16),
103102
]
104103
self.assertEqual(stack_trace, expected_stack_trace)
105104

Lib/test/test_peepholer.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import dis
2+
import gc
23
from itertools import combinations, product
34
import opcode
45
import sys
@@ -2472,6 +2473,13 @@ def test_unoptimized_if_support_killed(self):
24722473
]
24732474
self.check(insts, insts)
24742475

2476+
insts = [
2477+
("LOAD_FAST", 0, 1),
2478+
("DELETE_FAST", 0, 2),
2479+
("POP_TOP", None, 3),
2480+
]
2481+
self.check(insts, insts)
2482+
24752483
def test_unoptimized_if_aliased(self):
24762484
insts = [
24772485
("LOAD_FAST", 0, 1),
@@ -2606,6 +2614,22 @@ def test_send(self):
26062614
]
26072615
self.cfg_optimization_test(insts, expected, consts=[None])
26082616

2617+
def test_del_in_finally(self):
2618+
# This loads `obj` onto the stack, executes `del obj`, then returns the
2619+
# `obj` from the stack. See gh-133371 for more details.
2620+
def create_obj():
2621+
obj = [42]
2622+
try:
2623+
return obj
2624+
finally:
2625+
del obj
2626+
2627+
obj = create_obj()
2628+
# The crash in the linked issue happens while running GC during
2629+
# interpreter finalization, so run it here manually.
2630+
gc.collect()
2631+
self.assertEqual(obj, [42])
2632+
26092633

26102634

26112635
if __name__ == "__main__":

Lib/test/test_subprocess.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,13 @@ def test_call_timeout(self):
164164

165165
def test_timeout_exception(self):
166166
try:
167-
subprocess.run(['echo', 'hi'], timeout = -1)
167+
subprocess.run([sys.executable, '-c', 'import time;time.sleep(9)'], timeout = -1)
168168
except subprocess.TimeoutExpired as e:
169169
self.assertIn("-1 seconds", str(e))
170170
else:
171171
self.fail("Expected TimeoutExpired exception not raised")
172172
try:
173-
subprocess.run(['echo', 'hi'], timeout = 0)
173+
subprocess.run([sys.executable, '-c', 'import time;time.sleep(9)'], timeout = 0)
174174
except subprocess.TimeoutExpired as e:
175175
self.assertIn("0 seconds", str(e))
176176
else:

0 commit comments

Comments
 (0)