Перейти к содержимому

Назад

coroutines.py

Lib/asyncio/coroutines.pyCPython 3.15
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