mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
* Refactor: Introduce Union types for streamlined type handling Implemented Union types across various modules to consolidate and simplify type annotations. This change replaces repetitive union declarations with reusable Union aliases, improving code readability and maintainability. Updates applied to affected classes, methods, and imports accordingly. * Refactor unions into type aliases for better reusability Replaced inline `Union` types with predefined aliases like `MediaUnion`, `ReplyMarkupUnion`, and `ChatIdUnion`. Simplifies type annotations, improves code readability, and reduces duplication. Added `media_union.py` for grouping related media types. * Refactor type unions with ResultChatMemberUnion and ResultMenuButtonUnion Replaced verbose type definitions of chat member and menu button unions with `ResultChatMemberUnion` and `ResultMenuButtonUnion` for improved readability and maintainability. Updated relevant methods, modules, and documentation to use the new type aliases consistently. * Added changelog
95 lines
2.7 KiB
Python
95 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import (
|
|
TYPE_CHECKING,
|
|
Any,
|
|
ClassVar,
|
|
Dict,
|
|
Generator,
|
|
Generic,
|
|
Optional,
|
|
TypeVar,
|
|
)
|
|
|
|
from pydantic import BaseModel, ConfigDict
|
|
from pydantic.functional_validators import model_validator
|
|
|
|
from aiogram.client.context_controller import BotContextController
|
|
|
|
from ..types import InputFile, ResponseParameters
|
|
from ..types.base import UNSET_TYPE
|
|
|
|
if TYPE_CHECKING:
|
|
from ..client.bot import Bot
|
|
|
|
TelegramType = TypeVar("TelegramType", bound=Any)
|
|
|
|
|
|
class Request(BaseModel):
|
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
|
|
method: str
|
|
|
|
data: Dict[str, Optional[Any]]
|
|
files: Optional[Dict[str, InputFile]]
|
|
|
|
|
|
class Response(BaseModel, Generic[TelegramType]):
|
|
ok: bool
|
|
result: Optional[TelegramType] = None
|
|
description: Optional[str] = None
|
|
error_code: Optional[int] = None
|
|
parameters: Optional[ResponseParameters] = None
|
|
|
|
|
|
class TelegramMethod(BotContextController, BaseModel, Generic[TelegramType], ABC):
|
|
model_config = ConfigDict(
|
|
extra="allow",
|
|
populate_by_name=True,
|
|
arbitrary_types_allowed=True,
|
|
)
|
|
|
|
@model_validator(mode="before")
|
|
@classmethod
|
|
def remove_unset(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
Remove UNSET before fields validation.
|
|
|
|
We use UNSET as a sentinel value for `parse_mode` and replace it to real value later.
|
|
It isn't a problem when it's just default value for a model field,
|
|
but UNSET might be passing to a model initialization from `Bot.method_name`,
|
|
so we must take care of it and remove it before fields validation.
|
|
"""
|
|
if not isinstance(values, dict):
|
|
return values
|
|
return {k: v for k, v in values.items() if not isinstance(v, UNSET_TYPE)}
|
|
|
|
if TYPE_CHECKING:
|
|
__returning__: ClassVar[Any]
|
|
__api_method__: ClassVar[str]
|
|
else:
|
|
|
|
@property
|
|
@abstractmethod
|
|
def __returning__(self) -> type:
|
|
pass
|
|
|
|
@property
|
|
@abstractmethod
|
|
def __api_method__(self) -> str:
|
|
pass
|
|
|
|
async def emit(self, bot: Bot) -> TelegramType:
|
|
return await bot(self)
|
|
|
|
def __await__(self) -> Generator[Any, None, TelegramType]:
|
|
bot = self._bot
|
|
if not bot:
|
|
raise RuntimeError(
|
|
"This method is not mounted to a any bot instance, please call it explicilty "
|
|
"with bot instance `await bot(method)`\n"
|
|
"or mount method to a bot instance `method.as_(bot)` "
|
|
"and then call it `await method`"
|
|
)
|
|
return self.emit(bot).__await__()
|