coroutines.py
python
__all__ = ('iscoroutine',)
import collections.abc
import os
import sys
import types
def _is_debug_mode():
# См.: https://docs.python.org/3/library/asyncio-dev.html#asyncio-debug-mode.
return sys.flags.dev_mode or (not sys.flags.ignore_environment and
bool(os.environ.get('PYTHONASYNCIODEBUG')))
# Проверяйте в первую очередь нативные корутины для ускорения работы
# asyncio.iscoroutine.
_COROUTINE_TYPES = (types.CoroutineType, collections.abc.Coroutine)
_iscoroutine_typecache = set()
def iscoroutine(obj):
"""Возвращает True, если obj является объектом корутины."""
if type(obj) in _iscoroutine_typecache:
return True
if isinstance(obj, _COROUTINE_TYPES):
# На всякий случай не кэшируем более 100
# положительных типов. Этого не должно произойти, если только
# кто-то специально нагружает систему.
if len(_iscoroutine_typecache) < 100:
_iscoroutine_typecache.add(type(obj))
return True
else:
return False
def _format_coroutine(coro):
assert iscoroutine(coro)
def get_name(coro):
# Корутины, скомпилированные с Cython, иногда не имеют
# корректного __qualname__ или __name__. Хотя это ошибка
# в Cython, asyncio не должна падать с AttributeError
# в своих функциях __repr__.
if hasattr(coro, '__qualname__') and coro.__qualname__:
coro_name = coro.__qualname__
elif hasattr(coro, '__name__') and coro.__name__:
coro_name = coro.__name__
else:
# Прекратите маскировать ошибки Cython, показывайте их дружелюбным способом.
coro_name = f'<{type(coro).__name__} without __name__>'
return f'{coro_name}()'
def is_running(coro):
try:
return coro.cr_running
except AttributeError:
try:
return coro.gi_running
except AttributeError:
return False
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:
# Встроенные типы могут не иметь __qualname__ или __name__.
if is_running(coro):
return f'{coro_name} running'
else:
return coro_name
coro_frame = None
if hasattr(coro, 'gi_frame') and coro.gi_frame:
coro_frame = coro.gi_frame
elif hasattr(coro, 'cr_frame') and coro.cr_frame:
coro_frame = coro.cr_frame
# Если корутина Cython имеет фиктивный объект кода без корректного
# co_filename — покажите это.
filename = coro_code.co_filename or '<empty co_filename>'
lineno = 0
if coro_frame is not None:
lineno = coro_frame.f_lineno
coro_repr = f'{coro_name} running at {filename}:{lineno}'
else:
lineno = coro_code.co_firstlineno
coro_repr = f'{coro_name} done, defined at {filename}:{lineno}'
return coro_repr