У меня есть бот Discord, написанный с не переписанной версией discord.py, которая отправляет сообщение, похожее на сердцебиение (среди прочего). Я не знаю, правильно ли я понял, но из тестов я обнаружил, что мне нужно иметь функцию async def heartbeat()
в файле main.py
.
Выдержка из main.py
(сердцебиение работает как положено):
[...]
import asyncio
import datetime
from configparser import ConfigParser
startup_time = datetime.datetime.utcnow()
[...]
async def heartbeat():
await bot.wait_until_ready()
heartbeat_config = ConfigParser()
heartbeat_config.read('./config/config.ini')
hb_freq = int(heartbeat_config.get('Heartbeat', 'hb_freq')) # frequency of heartbeat message
hb_channel = heartbeat_config.get('Heartbeat', 'hb_channel') # target channel of heartbeat message
hb_channel = bot.get_channel(hb_channel) # get channel from bot's channels
await bot.send_message(hb_channel, "Starting up at: `" + str(startup_time) + "`")
await asyncio.sleep(hb_freq) # sleep for hb_freq seconds before entering loop
while not bot.is_closed:
now = datetime.datetime.utcnow() # time right now
tdelta = now - startup_time # time since startup
tdelta = tdelta - datetime.timedelta(microseconds=tdelta.microseconds) # remove microseconds from tdelta
beat = await bot.send_message(hb_channel, "Still running\nSince: `" + str(startup_time) + "`.\nCurrent uptime: `" + str(tdelta))
await asyncio.sleep(hb_freq) # sleep for hb_freq seconds before initialising next beat
await bot.delete_message(beat) # delete old beat so it can be replaced
[...]
if __name__ == "__main__":
global heartbeat_task
heartbeat_task = bot.loop.create_task(heartbeat()) # creates heartbeat task in the background
bot.run(token) # run bot
У меня есть несколько команд, которые должны взаимодействовать с созданным heartbeat_task
, но они находятся в другом модуле, который называется dev.py
(находится в том же каталоге, что и main.py
).
Выдержка из dev.py
:
[...]
from main import heartbeat_task, heartbeat
[...]
@commands.group(pass_context=True)
async def heart(self, ctx):
if ctx.invoked_subcommand is None:
return
@heart.command(pass_context=True)
async def stop(self, ctx):
# should cancel the task from main.py
heartbeat_task.cancel()
await self.bot.say('Heartbeat stopped by user {}'.format(ctx.message.author.name))
@heart.command(pass_context=True)
async def start(self, ctx):
# start the heartbeat if it is not running
global heartbeat_task
if heartbeat_task.cancelled():
heartbeat_task = self.bot.loop.create_task(heartbeat())
await self.bot.say('Heartbeat started by user {}'.format(ctx.message.author.name))
else:
return
[...]
Эти команды прекрасно работают, когда они являются частью main.py
(с необходимыми настройками, конечно, такими как удаление self
, импорт и т. Д.), Но так как я хочу, чтобы все связанные с разработчиком команды входили в модуль их, поэтому я попытался переместить их.
При попытке загрузить модуль появляется следующая ошибка:
ImportError: cannot import name 'heartbeat_task'.
Удаление этого импорта из dev.py
приводит к успешной загрузке модуля, но при использовании любой из команд консоль выдает ошибку:
NameError: name 'heartbeat_task' is not defined
Который восходит к линии heartbeat_task.cancel()
(в случае heart stop
// if heartbeat_task.cancelled():
(в случае heart start
).
Теперь мой вопрос.
Как я могу использовать async heartbeat()
в main.py
, но влиять на задачу с помощью команд в модуле dev.py
?
И если я не могу, каковы возможные альтернативы, которые держат команды в dev.py
(самой функции не нужно оставаться в main.py
, но предпочтительнее оставаться там)?
(Я искал довольно долгое время и не смог найти проблему, подобную моей, или решение, которое также помогло мне)