Сообщить об ошибке.

Включение режима отладки в asyncio в Python

По умолчанию модуль asyncio работает в режиме production. Для облегчения разработки в asyncio есть режим отладки.

Есть несколько способов включить режим отладки asyncio:

Содержание:


loop.get_debug():

Метод loop.get_debug() проверяет, включен ли режим отладки цикла событий.

Если для переменной среды PYTHONASYNCIODEBUG задана непустая строка, то возвращает True, в противном случае - False.

loop.set_debug(enabled: bool):

Метод loop.set_debug() устанавливает режим отладки цикла событий.

В режиме отладки вводятся дополнительные проверки времени выполнения, которые слишком дороги, чтобы их можно было включить по умолчанию. Новые предупреждения выдаются только при обнаружении проблемы.

Изменено в версии 3.7: режим разработки Python теперь также можно использовать для включения режима отладки.

Что делает включенный режим отладки?

  • Модуль asyncio проверяет наличие непредвиденных сопрограмм и выводит их, что позволяет сразу увидеть ошибки "забытого ожидания await".
  • Многие небезопасные асинхронные API-интерфейсы (например, методы loop.call_soon() и loop.call_at()) вызывают исключение, если они вызываются из неправильного потока.
  • Если выполнение операции ввода/вывода занимает слишком много времени, то выводится время выполнения селектора ввода/вывода.
  • Записываются обратные вызовы, занимающие более 100 мс. Для установки их минимальной продолжительности выполнения в секундах, которая должна считаться медленной, можно использовать атрибут цикла событий loop.slow_callback_duration.

Что еще можно использовать для лучшей информативности?

Пример включения режима отладки:

import os
os.environ['PYTHONASYNCIODEBUG'] = '1'
import asyncio
import logging, warnings

logging.basicConfig(level=logging.DEBUG)
warnings.resetwarnings()

# устаревший декоратор
@asyncio.coroutine
def dummy():
    # в асинхронном генераторе
    # нет вызова `yielded from` 
    print('=> dummy run!')

async def startdummy():
    print('=> calling dummy')
    dummy()

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    print(loop.get_debug())
    loop.run_until_complete(startdummy())


# test.py:10: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
#   def dummy():
# DEBUG:asyncio:Using selector: EpollSelector
# True
# => calling dummy
# ERROR:asyncio:<CoroWrapper dummy() running, defined at test.py:9, created at test.py:16> was never yielded from
# Coroutine object created at (most recent call last, truncated to 10 last lines):
#   File "test.py", line 21, in <module>
#     loop.run_until_complete(startdummy())
#   ...
#   File "test.py", line 16, in startdummy
#     dummy()