Skip to content

Commit c5deb74

Browse files
authored
Update asyncio library (#6601)
* Updated asyncio to v3.13.11 * Removed expectedFailure from `test_async_case.py`
1 parent a3d1b5e commit c5deb74

21 files changed

+936
-452
lines changed

Lib/asyncio/__main__.py

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,51 @@
11
import ast
22
import asyncio
3-
import code
43
import concurrent.futures
4+
import contextvars
55
import inspect
6+
import os
7+
import site
68
import sys
79
import threading
810
import types
911
import warnings
1012

13+
from _colorize import can_colorize, ANSIColors # type: ignore[import-not-found]
14+
from _pyrepl.console import InteractiveColoredConsole
15+
1116
from . import futures
1217

1318

14-
class AsyncIOInteractiveConsole(code.InteractiveConsole):
19+
class AsyncIOInteractiveConsole(InteractiveColoredConsole):
1520

1621
def __init__(self, locals, loop):
17-
super().__init__(locals)
22+
super().__init__(locals, filename="<stdin>")
1823
self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
1924

2025
self.loop = loop
26+
self.context = contextvars.copy_context()
2127

2228
def runcode(self, code):
29+
global return_code
2330
future = concurrent.futures.Future()
2431

2532
def callback():
33+
global return_code
2634
global repl_future
27-
global repl_future_interrupted
35+
global keyboard_interrupted
2836

2937
repl_future = None
30-
repl_future_interrupted = False
38+
keyboard_interrupted = False
3139

3240
func = types.FunctionType(code, self.locals)
3341
try:
3442
coro = func()
35-
except SystemExit:
36-
raise
43+
except SystemExit as se:
44+
return_code = se.code
45+
self.loop.stop()
46+
return
3747
except KeyboardInterrupt as ex:
38-
repl_future_interrupted = True
48+
keyboard_interrupted = True
3949
future.set_exception(ex)
4050
return
4151
except BaseException as ex:
@@ -47,39 +57,71 @@ def callback():
4757
return
4858

4959
try:
50-
repl_future = self.loop.create_task(coro)
60+
repl_future = self.loop.create_task(coro, context=self.context)
5161
futures._chain_future(repl_future, future)
5262
except BaseException as exc:
5363
future.set_exception(exc)
5464

55-
loop.call_soon_threadsafe(callback)
65+
self.loop.call_soon_threadsafe(callback, context=self.context)
5666

5767
try:
5868
return future.result()
59-
except SystemExit:
60-
raise
69+
except SystemExit as se:
70+
return_code = se.code
71+
self.loop.stop()
72+
return
6173
except BaseException:
62-
if repl_future_interrupted:
63-
self.write("\nKeyboardInterrupt\n")
74+
if keyboard_interrupted:
75+
if not CAN_USE_PYREPL:
76+
self.write("\nKeyboardInterrupt\n")
6477
else:
6578
self.showtraceback()
66-
79+
return self.STATEMENT_FAILED
6780

6881
class REPLThread(threading.Thread):
6982

7083
def run(self):
84+
global return_code
85+
7186
try:
7287
banner = (
7388
f'asyncio REPL {sys.version} on {sys.platform}\n'
7489
f'Use "await" directly instead of "asyncio.run()".\n'
7590
f'Type "help", "copyright", "credits" or "license" '
7691
f'for more information.\n'
77-
f'{getattr(sys, "ps1", ">>> ")}import asyncio'
7892
)
7993

80-
console.interact(
81-
banner=banner,
82-
exitmsg='exiting asyncio REPL...')
94+
console.write(banner)
95+
96+
if startup_path := os.getenv("PYTHONSTARTUP"):
97+
sys.audit("cpython.run_startup", startup_path)
98+
99+
import tokenize
100+
with tokenize.open(startup_path) as f:
101+
startup_code = compile(f.read(), startup_path, "exec")
102+
exec(startup_code, console.locals)
103+
104+
ps1 = getattr(sys, "ps1", ">>> ")
105+
if can_colorize() and CAN_USE_PYREPL:
106+
ps1 = f"{ANSIColors.BOLD_MAGENTA}{ps1}{ANSIColors.RESET}"
107+
console.write(f"{ps1}import asyncio\n")
108+
109+
if CAN_USE_PYREPL:
110+
from _pyrepl.simple_interact import (
111+
run_multiline_interactive_console,
112+
)
113+
try:
114+
run_multiline_interactive_console(console)
115+
except SystemExit:
116+
# expected via the `exit` and `quit` commands
117+
pass
118+
except BaseException:
119+
# unexpected issue
120+
console.showtraceback()
121+
console.write("Internal error, ")
122+
return_code = 1
123+
else:
124+
console.interact(banner="", exitmsg="")
83125
finally:
84126
warnings.filterwarnings(
85127
'ignore',
@@ -88,8 +130,25 @@ def run(self):
88130

89131
loop.call_soon_threadsafe(loop.stop)
90132

133+
def interrupt(self) -> None:
134+
if not CAN_USE_PYREPL:
135+
return
136+
137+
from _pyrepl.simple_interact import _get_reader
138+
r = _get_reader()
139+
if r.threading_hook is not None:
140+
r.threading_hook.add("") # type: ignore
141+
91142

92143
if __name__ == '__main__':
144+
sys.audit("cpython.run_stdin")
145+
146+
if os.getenv('PYTHON_BASIC_REPL'):
147+
CAN_USE_PYREPL = False
148+
else:
149+
from _pyrepl.main import CAN_USE_PYREPL
150+
151+
return_code = 0
93152
loop = asyncio.new_event_loop()
94153
asyncio.set_event_loop(loop)
95154

@@ -102,24 +161,45 @@ def run(self):
102161
console = AsyncIOInteractiveConsole(repl_locals, loop)
103162

104163
repl_future = None
105-
repl_future_interrupted = False
164+
keyboard_interrupted = False
106165

107166
try:
108167
import readline # NoQA
109168
except ImportError:
110-
pass
169+
readline = None
170+
171+
interactive_hook = getattr(sys, "__interactivehook__", None)
111172

112-
repl_thread = REPLThread()
173+
if interactive_hook is not None:
174+
sys.audit("cpython.run_interactivehook", interactive_hook)
175+
interactive_hook()
176+
177+
if interactive_hook is site.register_readline:
178+
# Fix the completer function to use the interactive console locals
179+
try:
180+
import rlcompleter
181+
except:
182+
pass
183+
else:
184+
if readline is not None:
185+
completer = rlcompleter.Completer(console.locals)
186+
readline.set_completer(completer.complete)
187+
188+
repl_thread = REPLThread(name="Interactive thread")
113189
repl_thread.daemon = True
114190
repl_thread.start()
115191

116192
while True:
117193
try:
118194
loop.run_forever()
119195
except KeyboardInterrupt:
196+
keyboard_interrupted = True
120197
if repl_future and not repl_future.done():
121198
repl_future.cancel()
122-
repl_future_interrupted = True
199+
repl_thread.interrupt()
123200
continue
124201
else:
125202
break
203+
204+
console.write('exiting asyncio REPL...\n')
205+
sys.exit(return_code)

0 commit comments

Comments
 (0)