Не могу использовать bot.polling() и Schedule вместе

Рейтинг: 0Ответов: 1Опубликовано: 26.06.2023

Есть телеграм бот на библиотеке telebot. Я хочу вызывать функцию notification_14_days каждый день и пытаюсь использовать для этого библиотеку schedule, но не получается использовать ее вместе с bot.polling.

Вычитал, что для этого надо разделить скрипт на 2 потока с помощью threading: в одном - schedule, в другом - остальной бот. И я не понимаю как это сделать.

Видел примеры, где в потоки добавляют одиночные функции, но не понимаю как запихнуть всю логику бота в один поток, а schedule во второй, ведь бот - это не одна функция.

import telebot
from telebot import types
import sqlite3
import datetime
from datetime import date
from datetime import datetime


bot = telebot.TeleBot('6197050938:AAH_ugNgg5CtmrOUsJZKYIuNxtC2EJevliY')


# Declaring /start command. Database initiating
@bot.message_handler(commands=['start'])
def startinit(message):

    # declare database

    conn = sqlite3.connect('coralbirthdaydb.sql')
    cur = conn.cursor()
    cur.execute('CREATE TABLE IF NOT EXISTS users (id integer PRIMARY KEY AUTOINCREMENT, name varchar(50), '
                'chatid varchar(50), DOB date)')
    cur.execute('CREATE TABLE IF NOT EXISTS present_list (chatid varchar(50) PRIMARY KEY, present varchar(255))')
    conn.commit()
    cur.close()
    conn.close()

    # start screen markup
    markup = types.InlineKeyboardMarkup()
    regbtn = types.InlineKeyboardButton('Registration', callback_data='registration')
    infobtn = types.InlineKeyboardButton('Info', callback_data='info')
    userlistbtn = types.InlineKeyboardButton('List of Users', callback_data='userlist')
    dltbtn = types.InlineKeyboardButton('Delete My User', callback_data='delete')
    notifbtn = types.InlineKeyboardButton('Check notification', callback_data='notification')
    preslistbtn = types.InlineKeyboardButton('Presents list', callback_data='preslist')
    updatepreslist = types.InlineKeyboardButton('Update my Birthday preferences', callback_data='updatepreslist')
    markup.row(regbtn)
    markup.row(infobtn, userlistbtn, dltbtn)
    markup.row(notifbtn, preslistbtn)
    markup.row(updatepreslist)
    bot.send_message(message.chat.id, 'Hi!\nMy name\'s Coral Birthday Bot!\nI\'m here to help '
                                      'you with the Birthday greetings.\nHow can I help you now?', reply_markup=markup)


# Handles button clicks
@bot.callback_query_handler(func=lambda callback: True)
def callback_message(callback):
    if callback.data == 'registration':
        bot.register_next_step_handler(bot.send_message(callback.message.chat.id, 'Please enter your Date of Birth'),
                                       dob_registration)
    elif callback.data == 'userlist':
        user_list(callback.message)
    elif callback.data == 'delete':
        user_delete(callback.message)
    elif callback.data == 'notification':
        notification_14_days()
    elif callback.data == 'preslist':
        show_present_list(callback.message)
    elif callback.data == 'updatepreslist':
        bot.register_next_step_handler(bot.send_message(callback.message.chat.id, 'What present do you want'
                                                                                  ' for'
                                                                                  ' your next Birthday?'), get_present_list)


# Updates user present wishes and commits them to db
def get_present_list(message):
    conn = sqlite3.connect('coralbirthdaydb.sql')
    cur = conn.cursor()
    print(f'{message.chat.id}\n{message.text}\n')
    cur.execute("INSERT INTO present_list (chatid, present) VALUES('%s','%s') "
                "ON CONFLICT(chatid) DO UPDATE SET present = excluded.present" % (message.chat.id, message.text))
    conn.commit()
    cur.close()
    conn.close()
    startinit(bot.send_message(message.chat.id, 'We have registered your birthday wish!'))


#shows all users' wished presents
def show_present_list(message):
    conn = sqlite3.connect('coralbirthdaydb.sql')
    cur = conn.cursor()
    cur.execute('SELECT * FROM present_list')
    presents = cur.fetchall()
    info = ''
    for i in presents:
        info += f'ChatId: {i[0]}, Present: {i[1]}\n\n'
    cur.close()
    conn.close()
    startinit(bot.send_message(message.chat.id, info))


# Registers user DOB
def dob_registration(message):
    global dob_value
    dob_value = message.text.strip()
    date_format = '%Y-%m-%d'
    try:
        dateformat = datetime.strptime(dob_value, date_format)
    except ValueError:
        bot.register_next_step_handler(bot.send_message(message.chat.id, 'Incorrect data format, should be '
                                                                         'YYYY-MM-DD\nTry again'), dob_registration)
        return
    namemsg = bot.send_message(message.chat.id, 'Enter your Full Name')
    bot.register_next_step_handler(namemsg, name_registration)


# Registers User Name
def name_registration(message):
    global name_value
    if len(message.text.split()) > 1:
        name_value = message.text
        user_commit(message)
    else:
        bot.register_next_step_handler(bot.send_message(message.chat.id, 'Enter a valid full name'), name_registration)


# commits new user to DB if not exist
def user_commit(message):
    conn = sqlite3.connect('coralbirthdaydb.sql')
    users = conn.cursor()
    users.execute('SELECT * FROM users')
    for i in users:
        if str(i[2]) == str(message.chat.id):
            users.close()
            conn.close()
            startinit(bot.send_message(message.chat.id, 'Your user is already registered'))
            return

    new_user = conn.cursor()
    new_user.execute("INSERT INTO users (name, chatid, DOB) VALUES "
                        "('%s', '%s', '%s')" % (name_value, message.chat.id, dob_value))
    conn.commit()
    new_user.close()
    conn.close()
    startinit(bot.send_message(message.chat.id, 'You were successfully registered!'))


# Shows User list
def user_list(message):
    conn = sqlite3.connect('coralbirthdaydb.sql')
    cur = conn.cursor()
    cur.execute('SELECT * FROM users')
    users = cur.fetchall()
    info = ''
    for i in users:
        info += f'ID: {i[0]}, Name: {i[1]}, ChatId: {i[2]}, Date of Birth: {i[3]}\n\n'
    cur.close()
    conn.close()
    if info != '':
       startinit(bot.send_message(message.chat.id, info))
    else:
        startinit(bot.send_message(message.chat.id, 'Where are no users in the system'))


# deletes your user
def user_delete(message):
    conn = sqlite3.connect('coralbirthdaydb.sql')
    user = conn.cursor()
    user.execute("DELETE FROM users where chatid='%s'" % message.chat.id)
    conn.commit()
    user.close()
    conn.close()
    startinit(bot.send_message(message.chat.id, 'Your user was removed from the system'))


# Notifies birthday user and all other users that it is
# 2 weeks before the birthday. Asks to update birthday preference
def notification_14_days():
        print('executed\n')
        todaydate = date.today()
        conn = sqlite3.connect('coralbirthdaydb.sql')
        cur = conn.cursor()
        cur.execute('SELECT chatid, DOB FROM users')
        users = cur.fetchall()
        for i in users:
            birthdate = i[1]
            birthdate = datetime.strptime(birthdate, '%Y-%m-%d').replace(year=2023)
            todaydate = datetime.combine(todaydate, datetime.min.time()).replace(year=2023)
            day_interval = birthdate - todaydate
            ix = str(day_interval).index(' ')
            str_day_interval = str(day_interval)[0:ix]
            if str_day_interval == '7':
                bot.send_message(i[0], 'Yoy are having a birthday in 2 weeks!\n'
                                       'Please update your Birthday present wish')

        cur.close()
        conn.close()


# makes bot run continuously
bot.polling(none_stop = True)

Ответы

▲ 1

Разобрался

Если есть бот наподобие:

@bot.message_handler(commands=['start'])
def startinit(message):
    print('I entered start command\n')


def notification_14_days():
    print('This func needs to run every 5 srconds\n')


bot.polling(none_stop=True)

В котором вы хотите, чтобы функция notification_14_days() запускалась каждые 5 секунд и не конфликтовала с bot.polling(), сработает вот такая структура через threading:

import threading
import schedule
import time


def notification_14_days():
    print('This func needs to run every 5 srconds\n')  


def schedule_func():
    schedule.every(5).seconds.do(notification_14_days)
    while True:
        time.sleep(1)
        schedule.run_pending()


threading.Thread(target=schedule_func).start()


@bot.message_handler(commands=['start'])
def startinit(message):
     print('I entered start command\n')


bot.polling(none_stop=True)