Telethon导致`RuntimeWarning:从未等待协程'MessageMethods.send_message'。

时间:2020-04-02 10:26:05

标签: python ipython python-asyncio telegram telethon

我正在尝试运行Telethon文档提供的this first code snippet。但是,在遇到多个问题(herehere)之后,我最终得到了这个修改后的版本:

import os
import sys
from telethon.sync import TelegramClient, events

# import nest_asyncio
# nest_asyncio.apply()

session_name = "<session_name>"
api_id = <api_id>
api_hash = "<api_hash>"


os.chdir(sys.path[0])

if f"{session_name}.session" in os.listdir():
    os.remove(f"{session_name}.session")

async with TelegramClient(session_name, api_id, api_hash) as client:
   client.send_message('me', 'Hello, myself!')
   print(client.download_profile_photo('me'))

   @client.on(events.NewMessage(pattern='(?i).*Hello'))
   async def handler(event):
      await event.reply('Hey!')

   client.run_until_disconnected()

但是现在我收到以下警告:

usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:23: RuntimeWarning: coroutine 'MessageMethods.send_message' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:24: RuntimeWarning: coroutine 'DownloadMethods.download_profile_photo' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:30: RuntimeWarning: coroutine 'UpdateMethods._run_until_disconnected' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

在Jupyter上运行代码时。现在这是我的问题:

  • 这些警告消息是什么意思,我该如何解决?
  • 如果正常工作,此代码的预期结果是什么?我应该在电报中收到消息吗?因为除了登录代码外,我不接收其他任何消息。
  • @行开头的@client.on...符号是什么意思?那条线应该做什么?从这一行开始,我不了解代码。如果您能帮助我理解它,将不胜感激。

2 个答案:

答案 0 :(得分:2)

Jupyter将运行asyncio事件循环,以便您可以在async for / with / await之外使用async def。这与Telethon的.sync魔术相冲突,在使用Jupyter,IPython或类似软件时,您应该尝试避免这种魔术。

要修改您的代码,请执行以下操作:

from telethon import TelegramClient, events
#            ^ note no .sync

session_name = "<session_name>"
api_id = <api_id>
api_hash = "<api_hash>"

async with TelegramClient(session_name, api_id, api_hash) as client:
    await client.send_message('me', 'Hello, myself!')
    # ^ note you need to use `await` in Jupyter
    # we are avoiding the `.sync` magic so it needs to be done by yourself

    print(await client.download_profile_photo('me'))
    #     ^ same here, needs await

    @client.on(events.NewMessage(pattern='(?i).*Hello'))
    async def handler(event):
        await event.reply('Hey!')

    await client.run_until_disconnected()
    # ^ once again needs await

如果您希望代码在任何地方运行(Jupyter,Python shell,正常运行),只需确保在async def内进行所有操作即可:

import asyncio

from telethon import TelegramClient, events

session_name = "<session_name>"
api_id = <api_id>
api_hash = "<api_hash>"

async def main():
    async with TelegramClient(session_name, api_id, api_hash) as client:
       await client.send_message('me', 'Hello, myself!')
       print(await client.download_profile_photo('me'))

       @client.on(events.NewMessage(pattern='(?i).*Hello'))
       async def handler(event):
           await event.reply('Hey!')

       await client.run_until_disconnected()

# Only this line changes, the rest will work anywhere.
# Jupyter
await main()

# Otherwise
asyncio.run(main())

答案 1 :(得分:1)

只需添加awaitclient.send_message('me', 'Hello, myself!')即可解决该错误,并在download_profile_photo完成工作后打印即可将图像下载到localhost,因此这就是为什么您不这样做的原因看到什么。您应该通读telethon documentationhow to use photo downloads correctly

所有对客户端的调用都有一个延迟,应始终等待,这样才不会阻塞您的代码。您应该阅读asyncio tutorial 正确的代码是:

async with TelegramClient(session_name, api_id, api_hash) as client:
   await client.send_message('me', 'Hello, myself!')
   print(await client.download_profile_photo('me'))

   @client.on(events.NewMessage(pattern='(?i).*Hello'))
   async def handler(event):
      await event.reply('Hey!')

   #await client.run_until_disconnected()

@是修饰符,您应该阅读PEP related to decorators,但简而言之,它们先执行一个函数。

在这种情况下,@client.on(events.NewMessage的意思是:

当有一个新事件碰巧是一条与指定模式匹配的消息时,请使用称为handler的此函数对其进行处理