@NATASHA_PULIMET

Как вернуться из модуля обратно в main?

Здраствуйте, я начал писать тг бота на питоне, просто для интереса. Сразу решил разбить всё по модулям, на данный момент у меня есть: main.py, key.py, create_bot.py и пакет handlers внутри пакета два файла holidays.py, init .py.
init .py.

тут будут происходить все инициализации модулей

from Handlers import holidays

create_bot.py

тут обманка для пайтона, чтобы импортировать всё из одного файла в другой и обратно без ошибки

import telebot

from key import token

from telebot import types




bot=telebot.TeleBot(token)


main.py

По моей задумке в мейне будет происходить приветствие, первоначальная обработка клавиатуры(возможно не так выразился, далее поймете) и какие-то не большие функции состоящие из send_message, аля похвалить собеседника(понимаю, что это не очень хорошая структура, но мне хочется).

from bot_create import token, bot, types



@bot.message_handler(commands=['start'])

def start_message(message):

bot.send_message(message.chat.id,'Привет')

@bot.message_handler(commands=['button'])

def button_message(message):

markup=types.ReplyKeyboardMarkup(resize_keyboard=True)

item1=types.KeyboardButton("Кнопка")

markup.add(item1)

bot.send_message(message.chat.id,'Выберите что вам надо',reply_markup=markup)

@bot.message_handler(content_types='text')

def message_reply(message):

if message.text=="Кнопка":

from Handlers import holidays

holidays.holidays_button(message)

bot.infinity_polling()

holidays.py

собственно модуль срабатывающий после нажатия на кнопку выглядит так.

from bot_create import token, bot, types, webbrowser

@bot.message_handler(content_types='text')
def holidays_button(message):
mark=types.ReplyKeyboardMarkup(resize_keyboard=True)
btn=types.KeyboardButton('Вугар')
btn2=types.KeyboardButton('Алмаз')
btn3=types.KeyboardButton('Алексей')
btn4=types.KeyboardButton('Валера')
btn5=types.KeyboardButton('Никита')
btn6=types.KeyboardButton('Вернуться в меню')
mark.add(btn, btn2, btn3, btn4, btn5, btn6)
bot.send_message(message.chat.id, 'кто вас интересует?', reply_markup=mark)
bot.register_next_step_handler(message, who)
def who(message):
if message.text == 'Вугар':
file=open('Много работы. Джим Керри. Брюс Всемогущий.mp4', 'br')
bot.send_message(message.chat.id, 'держи')
bot.send_video(message.chat.id, file)
bot.register_next_step_handler(message, who)
elif message.text == 'Никита':
file=open('Yoru Fake.mp4', 'br')
bot.send_message(message.chat.id, 'держи')
bot.send_video(message.chat.id, file)
bot.register_next_step_handler(message, who)
elif message.text == "Валера":
file=open('а хуй его знает.mp4', 'br')
bot.send_message(message.chat.id, 'держи')
bot.send_video(message.chat.id, file)
bot.register_next_step_handler(message, who)
elif message.text == "Алексей":
file=open('Пока на расслабоне, на чиле.mp4', 'br')
bot.send_message(message.chat.id, 'держи')
bot.send_video(message.chat.id, file)
bot.register_next_step_handler(message, who)
elif message.text == "Алмаз":
bot.send_message(message.chat.id, 'держи')
webbrowser.open("https://www.youtube.com/watch?v=vO5h-9Ibmck")
bot.register_next_step_handler(message, who)
else:
print(1)

и в else тобишь при нажатии на Вернуться в меню. я хочу вернуться в мейн, к функции button_message, но не совсем понимаю как это сделать, я пытался импортировать как весь main, так и только button_message в holidays и вызвать функцию в блоке else. В таком случае при нажатие на кнопку "Кнопка" ловлю ошибку "raise ApiTelegramException(method_name, result, result_json)

telebot.apihelper.ApiTelegramException: A request to the Telegram API was unsuccessful. Error code: 409. Description: Conflict: terminated by other getUpdates request; make sure that only one bot instance is running"

при чём она появляется даже не при попытки использовать button_message в блоке else, она возникает при импорте мейна в модуле. При импорте всего main.py или только message_button в bot_create и из bot_create уже в holidays происходит ошибка циклического импорта. Так же я пытался вырезать функцию, засунуть в bot_create и оттуда уже использовать в мейне и holidays, но не понимаю как это реализовать.
Подскажите, как можно вернуться в main.
upd: попробовал импорт внутри функции
from main import button_message
    if message.text == 'Вугар':
        file=open('Много работы. Джим Керри. Брюс Всемогущий.mp4', 'br')
        bot.send_message(message.chat.id, 'держи')
        bot.send_video(message.chat.id, file)
        bot.register_next_step_handler(message, who)
    elif message.text == 'Никита':
        file=open('Yoru Fake.mp4', 'br')
        bot.send_message(message.chat.id, 'держи')
        bot.send_video(message.chat.id, file)
        bot.register_next_step_handler(message, who)
    elif message.text == "Валера":
        file=open('а хуй его знает.mp4', 'br')
        bot.send_message(message.chat.id, 'держи')
        bot.send_video(message.chat.id, file)
        bot.register_next_step_handler(message, who)
    elif message.text == "Алексей":
        file=open('Пока на расслабоне, на чиле.mp4', 'br')
        bot.send_message(message.chat.id, 'держи')
        bot.send_video(message.chat.id, file)
        bot.register_next_step_handler(message, who)
    elif message.text == "Алмаз":
        bot.send_message(message.chat.id, 'держи')
        webbrowser.open("https://rt.pornhub.com/video/search?search=60+plus+milf")
        bot.register_next_step_handler(message, who)
    else:
        print(1)

теперь ошибка "telebot.apihelper.ApiTelegramException: A request to the Telegram API was unsuccessful. Error code: 409. Description: Conflict: terminated by other getUpdates request; make sure that only one bot instance is running"
возникает при нажатии на "выйти в главное меню". Осталось понять как её решить
  • Вопрос задан
  • 45 просмотров
Решения вопроса 1
Vindicar
@Vindicar
RTFM!
Фигню творишь. Отношения между модулями должны быть строго односторонними - один модуль предоставляет сервис, другой его использует. В этом случае просто не будет необходимости в циклическом импорте.

Если же у тебя более сложная ситуация, придётся выкручиваться. Например: main описывает бота, который используется модулем, который уже предоставляет сервис через этого бота. Тут ситуация усложняется телеботом, который не особенно пригоден для многомодульных ботов. Хотя есть приём, который можно сравнить с внедрением зависимостей.

module1.py
# бота передаём как параметр внутрь функции install_module
# если у тебя будут другие глобальные ресурсы, скажем, соединение с СУБД, можно передавать их также
def install_module(bot) -> None:  
    # да, мы описываем функцию прямо внутри другой функции. Так можно
    @bot.message_handler(commands=['some_command', ])
    def my_command(message):
        ...  # тут логика команды

    # и ещё одну...
    @bot.message_handler(commands=['other_command', ])
    def my_other_command(message):
        ...  # тут логика команды

Тогда в main.py будет что-то вроде
import telebot
bot=telebot.TeleBot('TOKEN')
# импортируем и активируем модуль
import module1
module1.install_module(bot)  # install_module() модуля должна вызываться строго однажды
# модулей может быть несколько
import module2
module2.install_module(bot)
# когда всё установлено, запускаем бота
bot.infinity_polling()

Идею можно развить таким образом: пусть твои модули лежат не рядом с main.py, а в подпапке modules. Тогда можно сделать что-то такое, чтобы автоматически подгрузить все модули из этой папки при старте бота.
from pathlib import Path
import sys
import importlib

import telebot

bot=telebot.TeleBot('TOKEN')

MAIN_DIR = Path(sys.argv[0]).parent.resolve()  # папка где лежит скрипт бота
MODULES_DIR = MAIN_DIR / 'modules'  # лежащая рядом папка modules
for item in MODULES_DIR.glob('*'):   # перебираем файлы и папки в папке modules
    # игнорируем папки и файлы, начинающиеся с _ или с .
    if item.name.startswith('_') or item.name.startswith('.'):
        continue
    # item - это имя пригодного для импорта модуля?
    if (item.isfile() and item.name.endswith('.py')) or (item.isdir() and (item / '__init__.py').isfile()):
        # да импортируем и активируем модуль
        module = importlib.import_module('modules.'+item.name)
        module.install_module(bot)

# когда всё установлено, запускаем бота
bot.infinity_polling()
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы