PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/asyncio/coroutines.py

https://bitbucket.org/mirror/cpython/
Python | 309 lines | 227 code | 50 blank | 32 comment | 48 complexity | d6ba0fb3ffff281824c42f7ccd3d1549 MD5 | raw file
Possible License(s): Unlicense, 0BSD, BSD-3-Clause
  1. __all__ = ['coroutine',
  2. 'iscoroutinefunction', 'iscoroutine']
  3. import functools
  4. import inspect
  5. import opcode
  6. import os
  7. import sys
  8. import traceback
  9. import types
  10. from . import compat
  11. from . import events
  12. from . import futures
  13. from .log import logger
  14. # Opcode of "yield from" instruction
  15. _YIELD_FROM = opcode.opmap['YIELD_FROM']
  16. # If you set _DEBUG to true, @coroutine will wrap the resulting
  17. # generator objects in a CoroWrapper instance (defined below). That
  18. # instance will log a message when the generator is never iterated
  19. # over, which may happen when you forget to use "yield from" with a
  20. # coroutine call. Note that the value of the _DEBUG flag is taken
  21. # when the decorator is used, so to be of any use it must be set
  22. # before you define your coroutines. A downside of using this feature
  23. # is that tracebacks show entries for the CoroWrapper.__next__ method
  24. # when _DEBUG is true.
  25. _DEBUG = (not sys.flags.ignore_environment and
  26. bool(os.environ.get('PYTHONASYNCIODEBUG')))
  27. try:
  28. _types_coroutine = types.coroutine
  29. except AttributeError:
  30. _types_coroutine = None
  31. try:
  32. _inspect_iscoroutinefunction = inspect.iscoroutinefunction
  33. except AttributeError:
  34. _inspect_iscoroutinefunction = lambda func: False
  35. try:
  36. from collections.abc import Coroutine as _CoroutineABC, \
  37. Awaitable as _AwaitableABC
  38. except ImportError:
  39. _CoroutineABC = _AwaitableABC = None
  40. # Check for CPython issue #21209
  41. def has_yield_from_bug():
  42. class MyGen:
  43. def __init__(self):
  44. self.send_args = None
  45. def __iter__(self):
  46. return self
  47. def __next__(self):
  48. return 42
  49. def send(self, *what):
  50. self.send_args = what
  51. return None
  52. def yield_from_gen(gen):
  53. yield from gen
  54. value = (1, 2, 3)
  55. gen = MyGen()
  56. coro = yield_from_gen(gen)
  57. next(coro)
  58. coro.send(value)
  59. return gen.send_args != (value,)
  60. _YIELD_FROM_BUG = has_yield_from_bug()
  61. del has_yield_from_bug
  62. def debug_wrapper(gen):
  63. # This function is called from 'sys.set_coroutine_wrapper'.
  64. # We only wrap here coroutines defined via 'async def' syntax.
  65. # Generator-based coroutines are wrapped in @coroutine
  66. # decorator.
  67. return CoroWrapper(gen, None)
  68. class CoroWrapper:
  69. # Wrapper for coroutine object in _DEBUG mode.
  70. def __init__(self, gen, func=None):
  71. assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen
  72. self.gen = gen
  73. self.func = func # Used to unwrap @coroutine decorator
  74. self._source_traceback = traceback.extract_stack(sys._getframe(1))
  75. self.__name__ = getattr(gen, '__name__', None)
  76. self.__qualname__ = getattr(gen, '__qualname__', None)
  77. def __repr__(self):
  78. coro_repr = _format_coroutine(self)
  79. if self._source_traceback:
  80. frame = self._source_traceback[-1]
  81. coro_repr += ', created at %s:%s' % (frame[0], frame[1])
  82. return '<%s %s>' % (self.__class__.__name__, coro_repr)
  83. def __iter__(self):
  84. return self
  85. def __next__(self):
  86. return self.gen.send(None)
  87. if _YIELD_FROM_BUG:
  88. # For for CPython issue #21209: using "yield from" and a custom
  89. # generator, generator.send(tuple) unpacks the tuple instead of passing
  90. # the tuple unchanged. Check if the caller is a generator using "yield
  91. # from" to decide if the parameter should be unpacked or not.
  92. def send(self, *value):
  93. frame = sys._getframe()
  94. caller = frame.f_back
  95. assert caller.f_lasti >= 0
  96. if caller.f_code.co_code[caller.f_lasti] != _YIELD_FROM:
  97. value = value[0]
  98. return self.gen.send(value)
  99. else:
  100. def send(self, value):
  101. return self.gen.send(value)
  102. def throw(self, exc):
  103. return self.gen.throw(exc)
  104. def close(self):
  105. return self.gen.close()
  106. @property
  107. def gi_frame(self):
  108. return self.gen.gi_frame
  109. @property
  110. def gi_running(self):
  111. return self.gen.gi_running
  112. @property
  113. def gi_code(self):
  114. return self.gen.gi_code
  115. if compat.PY35:
  116. def __await__(self):
  117. cr_await = getattr(self.gen, 'cr_await', None)
  118. if cr_await is not None:
  119. raise RuntimeError(
  120. "Cannot await on coroutine {!r} while it's "
  121. "awaiting for {!r}".format(self.gen, cr_await))
  122. return self
  123. @property
  124. def gi_yieldfrom(self):
  125. return self.gen.gi_yieldfrom
  126. @property
  127. def cr_await(self):
  128. return self.gen.cr_await
  129. @property
  130. def cr_running(self):
  131. return self.gen.cr_running
  132. @property
  133. def cr_code(self):
  134. return self.gen.cr_code
  135. @property
  136. def cr_frame(self):
  137. return self.gen.cr_frame
  138. def __del__(self):
  139. # Be careful accessing self.gen.frame -- self.gen might not exist.
  140. gen = getattr(self, 'gen', None)
  141. frame = getattr(gen, 'gi_frame', None)
  142. if frame is None:
  143. frame = getattr(gen, 'cr_frame', None)
  144. if frame is not None and frame.f_lasti == -1:
  145. msg = '%r was never yielded from' % self
  146. tb = getattr(self, '_source_traceback', ())
  147. if tb:
  148. tb = ''.join(traceback.format_list(tb))
  149. msg += ('\nCoroutine object created at '
  150. '(most recent call last):\n')
  151. msg += tb.rstrip()
  152. logger.error(msg)
  153. def coroutine(func):
  154. """Decorator to mark coroutines.
  155. If the coroutine is not yielded from before it is destroyed,
  156. an error message is logged.
  157. """
  158. if _inspect_iscoroutinefunction(func):
  159. # In Python 3.5 that's all we need to do for coroutines
  160. # defiend with "async def".
  161. # Wrapping in CoroWrapper will happen via
  162. # 'sys.set_coroutine_wrapper' function.
  163. return func
  164. if inspect.isgeneratorfunction(func):
  165. coro = func
  166. else:
  167. @functools.wraps(func)
  168. def coro(*args, **kw):
  169. res = func(*args, **kw)
  170. if isinstance(res, futures.Future) or inspect.isgenerator(res) or \
  171. isinstance(res, CoroWrapper):
  172. res = yield from res
  173. elif _AwaitableABC is not None:
  174. # If 'func' returns an Awaitable (new in 3.5) we
  175. # want to run it.
  176. try:
  177. await_meth = res.__await__
  178. except AttributeError:
  179. pass
  180. else:
  181. if isinstance(res, _AwaitableABC):
  182. res = yield from await_meth()
  183. return res
  184. if not _DEBUG:
  185. if _types_coroutine is None:
  186. wrapper = coro
  187. else:
  188. wrapper = _types_coroutine(coro)
  189. else:
  190. @functools.wraps(func)
  191. def wrapper(*args, **kwds):
  192. w = CoroWrapper(coro(*args, **kwds), func=func)
  193. if w._source_traceback:
  194. del w._source_traceback[-1]
  195. # Python < 3.5 does not implement __qualname__
  196. # on generator objects, so we set it manually.
  197. # We use getattr as some callables (such as
  198. # functools.partial may lack __qualname__).
  199. w.__name__ = getattr(func, '__name__', None)
  200. w.__qualname__ = getattr(func, '__qualname__', None)
  201. return w
  202. wrapper._is_coroutine = True # For iscoroutinefunction().
  203. return wrapper
  204. def iscoroutinefunction(func):
  205. """Return True if func is a decorated coroutine function."""
  206. return (getattr(func, '_is_coroutine', False) or
  207. _inspect_iscoroutinefunction(func))
  208. _COROUTINE_TYPES = (types.GeneratorType, CoroWrapper)
  209. if _CoroutineABC is not None:
  210. _COROUTINE_TYPES += (_CoroutineABC,)
  211. def iscoroutine(obj):
  212. """Return True if obj is a coroutine object."""
  213. return isinstance(obj, _COROUTINE_TYPES)
  214. def _format_coroutine(coro):
  215. assert iscoroutine(coro)
  216. coro_name = None
  217. if isinstance(coro, CoroWrapper):
  218. func = coro.func
  219. coro_name = coro.__qualname__
  220. if coro_name is not None:
  221. coro_name = '{}()'.format(coro_name)
  222. else:
  223. func = coro
  224. if coro_name is None:
  225. coro_name = events._format_callback(func, ())
  226. try:
  227. coro_code = coro.gi_code
  228. except AttributeError:
  229. coro_code = coro.cr_code
  230. try:
  231. coro_frame = coro.gi_frame
  232. except AttributeError:
  233. coro_frame = coro.cr_frame
  234. filename = coro_code.co_filename
  235. lineno = 0
  236. if (isinstance(coro, CoroWrapper) and
  237. not inspect.isgeneratorfunction(coro.func) and
  238. coro.func is not None):
  239. source = events._get_function_source(coro.func)
  240. if source is not None:
  241. filename, lineno = source
  242. if coro_frame is None:
  243. coro_repr = ('%s done, defined at %s:%s'
  244. % (coro_name, filename, lineno))
  245. else:
  246. coro_repr = ('%s running, defined at %s:%s'
  247. % (coro_name, filename, lineno))
  248. elif coro_frame is not None:
  249. lineno = coro_frame.f_lineno
  250. coro_repr = ('%s running at %s:%s'
  251. % (coro_name, filename, lineno))
  252. else:
  253. lineno = coro_code.co_firstlineno
  254. coro_repr = ('%s done, defined at %s:%s'
  255. % (coro_name, filename, lineno))
  256. return coro_repr