diff --git a/aiogram/client/bot.py b/aiogram/client/bot.py index 1c6de27c..ab25a549 100644 --- a/aiogram/client/bot.py +++ b/aiogram/client/bot.py @@ -20,9 +20,7 @@ from typing import ( import aiofiles from aiogram.utils.token import extract_bot_id, validate_token -from .default import Default, DefaultBotProperties -from .session.aiohttp import AiohttpSession -from .session.base import BaseSession + from ..methods import ( AddStickerToSet, AnswerCallbackQuery, @@ -235,6 +233,9 @@ from ..types import ( UserProfilePhotos, WebhookInfo, ) +from .default import Default, DefaultBotProperties +from .session.aiohttp import AiohttpSession +from .session.base import BaseSession T = TypeVar("T") diff --git a/aiogram/client/form.py b/aiogram/client/form.py index fb6511df..0e2750da 100644 --- a/aiogram/client/form.py +++ b/aiogram/client/form.py @@ -30,7 +30,10 @@ def _extract_files(value: Any) -> Tuple[Any, Dict[str, InputFile]]: return value, files -def extract_files(model: M, files: Dict[str, InputFile] = None) -> Tuple[M, Dict[str, InputFile]]: +def extract_files( + model: M, + files: Optional[Dict[str, InputFile]] = None, +) -> Tuple[M, Dict[str, InputFile]]: if files is None: files = {} update = {} @@ -53,7 +56,7 @@ def extract_files(model: M, files: Dict[str, InputFile] = None) -> Tuple[M, Dict return modified_model, files -def form_serialize(value: Any) -> Optional[str]: +def form_serialize(value: Any) -> str: """ Prepare jsonable value to send """ diff --git a/aiogram/types/base.py b/aiogram/types/base.py index e251cfa0..6756e3a1 100644 --- a/aiogram/types/base.py +++ b/aiogram/types/base.py @@ -1,4 +1,4 @@ -from typing import Any, Dict +from typing import Any, Dict, Union from unittest.mock import sentinel from pydantic import ( @@ -40,7 +40,9 @@ class TelegramObject(BotContextController, BaseModel): return {k: v for k, v in values.items() if not isinstance(v, UNSET_TYPE)} @model_serializer(mode="wrap", when_used="json") - def json_serialize(self, serializer: SerializerFunctionWrapHandler): + def json_serialize( + self, serializer: SerializerFunctionWrapHandler + ) -> Union[Dict[str, Any], Any]: """ Replacing `Default` placeholders with actual values from bot defaults. Ensures JSON serialization backward compatibility by handling non-standard objects. @@ -51,7 +53,7 @@ class TelegramObject(BotContextController, BaseModel): key: properties[value.name] for key, value in self if isinstance(value, Default) } return serializer(self.model_copy(update=default_fields)) - return serializer(self) + return serializer(self) # FIXME: why non-TelegramObject passed there? class MutableTelegramObject(TelegramObject): diff --git a/aiogram/types/custom.py b/aiogram/types/custom.py index 0fc6ecc8..252bdf75 100644 --- a/aiogram/types/custom.py +++ b/aiogram/types/custom.py @@ -1,7 +1,8 @@ from datetime import datetime, timedelta -from typing import Annotated, Union +from typing import Union from pydantic import PlainSerializer +from typing_extensions import Annotated # Make datetime compatible with Telegram Bot API (unixtime) diff --git a/aiogram/types/input_file.py b/aiogram/types/input_file.py index 692b0fd9..1fefb80e 100644 --- a/aiogram/types/input_file.py +++ b/aiogram/types/input_file.py @@ -116,8 +116,8 @@ class FSInputFile(InputFile): chunk_size=chunk_size, ) - @model_validator(mode="after") - def filename_from_path(self): + @model_validator(mode="after") # type: ignore + def filename_from_path(self) -> None: self.filename = self.filename or Path(self.path).name async def read(self, bot: "Bot") -> AsyncGenerator[bytes, None]: @@ -162,6 +162,8 @@ class URLInputFile(BotContextController, InputFile): async def read(self, bot: Optional["Bot"] = None) -> AsyncGenerator[bytes, None]: bot = self.bot or bot # FIXME: invalid order suspected + if bot is None: + raise AttributeError("There is no default bot. Specify it through param") stream = bot.session.stream_content( url=self.url, headers=self.headers,