mirror of
https://github.com/aiogram/aiogram.git
synced 2025-12-08 17:13:56 +00:00
Remove deprecated code-stuff.
This commit is contained in:
parent
abaa6a6cf6
commit
2ac011521c
5 changed files with 4 additions and 1053 deletions
|
|
@ -3,12 +3,10 @@ import logging
|
|||
import typing
|
||||
|
||||
from .filters import CommandsFilter, RegexpFilter, ContentTypeFilter, generate_default_filters
|
||||
from .handler import Handler, NextStepHandler
|
||||
from .handler import Handler
|
||||
from .storage import DisabledStorage, BaseStorage, FSMContext
|
||||
from .. import types
|
||||
from ..bot import Bot
|
||||
from ..types.message import ContentType
|
||||
from ..utils.deprecated import deprecated
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -22,7 +20,7 @@ class Dispatcher:
|
|||
Provide next step handler and etc.
|
||||
"""
|
||||
|
||||
def __init__(self, bot, loop=None, storage: typing.Optional[BaseStorage]=None):
|
||||
def __init__(self, bot, loop=None, storage: typing.Optional[BaseStorage] = None):
|
||||
if loop is None:
|
||||
loop = bot.loop
|
||||
if storage is None:
|
||||
|
|
@ -45,9 +43,7 @@ class Dispatcher:
|
|||
self.shipping_query_handlers = Handler(self)
|
||||
self.pre_checkout_query_handlers = Handler(self)
|
||||
|
||||
self.next_step_message_handlers = NextStepHandler(self)
|
||||
self.updates_handler.register(self.process_update)
|
||||
# self.message_handlers.register(self._notify_next_message)
|
||||
|
||||
self._pooling = False
|
||||
|
||||
|
|
@ -90,7 +86,6 @@ class Dispatcher:
|
|||
"""
|
||||
self.last_update_id = update.update_id
|
||||
if update.message:
|
||||
if not await self.next_step_message_handlers.notify(update.message):
|
||||
await self.message_handlers.notify(update.message)
|
||||
if update.edited_message:
|
||||
await self.edited_message_handlers.notify(update.edited_message)
|
||||
|
|
@ -687,23 +682,6 @@ class Dispatcher:
|
|||
|
||||
return decorator
|
||||
|
||||
@deprecated("Use FSM instead of next step message handler.")
|
||||
async def next_message(self, message: types.Message, otherwise=None, once=False, include_cancel=True,
|
||||
regexp=None, content_types=None, func=None, custom_filters=None, **kwargs):
|
||||
if content_types is None:
|
||||
content_types = []
|
||||
if custom_filters is None:
|
||||
custom_filters = []
|
||||
|
||||
filters_set = generate_default_filters(self,
|
||||
*custom_filters,
|
||||
regexp=regexp,
|
||||
content_types=content_types,
|
||||
func=func,
|
||||
**kwargs)
|
||||
self.next_step_message_handlers.register(message, otherwise, once, include_cancel, filters_set)
|
||||
return await self.next_step_message_handlers.wait(message)
|
||||
|
||||
def current_state(self, *,
|
||||
chat: typing.Union[str, int, None] = None,
|
||||
user: typing.Union[str, int, None] = None) -> FSMContext:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
from asyncio import Event
|
||||
|
||||
from .filters import check_filters, CancelFilter
|
||||
from .. import types
|
||||
from .filters import check_filters
|
||||
|
||||
|
||||
class SkipHandler(BaseException):
|
||||
|
|
@ -47,66 +44,3 @@ class Handler:
|
|||
continue
|
||||
except CancelHandler:
|
||||
break
|
||||
|
||||
|
||||
class NextStepHandler:
|
||||
def __init__(self, dispatcher):
|
||||
self.dispatcher = dispatcher
|
||||
self.handlers = {}
|
||||
|
||||
def register(self, message, otherwise=None, once=False, include_cancel=False, filters=None):
|
||||
identifier = gen_identifier(message.chat.id, message.chat.id)
|
||||
|
||||
if identifier not in self.handlers:
|
||||
self.handlers[identifier] = {'event': Event(), 'filters': filters,
|
||||
'otherwise': otherwise, 'once': once,
|
||||
'include_cancel': include_cancel,
|
||||
'message': None}
|
||||
return True
|
||||
|
||||
# In normal it's impossible.
|
||||
raise RuntimeError('Dialog already wait message.')
|
||||
# return False
|
||||
|
||||
async def notify(self, message):
|
||||
identifier = gen_identifier(message.chat.id, message.chat.id)
|
||||
if identifier not in self.handlers:
|
||||
return False
|
||||
handler = self.handlers[identifier]
|
||||
|
||||
include_cancel = handler['include_cancel']
|
||||
if include_cancel:
|
||||
filter_ = CancelFilter(include_cancel if isinstance(include_cancel, (list, set, tuple)) else None)
|
||||
if filter_.check(message):
|
||||
handler['event'].set()
|
||||
return True
|
||||
|
||||
if handler['filters'] and not await check_filters(handler['filters'], [message], {}):
|
||||
otherwise = handler['otherwise']
|
||||
if otherwise:
|
||||
await otherwise(message)
|
||||
if handler['once']:
|
||||
handler['event'].set()
|
||||
return True
|
||||
|
||||
handler['message'] = message
|
||||
handler['event'].set()
|
||||
return True
|
||||
|
||||
async def wait(self, message) -> types.Message:
|
||||
identifier = gen_identifier(message.chat.id, message.chat.id)
|
||||
|
||||
handler = self.handlers[identifier]
|
||||
event = handler.get('event')
|
||||
|
||||
await event.wait()
|
||||
message = self.handlers[identifier]['message']
|
||||
self.reset(identifier)
|
||||
return message
|
||||
|
||||
def reset(self, identifier):
|
||||
del self.handlers[identifier]
|
||||
|
||||
|
||||
def gen_identifier(chat_id, from_user_id):
|
||||
return "{0}:{1}".format(chat_id, from_user_id)
|
||||
|
|
|
|||
|
|
@ -1,799 +0,0 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
from .handler import SkipHandler
|
||||
from ..utils import json
|
||||
from ..utils.deprecated import deprecated
|
||||
|
||||
log = logging.getLogger('aiogram.StateMachine')
|
||||
|
||||
|
||||
@deprecated
|
||||
class BaseStorage:
|
||||
"""
|
||||
Skeleton for states storage
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _prepare_state_name(value):
|
||||
if callable(value):
|
||||
if hasattr(value, '__name__'):
|
||||
return value.__name__
|
||||
else:
|
||||
return value.__class__.__name__
|
||||
return value
|
||||
|
||||
def set_state(self, chat, user, state):
|
||||
"""
|
||||
Set state
|
||||
|
||||
:param chat: chat_id
|
||||
:param user: user_id
|
||||
:param state: value
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_state(self, chat, user):
|
||||
"""
|
||||
Get user state from
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def del_state(self, chat, user):
|
||||
"""
|
||||
Clear user state
|
||||
:param chat: cha
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def all_states(self, chat=None, user=None, state=None):
|
||||
"""
|
||||
Yield all states (Can use filters)
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param state:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_value(self, chat, user, key, value):
|
||||
"""
|
||||
Set value for user in storage
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param key:
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_value(self, chat, user, key, default=None):
|
||||
"""
|
||||
Get value from storage
|
||||
|
||||
By default, this method calls `self.get_data(chat, user).get(key, default)`
|
||||
:param chat:
|
||||
:param user:
|
||||
:param key:
|
||||
:param default:
|
||||
:return:
|
||||
"""
|
||||
return self.get_data(chat, user).get(key, default)
|
||||
|
||||
def del_value(self, chat, user, key):
|
||||
"""
|
||||
Delete value from storage
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param key:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_data(self, chat, user):
|
||||
"""
|
||||
Get all stored data for user
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:return: dict
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def update_data(self, chat, user, data):
|
||||
"""
|
||||
Update data in storage
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param data:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def clear_data(self, chat, user, key):
|
||||
"""
|
||||
Clear data in storage
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param key:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class BaseAsyncStorage(BaseStorage):
|
||||
async def set_state(self, chat, user, state):
|
||||
"""
|
||||
Set state
|
||||
|
||||
:param chat: chat_id
|
||||
:param user: user_id
|
||||
:param state: value
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def get_state(self, chat, user):
|
||||
"""
|
||||
Get user state from
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def del_state(self, chat, user):
|
||||
"""
|
||||
Clear user state
|
||||
:param chat: cha
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def all_states(self, chat=None, user=None, state=None):
|
||||
"""
|
||||
Yield all states (Can use filters)
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param state:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def set_value(self, chat, user, key, value):
|
||||
"""
|
||||
Set value for user in storage
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param key:
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def get_value(self, chat, user, key, default=None):
|
||||
"""
|
||||
Get value from storage
|
||||
|
||||
By default, this method calls `(await self.get_data(chat, user)).get(key, default)`
|
||||
:param chat:
|
||||
:param user:
|
||||
:param key:
|
||||
:param default:
|
||||
:return:
|
||||
"""
|
||||
return (await self.get_data(chat, user)).get(key, default)
|
||||
|
||||
async def del_value(self, chat, user, key):
|
||||
"""
|
||||
Delete value from storage
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param key:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def get_data(self, chat, user):
|
||||
"""
|
||||
Get all stored data for user
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:return: dict
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def update_data(self, chat, user, data):
|
||||
"""
|
||||
Update data in storage
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param data:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def clear_data(self, chat, user, key):
|
||||
"""
|
||||
Clear data in storage
|
||||
|
||||
:param chat:
|
||||
:param user:
|
||||
:param key:
|
||||
:return:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class MemoryStorage(BaseStorage):
|
||||
"""
|
||||
Simple in-memory state storage
|
||||
Based on builtin dict
|
||||
"""
|
||||
|
||||
def __init__(self, data=None):
|
||||
if data is None:
|
||||
data = {}
|
||||
self.data = data
|
||||
|
||||
def _prepare(self, chat, user):
|
||||
"""
|
||||
Add chat and user to storage if they are not exist
|
||||
:param chat:
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
result = False
|
||||
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
if chat not in self.data:
|
||||
self.data[chat] = {}
|
||||
result = True
|
||||
|
||||
if user not in self.data[chat]:
|
||||
self.data[chat][user] = {'state': None, 'data': {}}
|
||||
result = True
|
||||
|
||||
return result
|
||||
|
||||
def set_state(self, chat, user, state):
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
self._prepare(chat, user)
|
||||
self.data[chat][user]['state'] = self._prepare_state_name(state)
|
||||
|
||||
def get_state(self, chat, user):
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
self._prepare(chat, user)
|
||||
return self.data[chat][user]['state']
|
||||
|
||||
def del_state(self, chat, user):
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
self._prepare(chat, user)
|
||||
self.data[chat][user] = {'state': None, 'data': {}}
|
||||
|
||||
def all_states(self, chat=None, user=None, state=None):
|
||||
for chat_id, chat in self.data.items():
|
||||
if chat is not None and chat != chat_id:
|
||||
continue
|
||||
for user_id, user_state in chat.items():
|
||||
if user is not None and user != user_id:
|
||||
continue
|
||||
if state is not None and user_state == state:
|
||||
continue
|
||||
yield chat_id, user_id, user_state
|
||||
|
||||
def set_value(self, chat, user, key, value):
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
self._prepare(chat, user)
|
||||
self.data[chat][user]['data'][key] = value
|
||||
|
||||
def del_value(self, chat, user, key):
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
self._prepare(chat, user)
|
||||
del self.data[chat][user]['data'][key]
|
||||
|
||||
def get_data(self, chat, user):
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
self._prepare(chat, user)
|
||||
return self.data[chat][user]['data']
|
||||
|
||||
def update_data(self, chat, user, data):
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
self._prepare(chat, user)
|
||||
self.data[chat][user]['data'].update(data)
|
||||
|
||||
def clear_data(self, chat, user, key):
|
||||
chat = str(chat)
|
||||
user = str(user)
|
||||
|
||||
self._prepare(chat, user)
|
||||
self.data[chat][user]['data'].clear()
|
||||
|
||||
|
||||
class FileStorage(MemoryStorage):
|
||||
"""
|
||||
File-like storage for states.
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
super(FileStorage, self).__init__(self.load(filename))
|
||||
|
||||
@staticmethod
|
||||
def load(filename):
|
||||
"""
|
||||
Load data from file
|
||||
|
||||
:param filename:
|
||||
:return: dict
|
||||
"""
|
||||
if os.path.isfile(filename):
|
||||
with open(filename, 'r') as file:
|
||||
return json.load(file)
|
||||
return {}
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Write states to file
|
||||
|
||||
:return:
|
||||
"""
|
||||
with open(self.filename, 'w') as file:
|
||||
json.dump(self.data, file, indent=2)
|
||||
|
||||
def set_state(self, chat, user, state):
|
||||
super(FileStorage, self).set_state(chat, user, state)
|
||||
self.save()
|
||||
|
||||
def del_state(self, chat, user):
|
||||
super(FileStorage, self).del_state(chat, user)
|
||||
self.save()
|
||||
|
||||
def set_value(self, chat, user, key, value):
|
||||
super(FileStorage, self).set_value(chat, user, key, value)
|
||||
self.save()
|
||||
|
||||
def del_value(self, chat, user, key):
|
||||
super(FileStorage, self).del_value(chat, user, key)
|
||||
self.save()
|
||||
|
||||
def update_data(self, chat, user, data):
|
||||
super(FileStorage, self).update_data(chat, user, data)
|
||||
self.save()
|
||||
|
||||
def clear_data(self, chat, user, key):
|
||||
super(FileStorage, self).clear_data(chat, user, key)
|
||||
self.save()
|
||||
|
||||
|
||||
@deprecated
|
||||
class Controller:
|
||||
"""
|
||||
Storage controller
|
||||
|
||||
Make easy access from callback's
|
||||
"""
|
||||
|
||||
def __init__(self, state_machine, chat, user, state):
|
||||
self._state_machine = state_machine
|
||||
self._chat = chat
|
||||
self._user = user
|
||||
self._state = state
|
||||
|
||||
def set_state(self, value):
|
||||
"""
|
||||
Set state
|
||||
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
self._state_machine.set_state(self._chat, self._user, value)
|
||||
|
||||
def get_state(self):
|
||||
"""
|
||||
Get current state
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self._state_machine.get_state(self._chat, self._user)
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Reset state
|
||||
|
||||
:return:
|
||||
"""
|
||||
self._state_machine.del_state(self._chat, self._user)
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""
|
||||
Get value from storage
|
||||
|
||||
:param key:
|
||||
:param default:
|
||||
:return:
|
||||
"""
|
||||
return self._state_machine.storage.get_value(self._chat, self._user, key, default)
|
||||
|
||||
def pop(self, key, default=None):
|
||||
"""
|
||||
Pop item from storage
|
||||
|
||||
:param key:
|
||||
:param default:
|
||||
:return:
|
||||
"""
|
||||
result = self.get(key, default)
|
||||
self.delete(key)
|
||||
return result
|
||||
|
||||
def set(self, key, value):
|
||||
"""
|
||||
Set new value in user storage
|
||||
|
||||
:param key:
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
self._state_machine.storage.set_value(self._chat, self._user, key, value)
|
||||
|
||||
def delete(self, key):
|
||||
"""
|
||||
Delete key from user storage
|
||||
|
||||
:param key:
|
||||
:return:
|
||||
"""
|
||||
self._state_machine.storage.del_value(self._chat, self._user, key)
|
||||
|
||||
def update(self, data):
|
||||
"""
|
||||
Update user storage
|
||||
|
||||
:param data:
|
||||
:return:
|
||||
"""
|
||||
self._state_machine.storage.update_data(self._chat, self._user, data)
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
"""
|
||||
User data
|
||||
:return:
|
||||
"""
|
||||
return self._state_machine.storage.get_value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.set(key, value)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.get(item)
|
||||
|
||||
def __delitem__(self, key):
|
||||
self.delete(key)
|
||||
|
||||
def __str__(self):
|
||||
return "{0}:{1} - {2}".format(
|
||||
self._chat, self._user, self._state
|
||||
)
|
||||
|
||||
|
||||
@deprecated
|
||||
class AsyncController:
|
||||
"""
|
||||
Storage controller
|
||||
|
||||
Make easy access from callback's
|
||||
"""
|
||||
|
||||
def __init__(self, state_machine, chat, user, state):
|
||||
self._state_machine = state_machine
|
||||
self._chat = chat
|
||||
self._user = user
|
||||
self._state = state
|
||||
|
||||
async def set_state(self, value):
|
||||
"""
|
||||
Set state
|
||||
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
await self._state_machine.set_state(self._chat, self._user, value)
|
||||
|
||||
async def get_state(self):
|
||||
"""
|
||||
Get current state
|
||||
|
||||
:return:
|
||||
"""
|
||||
return await self._state_machine.get_state(self._chat, self._user)
|
||||
|
||||
async def clear(self):
|
||||
"""
|
||||
Reset state
|
||||
|
||||
:return:
|
||||
"""
|
||||
await self._state_machine.del_state(self._chat, self._user)
|
||||
|
||||
async def get(self, key, default=None):
|
||||
"""
|
||||
Get value from storage
|
||||
|
||||
:param key:
|
||||
:param default:
|
||||
:return:
|
||||
"""
|
||||
return await self._state_machine.storage.get_value(self._chat, self._user, key, default)
|
||||
|
||||
async def pop(self, key, default=None):
|
||||
"""
|
||||
Pop item from storage
|
||||
|
||||
:param key:
|
||||
:param default:
|
||||
:return:
|
||||
"""
|
||||
result = await self.get(key, default)
|
||||
await self.delete(key)
|
||||
return result
|
||||
|
||||
async def set(self, key, value):
|
||||
"""
|
||||
Set new value in user storage
|
||||
|
||||
:param key:
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
await self._state_machine.storage.set_value(self._chat, self._user, key, value)
|
||||
|
||||
async def delete(self, key):
|
||||
"""
|
||||
Delete key from user storage
|
||||
|
||||
:param key:
|
||||
:return:
|
||||
"""
|
||||
await self._state_machine.storage.del_value(self._chat, self._user, key)
|
||||
|
||||
async def update(self, data):
|
||||
"""
|
||||
Update user storage
|
||||
|
||||
:param data:
|
||||
:return:
|
||||
"""
|
||||
await self._state_machine.storage.update_data(self._chat, self._user, data)
|
||||
|
||||
@property
|
||||
async def data(self):
|
||||
"""
|
||||
User data
|
||||
|
||||
:return:
|
||||
"""
|
||||
return await self._state_machine.storage.get_data(self._chat, self._user)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
raise RuntimeError("Item assignment not allowed with async storage")
|
||||
|
||||
def __getitem__(self, item):
|
||||
raise RuntimeError("Item assignment not allowed with async storage")
|
||||
|
||||
def __delitem__(self, key):
|
||||
raise RuntimeError("Item assignment not allowed with async storage")
|
||||
|
||||
def __str__(self):
|
||||
return "{0}:{1} - {2}".format(
|
||||
self._chat, self._user, self._state
|
||||
)
|
||||
|
||||
|
||||
@deprecated('Use new FSM builded inside Dispatcher.')
|
||||
class StateMachine:
|
||||
"""
|
||||
Manage state
|
||||
"""
|
||||
|
||||
def __init__(self, dispatcher, states, storage=None):
|
||||
if storage is None:
|
||||
storage = MemoryStorage()
|
||||
|
||||
self.steps = self._prepare_states(states)
|
||||
self.storage = storage
|
||||
|
||||
dispatcher.message_handlers.register(self.process_message, index=0)
|
||||
|
||||
@staticmethod
|
||||
def _prepare_states(states):
|
||||
if isinstance(states, dict):
|
||||
return states
|
||||
elif isinstance(states, (list, tuple, set)):
|
||||
prepared_states = {}
|
||||
for state in states:
|
||||
if not callable(state):
|
||||
raise TypeError('State must be an callable')
|
||||
state_name = state.__name__
|
||||
prepared_states[state_name] = state
|
||||
return prepared_states
|
||||
raise TypeError('States must be an dict or list!')
|
||||
|
||||
def set_state(self, chat, user, state):
|
||||
"""
|
||||
Save state to storage
|
||||
:param chat:
|
||||
:param user:
|
||||
:param state:
|
||||
:return:
|
||||
"""
|
||||
log.debug("Set state for {0}:{1} to '{2}'".format(
|
||||
chat, user, state
|
||||
))
|
||||
self.storage.set_state(chat, user, state)
|
||||
|
||||
def get_state(self, chat, user):
|
||||
"""
|
||||
Get state from storage
|
||||
:param chat:
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
return self.storage.get_state(chat, user)
|
||||
|
||||
def del_state(self, chat, user):
|
||||
"""
|
||||
Clear user state
|
||||
:param chat:
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
log.debug("Reset state for {0}:{1}".format(chat, user))
|
||||
self.storage.del_state(chat, user)
|
||||
|
||||
async def process_message(self, message):
|
||||
"""
|
||||
Read message and process it
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
chat_id = message.chat.id
|
||||
from_user_id = message.from_user.id
|
||||
|
||||
state = self.get_state(chat_id, from_user_id)
|
||||
if state is None:
|
||||
raise SkipHandler()
|
||||
|
||||
if state not in self.steps:
|
||||
log.warning("Found unknown state '{0}' for {1}:{2}. Condition will be reset.".format(
|
||||
state, chat_id, from_user_id
|
||||
))
|
||||
self.del_state(chat_id, from_user_id)
|
||||
raise SkipHandler()
|
||||
|
||||
log.debug("Process state for {0}:{1} - '{2}'".format(
|
||||
chat_id, from_user_id, state
|
||||
))
|
||||
callback = self.steps[state]
|
||||
controller = Controller(self, chat_id, from_user_id, state)
|
||||
await callback(message, controller)
|
||||
|
||||
|
||||
@deprecated('Use new FSM builded inside Dispatcher.')
|
||||
class AsyncStateMachine:
|
||||
"""
|
||||
Manage state
|
||||
"""
|
||||
|
||||
def __init__(self, dispatcher, states, storage=None):
|
||||
assert isinstance(storage, BaseAsyncStorage)
|
||||
|
||||
self.steps = self._prepare_states(states)
|
||||
self.storage = storage
|
||||
|
||||
dispatcher.message_handlers.register(self.process_message, index=0)
|
||||
|
||||
@staticmethod
|
||||
def _prepare_states(states):
|
||||
if isinstance(states, dict):
|
||||
return states
|
||||
elif isinstance(states, (list, tuple, set)):
|
||||
prepared_states = {}
|
||||
for state in states:
|
||||
if not callable(state):
|
||||
raise TypeError('State must be an callable')
|
||||
state_name = state.__name__
|
||||
prepared_states[state_name] = state
|
||||
return prepared_states
|
||||
raise TypeError('States must be an dict or list!')
|
||||
|
||||
async def set_state(self, chat, user, state):
|
||||
"""
|
||||
Save state to storage
|
||||
:param chat:
|
||||
:param user:
|
||||
:param state:
|
||||
:return:
|
||||
"""
|
||||
log.debug("Set state for {0}:{1} to '{2}'".format(
|
||||
chat, user, state
|
||||
))
|
||||
await self.storage.set_state(chat, user, state)
|
||||
|
||||
async def get_state(self, chat, user):
|
||||
"""
|
||||
Get state from storage
|
||||
:param chat:
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
return await self.storage.get_state(chat, user)
|
||||
|
||||
async def del_state(self, chat, user):
|
||||
"""
|
||||
Clear user state
|
||||
:param chat:
|
||||
:param user:
|
||||
:return:
|
||||
"""
|
||||
log.debug("Reset state for {0}:{1}".format(chat, user))
|
||||
await self.storage.del_state(chat, user)
|
||||
|
||||
async def process_message(self, message):
|
||||
"""
|
||||
Read message and process it
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
chat_id = message.chat.id
|
||||
from_user_id = message.from_user.id
|
||||
|
||||
state = await self.get_state(chat_id, from_user_id)
|
||||
if state is None:
|
||||
raise SkipHandler()
|
||||
|
||||
if state not in self.steps:
|
||||
log.warning("Found unknown state '{0}' for {1}:{2}. Condition will be reset.".format(
|
||||
state, chat_id, from_user_id
|
||||
))
|
||||
await self.del_state(chat_id, from_user_id)
|
||||
raise SkipHandler()
|
||||
|
||||
log.debug("Process state for {0}:{1} - '{2}'".format(
|
||||
chat_id, from_user_id, state
|
||||
))
|
||||
callback = self.steps[state]
|
||||
controller = AsyncController(self, chat_id, from_user_id, state)
|
||||
await callback(message, controller)
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
import asyncio
|
||||
|
||||
from aiogram import Bot, types
|
||||
from aiogram.dispatcher import Dispatcher
|
||||
from aiogram.dispatcher.state import StateMachine, Controller
|
||||
|
||||
API_TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
bot = Bot(token=API_TOKEN, loop=loop)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
@dp.message_handler(commands=['start'])
|
||||
async def send_welcome(message: types.Message):
|
||||
"""
|
||||
Entry point to conversation
|
||||
"""
|
||||
await message.reply("Hi there! What's your name?")
|
||||
|
||||
# Set state
|
||||
# This method lock all messages from user and all messages will be redirected to next step handler in state machine
|
||||
state.set_state(message.chat.id, message.from_user.id, "name")
|
||||
|
||||
|
||||
async def process_name(message: types.Message, controller: Controller):
|
||||
"""
|
||||
Process user name
|
||||
"""
|
||||
# Save name to storage
|
||||
controller["name"] = message.text
|
||||
|
||||
await message.reply("How old are you?")
|
||||
|
||||
# Go to next state
|
||||
controller.set_state('age')
|
||||
|
||||
|
||||
async def process_age(message: types.Message, controller: Controller):
|
||||
# Check age. Age must be is digit
|
||||
if not message.text.isdigit():
|
||||
return await message.reply("Age should be a number.\nHow old are you?")
|
||||
|
||||
# Save age to storage
|
||||
controller["age"] = int(message.text)
|
||||
|
||||
# Configure ReplyKeyboardMarkup
|
||||
markup = types.ReplyKeyboardMarkup()
|
||||
markup.add("Male", "Female")
|
||||
markup.add("Other")
|
||||
|
||||
await message.reply("What is your gender?", reply_markup=markup)
|
||||
|
||||
# Go to next state
|
||||
controller.set_state("sex")
|
||||
|
||||
|
||||
async def process_sex(message: types.Message, controller: Controller):
|
||||
# Check reply
|
||||
if message.text not in ["Male", "Female", "Other"]:
|
||||
return await message.reply("Bad gender name. Choose you gender from keyboard.")
|
||||
|
||||
# Save sex to storage
|
||||
controller["sex"] = message.text
|
||||
|
||||
# Remove keyboard
|
||||
markup = types.ReplyKeyboardRemove()
|
||||
# And send message
|
||||
await bot.send_message(message.chat.id,
|
||||
f"Hi!\n"
|
||||
f"Nice to meet you, {controller['name']}.\n"
|
||||
f"Age: {controller['age']}\n"
|
||||
f"Sex: {controller['sex']}",
|
||||
reply_markup=markup)
|
||||
|
||||
# Finish conversation
|
||||
controller.clear()
|
||||
|
||||
|
||||
# Configure state machine
|
||||
state = StateMachine(dp, {
|
||||
"name": process_name,
|
||||
"age": process_age,
|
||||
"sex": process_sex
|
||||
})
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
loop.run_until_complete(dp.start_pooling())
|
||||
except KeyboardInterrupt:
|
||||
loop.stop()
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiogram import Bot, types
|
||||
from aiogram.dispatcher import Dispatcher
|
||||
from aiogram.types import ContentType
|
||||
|
||||
API_TOKEN = TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
bot = Bot(token=API_TOKEN, loop=loop)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
@dp.message_handler(commands=['start'])
|
||||
async def send_welcome(message: types.Message):
|
||||
await message.reply("Hi!\nI'm EchoBot!\nPowered by aiogram.")
|
||||
|
||||
|
||||
@dp.message_handler(commands=['sticker'])
|
||||
async def save_sticker(message: types.Message):
|
||||
async def handle_bad_message(msg: types.Message):
|
||||
"""
|
||||
Handler for unknown messages
|
||||
"""
|
||||
await msg.reply('That is not a sticker!')
|
||||
|
||||
# Create an reply markup (ForceReply)
|
||||
markup = types.ForceReply(selective=True)
|
||||
|
||||
# Send reply to user
|
||||
await message.reply('Please send me a sticker.', reply_markup=markup)
|
||||
|
||||
# Wait next message
|
||||
# It can only be a sticker
|
||||
msg = await dp.next_message(message,
|
||||
content_types=ContentType.STICKER,
|
||||
otherwise=handle_bad_message,
|
||||
include_cancel=True)
|
||||
|
||||
if not msg:
|
||||
# If user send /cancel
|
||||
return await message.reply('Canceled.')
|
||||
|
||||
# Download file to memory (io.BytesIO)
|
||||
photo = await bot.download_file_by_id(msg.sticker.file_id)
|
||||
|
||||
# And you can use other syntax:
|
||||
# photo = io.BytesIO()
|
||||
# await bot.download_file(msg.sticker.file_id, photo)
|
||||
# Or use filename for download file to filesystem:
|
||||
# await bot.download_file(msg.sticker.file_id, 'sticker.webp')
|
||||
|
||||
# Send document to user
|
||||
await bot.send_document(message.chat.id, photo, caption=msg.sticker.emoji,
|
||||
reply_to_message_id=message.message_id)
|
||||
|
||||
|
||||
async def main():
|
||||
count = await dp.skip_updates()
|
||||
print(f"Skipped {count} updates.")
|
||||
await dp.start_pooling()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
loop.run_until_complete(main())
|
||||
except KeyboardInterrupt:
|
||||
loop.stop()
|
||||
Loading…
Add table
Add a link
Reference in a new issue