mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Merge branch 'dev-3.x' into pre-commit-hook
This commit is contained in:
commit
41e7745574
9 changed files with 89 additions and 45 deletions
2
CHANGES/666.feature
Normal file
2
CHANGES/666.feature
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Ability to iterate over all states in StatesGroup.
|
||||
Aiogram already had in check for states group so this is relative feature.
|
||||
1
CHANGES/669.misc
Normal file
1
CHANGES/669.misc
Normal file
|
|
@ -0,0 +1 @@
|
|||
Moved update type detection from Dispatcher to Update object
|
||||
1
CHANGES/674.bugfix
Normal file
1
CHANGES/674.bugfix
Normal file
|
|
@ -0,0 +1 @@
|
|||
Fixed incorrect type checking in the :class:`aiogram.utils.keyboard.KeyboardBuilder`
|
||||
|
|
@ -9,7 +9,8 @@ from typing import Any, AsyncGenerator, Dict, List, Optional, Union
|
|||
from .. import loggers
|
||||
from ..client.bot import Bot
|
||||
from ..methods import GetUpdates, TelegramMethod
|
||||
from ..types import TelegramObject, Update, User
|
||||
from ..types import Update, User
|
||||
from ..types.update import UpdateTypeLookupError
|
||||
from ..utils.backoff import Backoff, BackoffConfig
|
||||
from ..utils.exceptions.base import TelegramAPIError
|
||||
from ..utils.exceptions.network import NetworkError
|
||||
|
|
@ -186,47 +187,10 @@ class Dispatcher(Router):
|
|||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
event: TelegramObject
|
||||
if update.message:
|
||||
update_type = "message"
|
||||
event = update.message
|
||||
elif update.edited_message:
|
||||
update_type = "edited_message"
|
||||
event = update.edited_message
|
||||
elif update.channel_post:
|
||||
update_type = "channel_post"
|
||||
event = update.channel_post
|
||||
elif update.edited_channel_post:
|
||||
update_type = "edited_channel_post"
|
||||
event = update.edited_channel_post
|
||||
elif update.inline_query:
|
||||
update_type = "inline_query"
|
||||
event = update.inline_query
|
||||
elif update.chosen_inline_result:
|
||||
update_type = "chosen_inline_result"
|
||||
event = update.chosen_inline_result
|
||||
elif update.callback_query:
|
||||
update_type = "callback_query"
|
||||
event = update.callback_query
|
||||
elif update.shipping_query:
|
||||
update_type = "shipping_query"
|
||||
event = update.shipping_query
|
||||
elif update.pre_checkout_query:
|
||||
update_type = "pre_checkout_query"
|
||||
event = update.pre_checkout_query
|
||||
elif update.poll:
|
||||
update_type = "poll"
|
||||
event = update.poll
|
||||
elif update.poll_answer:
|
||||
update_type = "poll_answer"
|
||||
event = update.poll_answer
|
||||
elif update.my_chat_member:
|
||||
update_type = "my_chat_member"
|
||||
event = update.my_chat_member
|
||||
elif update.chat_member:
|
||||
update_type = "chat_member"
|
||||
event = update.chat_member
|
||||
else:
|
||||
try:
|
||||
update_type = update.event_type
|
||||
event = update.event
|
||||
except UpdateTypeLookupError:
|
||||
warnings.warn(
|
||||
"Detected unknown update type.\n"
|
||||
"Seems like Telegram Bot API was updated and you have "
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import inspect
|
||||
from typing import Any, Optional, Tuple, Type, no_type_check
|
||||
from typing import Any, Iterator, Optional, Tuple, Type, no_type_check
|
||||
|
||||
from ...types import TelegramObject
|
||||
|
||||
|
|
@ -118,6 +118,9 @@ class StatesGroupMeta(type):
|
|||
def __str__(self) -> str:
|
||||
return f"<StatesGroup '{self.__full_group_name__}'>"
|
||||
|
||||
def __iter__(self) -> Iterator[State]:
|
||||
return iter(self.__all_states__)
|
||||
|
||||
|
||||
class StatesGroup(metaclass=StatesGroupMeta):
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING, Optional, cast
|
||||
|
||||
from ..utils.mypy_hacks import lru_cache
|
||||
from .base import TelegramObject
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
|
|
@ -53,3 +54,52 @@ class Update(TelegramObject):
|
|||
"""*Optional*. The bot's chat member status was updated in a chat. For private chats, this update is received only when the bot is blocked or unblocked by the user."""
|
||||
chat_member: Optional[ChatMemberUpdated] = None
|
||||
"""*Optional*. A chat member's status was updated in a chat. The bot must be an administrator in the chat and must explicitly specify 'chat_member' in the list of *allowed_updates* to receive these updates."""
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((type(self), self.update_id))
|
||||
|
||||
@property # type: ignore
|
||||
@lru_cache()
|
||||
def event_type(self) -> str:
|
||||
"""
|
||||
Detect update type
|
||||
If update type is unknown, raise UpdateTypeLookupError
|
||||
|
||||
:return:
|
||||
"""
|
||||
if self.message:
|
||||
return "message"
|
||||
if self.edited_message:
|
||||
return "edited_message"
|
||||
if self.channel_post:
|
||||
return "channel_post"
|
||||
if self.edited_channel_post:
|
||||
return "edited_channel_post"
|
||||
if self.inline_query:
|
||||
return "inline_query"
|
||||
if self.chosen_inline_result:
|
||||
return "chosen_inline_result"
|
||||
if self.callback_query:
|
||||
return "callback_query"
|
||||
if self.shipping_query:
|
||||
return "shipping_query"
|
||||
if self.pre_checkout_query:
|
||||
return "pre_checkout_query"
|
||||
if self.poll:
|
||||
return "poll"
|
||||
if self.poll_answer:
|
||||
return "poll_answer"
|
||||
if self.my_chat_member:
|
||||
return "my_chat_member"
|
||||
if self.chat_member:
|
||||
return "chat_member"
|
||||
|
||||
raise UpdateTypeLookupError("Update does not contain any known event type.")
|
||||
|
||||
@property
|
||||
def event(self) -> TelegramObject:
|
||||
return cast(TelegramObject, getattr(self, self.event_type))
|
||||
|
||||
|
||||
class UpdateTypeLookupError(LookupError):
|
||||
"""Update does not contain any known event type."""
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ class KeyboardBuilder(Generic[ButtonType]):
|
|||
return self.add(button)
|
||||
|
||||
def as_markup(self, **kwargs: Any) -> Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]:
|
||||
if self._button_type is ReplyKeyboardMarkup:
|
||||
if self._button_type is KeyboardButton:
|
||||
return ReplyKeyboardMarkup(keyboard=self.export(), **kwargs)
|
||||
return InlineKeyboardMarkup(inline_keyboard=self.export())
|
||||
|
||||
|
|
|
|||
16
aiogram/utils/mypy_hacks.py
Normal file
16
aiogram/utils/mypy_hacks.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import functools
|
||||
from typing import Callable, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def lru_cache(maxsize: int = 128, typed: bool = False) -> Callable[[T], T]:
|
||||
"""
|
||||
fix: lru_cache annotation doesn't work with a property
|
||||
this hack is only needed for the property, so type annotations are as they are
|
||||
"""
|
||||
|
||||
def wrapper(func: T) -> T:
|
||||
return functools.lru_cache(maxsize, typed)(func) # type: ignore
|
||||
|
||||
return wrapper
|
||||
|
|
@ -150,6 +150,13 @@ class TestStatesGroup:
|
|||
|
||||
assert MyGroup.MyNestedGroup.get_root() is MyGroup
|
||||
|
||||
def test_iterable(self):
|
||||
class Group(StatesGroup):
|
||||
x = State()
|
||||
y = State()
|
||||
|
||||
assert set(Group) == {Group.x, Group.y}
|
||||
|
||||
def test_empty_filter(self):
|
||||
class MyGroup(StatesGroup):
|
||||
pass
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue