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

Skip to content
Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit bc8fb71

Browse files
CPython Developersyouknowone
CPython Developers
authored andcommitted
Update asyncio from CPython 3.12.3
1 parent 5a95a7e commit bc8fb71

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 F438 thing we can return to the decorator based 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):
10000 145-
w = CoroWrapper(coro(*args, **kwds), func=func)
146-
if 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