cpython: 8dc8c93e74c9 (original) (raw)
Mercurial > cpython
changeset 91484:8dc8c93e74c9
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() [#21209]
Victor Stinner victor.stinner@gmail.com | |
---|---|
date | Mon, 30 Jun 2014 14:39:47 +0200 |
parents | 69d474dab479(current diff)defd09a5339a(diff) |
children | 2d0fa8f383c8 |
files | Lib/test/test_asyncio/test_tasks.py |
diffstat | 3 files changed, 52 insertions(+), 10 deletions(-)[+] [-] Lib/asyncio/base_events.py 4 Lib/asyncio/coroutines.py 57 Lib/test/test_asyncio/test_tasks.py 1 |
line wrap: on
line diff
--- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -19,11 +19,11 @@ import concurrent.futures import heapq import inspect import logging +import os import socket import subprocess +import time import traceback -import time -import os import sys from . import coroutines
--- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -3,14 +3,20 @@ import functools import inspect +import opcode import os import sys import traceback +import types from . import events from . import futures from .log import logger + +# Opcode of "yield from" instruction +_YIELD_FROM = opcode.opmap['YIELD_FROM'] +
If you set _DEBUG to true, @coroutine will wrap the resulting
generator objects in a CoroWrapper instance (defined below). That
instance will log a message when the generator is never iterated
@@ -25,6 +31,31 @@ from .log import logger _PY35 = (sys.version_info >= (3, 5)) + +# Check for CPython issue #21209 +def has_yield_from_bug():
- class MyGen:
def __init__(self):[](#l2.32)
self.send_args = None[](#l2.33)
def __iter__(self):[](#l2.34)
return self[](#l2.35)
def __next__(self):[](#l2.36)
return 42[](#l2.37)
def send(self, *what):[](#l2.38)
self.send_args = what[](#l2.39)
return None[](#l2.40)
- def yield_from_gen(gen):
yield from gen[](#l2.42)
- value = (1, 2, 3)
- gen = MyGen()
- coro = yield_from_gen(gen)
- next(coro)
- coro.send(value)
- return gen.send_args != (value,)
+_YIELD_FROM_BUG = has_yield_from_bug() +del has_yield_from_bug + + class CoroWrapper: # Wrapper for coroutine in _DEBUG mode. @@ -40,13 +71,21 @@ class CoroWrapper: def next(self): return next(self.gen)
- def send(self, *value):
# We use `*value` because of a bug in CPythons prior[](#l2.61)
# to 3.4.1. See issue #21209 and test_yield_from_corowrapper[](#l2.62)
# for details. This workaround should be removed in 3.5.0.[](#l2.63)
if len(value) == 1:[](#l2.64)
value = value[0][](#l2.65)
return self.gen.send(value)[](#l2.66)
- if _YIELD_FROM_BUG:
# For for CPython issue #21209: using "yield from" and a custom[](#l2.68)
# generator, generator.send(tuple) unpacks the tuple instead of passing[](#l2.69)
# the tuple unchanged. Check if the caller is a generator using "yield[](#l2.70)
# from" to decide if the parameter should be unpacked or not.[](#l2.71)
def send(self, *value):[](#l2.72)
frame = sys._getframe()[](#l2.73)
caller = frame.f_back[](#l2.74)
assert caller.f_lasti >= 0[](#l2.75)
if caller.f_code.co_code[caller.f_lasti] != _YIELD_FROM:[](#l2.76)
value = value[0][](#l2.77)
return self.gen.send(value)[](#l2.78)
- else:
def send(self, value):[](#l2.80)
return self.gen.send(value)[](#l2.81)
def throw(self, exc): return self.gen.throw(exc) @@ -119,9 +158,11 @@ def iscoroutinefunction(func): return getattr(func, '_is_coroutine', False) +_COROUTINE_TYPES = (CoroWrapper, types.GeneratorType) + def iscoroutine(obj): """Return True if obj is a coroutine object."""
--- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1621,6 +1621,7 @@ class TaskTests(test_utils.TestCase): (file, lineno, 'test_task_source_traceback'))
self.loop.run_until_complete(task)[](#l3.7)