Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b75380f

Browse files
committed
asyncio: sync with Tulip
- Sort imports - Simplify/optimize iscoroutine(). Inline inspect.isgenerator(obj): replace it with isinstance(obj, types.GeneratorType) - CoroWrapper: check at runtime if Python has the yield-from bug #21209. If Python has the bug, check if CoroWrapper.send() was called by yield-from to decide if parameters must be unpacked or not. - Fix "Task was destroyed but it is pending!" warning in test_task_source_traceback()
1 parent a6ec5ee commit b75380f

3 files changed

Lines changed: 52 additions & 10 deletions

File tree

Lib/asyncio/base_events.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
import heapq
2020
import inspect
2121
import logging
22+
import os
2223
import socket
2324
import subprocess
24-
import traceback
2525
import time
26-
import os
26+
import traceback
2727
import sys
2828

2929
from . import coroutines

Lib/asyncio/coroutines.py

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33

44
import functools
55
import inspect
6+
import opcode
67
import os
78
import sys
89
import traceback
10+
import types
911

1012
from . import events
1113
from . import futures
1214
from .log import logger
1315

16+
17+
# Opcode of "yield from" instruction
18+
_YIELD_FROM = opcode.opmap['YIELD_FROM']
19+
1420
# If you set _DEBUG to true, @coroutine will wrap the resulting
1521
# generator objects in a CoroWrapper instance (defined below). That
1622
# instance will log a message when the generator is never iterated
@@ -25,6 +31,31 @@
2531

2632
_PY35 = (sys.version_info >= (3, 5))
2733

34+
35+
# Check for CPython issue #21209
36+
def has_yield_from_bug():
37+
class MyGen:
38+
def __init__(self):
39+
self.send_args = None
40+
def __iter__(self):
41+
return self
42+
def __next__(self):
43+
return 42
44+
def send(self, *what):
45+
self.send_args = what
46+
return None
47+
def yield_from_gen(gen):
48+
yield from gen
49+
value = (1, 2, 3)
50+
gen = MyGen()
51+
coro = yield_from_gen(gen)
52+
next(coro)
53+
coro.send(value)
54+
return gen.send_args != (value,)
55+
_YIELD_FROM_BUG = has_yield_from_bug()
56+
del has_yield_from_bug
57+
58+
2859
class CoroWrapper:
2960
# Wrapper for coroutine in _DEBUG mode.
3061

@@ -40,13 +71,21 @@ def __iter__(self):
4071
def __next__(self):
4172
return next(self.gen)
4273

43-
def send(self, *value):
44-
# We use `*value` because of a bug in CPythons prior
45-
# to 3.4.1. See issue #21209 and test_yield_from_corowrapper
46-
# for details. This workaround should be removed in 3.5.0.
47-
if len(value) == 1:
48-
value = value[0]
49-
return self.gen.send(value)
74+
if _YIELD_FROM_BUG:
75+
# For for CPython issue #21209: using "yield from" and a custom
76+
# generator, generator.send(tuple) unpacks the tuple instead of passing
77+
# the tuple unchanged. Check if the caller is a generator using "yield
78+
# from" to decide if the parameter should be unpacked or not.
79+
def send(self, *value):
80+
frame = sys._getframe()
81+
caller = frame.f_back
82+
assert caller.f_lasti >= 0
83+
if caller.f_code.co_code[caller.f_lasti] != _YIELD_FROM:
84+
value = value[0]
85+
return self.gen.send(value)
86+
else:
87+
def send(self, value):
88+
return self.gen.send(value)
5089

5190
def throw(self, exc):
5291
return self.gen.throw(exc)
@@ -119,9 +158,11 @@ def iscoroutinefunction(func):
119158
return getattr(func, '_is_coroutine', False)
120159

121160

161+
_COROUTINE_TYPES = (CoroWrapper, types.GeneratorType)
162+
122163
def iscoroutine(obj):
123164
"""Return True if obj is a coroutine object."""
124-
return isinstance(obj, CoroWrapper) or inspect.isgenerator(obj)
165+
return isinstance(obj, _COROUTINE_TYPES)
125166

126167

127168
def _format_coroutine(coro):

Lib/test/test_asyncio/test_tasks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,7 @@ def test_task_source_traceback(self):
16211621
(__file__,
16221622
lineno,
16231623
'test_task_source_traceback'))
1624+
self.loop.run_until_complete(task)
16241625

16251626

16261627
class GatherTestsBase:

0 commit comments

Comments
 (0)