coroutines.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. __all__ = 'coroutine', 'iscoroutinefunction', 'iscoroutine'
  2. import collections.abc
  3. import functools
  4. import inspect
  5. import os
  6. import sys
  7. import traceback
  8. import types
  9. from . import base_futures
  10. from . import constants
  11. from . import format_helpers
  12. from .log import logger
  13. def _is_debug_mode():
  14. # If you set _DEBUG to true, @coroutine will wrap the resulting
  15. # generator objects in a CoroWrapper instance (defined below). That
  16. # instance will log a message when the generator is never iterated
  17. # over, which may happen when you forget to use "await" or "yield from"
  18. # with a coroutine call.
  19. # Note that the value of the _DEBUG flag is taken
  20. # when the decorator is used, so to be of any use it must be set
  21. # before you define your coroutines. A downside of using this feature
  22. # is that tracebacks show entries for the CoroWrapper.__next__ method
  23. # when _DEBUG is true.
  24. return sys.flags.dev_mode or (not sys.flags.ignore_environment and
  25. bool(os.environ.get('PYTHONASYNCIODEBUG')))
  26. _DEBUG = _is_debug_mode()
  27. class CoroWrapper:
  28. # Wrapper for coroutine object in _DEBUG mode.
  29. def __init__(self, gen, func=None):
  30. assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen
  31. self.gen = gen
  32. self.func = func # Used to unwrap @coroutine decorator
  33. self._source_traceback = format_helpers.extract_stack(sys._getframe(1))
  34. self.__name__ = getattr(gen, '__name__', None)
  35. self.__qualname__ = getattr(gen, '__qualname__', None)
  36. def __repr__(self):
  37. coro_repr = _format_coroutine(self)
  38. if self._source_traceback:
  39. frame = self._source_traceback[-1]
  40. coro_repr += f', created at {frame[0]}:{frame[1]}'
  41. return f'<{self.__class__.__name__} {coro_repr}>'
  42. def __iter__(self):
  43. return self
  44. def __next__(self):
  45. return self.gen.send(None)
  46. def send(self, value):
  47. return self.gen.send(value)
  48. def throw(self, type, value=None, traceback=None):
  49. return self.gen.throw(type, value, traceback)
  50. def close(self):
  51. return self.gen.close()
  52. @property
  53. def gi_frame(self):
  54. return self.gen.gi_frame
  55. @property
  56. def gi_running(self):
  57. return self.gen.gi_running
  58. @property
  59. def gi_code(self):
  60. return self.gen.gi_code
  61. def __await__(self):
  62. return self
  63. @property
  64. def gi_yieldfrom(self):
  65. return self.gen.gi_yieldfrom
  66. def __del__(self):
  67. # Be careful accessing self.gen.frame -- self.gen might not exist.
  68. gen = getattr(self, 'gen', None)
  69. frame = getattr(gen, 'gi_frame', None)
  70. if frame is not None and frame.f_lasti == -1:
  71. msg = f'{self!r} was never yielded from'
  72. tb = getattr(self, '_source_traceback', ())
  73. if tb:
  74. tb = ''.join(traceback.format_list(tb))
  75. msg += (f'\nCoroutine object created at '
  76. f'(most recent call last, truncated to '
  77. f'{constants.DEBUG_STACK_DEPTH} last lines):\n')
  78. msg += tb.rstrip()
  79. logger.error(msg)
  80. def coroutine(func):
  81. """Decorator to mark coroutines.
  82. If the coroutine is not yielded from before it is destroyed,
  83. an error message is logged.
  84. """
  85. if inspect.iscoroutinefunction(func):
  86. # In Python 3.5 that's all we need to do for coroutines
  87. # defined with "async def".
  88. return func
  89. if inspect.isgeneratorfunction(func):
  90. coro = func
  91. else:
  92. @functools.wraps(func)
  93. def coro(*args, **kw):
  94. res = func(*args, **kw)
  95. if (base_futures.isfuture(res) or inspect.isgenerator(res) or
  96. isinstance(res, CoroWrapper)):
  97. res = yield from res
  98. else:
  99. # If 'res' is an awaitable, run it.
  100. try:
  101. await_meth = res.__await__
  102. except AttributeError:
  103. pass
  104. else:
  105. if isinstance(res, collections.abc.Awaitable):
  106. res = yield from await_meth()
  107. return res
  108. coro = types.coroutine(coro)
  109. if not _DEBUG:
  110. wrapper = coro
  111. else:
  112. @functools.wraps(func)
  113. def wrapper(*args, **kwds):
  114. w = CoroWrapper(coro(*args, **kwds), func=func)
  115. if w._source_traceback:
  116. del w._source_traceback[-1]
  117. # Python < 3.5 does not implement __qualname__
  118. # on generator objects, so we set it manually.
  119. # We use getattr as some callables (such as
  120. # functools.partial may lack __qualname__).
  121. w.__name__ = getattr(func, '__name__', None)
  122. w.__qualname__ = getattr(func, '__qualname__', None)
  123. return w
  124. wrapper._is_coroutine = _is_coroutine # For iscoroutinefunction().
  125. return wrapper
  126. # A marker for iscoroutinefunction.
  127. _is_coroutine = object()
  128. def iscoroutinefunction(func):
  129. """Return True if func is a decorated coroutine function."""
  130. return (inspect.iscoroutinefunction(func) or
  131. getattr(func, '_is_coroutine', None) is _is_coroutine)
  132. # Prioritize native coroutine check to speed-up
  133. # asyncio.iscoroutine.
  134. _COROUTINE_TYPES = (types.CoroutineType, types.GeneratorType,
  135. collections.abc.Coroutine, CoroWrapper)
  136. _iscoroutine_typecache = set()
  137. def iscoroutine(obj):
  138. """Return True if obj is a coroutine object."""
  139. if type(obj) in _iscoroutine_typecache:
  140. return True
  141. if isinstance(obj, _COROUTINE_TYPES):
  142. # Just in case we don't want to cache more than 100
  143. # positive types. That shouldn't ever happen, unless
  144. # someone stressing the system on purpose.
  145. if len(_iscoroutine_typecache) < 100:
  146. _iscoroutine_typecache.add(type(obj))
  147. return True
  148. else:
  149. return False
  150. def _format_coroutine(coro):
  151. assert iscoroutine(coro)
  152. is_corowrapper = isinstance(coro, CoroWrapper)
  153. def get_name(coro):
  154. # Coroutines compiled with Cython sometimes don't have
  155. # proper __qualname__ or __name__. While that is a bug
  156. # in Cython, asyncio shouldn't crash with an AttributeError
  157. # in its __repr__ functions.
  158. if is_corowrapper:
  159. return format_helpers._format_callback(coro.func, (), {})
  160. if hasattr(coro, '__qualname__') and coro.__qualname__:
  161. coro_name = coro.__qualname__
  162. elif hasattr(coro, '__name__') and coro.__name__:
  163. coro_name = coro.__name__
  164. else:
  165. # Stop masking Cython bugs, expose them in a friendly way.
  166. coro_name = f'<{type(coro).__name__} without __name__>'
  167. return f'{coro_name}()'
  168. def is_running(coro):
  169. try:
  170. return coro.cr_running
  171. except AttributeError:
  172. try:
  173. return coro.gi_running
  174. except AttributeError:
  175. return False
  176. coro_code = None
  177. if hasattr(coro, 'cr_code') and coro.cr_code:
  178. coro_code = coro.cr_code
  179. elif hasattr(coro, 'gi_code') and coro.gi_code:
  180. coro_code = coro.gi_code
  181. coro_name = get_name(coro)
  182. if not coro_code:
  183. # Built-in types might not have __qualname__ or __name__.
  184. if is_running(coro):
  185. return f'{coro_name} running'
  186. else:
  187. return coro_name
  188. coro_frame = None
  189. if hasattr(coro, 'gi_frame') and coro.gi_frame:
  190. coro_frame = coro.gi_frame
  191. elif hasattr(coro, 'cr_frame') and coro.cr_frame:
  192. coro_frame = coro.cr_frame
  193. # If Cython's coroutine has a fake code object without proper
  194. # co_filename -- expose that.
  195. filename = coro_code.co_filename or '<empty co_filename>'
  196. lineno = 0
  197. if (is_corowrapper and
  198. coro.func is not None and
  199. not inspect.isgeneratorfunction(coro.func)):
  200. source = format_helpers._get_function_source(coro.func)
  201. if source is not None:
  202. filename, lineno = source
  203. if coro_frame is None:
  204. coro_repr = f'{coro_name} done, defined at {filename}:{lineno}'
  205. else:
  206. coro_repr = f'{coro_name} running, defined at {filename}:{lineno}'
  207. elif coro_frame is not None:
  208. lineno = coro_frame.f_lineno
  209. coro_repr = f'{coro_name} running at {filename}:{lineno}'
  210. else:
  211. lineno = coro_code.co_firstlineno
  212. coro_repr = f'{coro_name} done, defined at {filename}:{lineno}'
  213. return coro_repr