1
0
mirror of https://github.com/eternnoir/pyTelegramBotAPI.git synced 2023-08-10 21:12:57 +03:00

States Update

This commit is contained in:
_run 2022-01-24 21:24:56 +04:00
parent 124b07ee44
commit 8045ad56ea
5 changed files with 101 additions and 38 deletions

View File

@ -1,14 +1,22 @@
import telebot import telebot
from telebot import asyncio_filters from telebot import asyncio_filters
from telebot.async_telebot import AsyncTeleBot from telebot.async_telebot import AsyncTeleBot
# list of storages, you can use any storage
from telebot.asyncio_storage import StateRedisStorage,StateMemoryStorage,StatePickleStorage
# new feature for states.
from telebot.asyncio_handler_backends import State, StatesGroup
bot = AsyncTeleBot('TOKEN') bot = AsyncTeleBot('TOKEN')
# Just create different statesgroup
class MyStates(StatesGroup):
name = State() # statesgroup should contain states
surname = State()
age = State()
class MyStates:
name = 1
surname = 2
age = 3
@ -17,7 +25,7 @@ async def start_ex(message):
""" """
Start command. Here we are starting state Start command. Here we are starting state
""" """
await bot.set_state(message.from_user.id, MyStates.name) await bot.set_state(message.from_user.id, MyStates.name, message.chat.id)
await bot.send_message(message.chat.id, 'Hi, write me a name') await bot.send_message(message.chat.id, 'Hi, write me a name')
@ -28,7 +36,7 @@ async def any_state(message):
Cancel state Cancel state
""" """
await bot.send_message(message.chat.id, "Your state was cancelled.") await bot.send_message(message.chat.id, "Your state was cancelled.")
await bot.delete_state(message.from_user.id) await bot.delete_state(message.from_user.id, message.chat.id)
@bot.message_handler(state=MyStates.name) @bot.message_handler(state=MyStates.name)
async def name_get(message): async def name_get(message):
@ -36,8 +44,8 @@ async def name_get(message):
State 1. Will process when user's state is 1. State 1. Will process when user's state is 1.
""" """
await bot.send_message(message.chat.id, f'Now write me a surname') await bot.send_message(message.chat.id, f'Now write me a surname')
await bot.set_state(message.from_user.id, MyStates.surname) await bot.set_state(message.from_user.id, MyStates.surname, message.chat.id)
async with bot.retrieve_data(message.from_user.id) as data: async with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
data['name'] = message.text data['name'] = message.text
@ -47,16 +55,16 @@ async def ask_age(message):
State 2. Will process when user's state is 2. State 2. Will process when user's state is 2.
""" """
await bot.send_message(message.chat.id, "What is your age?") await bot.send_message(message.chat.id, "What is your age?")
await bot.set_state(message.from_user.id, MyStates.age) await bot.set_state(message.from_user.id, MyStates.age, message.chat.id)
async with bot.retrieve_data(message.from_user.id) as data: async with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
data['surname'] = message.text data['surname'] = message.text
# result # result
@bot.message_handler(state=MyStates.age, is_digit=True) @bot.message_handler(state=MyStates.age, is_digit=True)
async def ready_for_answer(message): async def ready_for_answer(message):
async with bot.retrieve_data(message.from_user.id) as data: async with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
await bot.send_message(message.chat.id, "Ready, take a look:\n<b>Name: {name}\nSurname: {surname}\nAge: {age}</b>".format(name=data['name'], surname=data['surname'], age=message.text), parse_mode="html") await bot.send_message(message.chat.id, "Ready, take a look:\n<b>Name: {name}\nSurname: {surname}\nAge: {age}</b>".format(name=data['name'], surname=data['surname'], age=message.text), parse_mode="html")
await bot.delete_state(message.from_user.id) await bot.delete_state(message.from_user.id, message.chat.id)
#incorrect number #incorrect number
@bot.message_handler(state=MyStates.age, is_digit=False) @bot.message_handler(state=MyStates.age, is_digit=False)

View File

@ -1,14 +1,39 @@
import telebot import telebot # telebot
from telebot import custom_filters from telebot import custom_filters
from telebot.handler_backends import State, StatesGroup #States
bot = telebot.TeleBot("") # States storage
from telebot.storage import StateRedisStorage, StatePickleStorage, StateMemoryStorage
class MyStates: # Beginning from version 4.4.0+, we support storages.
name = 1 # StateRedisStorage -> Redis-based storage.
surname = 2 # StatePickleStorage -> Pickle-based storage.
age = 3 # For redis, you will need to install redis.
# Pass host, db, password, or anything else,
# if you need to change config for redis.
# Pickle requires path. Default path is in folder .state-saves.
# If you were using older version of pytba for pickle,
# you need to migrate from old pickle to new by using
# StatePickleStorage().convert_old_to_new()
# Now, you can pass storage to bot.
state_storage = StateMemoryStorage() # you can init here another storage
bot = telebot.TeleBot("TOKEN",
state_storage=state_storage)
# States group.
class MyStates(StatesGroup):
# Just name variables differently
name = State() # creating instances of State class is enough from now
surname = State()
age = State()
@ -17,18 +42,18 @@ def start_ex(message):
""" """
Start command. Here we are starting state Start command. Here we are starting state
""" """
bot.set_state(message.from_user.id, MyStates.name) bot.set_state(message.from_user.id, MyStates.name, message.chat.id)
bot.send_message(message.chat.id, 'Hi, write me a name') bot.send_message(message.chat.id, 'Hi, write me a name')
# Any state
@bot.message_handler(state="*", commands='cancel') @bot.message_handler(state="*", commands='cancel')
def any_state(message): def any_state(message):
""" """
Cancel state Cancel state
""" """
bot.send_message(message.chat.id, "Your state was cancelled.") bot.send_message(message.chat.id, "Your state was cancelled.")
bot.delete_state(message.from_user.id) bot.delete_state(message.from_user.id, message.chat.id)
@bot.message_handler(state=MyStates.name) @bot.message_handler(state=MyStates.name)
def name_get(message): def name_get(message):
@ -36,8 +61,8 @@ def name_get(message):
State 1. Will process when user's state is 1. State 1. Will process when user's state is 1.
""" """
bot.send_message(message.chat.id, f'Now write me a surname') bot.send_message(message.chat.id, f'Now write me a surname')
bot.set_state(message.from_user.id, MyStates.surname) bot.set_state(message.from_user.id, MyStates.surname, message.chat.id)
with bot.retrieve_data(message.from_user.id) as data: with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
data['name'] = message.text data['name'] = message.text
@ -47,16 +72,16 @@ def ask_age(message):
State 2. Will process when user's state is 2. State 2. Will process when user's state is 2.
""" """
bot.send_message(message.chat.id, "What is your age?") bot.send_message(message.chat.id, "What is your age?")
bot.set_state(message.from_user.id, MyStates.age) bot.set_state(message.from_user.id, MyStates.age, message.chat.id)
with bot.retrieve_data(message.from_user.id) as data: with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
data['surname'] = message.text data['surname'] = message.text
# result # result
@bot.message_handler(state=MyStates.age, is_digit=True) @bot.message_handler(state=MyStates.age, is_digit=True)
def ready_for_answer(message): def ready_for_answer(message):
with bot.retrieve_data(message.from_user.id) as data: with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
bot.send_message(message.chat.id, "Ready, take a look:\n<b>Name: {name}\nSurname: {surname}\nAge: {age}</b>".format(name=data['name'], surname=data['surname'], age=message.text), parse_mode="html") bot.send_message(message.chat.id, "Ready, take a look:\n<b>Name: {name}\nSurname: {surname}\nAge: {age}</b>".format(name=data['name'], surname=data['surname'], age=message.text), parse_mode="html")
bot.delete_state(message.from_user.id) bot.delete_state(message.from_user.id, message.chat.id)
#incorrect number #incorrect number
@bot.message_handler(state=MyStates.age, is_digit=False) @bot.message_handler(state=MyStates.age, is_digit=False)
@ -68,7 +93,4 @@ def age_incorrect(message):
bot.add_custom_filter(custom_filters.StateFilter(bot)) bot.add_custom_filter(custom_filters.StateFilter(bot))
bot.add_custom_filter(custom_filters.IsDigitFilter()) bot.add_custom_filter(custom_filters.IsDigitFilter())
# set saving states into file.
bot.enable_saving_states() # you can delete this if you do not need to save states
bot.infinity_polling(skip_pending=True) bot.infinity_polling(skip_pending=True)

View File

@ -364,12 +364,13 @@ class AsyncTeleBot:
handler_error = None handler_error = None
data = {} data = {}
process_handler = True process_handler = True
middleware_result = await middleware.pre_process(message, data) if middleware:
if isinstance(middleware_result, SkipHandler): middleware_result = await middleware.pre_process(message, data)
await middleware.post_process(message, data, handler_error) if isinstance(middleware_result, SkipHandler):
process_handler = False await middleware.post_process(message, data, handler_error)
if isinstance(middleware_result, CancelUpdate): process_handler = False
return if isinstance(middleware_result, CancelUpdate):
return
for handler in handlers: for handler in handlers:
if not process_handler: if not process_handler:
break break
@ -2481,8 +2482,8 @@ class AsyncTeleBot:
""" """
return await asyncio_helper.delete_chat_photo(self.token, chat_id) return await asyncio_helper.delete_chat_photo(self.token, chat_id)
async def get_my_commands(self, scope: Optional[types.BotCommandScope]=None, async def get_my_commands(self, scope: Optional[types.BotCommandScope],
language_code: Optional[str]=None) -> List[types.BotCommand]: language_code: Optional[str]) -> List[types.BotCommand]:
""" """
Use this method to get the current list of the bot's commands. Use this method to get the current list of the bot's commands.
Returns List of BotCommand on success. Returns List of BotCommand on success.

View File

@ -17,3 +17,19 @@ class BaseMiddleware:
async def post_process(self, message, data, exception): async def post_process(self, message, data, exception):
raise NotImplementedError raise NotImplementedError
class State:
def __init__(self) -> None:
self.name = None
def __str__(self) -> str:
return self.name
class StatesGroup:
def __init_subclass__(cls) -> None:
# print all variables of a subclass
for name, value in cls.__dict__.items():
if not name.startswith('__') and not callable(value) and isinstance(value, State):
# change value of that variable
value.name = ':'.join((cls.__name__, name))

View File

@ -148,4 +148,20 @@ class RedisHandlerBackend(HandlerBackend):
self.clear_handlers(handler_group_id) self.clear_handlers(handler_group_id)
return handlers return handlers
class State:
def __init__(self) -> None:
self.name = None
def __str__(self) -> str:
return self.name
class StatesGroup:
def __init_subclass__(cls) -> None:
# print all variables of a subclass
for name, value in cls.__dict__.items():
if not name.startswith('__') and not callable(value) and isinstance(value, State):
# change value of that variable
value.name = ':'.join((cls.__name__, name))