| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  | __all__ = 'coroutine', 'iscoroutinefunction', 'iscoroutine' | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-19 07:18:45 -05:00
										 |  |  | import collections.abc | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | import functools | 
					
						
							|  |  |  | import inspect | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import traceback | 
					
						
							| 
									
										
										
										
											2014-06-30 14:39:11 +02:00
										 |  |  | import types | 
					
						
							| 
									
										
										
										
											2019-05-16 17:52:10 +03:00
										 |  |  | import warnings | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-28 12:52:37 -04:00
										 |  |  | from . import base_futures | 
					
						
							| 
									
										
										
										
											2017-12-15 07:04:38 +02:00
										 |  |  | from . import constants | 
					
						
							|  |  |  | from . import format_helpers | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | from .log import logger | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-30 14:39:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 07:14:07 -08:00
										 |  |  | def _is_debug_mode(): | 
					
						
							|  |  |  |     # 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 | 
					
						
							| 
									
										
										
										
											2017-12-11 17:35:49 +02:00
										 |  |  |     # over, which may happen when you forget to use "await" or "yield from" | 
					
						
							|  |  |  |     # with a coroutine call. | 
					
						
							|  |  |  |     # Note that the value of the _DEBUG flag is taken | 
					
						
							| 
									
										
										
										
											2017-11-20 07:14:07 -08:00
										 |  |  |     # when the decorator is used, so to be of any use it must be set | 
					
						
							|  |  |  |     # before you define your coroutines.  A downside of using this feature | 
					
						
							|  |  |  |     # is that tracebacks show entries for the CoroWrapper.__next__ method | 
					
						
							|  |  |  |     # when _DEBUG is true. | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |     return sys.flags.dev_mode or (not sys.flags.ignore_environment and | 
					
						
							|  |  |  |                                   bool(os.environ.get('PYTHONASYNCIODEBUG'))) | 
					
						
							| 
									
										
										
										
											2017-11-20 07:14:07 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _DEBUG = _is_debug_mode() | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-30 14:39:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | class CoroWrapper: | 
					
						
							| 
									
										
										
										
											2014-07-11 00:21:27 +02:00
										 |  |  |     # Wrapper for coroutine object in _DEBUG mode. | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-11 22:27:25 -04:00
										 |  |  |     def __init__(self, gen, func=None): | 
					
						
							|  |  |  |         assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |         self.gen = gen | 
					
						
							| 
									
										
										
										
											2016-01-11 08:42:49 +02:00
										 |  |  |         self.func = func  # Used to unwrap @coroutine decorator | 
					
						
							| 
									
										
										
										
											2017-12-15 07:04:38 +02:00
										 |  |  |         self._source_traceback = format_helpers.extract_stack(sys._getframe(1)) | 
					
						
							| 
									
										
										
										
											2015-05-11 22:27:25 -04:00
										 |  |  |         self.__name__ = getattr(gen, '__name__', None) | 
					
						
							|  |  |  |         self.__qualname__ = getattr(gen, '__qualname__', None) | 
					
						
							| 
									
										
										
										
											2014-07-05 15:29:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											2014-07-11 00:21:27 +02:00
										 |  |  |         coro_repr = _format_coroutine(self) | 
					
						
							|  |  |  |         if self._source_traceback: | 
					
						
							|  |  |  |             frame = self._source_traceback[-1] | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |             coro_repr += f', created at {frame[0]}:{frame[1]}' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return f'<{self.__class__.__name__} {coro_repr}>' | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __iter__(self): | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __next__(self): | 
					
						
							| 
									
										
										
										
											2015-05-31 21:37:09 -04:00
										 |  |  |         return self.gen.send(None) | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-29 18:23:43 +02:00
										 |  |  |     def send(self, value): | 
					
						
							|  |  |  |         return self.gen.send(value) | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-30 08:17:15 -07:00
										 |  |  |     def throw(self, type, value=None, traceback=None): | 
					
						
							|  |  |  |         return self.gen.throw(type, value, traceback) | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def close(self): | 
					
						
							|  |  |  |         return self.gen.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def gi_frame(self): | 
					
						
							|  |  |  |         return self.gen.gi_frame | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def gi_running(self): | 
					
						
							|  |  |  |         return self.gen.gi_running | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def gi_code(self): | 
					
						
							|  |  |  |         return self.gen.gi_code | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-28 14:43:52 +01:00
										 |  |  |     def __await__(self): | 
					
						
							|  |  |  |         return self | 
					
						
							| 
									
										
										
										
											2015-06-24 10:30:14 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-28 14:43:52 +01:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def gi_yieldfrom(self): | 
					
						
							|  |  |  |         return self.gen.gi_yieldfrom | 
					
						
							| 
									
										
										
										
											2015-07-03 00:41:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |     def __del__(self): | 
					
						
							|  |  |  |         # Be careful accessing self.gen.frame -- self.gen might not exist. | 
					
						
							|  |  |  |         gen = getattr(self, 'gen', None) | 
					
						
							|  |  |  |         frame = getattr(gen, 'gi_frame', None) | 
					
						
							|  |  |  |         if frame is not None and frame.f_lasti == -1: | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |             msg = f'{self!r} was never yielded from' | 
					
						
							| 
									
										
										
										
											2014-07-03 00:59:00 +02:00
										 |  |  |             tb = getattr(self, '_source_traceback', ()) | 
					
						
							|  |  |  |             if tb: | 
					
						
							|  |  |  |                 tb = ''.join(traceback.format_list(tb)) | 
					
						
							| 
									
										
										
										
											2017-11-07 17:23:29 +01:00
										 |  |  |                 msg += (f'\nCoroutine object created at ' | 
					
						
							|  |  |  |                         f'(most recent call last, truncated to ' | 
					
						
							|  |  |  |                         f'{constants.DEBUG_STACK_DEPTH} last lines):\n') | 
					
						
							| 
									
										
										
										
											2014-07-03 00:59:00 +02:00
										 |  |  |                 msg += tb.rstrip() | 
					
						
							|  |  |  |             logger.error(msg) | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def coroutine(func): | 
					
						
							|  |  |  |     """Decorator to mark coroutines.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     If the coroutine is not yielded from before it is destroyed, | 
					
						
							|  |  |  |     an error message is logged. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-05-16 17:52:10 +03:00
										 |  |  |     warnings.warn('"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead', | 
					
						
							|  |  |  |                   DeprecationWarning, | 
					
						
							|  |  |  |                   stacklevel=2) | 
					
						
							| 
									
										
										
										
											2017-11-29 18:23:43 +02:00
										 |  |  |     if inspect.iscoroutinefunction(func): | 
					
						
							| 
									
										
										
										
											2015-05-11 22:27:25 -04:00
										 |  |  |         # In Python 3.5 that's all we need to do for coroutines | 
					
						
							| 
									
										
										
										
											2017-06-24 07:18:54 +02:00
										 |  |  |         # defined with "async def". | 
					
						
							| 
									
										
										
										
											2015-05-11 22:27:25 -04:00
										 |  |  |         return func | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |     if inspect.isgeneratorfunction(func): | 
					
						
							|  |  |  |         coro = func | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         @functools.wraps(func) | 
					
						
							|  |  |  |         def coro(*args, **kw): | 
					
						
							|  |  |  |             res = func(*args, **kw) | 
					
						
							| 
									
										
										
										
											2016-10-28 12:52:37 -04:00
										 |  |  |             if (base_futures.isfuture(res) or inspect.isgenerator(res) or | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |                     isinstance(res, CoroWrapper)): | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |                 res = yield from res | 
					
						
							| 
									
										
										
										
											2017-11-29 18:23:43 +02:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |                 # If 'res' is an awaitable, run it. | 
					
						
							| 
									
										
										
										
											2015-05-30 21:02:12 -04:00
										 |  |  |                 try: | 
					
						
							|  |  |  |                     await_meth = res.__await__ | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 else: | 
					
						
							| 
									
										
										
										
											2017-12-19 07:18:45 -05:00
										 |  |  |                     if isinstance(res, collections.abc.Awaitable): | 
					
						
							| 
									
										
										
										
											2015-05-30 21:02:12 -04:00
										 |  |  |                         res = yield from await_meth() | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |             return res | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-24 12:14:33 -08:00
										 |  |  |     coro = types.coroutine(coro) | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |     if not _DEBUG: | 
					
						
							| 
									
										
										
										
											2018-01-24 12:14:33 -08:00
										 |  |  |         wrapper = coro | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |     else: | 
					
						
							|  |  |  |         @functools.wraps(func) | 
					
						
							|  |  |  |         def wrapper(*args, **kwds): | 
					
						
							| 
									
										
										
										
											2015-05-11 22:27:25 -04:00
										 |  |  |             w = CoroWrapper(coro(*args, **kwds), func=func) | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |             if w._source_traceback: | 
					
						
							|  |  |  |                 del w._source_traceback[-1] | 
					
						
							| 
									
										
										
										
											2015-05-11 22:27:25 -04:00
										 |  |  |             # Python < 3.5 does not implement __qualname__ | 
					
						
							|  |  |  |             # on generator objects, so we set it manually. | 
					
						
							|  |  |  |             # We use getattr as some callables (such as | 
					
						
							|  |  |  |             # functools.partial may lack __qualname__). | 
					
						
							|  |  |  |             w.__name__ = getattr(func, '__name__', None) | 
					
						
							|  |  |  |             w.__qualname__ = getattr(func, '__qualname__', None) | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |             return w | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-15 15:20:34 -05:00
										 |  |  |     wrapper._is_coroutine = _is_coroutine  # For iscoroutinefunction(). | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |     return wrapper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-15 15:20:34 -05:00
										 |  |  | # A marker for iscoroutinefunction. | 
					
						
							|  |  |  | _is_coroutine = object() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | def iscoroutinefunction(func): | 
					
						
							|  |  |  |     """Return True if func is a decorated coroutine function.""" | 
					
						
							| 
									
										
										
										
											2017-11-29 18:23:43 +02:00
										 |  |  |     return (inspect.iscoroutinefunction(func) or | 
					
						
							|  |  |  |             getattr(func, '_is_coroutine', None) is _is_coroutine) | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-29 18:23:43 +02:00
										 |  |  | # Prioritize native coroutine check to speed-up | 
					
						
							|  |  |  | # asyncio.iscoroutine. | 
					
						
							|  |  |  | _COROUTINE_TYPES = (types.CoroutineType, types.GeneratorType, | 
					
						
							| 
									
										
										
										
											2017-12-19 07:18:45 -05:00
										 |  |  |                     collections.abc.Coroutine, CoroWrapper) | 
					
						
							|  |  |  | _iscoroutine_typecache = set() | 
					
						
							| 
									
										
										
										
											2015-05-13 15:21:41 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-30 14:39:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | def iscoroutine(obj): | 
					
						
							|  |  |  |     """Return True if obj is a coroutine object.""" | 
					
						
							| 
									
										
										
										
											2017-12-19 07:18:45 -05:00
										 |  |  |     if type(obj) in _iscoroutine_typecache: | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if isinstance(obj, _COROUTINE_TYPES): | 
					
						
							|  |  |  |         # Just in case we don't want to cache more than 100 | 
					
						
							|  |  |  |         # positive types.  That shouldn't ever happen, unless | 
					
						
							|  |  |  |         # someone stressing the system on purpose. | 
					
						
							|  |  |  |         if len(_iscoroutine_typecache) < 100: | 
					
						
							|  |  |  |             _iscoroutine_typecache.add(type(obj)) | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _format_coroutine(coro): | 
					
						
							|  |  |  |     assert iscoroutine(coro) | 
					
						
							| 
									
										
										
										
											2015-05-02 18:38:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |     is_corowrapper = isinstance(coro, CoroWrapper) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_name(coro): | 
					
						
							|  |  |  |         # Coroutines compiled with Cython sometimes don't have | 
					
						
							|  |  |  |         # proper __qualname__ or __name__.  While that is a bug | 
					
						
							|  |  |  |         # in Cython, asyncio shouldn't crash with an AttributeError | 
					
						
							|  |  |  |         # in its __repr__ functions. | 
					
						
							|  |  |  |         if is_corowrapper: | 
					
						
							|  |  |  |             return format_helpers._format_callback(coro.func, (), {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if hasattr(coro, '__qualname__') and coro.__qualname__: | 
					
						
							|  |  |  |             coro_name = coro.__qualname__ | 
					
						
							|  |  |  |         elif hasattr(coro, '__name__') and coro.__name__: | 
					
						
							|  |  |  |             coro_name = coro.__name__ | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # Stop masking Cython bugs, expose them in a friendly way. | 
					
						
							|  |  |  |             coro_name = f'<{type(coro).__name__} without __name__>' | 
					
						
							|  |  |  |         return f'{coro_name}()' | 
					
						
							| 
									
										
										
										
											2016-10-05 19:32:49 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |     def is_running(coro): | 
					
						
							| 
									
										
										
										
											2016-10-05 19:32:49 -04:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |             return coro.cr_running | 
					
						
							| 
									
										
										
										
											2016-10-05 19:32:49 -04:00
										 |  |  |         except AttributeError: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |                 return coro.gi_running | 
					
						
							| 
									
										
										
										
											2016-10-05 19:32:49 -04:00
										 |  |  |             except AttributeError: | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |                 return False | 
					
						
							| 
									
										
										
										
											2016-10-05 19:32:49 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |     coro_code = None | 
					
						
							|  |  |  |     if hasattr(coro, 'cr_code') and coro.cr_code: | 
					
						
							|  |  |  |         coro_code = coro.cr_code | 
					
						
							|  |  |  |     elif hasattr(coro, 'gi_code') and coro.gi_code: | 
					
						
							|  |  |  |         coro_code = coro.gi_code | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     coro_name = get_name(coro) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not coro_code: | 
					
						
							|  |  |  |         # Built-in types might not have __qualname__ or __name__. | 
					
						
							|  |  |  |         if is_running(coro): | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |             return f'{coro_name} running' | 
					
						
							| 
									
										
										
										
											2016-10-05 19:32:49 -04:00
										 |  |  |         else: | 
					
						
							|  |  |  |             return coro_name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |     coro_frame = None | 
					
						
							|  |  |  |     if hasattr(coro, 'gi_frame') and coro.gi_frame: | 
					
						
							| 
									
										
										
										
											2015-06-24 10:30:14 -04:00
										 |  |  |         coro_frame = coro.gi_frame | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |     elif hasattr(coro, 'cr_frame') and coro.cr_frame: | 
					
						
							| 
									
										
										
										
											2015-06-24 10:30:14 -04:00
										 |  |  |         coro_frame = coro.cr_frame | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |     # If Cython's coroutine has a fake code object without proper | 
					
						
							|  |  |  |     # co_filename -- expose that. | 
					
						
							|  |  |  |     filename = coro_code.co_filename or '<empty co_filename>' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-11 08:42:49 +02:00
										 |  |  |     lineno = 0 | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |     if (is_corowrapper and | 
					
						
							|  |  |  |             coro.func is not None and | 
					
						
							|  |  |  |             not inspect.isgeneratorfunction(coro.func)): | 
					
						
							| 
									
										
										
										
											2017-12-15 07:04:38 +02:00
										 |  |  |         source = format_helpers._get_function_source(coro.func) | 
					
						
							| 
									
										
										
										
											2016-01-11 08:42:49 +02:00
										 |  |  |         if source is not None: | 
					
						
							|  |  |  |             filename, lineno = source | 
					
						
							| 
									
										
										
										
											2015-06-24 10:30:14 -04:00
										 |  |  |         if coro_frame is None: | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |             coro_repr = f'{coro_name} done, defined at {filename}:{lineno}' | 
					
						
							| 
									
										
										
										
											2014-07-11 00:21:27 +02:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |             coro_repr = f'{coro_name} running, defined at {filename}:{lineno}' | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-24 10:30:14 -04:00
										 |  |  |     elif coro_frame is not None: | 
					
						
							|  |  |  |         lineno = coro_frame.f_lineno | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |         coro_repr = f'{coro_name} running at {filename}:{lineno}' | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-29 00:46:45 +02:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2015-06-24 10:30:14 -04:00
										 |  |  |         lineno = coro_code.co_firstlineno | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |         coro_repr = f'{coro_name} done, defined at {filename}:{lineno}' | 
					
						
							| 
									
										
										
										
											2014-07-11 00:21:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return coro_repr |