Я использую асинхронную библиотеку (asyncpg) и хочу отладить некоторые асинхронные вызовы для запроса базы данных.

Я устанавливаю точку останова pdb и хочу попробовать несколько запросов:

(pdb) await asyncpg.fetch("select * from foo;")
*** SyntaxError: 'await' outside function

Было бы здорово иметь возможность сделать это, потому что это позволило бы мне попробовать несколько SQL-запросов и увидеть результат, не покидая своего отладчика.

Является ли это возможным?

25
LondonRob 15 Ноя 2019 в 14:34
2
asyncio.run(asyncpg.fetch("select * from foo;")) работает?
 – 
L3viathan
15 Ноя 2019 в 15:04
4
Я сомневаюсь, что это возможно сегодня, учитывая, что цикл событий asyncio не реентерабелен. Если ваша точка останова находится внутри асинхронной функции, это возможно теоретически , но очень нетривиально реализовать. Чтобы await работал, PDB необходимо изменить выполнение работающего генератора (как внутренняя реализация сопрограмм), чтобы обеспечить новую точку выхода (ожидания). Это сравнимо с тем, как при наличии точки останова внутри генератора вы не можете запустить yield bla из приглашения PDB.
 – 
user4815162342
15 Ноя 2019 в 15:07
 – 
amirouche
14 Янв 2020 в 10:09
1
Для этого есть открытый запрос функции, но действий не было: bugs.python.org/issue42045
 – 
shadowtalker
7 Апр 2021 в 18:13

2 ответа

У меня была аналогичная проблема с отладкой использования файла aiofile. Затем я нашел решение, используя nest_asyncio. Например, если у вас есть следующий пример сценария async:

import asyncio
from aiofile import async_open
import nest_asyncio


async def main():
    async with async_open("/tmp/hello.txt", 'w+') as afp:
        await afp.write("Hello ")
        await afp.write("world")
        afp.seek(0)
        breakpoint()
        print(await afp.read())


if __name__=="__main__":
    loop = asyncio.get_event_loop()
    nest_asyncio.apply(loop)
    loop.run_until_complete(main())

Затем можно сделать:

-> print(await afp.read())
(Pdb) loop = asyncio.get_event_loop()
(Pdb) loop.run_until_complete(afp.read())
'Hello world'
(Pdb) 

По общему признанию, это немного утомительнее, чем await asyncpg.fetch("select * from foo;") или await afp.read(), но он выполняет свою работу. Надеюсь, в будущем появится более элегантное решение.

1
M.D. 5 Июн 2021 в 10:34

Мы не можем напрямую отлаживать сопрограмму (поскольку, представьте, мы должны поместить pdb в функцию asyncpg.fetch, переопределив ее).

Вместо этого мы можем создать функцию синхронизации и преобразовать ее в асинхронную функцию, используя любой пакет, например awaits и и pdb:

Импортировать asyncio из awaits.awaitable импорт ожидает

@awaitable 
def overrided_fectch_function( a ,  b ): 
  print(a)
  import pdb; pdb.set_trace()
  return  a  +  b
  print(b)

# Now sum is a coroutine! While it is running in a separate thread, control is passed to the event-loop. 
print ( asyncio . run ( overrided_fectch_function ( 2 ,  2 )))
0
Siva Sankar 14 Июн 2021 в 14:50