8000 Update asyncio from CPython 3.12.3 · RustPython/RustPython@2399b4c · GitHub
[go: up one dir, main page]

Skip to content

Commit 2399b4c

Browse files
CPython Developersyouknowone
CPython Developers
authored andcommitted
Update asyncio from CPython 3.12.3
1 parent 30776ce commit 2399b4c

26 files changed

+2511
-1279
lines changed

Lib/asyncio/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from .streams import *
1818
from .subprocess import *
1919
from .tasks import *
20+
from .taskgroups import *
21+
from .timeouts import *
2022
from .threads import *
2123
from .transports import *
2224

@@ -32,7 +34,9 @@
3234
streams.__all__ +
3335
subprocess.__all__ +
3436
tasks.__all__ +
37+
taskgroups.__all__ +
3538
threads.__all__ +
39+
timeouts.__all__ +
3640
transports.__all__)
3741

3842
if sys.platform == 'win32': # pragma: no cover

Lib/asyncio/base_events.py

Lines changed: 167 additions & 76 deletions
Large diffs are not rendered by default.

Lib/asyncio/base_futures.py

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
__all__ = ()
22

33
import reprlib
4-
from _thread import get_ident
54

65
from . import format_helpers
76

@@ -42,16 +41,6 @@ def format_cb(callback):
4241
return f'cb=[{cb}]'
4342

4443

45-
# bpo-42183: _repr_running is needed for repr protection
46-
# when a Future or Task result contains itself directly or indirectly.
47-
# The logic is borrowed from @reprlib.recursive_repr decorator.
48-
# Unfortunately, the direct decorator usage is impossible because of
49-
# AttributeError: '_asyncio.Task' object has no attribute '__module__' error.
50-
#
51-
# After fixing this thing we can return to the decorator based F438 approach.
52-
_repr_running = set()
53-
54-
5544
def _future_repr_info(future):
5645
# (Future) -> str
5746
"""helper function for Future.__repr__"""
@@ -60,21 +49,19 @@ def _future_repr_info(future):
6049
if future._exception is not None:
6150
info.append(f'exception={future._exception!r}')
6251
else:
63-
key = id(future), get_ident()
64-
if key in _repr_running:
65-
result = '...'
66-
else:
67-
_repr_running.add(key)
68-
try:
69-
# use reprlib to limit the length of the output, especially
70-
# for very long strings
71-
result = reprlib.repr(future._result)
72-
finally:
73-
_repr_running.discard(key)
52+
# use reprlib to limit the length of the output, especially
53+
# for very long strings
54+
result = reprlib.repr(future._result)
7455
info.append(f'result={result}')
7556
if future._callbacks:
7657
info.append(_format_callbacks(future._callbacks))
7758
if future._source_traceback:
7859
frame = future._source_traceback[-1]
7960
info.append(f'created at {frame[0]}:{frame[1]}')
8061
return info
62+
63+
64+
@reprlib.recursive_repr()
65+
def _future_repr(future):
66+
info = ' '.join(_future_repr_info(future))
67+
return f'<{future.__class__.__name__} {info}>'

Lib/asyncio/base_subprocess.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,8 @@ def _process_exited(self, returncode):
215215
# object. On Python 3.6, it is required to avoid a ResourceWarning.
216216
self._proc.returncode = returncode
217217
self._call(self._protocol.process_exited)
218-
self._try_finish()
219218

220-
# wake up futures waiting for wait()
221-
for waiter in self._exit_waiters:
222-
if not waiter.cancelled():
223-
waiter.set_result(returncode)
224-
self._exit_waiters = None
219+
self._try_finish()
225220

226221
async def _wait(self):
227222
"""Wait until the process exit and return the process return code.
@@ -247,6 +242,11 @@ def _call_connection_lost(self, exc):
247242
try:
248243
self._protocol.connection_lost(exc)
249244
finally:
245+
# wake up futures waiting for wait()
246+
for waiter in self._exit_waiters:
247+
if not waiter.cancelled():
248+
waiter.set_result(self._returncode)
249+
self._exit_waiters = None
250250
self._loop = None
251251
self._proc = None
252252
self._protocol = None

Lib/asyncio/base_tasks.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import linecache
2+
import reprlib
23
import traceback
34

45
from . import base_futures
@@ -8,20 +9,28 @@
89
def _task_repr_info(task):
910
info = base_futures._future_repr_info(task)
1011

11-
if task._must_cancel:
12+
if task.cancelling() and not task.done():
1213
# replace status
1314
info[0] = 'cancelling'
1415

1516
info.insert(1, 'name=%r' % task.get_name())
1617

17-
coro = coroutines._format_coroutine(task._coro)
18-
info.insert(2, f'coro=<{coro}>')
19-
2018
if task._fut_waiter is not None:
21-
info.insert(3, f'wait_for={task._fut_waiter!r}')
19+
info.insert(2, f'wait_for={task._fut_waiter!r}')
20+
21+
if task._coro:
22+
coro = coroutines._format_coroutine(task._coro)
23+
info.insert(2, f'coro=<{coro}>')
24+
2225
return info
2326

2427

28+
@reprlib.recursive_repr()
29+
def _task_repr(task):
30+
info = ' '.join(_task_repr_info(task))
31+
return f'<{task.__class__.__name__} {info}>'
32+
33+
2534
def _task_get_stack(task, limit):
2635
frames = []
2736
if hasattr(task._coro, 'cr_frame'):

Lib/asyncio/constants.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Contains code from https://github.com/MagicStack/uvloop/tree/v0.16.0
2+
# SPDX-License-Identifier: PSF-2.0 AND (MIT OR Apache-2.0)
3+
# SPDX-FileCopyrightText: Copyright (c) 2015-2021 MagicStack Inc. http://magic.io
4+
15
import enum
26

37
# After the connection is lost, log warnings after this many write()s.
@@ -15,10 +19,20 @@
1519
# The default timeout matches that of Nginx.
1620
SSL_HANDSHAKE_TIMEOUT = 60.0
1721

22+
# Number of seconds to wait for SSL shutdown to complete
23+
# The default timeout mimics lingering_time
24+
SSL_SHUTDOWN_TIMEOUT = 30.0
25+
1826
# Used in sendfile fallback code. We use fallback for platforms
1927
# that don't support sendfile, or for TLS connections.
2028
SENDFILE_FALLBACK_READBUFFER_SIZE = 1024 * 256
2129

30+
FLOW_CONTROL_HIGH_WATER_SSL_READ = 256 # KiB
31+
FLOW_CONTROL_HIGH_WATER_SSL_WRITE = 512 # KiB
32+
33+
# Default timeout for joining the threads in the threadpool
34+
THREAD_JOIN_TIMEOUT = 300
35+
2236
# The enum should be here to break circular dependencies between
2337
# base_events and sslproto
2438
class _SendfileMode(enum.Enum):

Lib/asyncio/coroutines.py

Lines changed: 4 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,18 @@
1-
__all__ = 'coroutine', 'iscoroutinefunction', 'iscoroutine'
1+
__all__ = 'iscoroutinefunction', 'iscoroutine'
22

33
import collections.abc
4-
import functools
54
import inspect
65
import os
76
import sys
8-
import traceback
97
import types
10-
import warnings
11-
12-
from . import base_futures
13-
from . import constants
14-
from . import format_helpers
15-
from .log import logger
168

179

1810
def _is_debug_mode():
19-
# If you set _DEBUG to true, @coroutine will wrap the resulting
20-
# generator objects in a CoroWrapper instance (defined below). That
21-
# instance will log a message when the generator is never iterated
22-
# over, which may happen when you forget to use "await" or "yield from"
23-
# with a coroutine call.
24-
# Note that the value of the _DEBUG flag is taken
25-
# when the decorator is used, so to be of any use it must be set
26-
# before you define your coroutines. A downside of using this feature
27-
# is that tracebacks show entries for the CoroWrapper.__next__ method
28-
# when _DEBUG is true.
11+
# See: https://docs.python.org/3/library/asyncio-dev.html#asyncio-debug-mode.
2912
return sys.flags.dev_mode or (not sys.flags.ignore_environment and
3013
bool(os.environ.get('PYTHONASYNCIODEBUG')))
3114

3215

33-
_DEBUG = _is_debug_mode()
34-
35-
36-
class CoroWrapper:
37-
# Wrapper for coroutine object in _DEBUG mode.
38-
39-
def __init__(self, gen, func=None):
40-
assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen
41-
self.gen = gen
42-
self.func = func # Used to unwrap @coroutine decorator
43-
self._source_traceback = format_helpers.extract_stack(sys._getframe(1))
44-
self.__name__ = getattr(gen, '__name__', None)
45-
self.__qualname__ = getattr(gen, '__qualname__', None)
46-
47-
def __repr__(self):
48-
coro_repr = _format_coroutine(self)
49-
if self._source_traceback:
50-
frame = self._source_traceback[-1]
51-
coro_repr += f', created at {frame[0]}:{frame[1]}'
52-
53-
return f'<{self.__class__.__name__} {coro_repr}>'
54-
55-
def __iter__(self):
56-
return self
57-
58-
def __next__(self):
59-
return self.gen.send(None)
60-
61-
def send(self, value):
62-
return self.gen.send(value)
63-
64-
def throw(self, type, value=None, traceback=None):
65-
return self.gen.throw(type, value, traceback)
66-
67-
def close(self):
68-
return self.gen.close()
69-
70-
@property
71-
def gi_frame(self):
72-
return self.gen.gi_frame
73-
74-
@property
75-
def gi_running(self):
76-
return self.gen.gi_running
77-
78-
@property
79-
def gi_code(self):
80-
return self.gen.gi_code
81-
82-
def __await__(self):
83-
return self
84-
85-
@property
86-
def gi_yieldfrom(self):
87-
return self.gen.gi_yieldfrom
88-
89-
def __del__(self):
90-
# Be careful accessing self.gen.frame -- self.gen might not exist.
91-
gen = getattr(self, 'gen', None)
92-
frame = getattr(gen, 'gi_frame', None)
93-
if frame is not None and frame.f_lasti == -1:
94-
msg = f'{self!r} was never yielded from'
95-
tb = getattr(self, '_source_traceback', ())
96-
if tb:
97-
tb = ''.join(traceback.format_list(tb))
98-
msg += (f'\nCoroutine object created at '
99-
f'(most recent call last, truncated to '
100-
f'{constants.DEBUG_STACK_DEPTH} last lines):\n')
101-
msg += tb.rstrip()
102-
logger.error(msg)
103-
104-
105-
def coroutine(func):
106-
"""Decorator to mark coroutines.
107-
108-
If the coroutine is not yielded from before it is destroyed,
109-
an error message is logged.
110-
"""
111-
warnings.warn('"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead',
112-
DeprecationWarning,
113-
stacklevel=2)
114-
if inspect.iscoroutinefunction(func):
115-
# In Python 3.5 that's all we need to do for coroutines
116-
# defined with "async def".
117-
return func
118-
119-
if inspect.isgeneratorfunction(func):
120-
coro = func
121-
else:
122-
@functools.wraps(func)
123-
def coro(*args, **kw):
124-
res = func(*args, **kw)
125-
if (base_futures.isfuture(res) or inspect.isgenerator(res) or
126-
isinstance(res, CoroWrapper)):
127-
res = yield from res
128-
else:
129-
# If 'res' is an awaitable, run it.
130-
try:
131-
await_meth = res.__await__
132-
except AttributeError:
133-
pass
134-
else:
135-
if isinstance(res, collections.abc.Awaitable):
136-
res = yield from await_meth()
137-
return res
138-
139-
coro = types.coroutine(coro)
140-
if not _DEBUG:
141-
wrapper = coro
142-
else:
143-
@functools.wraps(func)
144-
def wrapper(*args, **kwds):
145-
w = CoroWrapper(coro(*args, **kwds), func=func)
146-
i F438 f w._source_traceback:
147-
del w._source_traceback[-1]
148-
# Python < 3.5 does not implement __qualname__
149-
# on generator objects, so we set it manually.
150-
# We use getattr as some callables (such as
151-
# functools.partial may lack __qualname__).
152-
w.__name__ = getattr(func, '__name__', None)
153-
w.__qualname__ = getattr(func, '__qualname__', None)
154-
return w
155-
156-
wrapper._is_coroutine = _is_coroutine # For iscoroutinefunction().
157-
return wrapper
158-
159-
16016
# A marker for iscoroutinefunction.
16117
_is_coroutine = object()
16218

@@ -169,8 +25,7 @@ def iscoroutinefunction(func):
16925

17026
# Prioritize native coroutine check to speed-up
17127
# asyncio.iscoroutine.
172-
_COROUTINE_TYPES = (types.CoroutineType, types.GeneratorType,
173-
collections.abc.Coroutine, CoroWrapper)
28+
_COROUTINE_TYPES = (types.CoroutineType, collections.abc.Coroutine)
17429
_iscoroutine_typecache = set()
17530

17631

@@ -193,16 +48,11 @@ def iscoroutine(obj):
19348
def _format_coroutine(coro):
19449
assert iscoroutine(coro)
19550

196-
is_corowrapper = isinstance(coro, CoroWrapper)
197-
19851
def get_name(coro):
19952
# Coroutines compiled with Cython sometimes don't have
20053
# proper __qualname__ or __name__. While that is a bug
20154
# in Cython, asyncio shouldn't crash with an AttributeError
20255
# in its __repr__ functions.
203-
if is_corowrapper:
204-
return format_helpers._format_callback(coro.func, (), {})
205-
20656
if hasattr(coro, '__qualname__') and coro.__qualname__:
20757
coro_name = coro.__qualname__
20858
elif hasattr(coro, '__name__') and coro.__name__:
@@ -247,18 +97,8 @@ def is_running(coro):
24797
filename = coro_code.co_filename or '<empty co_filename>'
24898

24999
lineno = 0
250-
if (is_corowrapper and
251-
coro.func is not None and
252-
not inspect.isgeneratorfunction(coro.func)):
253-
source = format_helpers._get_function_source(coro.func)
254-
if source is not None:
255-
filename, lineno = source
256-
if coro_frame is None:
257-
coro_repr = f'{coro_name} done, defined at {filename}:{lineno}'
258-
else:
259-
coro_repr = f'{coro_name} running, defined at {filename}:{lineno}'
260100

261-
elif coro_frame is not None:
101+
if coro_frame is not None:
262102
lineno = coro_frame.f_lineno
263103
coro_repr = f'{coro_name} running at {filename}:{lineno}'
264104

0 commit comments

Comments
 (0)
0