coroutines.py 8.6 KB

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