Update:
After few uncessful attempts to explain the problem, completely rewrote the question:
How to execute a function on startup?
from aiogram import Bot, Dispatcher, executor, types
API_TOKEN = 'API'
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)
#dp.message_handler()
async def echo(message: types.Message):
await message.answer(message.text)
async def notify_message() # THIS FUNCTION
# await bot.sendMessage(chat.id, 'Bot Started')
await print('Hello World')
if __name__ == '__main__':
notifty_message() # doesn't work
executor.start_polling(dp, skip_updates=True)
Tried without success::
if __name__ == '__main__':
dp.loop.create_task(notify_message()) # Function to execute
executor.start_polling(dp, skip_updates=True)
AttributeError: 'NoneType' object has no attribute 'create_task'
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.create_task(notify_message()) # Function to execute
executor.start_polling(dp, skip_updates=True)
TypeError: object NoneType can't be used in 'await' expression
If you want to iniate a dialogue, it's impossible, telegram doesn't allow bots to send first message. But if you want to save your users ids, you can make a database or just a txt file and write there any new user id. You will be able to send to all of them messages by inputing id from database instead of chat.id
I give you an example of how to send a message without using message.answer just use:
#dp.message_handler()
async def echo(message: types.Message):
await bot.send_message(message.chat.id, message.text)
I don't understand why you need to print ('The bot is running') When running "aiogram" it tells you that the bot was started
2021-06-01 09:31:42,729:INFO:Bot: YourBot [#YourBot]
2021-06-01 09:31:42,729:WARNING:Updates were skipped successfully.
2021-06-01 09:31:42,729:INFO:Start polling.
It was much simpler than expected. facepalm
Working Solution:
from aiogram import Bot, Dispatcher, executor, types
API_TOKEN = 'API'
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)
#dp.message_handler()
async def echo(message: types.Message):
await bot.send_message(message.chat.id, message.text)
def test_hi():
print("Hello World")
if __name__ == '__main__':
test_hi()
executor.start_polling(dp, skip_updates=True)
The second approach was correct, but asyncio event loop was not initialised. So, if it was important to call async function beside a bot, you would do:
from asyncio import get_event_loop
from aiogram import Bot, Dispatcher, executor, types
API_TOKEN = 'API'
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot=bot, loop=get_event_loop()) # Initialising event loop for the dispatcher
async def notify_message():
print('Hello World')
if __name__ == '__main__':
dp.loop.create_task(notify_message()) # Providing awaitable as an argument
executor.start_polling(dp, skip_updates=True)
you can call aiogram.executor.start(dispatcher, future) to run an async function (future)
from aiogram import Bot, Dispatcher, executor
bot = Bot(token='your_api_token')
dp = Dispatcher(bot)
async def notify_message() # THIS FUNCTION
# await bot.sendMessage(chat.id, 'Bot Started')
await print('Hello World')
#dp.message_handler()
async def echo(message: types.Message):
await message.answer(message.text)
if __name__ == '__main__':
executor.start(dp, notify_message())
executor.start_polling(dp, skip_updates=True)
Related
So, I'm trying to create a API with aiohttp that if you do /?state=start, it will call the my_Bot() function and start the bot itself. It is giving me multiple errors with a bunch of different ways I have tried. I have both the start/index function and my_Bot function async'ed and it is giving this error
RuntimeWarning: coroutine 'my_Bot' was never awaited my_Bot() RuntimeWarning: Enable tracemalloc to get the object allocation traceback
This is the code for the Python file. The index function is for loading the request and starting the bot and the my_Bot function is for actually loading/starting the Discord bot instance
import os
from dotenv import load_dotenv
import asyncio
load_dotenv()
app = web.Application()
async def index(request):
state = request.rel_url.query['state']
if state == 'start':
my_Bot()
return web.json_response({'state': 'Online'})
return web.FileResponse('index.html')
app.router.add_get('/', index)
app.router.add_get('/index', index)
app.router.add_get('/index.html', index)
async def get_token(request):
token = os.getenv('TOKEN')
return web.json_response({'token': token})
app.router.add_get('/token', get_token)
async def my_Bot():
import discord
from discord.ext import commands
bot = commands.Bot(command_prefix='>', self_bot=True)
#bot.event
async def on_ready():
print('Logged in as')
print(bot.user.name)
print(bot.user.id)
print('------')
#bot.command()
async def ping(ctx):
await ctx.send('pong')
bot.run(os.getenv('TOKEN'))
if __name__ == '__main__':
#my_Bot()
web.run_app(app)```
yeah because u typed async def my_bot so u should await it
you can make a function to run the bot asynchronously
async def main():
await my_Bot()
web.run_app(app)
if __name__ == '__main__':
asyncio.run(main())
I'm trying to record twitch chat messages while still recognizing commands, however, recording the messages using event_message seems to stop the command from working.
Anybody know how you would recognize/respond to commands and record message at the same time?
from twitchio.ext import commands
import time
from datetime import datetime
class Bot(commands.Bot):
def __init__(self):
super().__init__(
token='oauth:',
prefix='!',
initial_channels=['channelname']
)
# This function isn't running; event_message is stealing the input!
#commands.command(name='ping')
async def my_command(self, ctx):
print('Caught ping')
await ctx.send('pong')
# records the messages (or in this case, the time a message is sent)
async def event_message(self, message):
print(time.mktime(datetime.now().timetuple())) # prints the unix second
if __name__ == '__main__':
bot = Bot()
bot.run()
Reducing this down even more, the same issue occurs here; with the bot responding to the command, but not printing the message author or content:
from twitchio.ext import commands
import os
bot = commands.Bot(
token='', prefix="!", initial_channels=[""], client_id='', nick='', client_secret='')
#This isn't working; Should still grab the message author/name and print.
Ive tried twitchio versions between 1.3.0 and 2.3.0, but the issue persists.
#bot.event
async def event_message(ctx):
print(ctx.author.name)
print(ctx.content)
await bot.handle_commands(ctx)
#This is running
#bot.command(name='test')
async def test_command(ctx):
await ctx.send('this is a test response')
if __name__ == '__main__':
bot.run()
Issue was not including an "await bot.handle_commands(ctx)" command below the event_message function.
Attached below is a working code
from twitchio.ext import commands
class Bot(commands.Bot):
def __init__(self):
super().__init__(token='', prefix="!", initial_channels=[""])
#commands.command()
async def ping(self, ctx):
print('Caught Ping')
await ctx.send(f'Pong!')
async def event_message(self, message):
print(message.author.name, message.content)
await bot.handle_commands(message) # <--This is the new line
bot = Bot()
bot.run()
NOTE: An error is raised by the event_message function when the bot sees one of its' own messages in chat. This doesn't seem to inhibit function, but it can be fixed by changing the code to the following:
async def event_message(self, message):
if hasattr(message.author, 'name'): # <-- New Line
print(message.author.name, message.content)
await bot.handle_commands(message)
I have this code :
import asyncio
import aioconsole
async def imp():
print("Cool I'm printing")
await asyncio.sleep(2)
await imp()
async def console():
while True:
comm = await aioconsole.ainput(">>")
if 'cool' in comm:
await imp()
async def main():
console_use = asyncio.create_task(console())
await console_use
if __name__ == '__main__':
try:
asyncio.run(main())
except AttributeError:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
The problem is that when the code enter to the function imp() the console() function stops working and I would like to continue using the console for other functions. How can I solve that?
Ps. I tried doing threads, create tasks and nothing is working...
I am trying to use aiogram, but as a component of a larger application, most examples do the following call in the main after defining the callbacks>
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
What I am trying to implement is having the polling in a separate task which I can run concurrently with asyncio.gather() as shown below:
import asyncio
async def task1():
while True:
# Perform aiogram polling
await asyncio.sleep()
async def task2():
while True:
# Perform other application's component
await asyncio.sleep()
async def main():
await asyncio.gather(
task1(),
task2(),
)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
I searched in the code for the executor class, yet it performs an startup sequence and then calls itself the loop.get_event_loop() and loop.run_forever(),
Does aiogram have a built-in method for performing this?
The solution was to use the dispatcher directly rather than the executor utility as shown below:
async def task1():
await dp.start_polling()
async def task2():
while True:
# Perform other application's component
await asyncio.sleep(1)
async def main():
await asyncio.gather(
task1(),
task2(),
)
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())
Heyy,
how would I make my asynchronous code run on startup?
So this is the easiest example I could think of to make.
async def mainMenuCLI():
print("This is the CLI")
And I want the asynchronous mainMenuCLI to run on startup but I don't want it to take as many tasks because I'm not sure what is the max :(
I need it to be async because of async_input, discord.py and stuff, just don't tell me to make it sync, thanks!
If I understand your question... Do you need something likethis?
import asyncio
async def async_example():
print("hellooooo, I'm an async function")
async def main():
asyncio.Task(async_example())
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
You can add some tasks outside the async func if you need:
import asyncio
async def async_example():
print("hellooooo, I'm an async function")
await asyncio.sleep(1)
print("async function done")
async def main():
asyncio.Task(async_example())
print('This is before wait')
await asyncio.sleep(1)
print('This is after await')
await asyncio.sleep(1)
print('Ok, goodbye')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
*Note: if your py version is prior to 3.7, change asyncio.Task per asyncio.ensure_future.