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
from telebot import asyncio_filters
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')
# 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
"""
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')
@ -28,7 +36,7 @@ async def any_state(message):
Cancel state
"""
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)
async def name_get(message):
@ -36,8 +44,8 @@ async def name_get(message):
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.set_state(message.from_user.id, MyStates.surname)
async with bot.retrieve_data(message.from_user.id) as data:
await bot.set_state(message.from_user.id, MyStates.surname, message.chat.id)
async with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
data['name'] = message.text
@ -47,16 +55,16 @@ async def ask_age(message):
State 2. Will process when user's state is 2.
"""
await bot.send_message(message.chat.id, "What is your age?")
await bot.set_state(message.from_user.id, MyStates.age)
async with bot.retrieve_data(message.from_user.id) as data:
await bot.set_state(message.from_user.id, MyStates.age, message.chat.id)
async with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
data['surname'] = message.text
# result
@bot.message_handler(state=MyStates.age, is_digit=True)
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.delete_state(message.from_user.id)
await bot.delete_state(message.from_user.id, message.chat.id)
#incorrect number
@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.handler_backends import State, StatesGroup #States
bot = telebot.TeleBot("")
# States storage
from telebot.storage import StateRedisStorage, StatePickleStorage, StateMemoryStorage
class MyStates:
name = 1
surname = 2
age = 3
# Beginning from version 4.4.0+, we support storages.
# StateRedisStorage -> Redis-based storage.
# StatePickleStorage -> Pickle-based storage.
# 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
"""
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')
# Any state
@bot.message_handler(state="*", commands='cancel')
def any_state(message):
"""
Cancel state
"""
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)
def name_get(message):
@ -36,8 +61,8 @@ def name_get(message):
State 1. Will process when user's state is 1.
"""
bot.send_message(message.chat.id, f'Now write me a surname')
bot.set_state(message.from_user.id, MyStates.surname)
with bot.retrieve_data(message.from_user.id) as data:
bot.set_state(message.from_user.id, MyStates.surname, message.chat.id)
with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
data['name'] = message.text
@ -47,16 +72,16 @@ def ask_age(message):
State 2. Will process when user's state is 2.
"""
bot.send_message(message.chat.id, "What is your age?")
bot.set_state(message.from_user.id, MyStates.age)
with bot.retrieve_data(message.from_user.id) as data:
bot.set_state(message.from_user.id, MyStates.age, message.chat.id)
with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
data['surname'] = message.text
# result
@bot.message_handler(state=MyStates.age, is_digit=True)
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.delete_state(message.from_user.id)
bot.delete_state(message.from_user.id, message.chat.id)
#incorrect number
@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.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)

View File

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

View File

@ -17,3 +17,19 @@ class BaseMiddleware:
async def post_process(self, message, data, exception):
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)
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))