Remove deprecated code-stuff.

This commit is contained in:
Alex Root Junior 2017-08-04 17:56:05 +03:00
parent abaa6a6cf6
commit 2ac011521c
5 changed files with 4 additions and 1053 deletions

View file

@ -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__)
@ -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:

View file

@ -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)

View file

@ -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)

View file

@ -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()

View file

@ -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()