0

I keep getting an error in the following code

INFO:userbot:Starting userbot Ynjxsjmh
<coroutine object AuthMethods._start at 0x7fde36d996d0>
Traceback (most recent call last):
  File "userbot.py", line 58, in <module>
    asyncio.get_event_loop().run_until_complete(main())
  File "/home/winy/.pyenv/versions/3.6.8/lib/python3.6/asyncio/base_events.py", line 484, in run_until_complete
    return future.result()
  File "userbot.py", line 53, in main
    await bot.send_message_to_friends()
  File "userbot.py", line 47, in send_message_to_friends
    for friend in friends
  File "userbot.py", line 47, in <listcomp>
    for friend in friends
AttributeError: 'coroutine' object has no attribute 'send_message'
sys:1: RuntimeWarning: coroutine 'AuthMethods._start' was never awaited
import asyncio
import logging
import json
import sys
from configparser import ConfigParser
from os import listdir, path

from telethon import TelegramClient


class UserBot:
    """telegram user bot class."""

    def __init__(self):
        """init the userbot."""

        self.logger = logging.getLogger("userbot")
        config = ConfigParser()
        config.read(path.join(path.dirname(__file__), "config.ini"))

        for configsection in config:
            if ("api_id" in config[configsection] and
                "api_hash" in config[configsection]):
                self.api_id = config[configsection]["api_id"]
                self.api_hash = config[configsection]["api_hash"]
                self.name = configsection
            else:
                self.logger.warning(f"Invalid configration in {configsection}")

        try:
            client = TelegramClient(self.name, self.api_id, self.api_hash)
        except (NameError, AttributeError):
            raise ValueError("Invalid configration: need api_id and api_hash")

        self.logger.info(f"Starting userbot {self.name}")
        self.userbot = client.start()
        print(self.userbot)
        print(client.start())

    async def send_message_to_friends(self):
        friends = [
            '@friend1__username',
        ]

        # wait for all client.send_message to complete
        await asyncio.wait([
            self.userbot.send_message(friend, 'test')
            for friend in friends
        ])


async def main():
    bot = UserBot()
    await bot.send_message_to_friends()


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    asyncio.get_event_loop().run_until_complete(main())

However, the example I'm following doesn't give the error.

An example from An Introduction to Asyncio gives the following code:

# we will have to await things, so we need an async def
async def main(message):
    # start is a coroutine, so we need to await it to run it
    client = await TelegramClient('me', api_id, api_hash).start()

    # wait for all three client.send_message to complete
    await asyncio.wait([
        client.send_message(friend, message)
        for friend in friends
    ])

    # and close our client
    await client.disconnect()

It says start is a coroutine, so we need to await it to run it. So I think the problem in my code is that I don't await start at self.userbot = client.start().

My question is why the emacs-china-bot doesn't await start but still works. How can I modify my code to make it work except using importlib.util like what emacs-china-bot does.

I also see an example from Telethon Documentation

enter image description here

In this example, it uses with..as.. syntax rather than await start, how does this work?


I edit my code like what the poster in How to set class attribute with await in __init__ does:

import asyncio
import logging
import json
import sys
from configparser import ConfigParser
from os import listdir, path

from telethon import TelegramClient


class UserBot:
    """telegram user bot class."""

    def __init__(self):
        """init the userbot."""

        self.logger = logging.getLogger("userbot")
        config = ConfigParser()
        config.read(path.join(path.dirname(__file__), "config.ini"))

        for configsection in config:
            if ("api_id" in config[configsection] and
                "api_hash" in config[configsection]):
                self.api_id = config[configsection]["api_id"]
                self.api_hash = config[configsection]["api_hash"]
                self.name = configsection
            else:
                self.logger.warning(f"Invalid configration in {configsection}")

        try:
            self.client = TelegramClient(self.name, self.api_id, self.api_hash)
        except (NameError, AttributeError):
            raise ValueError("Invalid configration: need api_id and api_hash")

    async def async_init(self):
        self.logger.info(f"Starting userbot {self.name}")
        self.userbot = await self.client.start()

    async def send_message_to_friends(self):
        friends = [
            '@friend1__username',
        ]

        # wait for all client.send_message to complete
        await asyncio.wait([
            self.userbot.send_message(friend, 'test')
            for friend in friends
        ])


async def main():
    bot = UserBot()
    await bot.async_init()
    await bot.send_message_to_friends()


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    asyncio.get_event_loop().run_until_complete(main())

This question is still looking for answers why the emacs-china-bot doesn't await start but still works.

Ynjxsjmh
  • 16,448
  • 3
  • 17
  • 42
  • the example into Telethon docs use `sync` so it doesn't need await, you need to change your code to `await client.start()` – TheKill-996 Dec 24 '20 at 12:07
  • @TheKill-996 Thank you for your advice. If I change my code to `await client.start()`, I need to change init function to async. Now I'm following [`How to set class attribute with await in __init__ `](https://stackoverflow.com/questions/33128325/how-to-set-class-attribute-with-await-in-init) to make that change. – Ynjxsjmh Dec 24 '20 at 12:24

0 Answers0