From 023245c76b0d49468ffd0affbcae0424f7a4aa90 Mon Sep 17 00:00:00 2001 From: Dima Boger Date: Sun, 12 Apr 2020 17:16:35 +0300 Subject: [PATCH] :sparkles: Add sentinel value for parse_mode which can be None itself Resolves #302. We decided to use sentinel pattern (https://python-patterns.guide/python/sentinel-object/) as a solution, but got a few problems with plain `object()`, so instead we use unittest.mock.sentinel and we hope it won't cause side effects. Most of work done via tg-codegen (https://github.com/aiogram/tg-codegen/pull/1), so it's good to review only implementation of sentinel, processing sentinel in `prepare_parse_mode`, changes in base method model and little test fixes. --- aiogram/api/client/bot.py | 19 +++++---- aiogram/api/methods/base.py | 42 ++++++++++++++----- aiogram/api/methods/edit_message_caption.py | 4 +- aiogram/api/methods/edit_message_text.py | 4 +- aiogram/api/methods/send_animation.py | 3 +- aiogram/api/methods/send_audio.py | 3 +- aiogram/api/methods/send_document.py | 3 +- aiogram/api/methods/send_message.py | 3 +- aiogram/api/methods/send_photo.py | 3 +- aiogram/api/methods/send_video.py | 3 +- aiogram/api/methods/send_voice.py | 3 +- aiogram/api/types/__init__.py | 3 +- aiogram/api/types/base.py | 6 +++ .../api/types/inline_query_result_audio.py | 3 +- .../types/inline_query_result_cached_audio.py | 3 +- .../inline_query_result_cached_document.py | 3 +- .../types/inline_query_result_cached_gif.py | 3 +- .../inline_query_result_cached_mpeg4_gif.py | 3 +- .../types/inline_query_result_cached_photo.py | 3 +- .../types/inline_query_result_cached_video.py | 3 +- .../types/inline_query_result_cached_voice.py | 3 +- .../api/types/inline_query_result_document.py | 3 +- aiogram/api/types/inline_query_result_gif.py | 3 +- .../types/inline_query_result_mpeg4_gif.py | 3 +- .../api/types/inline_query_result_photo.py | 3 +- .../api/types/inline_query_result_video.py | 3 +- .../api/types/inline_query_result_voice.py | 3 +- aiogram/api/types/input_media_animation.py | 3 +- aiogram/api/types/input_media_audio.py | 3 +- aiogram/api/types/input_media_document.py | 3 +- aiogram/api/types/input_media_photo.py | 3 +- aiogram/api/types/input_media_video.py | 3 +- .../api/types/input_text_message_content.py | 3 +- tests/test_api/test_methods/test_base.py | 2 +- 34 files changed, 108 insertions(+), 53 deletions(-) diff --git a/aiogram/api/client/bot.py b/aiogram/api/client/bot.py index 27293d83..56cedcf8 100644 --- a/aiogram/api/client/bot.py +++ b/aiogram/api/client/bot.py @@ -82,6 +82,7 @@ from ..methods import ( UploadStickerFile, ) from ..types import ( + UNSET, BotCommand, Chat, ChatMember, @@ -339,7 +340,7 @@ class Bot(ContextInstanceMixin["Bot"]): self, chat_id: Union[int, str], text: str, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, disable_web_page_preview: Optional[bool] = None, disable_notification: Optional[bool] = None, reply_to_message_id: Optional[int] = None, @@ -411,7 +412,7 @@ class Bot(ContextInstanceMixin["Bot"]): chat_id: Union[int, str], photo: Union[InputFile, str], caption: Optional[str] = None, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, disable_notification: Optional[bool] = None, reply_to_message_id: Optional[int] = None, reply_markup: Optional[ @@ -457,7 +458,7 @@ class Bot(ContextInstanceMixin["Bot"]): chat_id: Union[int, str], audio: Union[InputFile, str], caption: Optional[str] = None, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, duration: Optional[int] = None, performer: Optional[str] = None, title: Optional[str] = None, @@ -525,7 +526,7 @@ class Bot(ContextInstanceMixin["Bot"]): document: Union[InputFile, str], thumb: Optional[Union[InputFile, str]] = None, caption: Optional[str] = None, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, disable_notification: Optional[bool] = None, reply_to_message_id: Optional[int] = None, reply_markup: Optional[ @@ -585,7 +586,7 @@ class Bot(ContextInstanceMixin["Bot"]): height: Optional[int] = None, thumb: Optional[Union[InputFile, str]] = None, caption: Optional[str] = None, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, supports_streaming: Optional[bool] = None, disable_notification: Optional[bool] = None, reply_to_message_id: Optional[int] = None, @@ -654,7 +655,7 @@ class Bot(ContextInstanceMixin["Bot"]): height: Optional[int] = None, thumb: Optional[Union[InputFile, str]] = None, caption: Optional[str] = None, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, disable_notification: Optional[bool] = None, reply_to_message_id: Optional[int] = None, reply_markup: Optional[ @@ -716,7 +717,7 @@ class Bot(ContextInstanceMixin["Bot"]): chat_id: Union[int, str], voice: Union[InputFile, str], caption: Optional[str] = None, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, duration: Optional[int] = None, disable_notification: Optional[bool] = None, reply_to_message_id: Optional[int] = None, @@ -1696,7 +1697,7 @@ class Bot(ContextInstanceMixin["Bot"]): chat_id: Optional[Union[int, str]] = None, message_id: Optional[int] = None, inline_message_id: Optional[str] = None, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, disable_web_page_preview: Optional[bool] = None, reply_markup: Optional[InlineKeyboardMarkup] = None, ) -> Union[Message, bool]: @@ -1738,7 +1739,7 @@ class Bot(ContextInstanceMixin["Bot"]): message_id: Optional[int] = None, inline_message_id: Optional[str] = None, caption: Optional[str] = None, - parse_mode: Optional[str] = None, + parse_mode: Optional[str] = UNSET, reply_markup: Optional[InlineKeyboardMarkup] = None, ) -> Union[Message, bool]: """ diff --git a/aiogram/api/methods/base.py b/aiogram/api/methods/base.py index 72eafa05..35d5abe1 100644 --- a/aiogram/api/methods/base.py +++ b/aiogram/api/methods/base.py @@ -4,10 +4,10 @@ import abc import secrets from typing import TYPE_CHECKING, Any, Dict, Generator, Generic, Optional, TypeVar, Union -from pydantic import BaseConfig, BaseModel, Extra +from pydantic import BaseConfig, BaseModel, Extra, root_validator from pydantic.generics import GenericModel -from ..types import InputFile, ResponseParameters +from ..types import UNSET, InputFile, ResponseParameters if TYPE_CHECKING: # pragma: no cover from ..client.bot import Bot @@ -46,6 +46,20 @@ class TelegramMethod(abc.ABC, BaseModel, Generic[T]): arbitrary_types_allowed = True orm_mode = True + @root_validator(pre=True) + def remove_unset(cls, values: Dict[str, Any]) -> Dict[str, Any]: + """ + Remove UNSET from `parse_mode` 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 "parse_mode" in values and values["parse_mode"] is UNSET: + values.pop("parse_mode") + return values + @property @abc.abstractmethod def __returning__(self) -> type: # pragma: no cover @@ -106,18 +120,24 @@ def prepare_media_file(data: Dict[str, Any], files: Dict[str, InputFile]) -> Non def prepare_parse_mode(root: Any) -> None: + """ + Find and set parse_mode with highest priority. + + Developer can manually set parse_mode for each message (or message-like) object, + but if parse_mode was unset we should use value from Bot object. + + We can't use None for "unset state", because None itself is the parse_mode option. + """ if isinstance(root, list): for item in root: prepare_parse_mode(item) return - if root.get("parse_mode"): - return + if root.get("parse_mode", UNSET) is UNSET: + from ..client.bot import Bot - from ..client.bot import Bot - - bot = Bot.get_current(no_error=True) - if bot and bot.parse_mode: - root["parse_mode"] = bot.parse_mode - return - return + bot = Bot.get_current(no_error=True) + if bot and bot.parse_mode: + root["parse_mode"] = bot.parse_mode + else: + root["parse_mode"] = None diff --git a/aiogram/api/methods/edit_message_caption.py b/aiogram/api/methods/edit_message_caption.py index 75b5cc69..ebbe9c7b 100644 --- a/aiogram/api/methods/edit_message_caption.py +++ b/aiogram/api/methods/edit_message_caption.py @@ -1,6 +1,6 @@ from typing import Any, Dict, Optional, Union -from ..types import InlineKeyboardMarkup, Message +from ..types import UNSET, InlineKeyboardMarkup, Message from .base import Request, TelegramMethod, prepare_parse_mode @@ -23,7 +23,7 @@ class EditMessageCaption(TelegramMethod[Union[Message, bool]]): """Required if chat_id and message_id are not specified. Identifier of the inline message""" caption: Optional[str] = None """New caption of the message, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/methods/edit_message_text.py b/aiogram/api/methods/edit_message_text.py index 5c3c4c4c..20098fdc 100644 --- a/aiogram/api/methods/edit_message_text.py +++ b/aiogram/api/methods/edit_message_text.py @@ -1,6 +1,6 @@ from typing import Any, Dict, Optional, Union -from ..types import InlineKeyboardMarkup, Message +from ..types import UNSET, InlineKeyboardMarkup, Message from .base import Request, TelegramMethod @@ -23,7 +23,7 @@ class EditMessageText(TelegramMethod[Union[Message, bool]]): """Required if inline_message_id is not specified. Identifier of the message to edit""" inline_message_id: Optional[str] = None """Required if chat_id and message_id are not specified. Identifier of the inline message""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message.""" disable_web_page_preview: Optional[bool] = None diff --git a/aiogram/api/methods/send_animation.py b/aiogram/api/methods/send_animation.py index 27007d1b..aca62a40 100644 --- a/aiogram/api/methods/send_animation.py +++ b/aiogram/api/methods/send_animation.py @@ -1,6 +1,7 @@ from typing import Any, Dict, Optional, Union from ..types import ( + UNSET, ForceReply, InlineKeyboardMarkup, InputFile, @@ -45,7 +46,7 @@ class SendAnimation(TelegramMethod[Message]): caption: Optional[str] = None """Animation caption (may also be used when resending animation by file_id), 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" disable_notification: Optional[bool] = None diff --git a/aiogram/api/methods/send_audio.py b/aiogram/api/methods/send_audio.py index a67ca833..be4870c4 100644 --- a/aiogram/api/methods/send_audio.py +++ b/aiogram/api/methods/send_audio.py @@ -1,6 +1,7 @@ from typing import Any, Dict, Optional, Union from ..types import ( + UNSET, ForceReply, InlineKeyboardMarkup, InputFile, @@ -33,7 +34,7 @@ class SendAudio(TelegramMethod[Message]): file from the Internet, or upload a new one using multipart/form-data.""" caption: Optional[str] = None """Audio caption, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" duration: Optional[int] = None diff --git a/aiogram/api/methods/send_document.py b/aiogram/api/methods/send_document.py index 3c070539..c67588e4 100644 --- a/aiogram/api/methods/send_document.py +++ b/aiogram/api/methods/send_document.py @@ -1,6 +1,7 @@ from typing import Any, Dict, Optional, Union from ..types import ( + UNSET, ForceReply, InlineKeyboardMarkup, InputFile, @@ -39,7 +40,7 @@ class SendDocument(TelegramMethod[Message]): caption: Optional[str] = None """Document caption (may also be used when resending documents by file_id), 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" disable_notification: Optional[bool] = None diff --git a/aiogram/api/methods/send_message.py b/aiogram/api/methods/send_message.py index 849a1f5b..54f0fe37 100644 --- a/aiogram/api/methods/send_message.py +++ b/aiogram/api/methods/send_message.py @@ -1,6 +1,7 @@ from typing import Any, Dict, Optional, Union from ..types import ( + UNSET, ForceReply, InlineKeyboardMarkup, Message, @@ -24,7 +25,7 @@ class SendMessage(TelegramMethod[Message]): @channelusername)""" text: str """Text of the message to be sent, 1-4096 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message.""" disable_web_page_preview: Optional[bool] = None diff --git a/aiogram/api/methods/send_photo.py b/aiogram/api/methods/send_photo.py index 328b29b6..89a25864 100644 --- a/aiogram/api/methods/send_photo.py +++ b/aiogram/api/methods/send_photo.py @@ -1,6 +1,7 @@ from typing import Any, Dict, Optional, Union from ..types import ( + UNSET, ForceReply, InlineKeyboardMarkup, InputFile, @@ -30,7 +31,7 @@ class SendPhoto(TelegramMethod[Message]): caption: Optional[str] = None """Photo caption (may also be used when resending photos by file_id), 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" disable_notification: Optional[bool] = None diff --git a/aiogram/api/methods/send_video.py b/aiogram/api/methods/send_video.py index 07c4a3b6..f2659348 100644 --- a/aiogram/api/methods/send_video.py +++ b/aiogram/api/methods/send_video.py @@ -1,6 +1,7 @@ from typing import Any, Dict, Optional, Union from ..types import ( + UNSET, ForceReply, InlineKeyboardMarkup, InputFile, @@ -45,7 +46,7 @@ class SendVideo(TelegramMethod[Message]): caption: Optional[str] = None """Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" supports_streaming: Optional[bool] = None diff --git a/aiogram/api/methods/send_voice.py b/aiogram/api/methods/send_voice.py index 17522782..1369ad1c 100644 --- a/aiogram/api/methods/send_voice.py +++ b/aiogram/api/methods/send_voice.py @@ -1,6 +1,7 @@ from typing import Any, Dict, Optional, Union from ..types import ( + UNSET, ForceReply, InlineKeyboardMarkup, InputFile, @@ -33,7 +34,7 @@ class SendVoice(TelegramMethod[Message]): Internet, or upload a new one using multipart/form-data.""" caption: Optional[str] = None """Voice message caption, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" duration: Optional[int] = None diff --git a/aiogram/api/types/__init__.py b/aiogram/api/types/__init__.py index 429b6f41..f8fd0fcd 100644 --- a/aiogram/api/types/__init__.py +++ b/aiogram/api/types/__init__.py @@ -1,6 +1,6 @@ from .animation import Animation from .audio import Audio -from .base import TelegramObject +from .base import UNSET, TelegramObject from .bot_command import BotCommand from .callback_game import CallbackGame from .callback_query import CallbackQuery @@ -101,6 +101,7 @@ from .webhook_info import WebhookInfo __all__ = ( "TelegramObject", + "UNSET", "BufferedInputFile", "FSInputFile", "Update", diff --git a/aiogram/api/types/base.py b/aiogram/api/types/base.py index 8c098202..06618234 100644 --- a/aiogram/api/types/base.py +++ b/aiogram/api/types/base.py @@ -1,4 +1,6 @@ import datetime +from typing import Any +from unittest.mock import sentinel from pydantic import BaseModel, Extra @@ -19,3 +21,7 @@ class TelegramObject(ContextInstanceMixin["TelegramObject"], BaseModel): class MutableTelegramObject(TelegramObject): class Config: allow_mutation = True + + +UNSET: Any = sentinel.UNSET # special sentinel object which used in sutuation when None might be a useful value +print(id(UNSET)) diff --git a/aiogram/api/types/inline_query_result_audio.py b/aiogram/api/types/inline_query_result_audio.py index c47104ba..687de9f0 100644 --- a/aiogram/api/types/inline_query_result_audio.py +++ b/aiogram/api/types/inline_query_result_audio.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -32,7 +33,7 @@ class InlineQueryResultAudio(InlineQueryResult): """Title""" caption: Optional[str] = None """Caption, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" performer: Optional[str] = None diff --git a/aiogram/api/types/inline_query_result_cached_audio.py b/aiogram/api/types/inline_query_result_cached_audio.py index 426ea462..af508b2e 100644 --- a/aiogram/api/types/inline_query_result_cached_audio.py +++ b/aiogram/api/types/inline_query_result_cached_audio.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -30,7 +31,7 @@ class InlineQueryResultCachedAudio(InlineQueryResult): """A valid file identifier for the audio file""" caption: Optional[str] = None """Caption, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_cached_document.py b/aiogram/api/types/inline_query_result_cached_document.py index 27bcd27e..f9024291 100644 --- a/aiogram/api/types/inline_query_result_cached_document.py +++ b/aiogram/api/types/inline_query_result_cached_document.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -34,7 +35,7 @@ class InlineQueryResultCachedDocument(InlineQueryResult): """Short description of the result""" caption: Optional[str] = None """Caption of the document to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_cached_gif.py b/aiogram/api/types/inline_query_result_cached_gif.py index 2b85bcd9..3408a404 100644 --- a/aiogram/api/types/inline_query_result_cached_gif.py +++ b/aiogram/api/types/inline_query_result_cached_gif.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -30,7 +31,7 @@ class InlineQueryResultCachedGif(InlineQueryResult): """Title for the result""" caption: Optional[str] = None """Caption of the GIF file to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_cached_mpeg4_gif.py b/aiogram/api/types/inline_query_result_cached_mpeg4_gif.py index 5611e114..71a4e926 100644 --- a/aiogram/api/types/inline_query_result_cached_mpeg4_gif.py +++ b/aiogram/api/types/inline_query_result_cached_mpeg4_gif.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -31,7 +32,7 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): """Title for the result""" caption: Optional[str] = None """Caption of the MPEG-4 file to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_cached_photo.py b/aiogram/api/types/inline_query_result_cached_photo.py index da865bed..1e7abd57 100644 --- a/aiogram/api/types/inline_query_result_cached_photo.py +++ b/aiogram/api/types/inline_query_result_cached_photo.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -32,7 +33,7 @@ class InlineQueryResultCachedPhoto(InlineQueryResult): """Short description of the result""" caption: Optional[str] = None """Caption of the photo to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_cached_video.py b/aiogram/api/types/inline_query_result_cached_video.py index db71f4f2..b6161679 100644 --- a/aiogram/api/types/inline_query_result_cached_video.py +++ b/aiogram/api/types/inline_query_result_cached_video.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -32,7 +33,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult): """Short description of the result""" caption: Optional[str] = None """Caption of the video to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_cached_voice.py b/aiogram/api/types/inline_query_result_cached_voice.py index 9d65b6fd..12491b88 100644 --- a/aiogram/api/types/inline_query_result_cached_voice.py +++ b/aiogram/api/types/inline_query_result_cached_voice.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -32,7 +33,7 @@ class InlineQueryResultCachedVoice(InlineQueryResult): """Voice message title""" caption: Optional[str] = None """Caption, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_document.py b/aiogram/api/types/inline_query_result_document.py index 625b4675..0c66579c 100644 --- a/aiogram/api/types/inline_query_result_document.py +++ b/aiogram/api/types/inline_query_result_document.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -35,7 +36,7 @@ class InlineQueryResultDocument(InlineQueryResult): """Mime type of the content of the file, either 'application/pdf' or 'application/zip'""" caption: Optional[str] = None """Caption of the document to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" description: Optional[str] = None diff --git a/aiogram/api/types/inline_query_result_gif.py b/aiogram/api/types/inline_query_result_gif.py index ffaa7a66..1285b96f 100644 --- a/aiogram/api/types/inline_query_result_gif.py +++ b/aiogram/api/types/inline_query_result_gif.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -38,7 +39,7 @@ class InlineQueryResultGif(InlineQueryResult): """Title for the result""" caption: Optional[str] = None """Caption of the GIF file to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_mpeg4_gif.py b/aiogram/api/types/inline_query_result_mpeg4_gif.py index 59d1ef01..4fa6a8e9 100644 --- a/aiogram/api/types/inline_query_result_mpeg4_gif.py +++ b/aiogram/api/types/inline_query_result_mpeg4_gif.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -39,7 +40,7 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult): """Title for the result""" caption: Optional[str] = None """Caption of the MPEG-4 file to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_photo.py b/aiogram/api/types/inline_query_result_photo.py index 7ee7e4f5..5927c62c 100644 --- a/aiogram/api/types/inline_query_result_photo.py +++ b/aiogram/api/types/inline_query_result_photo.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -38,7 +39,7 @@ class InlineQueryResultPhoto(InlineQueryResult): """Short description of the result""" caption: Optional[str] = None """Caption of the photo to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" reply_markup: Optional[InlineKeyboardMarkup] = None diff --git a/aiogram/api/types/inline_query_result_video.py b/aiogram/api/types/inline_query_result_video.py index a0010fea..5ea390ed 100644 --- a/aiogram/api/types/inline_query_result_video.py +++ b/aiogram/api/types/inline_query_result_video.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -36,7 +37,7 @@ class InlineQueryResultVideo(InlineQueryResult): """Title for the result""" caption: Optional[str] = None """Caption of the video to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" video_width: Optional[int] = None diff --git a/aiogram/api/types/inline_query_result_voice.py b/aiogram/api/types/inline_query_result_voice.py index b4b10f4f..74d17448 100644 --- a/aiogram/api/types/inline_query_result_voice.py +++ b/aiogram/api/types/inline_query_result_voice.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional from pydantic import Field +from .base import UNSET from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover @@ -33,7 +34,7 @@ class InlineQueryResultVoice(InlineQueryResult): """Recording title""" caption: Optional[str] = None """Caption, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" voice_duration: Optional[int] = None diff --git a/aiogram/api/types/input_media_animation.py b/aiogram/api/types/input_media_animation.py index de994e85..e62dc95e 100644 --- a/aiogram/api/types/input_media_animation.py +++ b/aiogram/api/types/input_media_animation.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional, Union from pydantic import Field +from .base import UNSET from .input_media import InputMedia if TYPE_CHECKING: # pragma: no cover @@ -33,7 +34,7 @@ class InputMediaAnimation(InputMedia): multipart/form-data under .""" caption: Optional[str] = None """Caption of the animation to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" width: Optional[int] = None diff --git a/aiogram/api/types/input_media_audio.py b/aiogram/api/types/input_media_audio.py index 9d700101..40059bd9 100644 --- a/aiogram/api/types/input_media_audio.py +++ b/aiogram/api/types/input_media_audio.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional, Union from pydantic import Field +from .base import UNSET from .input_media import InputMedia if TYPE_CHECKING: # pragma: no cover @@ -33,7 +34,7 @@ class InputMediaAudio(InputMedia): multipart/form-data under .""" caption: Optional[str] = None """Caption of the audio to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" duration: Optional[int] = None diff --git a/aiogram/api/types/input_media_document.py b/aiogram/api/types/input_media_document.py index 5f95b233..d57f1178 100644 --- a/aiogram/api/types/input_media_document.py +++ b/aiogram/api/types/input_media_document.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional, Union from pydantic import Field +from .base import UNSET from .input_media import InputMedia if TYPE_CHECKING: # pragma: no cover @@ -33,6 +34,6 @@ class InputMediaDocument(InputMedia): multipart/form-data under .""" caption: Optional[str] = None """Caption of the document to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" diff --git a/aiogram/api/types/input_media_photo.py b/aiogram/api/types/input_media_photo.py index 7698d95d..c92b45e4 100644 --- a/aiogram/api/types/input_media_photo.py +++ b/aiogram/api/types/input_media_photo.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional, Union from pydantic import Field +from .base import UNSET from .input_media import InputMedia if TYPE_CHECKING: # pragma: no cover @@ -26,6 +27,6 @@ class InputMediaPhoto(InputMedia): name.""" caption: Optional[str] = None """Caption of the photo to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" diff --git a/aiogram/api/types/input_media_video.py b/aiogram/api/types/input_media_video.py index a0cdd46f..61e73c1e 100644 --- a/aiogram/api/types/input_media_video.py +++ b/aiogram/api/types/input_media_video.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional, Union from pydantic import Field +from .base import UNSET from .input_media import InputMedia if TYPE_CHECKING: # pragma: no cover @@ -33,7 +34,7 @@ class InputMediaVideo(InputMedia): multipart/form-data under .""" caption: Optional[str] = None """Caption of the video to be sent, 0-1024 characters after entities parsing""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.""" width: Optional[int] = None diff --git a/aiogram/api/types/input_text_message_content.py b/aiogram/api/types/input_text_message_content.py index ff3ef5d9..3c5bda13 100644 --- a/aiogram/api/types/input_text_message_content.py +++ b/aiogram/api/types/input_text_message_content.py @@ -2,6 +2,7 @@ from __future__ import annotations from typing import Optional +from .base import UNSET from .input_message_content import InputMessageContent @@ -14,7 +15,7 @@ class InputTextMessageContent(InputMessageContent): message_text: str """Text of the message to be sent, 1-4096 characters""" - parse_mode: Optional[str] = None + parse_mode: Optional[str] = UNSET """Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message.""" disable_web_page_preview: Optional[bool] = None diff --git a/tests/test_api/test_methods/test_base.py b/tests/test_api/test_methods/test_base.py index c32a075b..e3627d54 100644 --- a/tests/test_api/test_methods/test_base.py +++ b/tests/test_api/test_methods/test_base.py @@ -59,4 +59,4 @@ class TestPrepareParseMode: def test_bot_not_in_context(self): data = {} prepare_parse_mode(data) - assert "parse_mode" not in data + assert data["parse_mode"] is None