@ProooNoob

Как реализовать разные скрипты Telegram bot'а в нескольких файлов?

Всех приветствую!
У меня есть файлы Main.py, Cicle_a.py, Cicle_b.py, по сути это один скрипт, но я хотел бы разнести его на несколько файлов для удобства.

В Main.py сделана обычная Reply клавиатура и обработчики нажатий:

import Config 
import Cycle_a
import Cycle_b

bot = telebot.TeleBot(Config.Token_Bot)


def menu_step(message):
    markup = types.ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True)
    markup.add('Анкета 1', 'Анкета 2')
    markup.add('Обратная связь')
    bot.send_message(message.chat.id, 'Выбери ниже', reply_markup=markup)

@bot.message_handler(content_types=['text'])
def menu_two_step(message):
    if message.text.lower() == 'анкета 1': 
        null_anketa_step(message)
    if message.text.lower() == 'анкета 2': 
        null_anketass_step(message)

if __name__=='__main__':
    bot.polling(none_stop=True)


В Cycle_a.py реализован обычный пошаговый бот для анкетирования.

import telebot
from telebot import types
import sqlite3
#import Main.py
#from Main.py import bot #Пробовал так для обращения к боту, но циклический импорт
from Config import Group_id

bot = telebot.TeleBot(Config.Token_Bot)

user_data = {}

class User:
    def __init__(self, datas):
        self.datas = datas
        self.datass = ''

conn = sqlite3.connect('DataBase.db', check_same_thread=False)
cursor = conn.cursor()

def db_table_val(user_id: int, dataone: str, datatwo: str):
    cursor.execute('INSERT INTO datatable (user_id, dataone, datatwo) VALUES (?, ?, ?)', (user_id, dataone, datatwo))
    conn.commit()

@bot.message_handler(commands=['anketaone'])
def null_anketa_step(message):
        msg = bot.send_message(message.chat.id, "Введите данные №1")
        bot.register_next_step_handler(msg, process_one_step)

def process_one_step(message):
    try:
        user_id = message.from_user.id
        user_data[user_id] = User(message.text)
        msg = bot.send_message(message.chat.id, 'Введите данные №2')
        bot.register_next_step_handler(msg, process_two_step)
    except Exception as e:
        bot.send_message(message.chat.id, 'Ошибка')

def process_two_step(message):
    try:
        user_id = message.from_user.id
        user = user_data[user_id]
        user_data[user_id] = User(message.text)
        db_table_val(user_id=user_id, dataone=user.datas, datatwo=user.datass)
        bot.send_message(message.chat.id, 'Вы успешно ввели все данные')
    except Exception as e:
        bot.send_message(message.chat.id, 'Ошибка')
        bot.send_message(Group_id, 'У вас новая анкета!')
 
if __name__=='__main__':
    bot.polling(none_stop=True)


В Cycle_b.py, все тоже самое, но с другими вопросами и в большим количестве.

Возникла такая проблема, если везде устанавливать bot.polling(none_stop=True) , то бот вообще перестаёт обрабатывать сообщения, если в каждом файле:
if __name__=='__main__':
    bot.polling(none_stop=True)

То бот нормально работает, реагирует на вызов меню, при нажатии клавиши "Анкета 1" переводит на "Введите данные №1", но после получения текста от пользователя не переводит дальше (т.е. скрипт дальше этого шага не двигается).
Ошибок никаких нет, отловить тоже не получилось и можно вызвать повторно команду /start
Как по мне ошибка состоит именно в условиях побочных циклов:
if __name__=='__main__':
    bot.polling(none_stop=True)

Но у меня недостаточно навыков и я не понимаю как правильно сделать)
Буду очень рад, если кто-то подскажет, приведет пример или направит на правильный путь в решении этой проблемы, а то уже замучился с этим, а все в один код сувать очень не хочется(
  • Вопрос задан
  • 1732 просмотра
Решения вопроса 1
Vindicar
@Vindicar
RTFM!
Проблема в том, что тебе нужно продекорировать функции через @bot.чтототам, но другие файлы ничего не знают о боте, так как он описан в главном файле. Так?
Нужно учесть, как работает декоратор. Код вроде
@bot.message_handler(commands=['anketaone'])
def null_anketa_step(message):
    pass

на самом деле работает примерно так:
temp_wrapper = bot.message_handler(commands=['anketaone'])
def null_anketa_step(message):
    pass
null_anketa_step = temp_wrapper(null_anketa_step)

Т.е. иными словами, декоратор - это просто вызов функции, в которую передаётся функция или класс!
Тогда самый простой способ будет таким:
def null_anketa_step(message):
    pass
#какой-то другой обработчик
def some_other_handler(message):
    pass

def init_bot(bot):
    #а в этой функции мы регистрируем обработчики
    bot.message_handler(commands=['anketaone']) (null_anketa_step)
    #обрати внимание на две пары скобок. Вызов bot.message_handler() возвращает функцию (wrapper),
    #и мы эту функцию тут же вызываем, передавая в неё обработчик
    bot.message_handler(commands=['somethingelse']) (some_other_handler)

Тогда в главном файле ты делаешь примерно так:
bot = ........ #создаём бота
from second_file import init_bot as init_second #импортируем второй файл
#функцию импортируем под другим именем, чтобы не было коллизий между файлами
init_second(bot) #вызываем функцию регистрации init_bot()

if __name__=='__main__':
    bot.polling(none_stop=True)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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