1414from .log import logger
1515
1616
17+ _PY35 = sys .version_info >= (3 , 5 )
18+
19+
1720# Opcode of "yield from" instruction
1821_YIELD_FROM = opcode .opmap ['YIELD_FROM' ]
1922
3033 and bool (os .environ .get ('PYTHONASYNCIODEBUG' )))
3134
3235
36+ try :
37+ types .coroutine
38+ except AttributeError :
39+ native_coroutine_support = False
40+ else :
41+ native_coroutine_support = True
42+
43+ try :
44+ _iscoroutinefunction = inspect .iscoroutinefunction
45+ except AttributeError :
46+ _iscoroutinefunction = lambda func : False
47+
48+ try :
49+ inspect .CO_COROUTINE
50+ except AttributeError :
51+ _is_native_coro_code = lambda code : False
52+ else :
53+ _is_native_coro_code = lambda code : (code .co_flags &
54+ inspect .CO_COROUTINE )
55+
56+
3357# Check for CPython issue #21209
3458def has_yield_from_bug ():
3559 class MyGen :
@@ -54,16 +78,27 @@ def yield_from_gen(gen):
5478del has_yield_from_bug
5579
5680
81+ def debug_wrapper (gen ):
82+ # This function is called from 'sys.set_coroutine_wrapper'.
83+ # We only wrap here coroutines defined via 'async def' syntax.
84+ # Generator-based coroutines are wrapped in @coroutine
85+ # decorator.
86+ if _is_native_coro_code (gen .gi_code ):
87+ return CoroWrapper (gen , None )
88+ else :
89+ return gen
90+
91+
5792class CoroWrapper :
5893 # Wrapper for coroutine object in _DEBUG mode.
5994
60- def __init__ (self , gen , func ):
61- assert inspect .isgenerator (gen ), gen
95+ def __init__ (self , gen , func = None ):
96+ assert inspect .isgenerator (gen ) or inspect . iscoroutine ( gen ) , gen
6297 self .gen = gen
63- self .func = func
98+ self .func = func # Used to unwrap @coroutine decorator
6499 self ._source_traceback = traceback .extract_stack (sys ._getframe (1 ))
65- # __name__, __qualname__, __doc__ attributes are set by the coroutine( )
66- # decorator
100+ self . __name__ = getattr ( gen , '__name__' , None )
101+ self . __qualname__ = getattr ( gen , '__qualname__' , None )
67102
68103 def __repr__ (self ):
69104 coro_repr = _format_coroutine (self )
@@ -75,6 +110,9 @@ def __repr__(self):
75110 def __iter__ (self ):
76111 return self
77112
113+ if _PY35 :
114+ __await__ = __iter__ # make compatible with 'await' expression
115+
78116 def __next__ (self ):
79117 return next (self .gen )
80118
@@ -133,6 +171,14 @@ def coroutine(func):
133171 If the coroutine is not yielded from before it is destroyed,
134172 an error message is logged.
135173 """
174+ is_coroutine = _iscoroutinefunction (func )
175+ if is_coroutine and _is_native_coro_code (func .__code__ ):
176+ # In Python 3.5 that's all we need to do for coroutines
177+ # defiend with "async def".
178+ # Wrapping in CoroWrapper will happen via
179+ # 'sys.set_coroutine_wrapper' function.
180+ return func
181+
136182 if inspect .isgeneratorfunction (func ):
137183 coro = func
138184 else :
@@ -144,18 +190,22 @@ def coro(*args, **kw):
144190 return res
145191
146192 if not _DEBUG :
147- wrapper = coro
193+ if native_coroutine_support :
194+ wrapper = types .coroutine (coro )
195+ else :
196+ wrapper = coro
148197 else :
149198 @functools .wraps (func )
150199 def wrapper (* args , ** kwds ):
151- w = CoroWrapper (coro (* args , ** kwds ), func )
200+ w = CoroWrapper (coro (* args , ** kwds ), func = func )
152201 if w ._source_traceback :
153202 del w ._source_traceback [- 1 ]
154- if hasattr (func , '__name__' ):
155- w .__name__ = func .__name__
156- if hasattr (func , '__qualname__' ):
157- w .__qualname__ = func .__qualname__
158- w .__doc__ = func .__doc__
203+ # Python < 3.5 does not implement __qualname__
204+ # on generator objects, so we set it manually.
205+ # We use getattr as some callables (such as
206+ # functools.partial may lack __qualname__).
207+ w .__name__ = getattr (func , '__name__' , None )
208+ w .__qualname__ = getattr (func , '__qualname__' , None )
159209 return w
160210
161211 wrapper ._is_coroutine = True # For iscoroutinefunction().
@@ -164,7 +214,8 @@ def wrapper(*args, **kwds):
164214
165215def iscoroutinefunction (func ):
166216 """Return True if func is a decorated coroutine function."""
167- return getattr (func , '_is_coroutine' , False )
217+ return (getattr (func , '_is_coroutine' , False ) or
218+ _iscoroutinefunction (func ))
168219
169220
170221_COROUTINE_TYPES = (types .GeneratorType , CoroWrapper )
0 commit comments