Some refactor

This commit is contained in:
Suren Khorenyan 2019-07-22 00:11:06 +03:00
parent cabb10bc06
commit ad7238fda8
7 changed files with 106 additions and 93 deletions

View file

@ -97,22 +97,22 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
filters_factory.bind(Text, event_handlers=[
self.message_handlers, self.edited_message_handlers,
self.channel_post_handlers, self.edited_channel_post_handlers,
self.callback_query_handlers, self.poll_handlers, self.inline_query_handlers
self.callback_query_handlers, self.poll_handlers, self.inline_query_handlers,
])
filters_factory.bind(HashTag, event_handlers=[
self.message_handlers, self.edited_message_handlers,
self.channel_post_handlers, self.edited_channel_post_handlers
self.channel_post_handlers, self.edited_channel_post_handlers,
])
filters_factory.bind(Regexp, event_handlers=[
self.message_handlers, self.edited_message_handlers,
self.channel_post_handlers, self.edited_channel_post_handlers,
self.callback_query_handlers, self.poll_handlers, self.inline_query_handlers
self.callback_query_handlers, self.poll_handlers, self.inline_query_handlers,
])
filters_factory.bind(RegexpCommandsFilter, event_handlers=[
self.message_handlers, self.edited_message_handlers
self.message_handlers, self.edited_message_handlers,
])
filters_factory.bind(ExceptionsFilter, event_handlers=[
self.errors_handlers
self.errors_handlers,
])
filters_factory.bind(IdFilter, event_handlers=[
self.message_handlers, self.edited_message_handlers,

View file

@ -205,6 +205,13 @@ class Text(Filter):
Simple text filter
"""
_default_params = (
('text', 'equals'),
('text_contains', 'contains'),
('text_startswith', 'startswith'),
('text_endswith', 'endswith'),
)
def __init__(self,
equals: Optional[Union[str, LazyProxy, Iterable[Union[str, LazyProxy]]]] = None,
contains: Optional[Union[str, LazyProxy, Iterable[Union[str, LazyProxy]]]] = None,
@ -244,14 +251,9 @@ class Text(Filter):
@classmethod
def validate(cls, full_config: Dict[str, Any]):
if 'text' in full_config:
return {'equals': full_config.pop('text')}
elif 'text_contains' in full_config:
return {'contains': full_config.pop('text_contains')}
elif 'text_startswith' in full_config:
return {'startswith': full_config.pop('text_startswith')}
elif 'text_endswith' in full_config:
return {'endswith': full_config.pop('text_endswith')}
for param, key in cls._default_params:
if param in full_config:
return {key: full_config.pop(param)}
async def check(self, obj: Union[Message, CallbackQuery, InlineQuery, Poll]):
if isinstance(obj, Message):

View file

@ -25,17 +25,17 @@ class State:
@property
def state(self):
if self._state is None:
return None
elif self._state == '*':
if self._state is None or self._state == '*':
return self._state
elif self._group_name is None and self._group:
if self._group_name is None and self._group:
group = self._group.__full_group_name__
elif self._group_name:
group = self._group_name
else:
group = '@'
return f"{group}:{self._state}"
return f'{group}:{self._state}'
def set_parent(self, group):
if not issubclass(group, StatesGroup):
@ -73,7 +73,6 @@ class StatesGroupMeta(type):
elif inspect.isclass(prop) and issubclass(prop, StatesGroup):
childs.append(prop)
prop._parent = cls
# continue
cls._parent = None
cls._childs = tuple(childs)
@ -83,13 +82,13 @@ class StatesGroupMeta(type):
return cls
@property
def __group_name__(cls):
def __group_name__(cls) -> str:
return cls._group_name
@property
def __full_group_name__(cls):
def __full_group_name__(cls) -> str:
if cls._parent:
return cls._parent.__full_group_name__ + '.' + cls._group_name
return '.'.join((cls._parent.__full_group_name__, cls._group_name))
return cls._group_name
@property
@ -97,7 +96,7 @@ class StatesGroupMeta(type):
return cls._states
@property
def childs(cls):
def childs(cls) -> tuple:
return cls._childs
@property
@ -130,9 +129,9 @@ class StatesGroupMeta(type):
def __contains__(cls, item):
if isinstance(item, str):
return item in cls.all_states_names
elif isinstance(item, State):
if isinstance(item, State):
return item in cls.all_states
elif isinstance(item, StatesGroup):
if isinstance(item, StatesGroup):
return item in cls.all_childs
return False

View file

@ -31,7 +31,7 @@ T = TypeVar('T')
class ContextInstanceMixin:
def __init_subclass__(cls, **kwargs):
cls.__context_instance = contextvars.ContextVar('instance_' + cls.__name__)
cls.__context_instance = contextvars.ContextVar(f'instance_{cls.__name__}')
return cls
@classmethod
@ -43,5 +43,5 @@ class ContextInstanceMixin:
@classmethod
def set_current(cls: Type[T], value: T):
if not isinstance(value, cls):
raise TypeError(f"Value should be instance of '{cls.__name__}' not '{type(value).__name__}'")
raise TypeError(f'Value should be instance of {cls.__name__!r} not {type(value).__name__!r}')
cls.__context_instance.set(value)

View file

@ -15,3 +15,4 @@ sphinx-rtd-theme>=0.4.3
sphinxcontrib-programoutput>=0.14
aiohttp-socks>=0.2.2
rethinkdb>=2.4.1
coverage==4.5.3

View file

@ -1,16 +1,19 @@
import asyncio
from typing import Optional
import logging
import aiogram.utils.markdown as md
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ParseMode
from aiogram.utils import executor
logging.basicConfig(level=logging.INFO)
API_TOKEN = 'BOT TOKEN HERE'
bot = Bot(token=API_TOKEN)
# For example use simple MemoryStorage for Dispatcher.
@ -25,7 +28,7 @@ class Form(StatesGroup):
gender = State() # Will be represented in storage as 'Form:gender'
@dp.message_handler(commands=['start'])
@dp.message_handler(commands='start')
async def cmd_start(message: types.Message):
"""
Conversation's entry point
@ -37,19 +40,21 @@ async def cmd_start(message: types.Message):
# You can use state '*' if you need to handle all states
@dp.message_handler(state='*', commands=['cancel'])
@dp.message_handler(lambda message: message.text.lower() == 'cancel', state='*')
async def cancel_handler(message: types.Message, state: FSMContext, raw_state: Optional[str] = None):
@dp.message_handler(state='*', commands='cancel')
@dp.message_handler(Text(equals='cancel', ignore_case=True), state='*')
async def cancel_handler(message: types.Message, state: FSMContext):
"""
Allow user to cancel any action
"""
if raw_state is None:
current_state = await state.get_state()
if current_state is None:
return
logging.info('Cancelling state %r', current_state)
# Cancel state and inform user about it
await state.finish()
# And remove keyboard (just in case)
await message.reply('Canceled.', reply_markup=types.ReplyKeyboardRemove())
await message.reply('Cancelled.', reply_markup=types.ReplyKeyboardRemove())
@dp.message_handler(state=Form.name)
@ -66,7 +71,7 @@ async def process_name(message: types.Message, state: FSMContext):
# Check age. Age gotta be digit
@dp.message_handler(lambda message: not message.text.isdigit(), state=Form.age)
async def failed_process_age(message: types.Message):
async def process_age_invalid(message: types.Message):
"""
If age is invalid
"""
@ -88,11 +93,11 @@ async def process_age(message: types.Message, state: FSMContext):
@dp.message_handler(lambda message: message.text not in ["Male", "Female", "Other"], state=Form.gender)
async def failed_process_gender(message: types.Message):
async def process_gender_invalid(message: types.Message):
"""
In this example gender has to be one of: Male, Female, Other.
"""
return await message.reply("Bad gender name. Choose you gender from keyboard.")
return await message.reply("Bad gender name. Choose your gender from the keyboard.")
@dp.message_handler(state=Form.gender)
@ -104,11 +109,17 @@ async def process_gender(message: types.Message, state: FSMContext):
markup = types.ReplyKeyboardRemove()
# And send message
await bot.send_message(message.chat.id, md.text(
md.text('Hi! Nice to meet you,', md.bold(data['name'])),
md.text('Age:', data['age']),
md.text('Gender:', data['gender']),
sep='\n'), reply_markup=markup, parse_mode=ParseMode.MARKDOWN)
await bot.send_message(
message.chat.id,
md.text(
md.text('Hi! Nice to meet you,', md.bold(data['name'])),
md.text('Age:', md.code(data['age'])),
md.text('Gender:', data['gender']),
sep='\n',
),
reply_markup=markup,
parse_mode=ParseMode.MARKDOWN,
)
# Finish conversation
await state.finish()

View file

@ -8,7 +8,7 @@ USER = {
"first_name": "FirstName",
"last_name": "LastName",
"username": "username",
"language_code": "ru"
"language_code": "ru",
}
CHAT = {
@ -16,14 +16,14 @@ CHAT = {
"first_name": "FirstName",
"last_name": "LastName",
"username": "username",
"type": "private"
"type": "private",
}
PHOTO = {
"file_id": "AgADBAADFak0G88YZAf8OAug7bHyS9x2ZxkABHVfpJywcloRAAGAAQABAg",
"file_size": 1101,
"width": 90,
"height": 51
"height": 51,
}
AUDIO = {
@ -32,7 +32,7 @@ AUDIO = {
"title": "The Best Song",
"performer": "The Best Singer",
"file_id": "CQADAgADbQEAAsnrIUpNoRRNsH7_hAI",
"file_size": 9507774
"file_size": 9507774,
}
CHAT_MEMBER = {
@ -44,7 +44,7 @@ CHAT_MEMBER = {
"can_invite_users": True,
"can_restrict_members": True,
"can_pin_messages": True,
"can_promote_members": False
"can_promote_members": False,
}
CONTACT = {
@ -57,7 +57,7 @@ DOCUMENT = {
"file_name": "test.docx",
"mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"file_id": "BQADAgADpgADy_JxS66XQTBRHFleAg",
"file_size": 21331
"file_size": 21331,
}
ANIMATION = {
@ -65,51 +65,51 @@ ANIMATION = {
"mime_type": "video/mp4",
"thumb": PHOTO,
"file_id": "CgADBAAD4DUAAoceZAe2WiE9y0crrAI",
"file_size": 65837
"file_size": 65837,
}
ENTITY_BOLD = {
"offset": 5,
"length": 2,
"type": "bold"
"type": "bold",
}
ENTITY_ITALIC = {
"offset": 8,
"length": 1,
"type": "italic"
"type": "italic",
}
ENTITY_LINK = {
"offset": 10,
"length": 6,
"type": "text_link",
"url": "http://google.com/"
"url": "http://google.com/",
}
ENTITY_CODE = {
"offset": 17,
"length": 7,
"type": "code"
"type": "code",
}
ENTITY_PRE = {
"offset": 30,
"length": 4,
"type": "pre"
"type": "pre",
}
ENTITY_MENTION = {
"offset": 47,
"length": 9,
"type": "mention"
"type": "mention",
}
GAME = {
"title": "Karate Kido",
"description": "No trees were harmed in the making of this game :)",
"photo": [PHOTO, PHOTO, PHOTO],
"animation": ANIMATION
"animation": ANIMATION,
}
INVOICE = {
@ -120,19 +120,19 @@ INVOICE = {
"Order our Working Time Machine today!",
"start_parameter": "time-machine-example",
"currency": "USD",
"total_amount": 6250
"total_amount": 6250,
}
LOCATION = {
"latitude": 50.693416,
"longitude": 30.624605
"longitude": 30.624605,
}
VENUE = {
"location": LOCATION,
"title": "Venue Name",
"address": "Venue Address",
"foursquare_id": "4e6f2cec483bad563d150f98"
"foursquare_id": "4e6f2cec483bad563d150f98",
}
SHIPPING_ADDRESS = {
@ -141,7 +141,7 @@ SHIPPING_ADDRESS = {
"city": "DefaultCity",
"street_line1": "Central",
"street_line2": "Middle",
"post_code": "424242"
"post_code": "424242",
}
STICKER = {
@ -156,7 +156,7 @@ STICKER = {
"height": 128
},
"file_id": "AAbbCCddEEffGGhh1234567890",
"file_size": 12345
"file_size": 12345,
}
SUCCESSFUL_PAYMENT = {
@ -164,7 +164,7 @@ SUCCESSFUL_PAYMENT = {
"total_amount": 6250,
"invoice_payload": "HAPPY FRIDAYS COUPON",
"telegram_payment_charge_id": "_",
"provider_payment_charge_id": "12345678901234_test"
"provider_payment_charge_id": "12345678901234_test",
}
VIDEO = {
@ -174,7 +174,7 @@ VIDEO = {
"mime_type": "video/quicktime",
"thumb": PHOTO,
"file_id": "BAADAgpAADdawy_JxS72kRvV3cortAg",
"file_size": 10099782
"file_size": 10099782,
}
VIDEO_NOTE = {
@ -182,14 +182,14 @@ VIDEO_NOTE = {
"length": 240,
"thumb": PHOTO,
"file_id": "AbCdEfGhIjKlMnOpQrStUvWxYz",
"file_size": 186562
"file_size": 186562,
}
VOICE = {
"duration": 1,
"mime_type": "audio/ogg",
"file_id": "AwADawAgADADy_JxS2gopIVIIxlhAg",
"file_size": 4321
"file_size": 4321,
}
CALLBACK_QUERY = {}
@ -206,7 +206,7 @@ EDITED_MESSAGE = {
"chat": CHAT,
"date": 1508825372,
"edit_date": 1508825379,
"text": "hi there (edited)"
"text": "hi there (edited)",
}
FORWARDED_MESSAGE = {
@ -219,7 +219,7 @@ FORWARDED_MESSAGE = {
"forward_date": 1522749037,
"text": "Forwarded text with entities from public channel ",
"entities": [ENTITY_BOLD, ENTITY_CODE, ENTITY_ITALIC, ENTITY_LINK,
ENTITY_LINK, ENTITY_MENTION, ENTITY_PRE]
ENTITY_LINK, ENTITY_MENTION, ENTITY_PRE],
}
INLINE_QUERY = {}
@ -229,7 +229,7 @@ MESSAGE = {
"from": USER,
"chat": CHAT,
"date": 1508709711,
"text": "Hi, world!"
"text": "Hi, world!",
}
MESSAGE_WITH_AUDIO = {
@ -238,7 +238,7 @@ MESSAGE_WITH_AUDIO = {
"chat": CHAT,
"date": 1508739776,
"audio": AUDIO,
"caption": "This is my favourite song"
"caption": "This is my favourite song",
}
MESSAGE_WITH_AUTHOR_SIGNATURE = {}
@ -250,7 +250,7 @@ MESSAGE_WITH_CONTACT = {
"from": USER,
"chat": CHAT,
"date": 1522850298,
"contact": CONTACT
"contact": CONTACT,
}
MESSAGE_WITH_DELETE_CHAT_PHOTO = {}
@ -261,7 +261,7 @@ MESSAGE_WITH_DOCUMENT = {
"chat": CHAT,
"date": 1508768012,
"document": DOCUMENT,
"caption": "Read my document"
"caption": "Read my document",
}
MESSAGE_WITH_EDIT_DATE = {}
@ -273,7 +273,7 @@ MESSAGE_WITH_GAME = {
"from": USER,
"chat": CHAT,
"date": 1508824810,
"game": GAME
"game": GAME,
}
MESSAGE_WITH_GROUP_CHAT_CREATED = {}
@ -283,7 +283,7 @@ MESSAGE_WITH_INVOICE = {
"from": USER,
"chat": CHAT,
"date": 1508761719,
"invoice": INVOICE
"invoice": INVOICE,
}
MESSAGE_WITH_LEFT_CHAT_MEMBER = {}
@ -293,7 +293,7 @@ MESSAGE_WITH_LOCATION = {
"from": USER,
"chat": CHAT,
"date": 1508755473,
"location": LOCATION
"location": LOCATION,
}
MESSAGE_WITH_MIGRATE_TO_CHAT_ID = {
@ -301,7 +301,7 @@ MESSAGE_WITH_MIGRATE_TO_CHAT_ID = {
"from": USER,
"chat": CHAT,
"date": 1526943253,
"migrate_to_chat_id": -1234567890987
"migrate_to_chat_id": -1234567890987,
}
MESSAGE_WITH_MIGRATE_FROM_CHAT_ID = {
@ -309,7 +309,7 @@ MESSAGE_WITH_MIGRATE_FROM_CHAT_ID = {
"from": USER,
"chat": CHAT,
"date": 1526943253,
"migrate_from_chat_id": -123456789
"migrate_from_chat_id": -123456789,
}
MESSAGE_WITH_NEW_CHAT_MEMBERS = {}
@ -324,7 +324,7 @@ MESSAGE_WITH_PHOTO = {
"chat": CHAT,
"date": 1508825154,
"photo": [PHOTO, PHOTO, PHOTO, PHOTO],
"caption": "photo description"
"caption": "photo description",
}
MESSAGE_WITH_MEDIA_GROUP = {
@ -333,7 +333,7 @@ MESSAGE_WITH_MEDIA_GROUP = {
"chat": CHAT,
"date": 1522843665,
"media_group_id": "12182749320567362",
"photo": [PHOTO, PHOTO, PHOTO, PHOTO]
"photo": [PHOTO, PHOTO, PHOTO, PHOTO],
}
MESSAGE_WITH_PINNED_MESSAGE = {}
@ -345,7 +345,7 @@ MESSAGE_WITH_STICKER = {
"from": USER,
"chat": CHAT,
"date": 1508771450,
"sticker": STICKER
"sticker": STICKER,
}
MESSAGE_WITH_SUCCESSFUL_PAYMENT = {
@ -353,7 +353,7 @@ MESSAGE_WITH_SUCCESSFUL_PAYMENT = {
"from": USER,
"chat": CHAT,
"date": 1508761169,
"successful_payment": SUCCESSFUL_PAYMENT
"successful_payment": SUCCESSFUL_PAYMENT,
}
MESSAGE_WITH_SUPERGROUP_CHAT_CREATED = {}
@ -364,7 +364,7 @@ MESSAGE_WITH_VENUE = {
"chat": CHAT,
"date": 1522849819,
"location": LOCATION,
"venue": VENUE
"venue": VENUE,
}
MESSAGE_WITH_VIDEO = {
@ -373,7 +373,7 @@ MESSAGE_WITH_VIDEO = {
"chat": CHAT,
"date": 1508756494,
"video": VIDEO,
"caption": "description"
"caption": "description",
}
MESSAGE_WITH_VIDEO_NOTE = {
@ -381,7 +381,7 @@ MESSAGE_WITH_VIDEO_NOTE = {
"from": USER,
"chat": CHAT,
"date": 1522835890,
"video_note": VIDEO_NOTE
"video_note": VIDEO_NOTE,
}
MESSAGE_WITH_VOICE = {
@ -389,7 +389,7 @@ MESSAGE_WITH_VOICE = {
"from": USER,
"chat": CHAT,
"date": 1508768403,
"voice": VOICE
"voice": VOICE,
}
PRE_CHECKOUT_QUERY = {
@ -397,7 +397,7 @@ PRE_CHECKOUT_QUERY = {
"from": USER,
"currency": "USD",
"total_amount": 6250,
"invoice_payload": "HAPPY FRIDAYS COUPON"
"invoice_payload": "HAPPY FRIDAYS COUPON",
}
REPLY_MESSAGE = {
@ -406,37 +406,37 @@ REPLY_MESSAGE = {
"chat": CHAT,
"date": 1508751866,
"reply_to_message": MESSAGE,
"text": "Reply to quoted message"
"text": "Reply to quoted message",
}
SHIPPING_QUERY = {
"id": "262181558684397422",
"from": USER,
"invoice_payload": "HAPPY FRIDAYS COUPON",
"shipping_address": SHIPPING_ADDRESS
"shipping_address": SHIPPING_ADDRESS,
}
USER_PROFILE_PHOTOS = {
"total_count": 1, "photos": [
[PHOTO, PHOTO, PHOTO]
]
[PHOTO, PHOTO, PHOTO],
],
}
FILE = {
"file_id": "XXXYYYZZZ",
"file_size": 5254,
"file_path": "voice\/file_8"
"file_path": "voice/file_8",
}
INVITE_LINK = 'https://t.me/joinchat/AbCdEfjKILDADwdd123'
UPDATE = {
"update_id": 123456789,
"message": MESSAGE
"message": MESSAGE,
}
WEBHOOK_INFO = {
"url": "",
"has_custom_certificate": False,
"pending_update_count": 0
"pending_update_count": 0,
}