P
P
ProooNoob2021-11-12 15:31:03
Python
ProooNoob, 2021-11-12 15:31:03

How to implement different Telegram bot scripts in several files?

I welcome everyone!
I have files Main.py, Cicle_a.py, Cicle_b.py, in fact this is one script, but I would like to split it into several files for convenience.

Main.py has the usual Reply keyboard and click handlers:

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 implements the usual step-by-step survey bot.

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)


In Cycle_b.py, everything is the same, but with different questions and more.

There was such a problem, if you set bot.polling(none_stop=True) everywhere, then the bot stops processing messages altogether if in each file:
if __name__=='__main__':
    bot.polling(none_stop=True)

Then the bot works normally, responds to the menu call, when the "Questionnaire 1" key is pressed, it translates to "Enter data No. 1", but after receiving the text from the user, it does not translate further (i.e. the script does not move further than this step).
There are no errors, it also failed to catch, and you can call the /start command again.
As for me, the error lies precisely in the conditions of the side loops:
if __name__=='__main__':
    bot.polling(none_stop=True)

But I don’t have enough skills and I don’t understand how to do it right)
I would be very happy if someone tells me, gives an example or directs me on the right path in solving this problem, otherwise I’m already tormented with this, and it’s very difficult to put everything into one code I want to(

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
Vindicar, 2021-11-12
@ProooNoob

The problem is that you need to decorate the functions with @bot.whatever, but the other files don't know anything about the bot since it's described in the main file. So?
You need to consider how the decorator works. code like

@bot.message_handler(commands=['anketaone'])
def null_anketa_step(message):
    pass

actually works like this:
temp_wrapper = bot.message_handler(commands=['anketaone'])
def null_anketa_step(message):
    pass
null_anketa_step = temp_wrapper(null_anketa_step)

Those. in other words, a decorator is just a function call to which a function or class is passed!
Then the easiest way would be:
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)

Then in the main file you do something like this:
bot = ........ #создаём бота
from second_file import init_bot as init_second #импортируем второй файл
#функцию импортируем под другим именем, чтобы не было коллизий между файлами
init_second(bot) #вызываем функцию регистрации init_bot()

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

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question