diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 711e00dd62d..ba3c919eff0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,24 +33,30 @@ jobs: python -W ignore -m pip install -r requirements-dev.txt - name: Test with pytest - # We run three different suites here - # 1. Test just the build process + # We run 3 different suites here + # 1. Test just utils.helpers.py without pytz being installed # 2. Test just test_no_passport.py without passport dependencies being installed # 3. Test everything else - # The second one is achieved by mocking the imports, see test_no_passport.py for details + # The first & second one are achieved by mocking the corresponding import + # See test_helpers.py & test_no_passport.py for details run: | - pytest -v -s --cov -k test_no_passport.py + pytest -v --cov -k test_no_passport.py no_passport_exit=$? export TEST_NO_PASSPORT='false' - pytest -v -s --cov --cov-append - passport_exit=$? - global_exit=$(( passport_exit > no_passport_exit ? passport_exit : no_passport_exit )) + pytest -v --cov --cov-append -k test_helpers.py + no_pytz_exit=$? + export TEST_NO_PYTZ='false' + pytest -v --cov --cov-append + full_exit=$? + special_exit=$(( no_pytz_exit > no_passport_exit ? no_pytz_exit : no_passport_exit )) + global_exit=$(( special_exit > full_exit ? special_exit : full_exit )) exit ${global_exit} env: JOB_INDEX: ${{ strategy.job-index }} BOTS: W3sidG9rZW4iOiAiNjk2MTg4NzMyOkFBR1Z3RUtmSEhsTmpzY3hFRE5LQXdraEdzdFpfa28xbUMwIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WldGaU1UUmxNbVF5TnpNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMi43IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMzkwOTgzOTk3IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzI3X2JvdCJ9LCB7InRva2VuIjogIjY3MTQ2ODg4NjpBQUdQR2ZjaVJJQlVORmU4MjR1SVZkcTdKZTNfWW5BVE5HdyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpHWXdPVGxrTXpNeE4yWTIiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTQ0NjAyMjUyMiIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zNF9ib3QifSwgeyJ0b2tlbiI6ICI2MjkzMjY1Mzg6QUFGUnJaSnJCN29CM211ekdzR0pYVXZHRTVDUXpNNUNVNG8iLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpNbU01WVdKaFl6a3hNMlUxIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgQ1B5dGhvbiAzLjUiLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDE0OTY5MTc3NTAiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX2NweXRob25fMzVfYm90In0sIHsidG9rZW4iOiAiNjQwMjA4OTQzOkFBRmhCalFwOXFtM1JUeFN6VXBZekJRakNsZS1Kano1aGNrIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WXpoa1pUZzFOamMxWXpWbCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMy42IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMzMzODcxNDYxIiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzM2X2JvdCJ9LCB7InRva2VuIjogIjY5NTEwNDA4ODpBQUhmenlsSU9qU0lJUy1lT25JMjB5MkUyMEhvZEhzZnotMCIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk9HUTFNRGd3WmpJd1pqRmwiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNyIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTQ3ODI5MzcxNCIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zN19ib3QifSwgeyJ0b2tlbiI6ICI2OTE0MjM1NTQ6QUFGOFdrakNaYm5IcVBfaTZHaFRZaXJGRWxackdhWU9oWDAiLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpZamM1TlRoaU1tUXlNV1ZoIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgUHlQeSAyLjciLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDEzNjM5MzI1NzMiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX3B5cHlfMjdfYm90In0sIHsidG9rZW4iOiAiNjg0MzM5OTg0OkFBRk1nRUVqcDAxcjVyQjAwN3lDZFZOc2c4QWxOc2FVLWNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TVRBek1UWTNNR1V5TmpnMCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIFB5UHkgMy41IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDA3ODM2NjA1IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19weXB5XzM1X2JvdCJ9LCB7InRva2VuIjogIjY5MDA5MTM0NzpBQUZMbVI1cEFCNVljcGVfbU9oN3pNNEpGQk9oMHozVDBUbyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpEaGxOekU1TURrd1lXSmkiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIEFwcFZleW9yIHVzaW5nIENQeXRob24gMy40IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMjc5NjAwMDI2IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX2FwcHZleW9yX2NweXRob25fMzRfYm90In0sIHsidG9rZW4iOiAiNjk0MzA4MDUyOkFBRUIyX3NvbkNrNTVMWTlCRzlBTy1IOGp4aVBTNTVvb0JBIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WW1aaVlXWm1NakpoWkdNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gQXBwVmV5b3IgdXNpbmcgQ1B5dGhvbiAyLjciLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDEyOTMwNzkxNjUiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfYXBwdmV5b3JfY3B5dGhvbl8yN19ib3QifSwgeyJ0b2tlbiI6ICIxMDU1Mzk3NDcxOkFBRzE4bkJfUzJXQXd1SjNnN29oS0JWZ1hYY2VNbklPeVNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TmpBd056QXpZalZpTkdOayIsICJuYW1lIjogIlBUQiB0ZXN0cyBbMF0iLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDExODU1MDk2MzYiLCAidXNlcm5hbWUiOiAicHRiXzBfYm90In0sIHsidG9rZW4iOiAiMTA0NzMyNjc3MTpBQUY4bk90ODFGcFg4bGJidno4VWV3UVF2UmZUYkZmQnZ1SSIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOllUVTFOVEk0WkdSallqbGkiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzFdIiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDg0Nzk3NjEyIiwgInVzZXJuYW1lIjogInB0Yl8xX2JvdCJ9LCB7InRva2VuIjogIjk3MTk5Mjc0NTpBQUdPa09hVzBOSGpnSXY1LTlqUWJPajR2R3FkaFNGLVV1cyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk5XWmtNV1ZoWWpsallqVTUiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzJdIiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDAyMjU1MDcwIiwgInVzZXJuYW1lIjogInB0Yl8yX2JvdCJ9XQ== - TEST_BUILD: "true" + TEST_NO_PYTZ : "true" TEST_NO_PASSPORT: "true" + TEST_BUILD: "true" shell: bash --noprofile --norc {0} - name: Submit coverage diff --git a/docs/source/conf.py b/docs/source/conf.py index c770db522be..b5b13afa6f3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,6 +33,9 @@ 'sphinx.ext.autodoc', 'sphinx.ext.napoleon' ] +# Don't show type hints in the signature - that just makes it hardly readable +# and we document the types anyway +autodoc_typehints = 'description' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/examples/persistentconversationbot.py b/examples/persistentconversationbot.py index 1d9afe10959..1c9129af899 100644 --- a/examples/persistentconversationbot.py +++ b/examples/persistentconversationbot.py @@ -122,7 +122,7 @@ def done(update: Update, context: CallbackContext) -> None: del context.user_data['choice'] update.message.reply_text( - "I learned these facts about you:" f"{facts_to_str(context.user_data)}" "Until next time!" + "I learned these facts about you:" f"{facts_to_str(context.user_data)} Until next time!" ) return ConversationHandler.END diff --git a/examples/pollbot.py b/examples/pollbot.py index 50f80110714..d2f27123d30 100644 --- a/examples/pollbot.py +++ b/examples/pollbot.py @@ -148,7 +148,7 @@ def receive_poll(update: Update, context: CallbackContext) -> None: def help_handler(update: Update, context: CallbackContext) -> None: """Display a help message""" - update.message.reply_text("Use /quiz, /poll or /preview to test this " "bot.") + update.message.reply_text("Use /quiz, /poll or /preview to test this bot.") def main() -> None: diff --git a/telegram/bot.py b/telegram/bot.py index 94ea76af2d1..b76e1b1720a 100644 --- a/telegram/bot.py +++ b/telegram/bot.py @@ -21,7 +21,6 @@ """This module contains an object that represents a Telegram Bot.""" import functools -import inspect import logging from datetime import datetime @@ -34,6 +33,8 @@ TypeVar, Union, no_type_check, + Dict, + cast, ) try: @@ -93,9 +94,10 @@ to_timestamp, is_local_file, parse_file_input, + DEFAULT_20, ) from telegram.utils.request import Request -from telegram.utils.types import FileInput, JSONDict +from telegram.utils.types import FileInput, JSONDict, ODVInput, DVInput if TYPE_CHECKING: from telegram.ext import Defaults @@ -155,41 +157,6 @@ class Bot(TelegramObject): """ - def __new__(cls, *args: object, **kwargs: object) -> 'Bot': # pylint: disable=W0613 - # Get default values from kwargs - defaults = kwargs.get('defaults') - - # Make an instance of the class - instance = super().__new__(cls) - - if not defaults: - return instance - - # For each method ... - for method_name, method in inspect.getmembers(instance, predicate=inspect.ismethod): - # ... get kwargs - signature = inspect.signature(method, follow_wrapped=True) - kwarg_names = ( - p.name - for p in signature.parameters.values() - if p.default != inspect.Signature.empty - ) - # ... check if Defaults has a attribute that matches the kwarg name - needs_default = ( - kwarg_name for kwarg_name in kwarg_names if hasattr(defaults, kwarg_name) - ) - # ... make a dict of kwarg name and the default value - default_kwargs = { - kwarg_name: getattr(defaults, kwarg_name) - for kwarg_name in needs_default - if (getattr(defaults, kwarg_name) is not DEFAULT_NONE) - } - # ... apply the defaults using a partial - if default_kwargs: - setattr(instance, method_name, functools.partial(method, **default_kwargs)) - - return instance - def __init__( self, token: str, @@ -228,11 +195,47 @@ def __init__( private_key, password=private_key_password, backend=default_backend() ) + def _insert_defaults( + self, data: Dict[str, object], timeout: ODVInput[float] + ) -> Optional[float]: + """ + Inserts the defaults values for optional kwargs for which tg.ext.Defaults provides + convenience functionality, i.e. the kwargs with a tg.utils.helpers.DefaultValue default + + data is edited in-place. As timeout is not passed via the kwargs, it needs to be passed + separately and gets returned. + + This can only work, if all kwargs that may have defaults are passed in data! + """ + effective_timeout = DefaultValue.get_value(timeout) + + # If we have no Defaults, we just need to replace DefaultValue instances + # with the actual value + if not self.defaults: + data.update((key, DefaultValue.get_value(value)) for key, value in data.items()) + return effective_timeout + + # if we have Defaults, we replace all DefaultValue instances with the relevant + # Defaults value. If there is none, we fall back to the default value of the bot method + for key, val in data.items(): + if isinstance(val, DefaultValue): + data[key] = self.defaults.api_defaults.get(key, val.value) + + if isinstance(timeout, DefaultValue): + # If we get here, we use Defaults.timeout, unless that's not set, which is the + # case if isinstance(self.defaults.timeout, DefaultValue) + return ( + self.defaults.timeout + if not isinstance(self.defaults.timeout, DefaultValue) + else effective_timeout + ) + return effective_timeout + def _post( self, endpoint: str, data: JSONDict = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[bool, JSONDict, None]: if data is None: @@ -244,27 +247,36 @@ def _post( else: data = api_kwargs - return self.request.post(f'{self.base_url}/{endpoint}', data=data, timeout=timeout) + # Insert is in-place, so no return value for data + if endpoint != 'getUpdates': + effective_timeout = self._insert_defaults(data, timeout) + else: + effective_timeout = cast(float, timeout) + # Drop any None values because Telegram doesn't handle them well + data = {key: value for key, value in data.items() if value is not None} + + return self.request.post( + f'{self.base_url}/{endpoint}', data=data, timeout=effective_timeout + ) def _message( self, endpoint: str, data: JSONDict, reply_to_message_id: Union[str, int] = None, - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: ReplyMarkup = None, - allow_sending_without_reply: bool = None, - timeout: float = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[bool, Message]: if reply_to_message_id is not None: data['reply_to_message_id'] = reply_to_message_id - if disable_notification is not None: - data['disable_notification'] = disable_notification - - if allow_sending_without_reply is not None: - data['allow_sending_without_reply'] = allow_sending_without_reply + # We don't check if (DEFAULT_)None here, so that _put is able to insert the defaults + # correctly, if necessary + data['disable_notification'] = disable_notification + data['allow_sending_without_reply'] = allow_sending_without_reply if reply_markup is not None: if isinstance(reply_markup, ReplyMarkup): @@ -276,7 +288,7 @@ def _message( if data.get('media') and (data['media'].parse_mode == DEFAULT_NONE): if self.defaults: - data['media'].parse_mode = self.defaults.parse_mode + data['media'].parse_mode = DefaultValue.get_value(self.defaults.parse_mode) else: data['media'].parse_mode = None @@ -374,7 +386,7 @@ def name(self) -> str: return f'@{self.username}' @log - def get_me(self, timeout: int = None, api_kwargs: JSONDict = None) -> User: + def get_me(self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None) -> User: """A simple method for testing your bot's auth token. Requires no parameters. Args: @@ -403,14 +415,14 @@ def send_message( self, chat_id: Union[int, str], text: str, - parse_mode: str = None, - disable_web_page_preview: bool = None, - disable_notification: bool = False, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Message: """Use this method to send text messages. @@ -449,14 +461,15 @@ def send_message( :class:`telegram.error.TelegramError` """ - data: JSONDict = {'chat_id': chat_id, 'text': text} + data: JSONDict = { + 'chat_id': chat_id, + 'text': text, + 'parse_mode': parse_mode, + 'disable_web_page_preview': disable_web_page_preview, + } - if parse_mode: - data['parse_mode'] = parse_mode if entities: data['entities'] = [me.to_dict() for me in entities] - if disable_web_page_preview: - data['disable_web_page_preview'] = disable_web_page_preview return self._message( # type: ignore[return-value] 'sendMessage', @@ -474,7 +487,7 @@ def delete_message( self, chat_id: Union[str, int], message_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -520,8 +533,8 @@ def forward_message( chat_id: Union[int, str], from_chat_id: Union[str, int], message_id: Union[str, int], - disable_notification: bool = False, - timeout: float = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Message: """Use this method to forward messages of any kind. @@ -570,13 +583,13 @@ def send_photo( chat_id: int, photo: Union[FileInput, 'PhotoSize'], caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> Message: @@ -634,12 +647,12 @@ def send_photo( data: JSONDict = { 'chat_id': chat_id, 'photo': parse_file_input(photo, PhotoSize, filename=filename), + 'parse_mode': parse_mode, } if caption: data['caption'] = caption - if parse_mode: - data['parse_mode'] = parse_mode + if caption_entities: data['caption_entities'] = [me.to_dict() for me in caption_entities] @@ -663,14 +676,14 @@ def send_audio( performer: str = None, title: str = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> Message: @@ -747,6 +760,7 @@ def send_audio( data: JSONDict = { 'chat_id': chat_id, 'audio': parse_file_input(audio, Audio, filename=filename), + 'parse_mode': parse_mode, } if duration: @@ -757,8 +771,7 @@ def send_audio( data['title'] = title if caption: data['caption'] = caption - if parse_mode: - data['parse_mode'] = parse_mode + if caption_entities: data['caption_entities'] = [me.to_dict() for me in caption_entities] if thumb: @@ -782,15 +795,15 @@ def send_document( document: Union[FileInput, 'Document'], filename: str = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, api_kwargs: JSONDict = None, disable_content_type_detection: bool = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Message: """ @@ -860,12 +873,12 @@ def send_document( data: JSONDict = { 'chat_id': chat_id, 'document': parse_file_input(document, Document, filename=filename), + 'parse_mode': parse_mode, } if caption: data['caption'] = caption - if parse_mode: - data['parse_mode'] = parse_mode + if caption_entities: data['caption_entities'] = [me.to_dict() for me in caption_entities] if disable_content_type_detection is not None: @@ -889,12 +902,12 @@ def send_sticker( self, chat_id: Union[int, str], sticker: Union[FileInput, 'Sticker'], - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> Message: """ Use this method to send static .WEBP or animated .TGS stickers. @@ -955,17 +968,17 @@ def send_video( video: Union[FileInput, 'Video'], duration: int = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, width: int = None, height: int = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: bool = None, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> Message: @@ -1045,14 +1058,13 @@ def send_video( data: JSONDict = { 'chat_id': chat_id, 'video': parse_file_input(video, Video, filename=filename), + 'parse_mode': parse_mode, } if duration: data['duration'] = duration if caption: data['caption'] = caption - if parse_mode: - data['parse_mode'] = parse_mode if caption_entities: data['caption_entities'] = [me.to_dict() for me in caption_entities] if supports_streaming: @@ -1082,13 +1094,13 @@ def send_video_note( video_note: Union[FileInput, 'VideoNote'], duration: int = None, length: int = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: str = None, ) -> Message: """ @@ -1184,13 +1196,13 @@ def send_animation( height: int = None, thumb: FileInput = None, caption: str = None, - parse_mode: str = None, - disable_notification: bool = False, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> Message: @@ -1264,6 +1276,7 @@ def send_animation( data: JSONDict = { 'chat_id': chat_id, 'animation': parse_file_input(animation, Animation, filename=filename), + 'parse_mode': parse_mode, } if duration: @@ -1276,8 +1289,6 @@ def send_animation( data['thumb'] = parse_file_input(thumb, attach=True) if caption: data['caption'] = caption - if parse_mode: - data['parse_mode'] = parse_mode if caption_entities: data['caption_entities'] = [me.to_dict() for me in caption_entities] @@ -1299,13 +1310,13 @@ def send_voice( voice: Union[FileInput, 'Voice'], duration: int = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> Message: @@ -1368,14 +1379,14 @@ def send_voice( data: JSONDict = { 'chat_id': chat_id, 'voice': parse_file_input(voice, Voice, filename=filename), + 'parse_mode': parse_mode, } if duration: data['duration'] = duration if caption: data['caption'] = caption - if parse_mode: - data['parse_mode'] = parse_mode + if caption_entities: data['caption_entities'] = [me.to_dict() for me in caption_entities] @@ -1397,11 +1408,11 @@ def send_media_group( media: List[ Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] ], - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> List[Message]: """Use this method to send a group of photos or videos as an album. @@ -1427,29 +1438,26 @@ def send_media_group( Raises: :class:`telegram.error.TelegramError` """ - data: JSONDict = {'chat_id': chat_id, 'media': media} + data: JSONDict = { + 'chat_id': chat_id, + 'media': media, + 'disable_notification': disable_notification, + 'allow_sending_without_reply': allow_sending_without_reply, + } for m in data['media']: if m.parse_mode == DEFAULT_NONE: if self.defaults: - m.parse_mode = self.defaults.parse_mode + m.parse_mode = DefaultValue.get_value(self.defaults.parse_mode) else: m.parse_mode = None if reply_to_message_id: data['reply_to_message_id'] = reply_to_message_id - if disable_notification: - data['disable_notification'] = disable_notification - if allow_sending_without_reply is not None: - data['allow_sending_without_reply'] = allow_sending_without_reply result = self._post('sendMediaGroup', data, timeout=timeout, api_kwargs=api_kwargs) - if self.defaults: - for res in result: # type: ignore - res['default_quote'] = self.defaults.quote # type: ignore - - return [Message.de_json(res, self) for res in result] # type: ignore + return Message.de_list(result, self) # type: ignore @log def send_location( @@ -1457,17 +1465,17 @@ def send_location( chat_id: Union[int, str], latitude: float = None, longitude: float = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, location: Location = None, live_period: int = None, api_kwargs: JSONDict = None, horizontal_accuracy: float = None, heading: int = None, proximity_alert_radius: int = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> Message: """Use this method to send point on the map. @@ -1513,12 +1521,12 @@ def send_location( """ if not ((latitude is not None and longitude is not None) or location): raise ValueError( - "Either location or latitude and longitude must be passed as" "argument." + "Either location or latitude and longitude must be passed as argument." ) if not (latitude is not None or longitude is not None) ^ bool(location): raise ValueError( - "Either location or latitude and longitude must be passed as" "argument. Not both." + "Either location or latitude and longitude must be passed as argument. Not both." ) if isinstance(location, Location): @@ -1557,7 +1565,7 @@ def edit_message_live_location( longitude: float = None, location: Location = None, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, horizontal_accuracy: float = None, heading: int = None, @@ -1602,11 +1610,11 @@ def edit_message_live_location( """ if not (all([latitude, longitude]) or location): raise ValueError( - "Either location or latitude and longitude must be passed as" "argument." + "Either location or latitude and longitude must be passed as argument." ) if not (latitude is not None or longitude is not None) ^ bool(location): raise ValueError( - "Either location or latitude and longitude must be passed as" "argument. Not both." + "Either location or latitude and longitude must be passed as argument. Not both." ) if isinstance(location, Location): @@ -1643,7 +1651,7 @@ def stop_message_live_location( message_id: Union[str, int] = None, inline_message_id: Union[str, int] = None, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """Use this method to stop updating a live location message sent by the bot or via the bot @@ -1695,16 +1703,16 @@ def send_venue( title: str = None, address: str = None, foursquare_id: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, venue: Venue = None, foursquare_type: str = None, api_kwargs: JSONDict = None, google_place_id: str = None, google_place_type: str = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> Message: """Use this method to send information about a venue. @@ -1805,14 +1813,14 @@ def send_contact( phone_number: str = None, first_name: str = None, last_name: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, contact: Contact = None, vcard: str = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> Message: """Use this method to send phone contacts. @@ -1853,7 +1861,7 @@ def send_contact( """ if (not contact) and (not all([phone_number, first_name])): raise ValueError( - "Either contact or phone_number and first_name must be passed as" "arguments." + "Either contact or phone_number and first_name must be passed as arguments." ) if isinstance(contact, Contact): @@ -1889,12 +1897,12 @@ def send_game( self, chat_id: Union[int, str], game_short_name: str, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> Message: """Use this method to send a game. @@ -1943,7 +1951,7 @@ def send_chat_action( self, chat_id: Union[str, int], action: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -1989,7 +1997,7 @@ def answer_inline_query( next_offset: str = None, switch_pm_text: str = None, switch_pm_parameter: str = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, current_offset: str = None, api_kwargs: JSONDict = None, ) -> bool: @@ -2054,27 +2062,29 @@ def answer_inline_query( @no_type_check def _set_defaults(res): # pylint: disable=W0212 - if res._has_parse_mode and res.parse_mode == DEFAULT_NONE: + if hasattr(res, 'parse_mode') and res.parse_mode == DEFAULT_NONE: if self.defaults: res.parse_mode = self.defaults.parse_mode else: res.parse_mode = None - if res._has_input_message_content and res.input_message_content: + if hasattr(res, 'input_message_content') and res.input_message_content: if ( - res.input_message_content._has_parse_mode + hasattr(res.input_message_content, 'parse_mode') and res.input_message_content.parse_mode == DEFAULT_NONE ): if self.defaults: - res.input_message_content.parse_mode = self.defaults.parse_mode + res.input_message_content.parse_mode = DefaultValue.get_value( + self.defaults.parse_mode + ) else: res.input_message_content.parse_mode = None if ( - res.input_message_content._has_disable_web_page_preview + hasattr(res.input_message_content, 'disable_web_page_preview') and res.input_message_content.disable_web_page_preview == DEFAULT_NONE ): if self.defaults: res.input_message_content.disable_web_page_preview = ( - self.defaults.disable_web_page_preview + DefaultValue.get_value(self.defaults.disable_web_page_preview) ) else: res.input_message_content.disable_web_page_preview = None @@ -2142,7 +2152,7 @@ def get_user_profile_photos( user_id: Union[str, int], offset: int = None, limit: int = 100, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Optional[UserProfilePhotos]: """Use this method to get a list of profile pictures for a user. @@ -2183,7 +2193,7 @@ def get_file( file_id: Union[ str, Animation, Audio, ChatPhoto, Document, PhotoSize, Sticker, Video, VideoNote, Voice ], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> File: """ @@ -2242,7 +2252,7 @@ def kick_chat_member( self, chat_id: Union[str, int], user_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, until_date: Union[int, datetime] = None, api_kwargs: JSONDict = None, ) -> bool: @@ -2292,7 +2302,7 @@ def unban_chat_member( self, chat_id: Union[str, int], user_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, only_if_banned: bool = None, ) -> bool: @@ -2339,7 +2349,7 @@ def answer_callback_query( show_alert: bool = False, url: str = None, cache_time: int = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -2401,10 +2411,10 @@ def edit_message_text( chat_id: Union[str, int] = None, message_id: Union[str, int] = None, inline_message_id: Union[str, int] = None, - parse_mode: str = None, - disable_web_page_preview: bool = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Union[Message, bool]: @@ -2443,7 +2453,11 @@ def edit_message_text( :class:`telegram.error.TelegramError` """ - data: JSONDict = {'text': text} + data: JSONDict = { + 'text': text, + 'parse_mode': parse_mode, + 'disable_web_page_preview': disable_web_page_preview, + } if chat_id: data['chat_id'] = chat_id @@ -2451,12 +2465,8 @@ def edit_message_text( data['message_id'] = message_id if inline_message_id: data['inline_message_id'] = inline_message_id - if parse_mode: - data['parse_mode'] = parse_mode if entities: data['entities'] = [me.to_dict() for me in entities] - if disable_web_page_preview: - data['disable_web_page_preview'] = disable_web_page_preview return self._message( 'editMessageText', @@ -2474,8 +2484,8 @@ def edit_message_caption( inline_message_id: Union[str, int] = None, caption: str = None, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, - parse_mode: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Union[Message, bool]: @@ -2520,12 +2530,10 @@ def edit_message_caption( 'inline_message_id is not specified' ) - data: JSONDict = {} + data: JSONDict = {'parse_mode': parse_mode} if caption: data['caption'] = caption - if parse_mode: - data['parse_mode'] = parse_mode if caption_entities: data['caption_entities'] = [me.to_dict() for me in caption_entities] if chat_id: @@ -2551,7 +2559,7 @@ def edit_message_media( inline_message_id: Union[str, int] = None, media: 'InputMedia' = None, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """ @@ -2617,7 +2625,7 @@ def edit_message_reply_markup( message_id: Union[str, int] = None, inline_message_id: Union[str, int] = None, reply_markup: Optional['InlineKeyboardMarkup'] = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """ @@ -2696,6 +2704,9 @@ def get_updates( timeout (:obj:`int`, optional): Timeout in seconds for long polling. Defaults to 0, i.e. usual short polling. Should be positive, short polling should be used for testing purposes only. + read_latency (:obj:`float`| :obj:`int`, optional): Grace time in seconds for receiving + the reply from server. Will be added to the ``timeout`` value and used as the read + timeout from server. Defaults to ``2``. allowed_updates (List[:obj:`str`]), optional): A JSON-serialized list the types of updates you want your bot to receive. For example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these types. @@ -2745,10 +2756,6 @@ def get_updates( else: self.logger.debug('No new updates found.') - if self.defaults: - for u in result: # type: ignore - u['default_quote'] = self.defaults.quote # type: ignore - return [Update.de_json(u, self) for u in result] # type: ignore @log @@ -2756,7 +2763,7 @@ def set_webhook( self, url: str = None, certificate: FileInput = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, max_connections: int = 40, allowed_updates: List[str] = None, api_kwargs: JSONDict = None, @@ -2845,7 +2852,10 @@ def set_webhook( @log def delete_webhook( - self, timeout: float = None, api_kwargs: JSONDict = None, drop_pending_updates: bool = None + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + drop_pending_updates: bool = None, ) -> bool: """ Use this method to remove webhook integration if you decide to switch back to @@ -2878,7 +2888,10 @@ def delete_webhook( @log def leave_chat( - self, chat_id: Union[str, int], timeout: float = None, api_kwargs: JSONDict = None + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> bool: """Use this method for your bot to leave a group, supergroup or channel. @@ -2906,7 +2919,10 @@ def leave_chat( @log def get_chat( - self, chat_id: Union[str, int], timeout: float = None, api_kwargs: JSONDict = None + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> Chat: """ Use this method to get up to date information about the chat (current name of the user for @@ -2932,14 +2948,14 @@ def get_chat( result = self._post('getChat', data, timeout=timeout, api_kwargs=api_kwargs) - if self.defaults: - result['default_quote'] = self.defaults.quote # type: ignore - return Chat.de_json(result, self) # type: ignore @log def get_chat_administrators( - self, chat_id: Union[str, int], timeout: float = None, api_kwargs: JSONDict = None + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> List[ChatMember]: """ Use this method to get a list of administrators in a chat. @@ -2967,11 +2983,14 @@ def get_chat_administrators( result = self._post('getChatAdministrators', data, timeout=timeout, api_kwargs=api_kwargs) - return [ChatMember.de_json(x, self) for x in result] # type: ignore + return ChatMember.de_list(result, self) # type: ignore @log def get_chat_members_count( - self, chat_id: Union[str, int], timeout: float = None, api_kwargs: JSONDict = None + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> int: """Use this method to get the number of members in a chat. @@ -3002,7 +3021,7 @@ def get_chat_member( self, chat_id: Union[str, int], user_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> ChatMember: """Use this method to get information about a member of a chat. @@ -3035,7 +3054,7 @@ def set_chat_sticker_set( self, chat_id: Union[str, int], sticker_set_name: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Use this method to set a new group sticker set for a supergroup. @@ -3065,7 +3084,10 @@ def set_chat_sticker_set( @log def delete_chat_sticker_set( - self, chat_id: Union[str, int], timeout: float = None, api_kwargs: JSONDict = None + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> bool: """Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. @@ -3090,7 +3112,9 @@ def delete_chat_sticker_set( return result # type: ignore[return-value] - def get_webhook_info(self, timeout: float = None, api_kwargs: JSONDict = None) -> WebhookInfo: + def get_webhook_info( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> WebhookInfo: """Use this method to get current webhook status. Requires no parameters. If the bot is using getUpdates, will return an object with the url field empty. @@ -3120,7 +3144,7 @@ def set_game_score( inline_message_id: Union[str, int] = None, force: bool = None, disable_edit_message: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """ @@ -3181,7 +3205,7 @@ def get_game_high_scores( chat_id: Union[str, int] = None, message_id: Union[str, int] = None, inline_message_id: Union[str, int] = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> List[GameHighScore]: """ @@ -3220,7 +3244,7 @@ def get_game_high_scores( result = self._post('getGameHighScores', data, timeout=timeout, api_kwargs=api_kwargs) - return [GameHighScore.de_json(hs, self) for hs in result] # type: ignore + return GameHighScore.de_list(result, self) # type: ignore @log def send_invoice( @@ -3242,15 +3266,15 @@ def send_invoice( need_email: bool = None, need_shipping_address: bool = None, is_flexible: bool = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: InlineKeyboardMarkup = None, provider_data: Union[str, object] = None, send_phone_number_to_provider: bool = None, send_email_to_provider: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> Message: """Use this method to send invoices. @@ -3370,7 +3394,7 @@ def answer_shipping_query( ok: bool, shipping_options: List[ShippingOption] = None, error_message: str = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -3434,7 +3458,7 @@ def answer_pre_checkout_query( pre_checkout_query_id: str, ok: bool, error_message: str = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -3494,7 +3518,7 @@ def restrict_chat_member( user_id: Union[str, int], permissions: ChatPermissions, until_date: Union[int, datetime] = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -3561,7 +3585,7 @@ def promote_chat_member( can_restrict_members: bool = None, can_pin_messages: bool = None, can_promote_members: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, is_anonymous: bool = None, ) -> bool: @@ -3637,7 +3661,7 @@ def set_chat_permissions( self, chat_id: Union[str, int], permissions: ChatPermissions, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -3674,7 +3698,7 @@ def set_chat_administrator_custom_title( chat_id: Union[int, str], user_id: Union[int, str], custom_title: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -3710,7 +3734,10 @@ def set_chat_administrator_custom_title( @log def export_chat_invite_link( - self, chat_id: Union[str, int], timeout: float = None, api_kwargs: JSONDict = None + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> str: """ Use this method to generate a new invite link for a chat; any previously generated link @@ -3744,7 +3771,7 @@ def set_chat_photo( self, chat_id: Union[str, int], photo: FileInput, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, ) -> bool: """Use this method to set a new profile photo for the chat. @@ -3780,7 +3807,10 @@ def set_chat_photo( @log def delete_chat_photo( - self, chat_id: Union[str, int], timeout: float = None, api_kwargs: JSONDict = None + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> bool: """ Use this method to delete a chat photo. Photos can't be changed for private chats. The bot @@ -3814,7 +3844,7 @@ def set_chat_title( self, chat_id: Union[str, int], title: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -3850,7 +3880,7 @@ def set_chat_description( self, chat_id: Union[str, int], description: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -3886,8 +3916,8 @@ def pin_chat_message( self, chat_id: Union[str, int], message_id: Union[str, int], - disable_notification: bool = None, - timeout: float = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -3916,10 +3946,11 @@ def pin_chat_message( :class:`telegram.error.TelegramError` """ - data: JSONDict = {'chat_id': chat_id, 'message_id': message_id} - - if disable_notification is not None: - data['disable_notification'] = disable_notification + data: JSONDict = { + 'chat_id': chat_id, + 'message_id': message_id, + 'disable_notification': disable_notification, + } return self._post( # type: ignore[return-value] 'pinChatMessage', data, timeout=timeout, api_kwargs=api_kwargs @@ -3929,7 +3960,7 @@ def pin_chat_message( def unpin_chat_message( self, chat_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, message_id: Union[str, int] = None, ) -> bool: @@ -3970,7 +4001,7 @@ def unpin_chat_message( def unpin_all_chat_messages( self, chat_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -4004,7 +4035,10 @@ def unpin_all_chat_messages( @log def get_sticker_set( - self, name: str, timeout: float = None, api_kwargs: JSONDict = None + self, + name: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> StickerSet: """Use this method to get a sticker set. @@ -4034,7 +4068,7 @@ def upload_sticker_file( self, user_id: Union[str, int], png_sticker: FileInput, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, ) -> File: """ @@ -4084,7 +4118,7 @@ def create_new_sticker_set( png_sticker: FileInput = None, contains_masks: bool = None, mask_position: MaskPosition = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, tgs_sticker: FileInput = None, api_kwargs: JSONDict = None, ) -> bool: @@ -4171,7 +4205,7 @@ def add_sticker_to_set( emojis: str, png_sticker: FileInput = None, mask_position: MaskPosition = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, tgs_sticker: FileInput = None, api_kwargs: JSONDict = None, ) -> bool: @@ -4192,6 +4226,7 @@ def add_sticker_to_set( Args: user_id (:obj:`int`): User identifier of created sticker set owner. + name (:obj:`str`): Sticker set name. png_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ optional): PNG image with the sticker, @@ -4244,7 +4279,11 @@ def add_sticker_to_set( @log def set_sticker_position_in_set( - self, sticker: str, position: int, timeout: float = None, api_kwargs: JSONDict = None + self, + sticker: str, + position: int, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> bool: """Use this method to move a sticker in a set created by the bot to a specific position. @@ -4274,7 +4313,10 @@ def set_sticker_position_in_set( @log def delete_sticker_from_set( - self, sticker: str, timeout: float = None, api_kwargs: JSONDict = None + self, + sticker: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, ) -> bool: """Use this method to delete a sticker from a set created by the bot. @@ -4305,7 +4347,7 @@ def set_sticker_set_thumb( name: str, user_id: Union[str, int], thumb: FileInput = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Use this method to set the thumbnail of a sticker set. Animated thumbnails can be set @@ -4356,7 +4398,7 @@ def set_passport_data_errors( self, user_id: Union[str, int], errors: List[PassportElementError], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -4403,16 +4445,16 @@ def send_poll( allows_multiple_answers: bool = False, correct_option_id: int = None, is_closed: bool = None, - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, explanation: str = None, - explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE, + explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: int = None, close_date: Union[int, datetime] = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Message: """ @@ -4472,13 +4514,12 @@ def send_poll( :class:`telegram.error.TelegramError` """ - data: JSONDict = {'chat_id': chat_id, 'question': question, 'options': options} - - if explanation_parse_mode == DEFAULT_NONE: - if self.defaults: - explanation_parse_mode = self.defaults.parse_mode - else: - explanation_parse_mode = None + data: JSONDict = { + 'chat_id': chat_id, + 'question': question, + 'options': options, + 'explanation_parse_mode': explanation_parse_mode, + } if not is_anonymous: data['is_anonymous'] = is_anonymous @@ -4492,8 +4533,6 @@ def send_poll( data['is_closed'] = is_closed if explanation: data['explanation'] = explanation - if explanation_parse_mode: - data['explanation_parse_mode'] = explanation_parse_mode if explanation_entities: data['explanation_entities'] = [me.to_dict() for me in explanation_entities] if open_period: @@ -4522,7 +4561,7 @@ def stop_poll( chat_id: Union[int, str], message_id: Union[int, str], reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Poll: """ @@ -4566,13 +4605,13 @@ def stop_poll( def send_dice( self, chat_id: Union[int, str], - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, emoji: str = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> Message: """ Use this method to send an animated emoji, which will have a random value. On success, the @@ -4626,7 +4665,7 @@ def send_dice( @log def get_my_commands( - self, timeout: float = None, api_kwargs: JSONDict = None + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None ) -> List[BotCommand]: """ Use this method to get the current list of the bot's commands. @@ -4647,15 +4686,15 @@ def get_my_commands( """ result = self._post('getMyCommands', timeout=timeout, api_kwargs=api_kwargs) - self._commands = [BotCommand.de_json(c, self) for c in result] # type: ignore + self._commands = BotCommand.de_list(result, self) # type: ignore[assignment,arg-type] - return self._commands + return self._commands # type: ignore[return-value] @log def set_my_commands( self, commands: List[Union[BotCommand, Tuple[str, str]]], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """ @@ -4691,7 +4730,7 @@ def set_my_commands( return result # type: ignore[return-value] @log - def log_out(self) -> bool: + def log_out(self, timeout: ODVInput[float] = DEFAULT_NONE) -> bool: """ Use this method to log out from the cloud Bot API server before launching the bot locally. You *must* log out the bot before running it locally, otherwise there is no guarantee that @@ -4699,6 +4738,11 @@ def log_out(self) -> bool: local server, but will not be able to log in back to the cloud Bot API server for 10 minutes. + Args: + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + Returns: :obj:`True`: On success @@ -4706,16 +4750,21 @@ def log_out(self) -> bool: :class:`telegram.error.TelegramError` """ - return self._post('logOut') # type: ignore[return-value] + return self._post('logOut', timeout=timeout) # type: ignore[return-value] @log - def close(self) -> bool: + def close(self, timeout: ODVInput[float] = DEFAULT_NONE) -> bool: """ Use this method to close the bot instance before moving it from one local server to another. You need to delete the webhook before calling this method to ensure that the bot isn't launched again after server restart. The method will return error 429 in the first 10 minutes after the bot is launched. + Args: + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + Returns: :obj:`True`: On success @@ -4723,7 +4772,7 @@ def close(self) -> bool: :class:`telegram.error.TelegramError` """ - return self._post('close') # type: ignore[return-value] + return self._post('close', timeout=timeout) # type: ignore[return-value] @log def copy_message( @@ -4732,13 +4781,13 @@ def copy_message( from_chat_id: Union[str, int], message_id: Union[str, int], caption: str = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - allow_sending_without_reply: bool = False, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> MessageId: """ @@ -4784,19 +4833,16 @@ def copy_message( 'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id, + 'parse_mode': parse_mode, + 'disable_notification': disable_notification, + 'allow_sending_without_reply': allow_sending_without_reply, } if caption: data['caption'] = caption - if parse_mode: - data['parse_mode'] = parse_mode if caption_entities: data['caption_entities'] = caption_entities - if disable_notification: - data['disable_notification'] = disable_notification if reply_to_message_id: data['reply_to_message_id'] = reply_to_message_id - if allow_sending_without_reply: - data['allow_sending_without_reply'] = allow_sending_without_reply if reply_markup: if isinstance(reply_markup, ReplyMarkup): # We need to_json() instead of to_dict() here, because reply_markups may be diff --git a/telegram/callbackquery.py b/telegram/callbackquery.py index 94676f59ee3..3bafb8d31c9 100644 --- a/telegram/callbackquery.py +++ b/telegram/callbackquery.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple, ClassVar from telegram import Message, TelegramObject, User, Location, ReplyMarkup, constants -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput, DVInput if TYPE_CHECKING: from telegram import ( @@ -128,7 +129,7 @@ def answer( show_alert: bool = False, url: str = None, cache_time: int = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -155,10 +156,10 @@ def answer( def edit_message_text( self, text: str, - parse_mode: str = None, - disable_web_page_preview: bool = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: 'InlineKeyboardMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Union[Message, bool]: @@ -206,8 +207,8 @@ def edit_message_caption( self, caption: str = None, reply_markup: 'InlineKeyboardMarkup' = None, - timeout: float = None, - parse_mode: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Union[Message, bool]: @@ -253,7 +254,7 @@ def edit_message_caption( def edit_message_reply_markup( self, reply_markup: Optional['InlineKeyboardMarkup'] = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """Shortcut for either:: @@ -300,7 +301,7 @@ def edit_message_media( self, media: 'InputMedia' = None, reply_markup: 'InlineKeyboardMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """Shortcut for either:: @@ -343,7 +344,7 @@ def edit_message_live_location( longitude: float = None, location: Location = None, reply_markup: 'InlineKeyboardMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, horizontal_accuracy: float = None, heading: int = None, @@ -398,7 +399,7 @@ def edit_message_live_location( def stop_message_live_location( self, reply_markup: 'InlineKeyboardMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """Shortcut for either:: @@ -441,7 +442,7 @@ def set_game_score( score: int, force: bool = None, disable_edit_message: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """Shortcut for either:: @@ -485,7 +486,7 @@ def set_game_score( def get_game_high_scores( self, user_id: Union[int, str], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> List['GameHighScore']: """Shortcut for either:: @@ -521,7 +522,7 @@ def get_game_high_scores( def delete_message( self, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -542,8 +543,8 @@ def delete_message( def pin_message( self, - disable_notification: bool = None, - timeout: float = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -568,7 +569,7 @@ def pin_message( def unpin_message( self, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -594,13 +595,13 @@ def copy_message( self, chat_id: Union[int, str], caption: str = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - allow_sending_without_reply: bool = False, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> 'MessageId': """Shortcut for:: diff --git a/telegram/chat.py b/telegram/chat.py index dc55ffbe04d..aa9cbc31d3e 100644 --- a/telegram/chat.py +++ b/telegram/chat.py @@ -22,11 +22,11 @@ from typing import TYPE_CHECKING, List, Optional, ClassVar, Union, Tuple, Any from telegram import ChatPhoto, TelegramObject, constants -from telegram.utils.types import JSONDict, FileInput +from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput from .chatpermissions import ChatPermissions from .chatlocation import ChatLocation -from .utils.helpers import DefaultValue, DEFAULT_NONE +from .utils.helpers import DEFAULT_NONE, DEFAULT_20 if TYPE_CHECKING: from telegram import ( @@ -231,7 +231,7 @@ def de_json(cls, data: JSONDict, bot: 'Bot') -> Optional['Chat']: return cls(bot=bot, **data) - def leave(self, timeout: float = None, api_kwargs: JSONDict = None) -> bool: + def leave(self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None) -> bool: """Shortcut for:: bot.leave_chat(update.effective_chat.id, *args, **kwargs) @@ -249,7 +249,7 @@ def leave(self, timeout: float = None, api_kwargs: JSONDict = None) -> bool: ) def get_administrators( - self, timeout: float = None, api_kwargs: JSONDict = None + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None ) -> List['ChatMember']: """Shortcut for:: @@ -271,7 +271,9 @@ def get_administrators( api_kwargs=api_kwargs, ) - def get_members_count(self, timeout: float = None, api_kwargs: JSONDict = None) -> int: + def get_members_count( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> int: """Shortcut for:: bot.get_chat_members_count(update.effective_chat.id, *args, **kwargs) @@ -292,7 +294,7 @@ def get_members_count(self, timeout: float = None, api_kwargs: JSONDict = None) def get_member( self, user_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> 'ChatMember': """Shortcut for:: @@ -315,7 +317,7 @@ def get_member( def kick_member( self, user_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, until_date: Union[int, datetime] = None, api_kwargs: JSONDict = None, ) -> bool: @@ -346,7 +348,7 @@ def kick_member( def unban_member( self, user_id: Union[str, int], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, only_if_banned: bool = None, ) -> bool: @@ -379,7 +381,7 @@ def promote_member( can_restrict_members: bool = None, can_pin_messages: bool = None, can_promote_members: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, is_anonymous: bool = None, ) -> bool: @@ -417,7 +419,7 @@ def restrict_member( user_id: Union[str, int], permissions: ChatPermissions, until_date: Union[int, datetime] = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -445,7 +447,7 @@ def restrict_member( def set_permissions( self, permissions: ChatPermissions, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -470,7 +472,7 @@ def set_administrator_custom_title( self, user_id: Union[int, str], custom_title: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -495,8 +497,8 @@ def set_administrator_custom_title( def pin_message( self, message_id: Union[str, int], - disable_notification: bool = None, - timeout: float = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -522,7 +524,7 @@ def pin_message( def unpin_message( self, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, message_id: Union[str, int] = None, ) -> bool: @@ -548,7 +550,7 @@ def unpin_message( def unpin_all_messages( self, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -573,14 +575,14 @@ def unpin_all_messages( def send_message( self, text: str, - parse_mode: str = None, - disable_web_page_preview: bool = None, - disable_notification: bool = False, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> 'Message': """Shortcut for:: @@ -612,11 +614,11 @@ def send_media_group( media: List[ Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] ], - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> List['Message']: """Shortcut for:: @@ -641,7 +643,7 @@ def send_media_group( def send_chat_action( self, action: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -668,13 +670,13 @@ def send_photo( self, photo: Union[FileInput, 'PhotoSize'], caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -708,14 +710,14 @@ def send_contact( phone_number: str = None, first_name: str = None, last_name: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, contact: 'Contact' = None, vcard: str = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -749,14 +751,14 @@ def send_audio( performer: str = None, title: str = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -794,15 +796,15 @@ def send_document( document: Union[FileInput, 'Document'], filename: str = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, api_kwargs: JSONDict = None, disable_content_type_detection: bool = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> 'Message': """Shortcut for:: @@ -834,13 +836,13 @@ def send_document( def send_dice( self, - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, emoji: str = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -866,12 +868,12 @@ def send_dice( def send_game( self, game_short_name: str, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'InlineKeyboardMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -912,15 +914,15 @@ def send_invoice( need_email: bool = None, need_shipping_address: bool = None, is_flexible: bool = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'InlineKeyboardMarkup' = None, provider_data: Union[str, object] = None, send_phone_number_to_provider: bool = None, send_email_to_provider: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -965,17 +967,17 @@ def send_location( self, latitude: float = None, longitude: float = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, location: 'Location' = None, live_period: int = None, api_kwargs: JSONDict = None, horizontal_accuracy: float = None, heading: int = None, proximity_alert_radius: int = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -1012,13 +1014,13 @@ def send_animation( height: int = None, thumb: FileInput = None, caption: str = None, - parse_mode: str = None, - disable_notification: bool = False, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -1054,12 +1056,12 @@ def send_animation( def send_sticker( self, sticker: Union[FileInput, 'Sticker'], - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -1089,16 +1091,16 @@ def send_venue( title: str = None, address: str = None, foursquare_id: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, venue: 'Venue' = None, foursquare_type: str = None, api_kwargs: JSONDict = None, google_place_id: str = None, google_place_type: str = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -1134,17 +1136,17 @@ def send_video( video: Union[FileInput, 'Video'], duration: int = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, width: int = None, height: int = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: bool = None, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -1183,13 +1185,13 @@ def send_video_note( video_note: Union[FileInput, 'VideoNote'], duration: int = None, length: int = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: str = None, ) -> 'Message': """Shortcut for:: @@ -1222,13 +1224,13 @@ def send_voice( voice: Union[FileInput, 'Voice'], duration: int = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -1268,16 +1270,16 @@ def send_poll( allows_multiple_answers: bool = False, correct_option_id: int = None, is_closed: bool = None, - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, explanation: str = None, - explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE, + explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: int = None, close_date: Union[int, datetime] = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> 'Message': """Shortcut for:: @@ -1317,13 +1319,13 @@ def send_copy( from_chat_id: Union[str, int], message_id: Union[str, int], caption: str = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - allow_sending_without_reply: bool = False, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> 'MessageId': """Shortcut for:: @@ -1356,13 +1358,13 @@ def copy_message( chat_id: Union[int, str], message_id: Union[str, int], caption: str = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - allow_sending_without_reply: bool = False, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> 'MessageId': """Shortcut for:: diff --git a/telegram/ext/basepersistence.py b/telegram/ext/basepersistence.py index 834bfa7f203..c7968f4bdff 100644 --- a/telegram/ext/basepersistence.py +++ b/telegram/ext/basepersistence.py @@ -291,7 +291,7 @@ def _insert_bot(self, obj: object, memo: Dict[int, object]) -> object: # pylint @abstractmethod def get_user_data(self) -> DefaultDict[int, Dict[object, object]]: - """ "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a + """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a persistence object. It should return the ``user_data`` if stored, or an empty ``defaultdict(dict)``. @@ -301,7 +301,7 @@ def get_user_data(self) -> DefaultDict[int, Dict[object, object]]: @abstractmethod def get_chat_data(self) -> DefaultDict[int, Dict[object, object]]: - """ "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a + """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a persistence object. It should return the ``chat_data`` if stored, or an empty ``defaultdict(dict)``. @@ -311,7 +311,7 @@ def get_chat_data(self) -> DefaultDict[int, Dict[object, object]]: @abstractmethod def get_bot_data(self) -> Dict[object, object]: - """ "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a + """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a persistence object. It should return the ``bot_data`` if stored, or an empty :obj:`dict`. @@ -321,7 +321,7 @@ def get_bot_data(self) -> Dict[object, object]: @abstractmethod def get_conversations(self, name: str) -> ConversationDict: - """ "Will be called by :class:`telegram.ext.Dispatcher` when a + """Will be called by :class:`telegram.ext.Dispatcher` when a :class:`telegram.ext.ConversationHandler` is added if :attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`. It should return the conversations for the handler with `name` or an empty :obj:`dict` diff --git a/telegram/ext/callbackcontext.py b/telegram/ext/callbackcontext.py index cb4dde61f48..388ff68a20d 100644 --- a/telegram/ext/callbackcontext.py +++ b/telegram/ext/callbackcontext.py @@ -118,7 +118,7 @@ def bot_data(self) -> Dict: @bot_data.setter def bot_data(self, value: object) -> NoReturn: raise AttributeError( - "You can not assign a new value to bot_data, see " "https://git.io/fjxKe" + "You can not assign a new value to bot_data, see https://git.io/Jt6ic" ) @property @@ -128,7 +128,7 @@ def chat_data(self) -> Optional[Dict]: @chat_data.setter def chat_data(self, value: object) -> NoReturn: raise AttributeError( - "You can not assign a new value to chat_data, see " "https://git.io/fjxKe" + "You can not assign a new value to chat_data, see https://git.io/Jt6ic" ) @property @@ -138,7 +138,7 @@ def user_data(self) -> Optional[Dict]: @user_data.setter def user_data(self, value: object) -> NoReturn: raise AttributeError( - "You can not assign a new value to user_data, see " "https://git.io/fjxKe" + "You can not assign a new value to user_data, see https://git.io/Jt6ic" ) @classmethod diff --git a/telegram/ext/defaults.py b/telegram/ext/defaults.py index 417d9158ac9..bac294b3588 100644 --- a/telegram/ext/defaults.py +++ b/telegram/ext/defaults.py @@ -18,11 +18,12 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. # pylint: disable=R0201, E0401 """This module contains the class Defaults, which allows to pass default values to Updater.""" -from typing import NoReturn, Optional, Union +from typing import NoReturn, Optional, Dict, Any import pytz -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput class Defaults: @@ -47,6 +48,9 @@ class Defaults: appearing throughout PTB, i.e. if a timezone naive date(time) object is passed somewhere, it will be assumed to be in ``tzinfo``. Must be a timezone provided by the ``pytz`` module. Defaults to UTC. + + Note: + Will *not* be used for :meth:`telegram.Bot.get_updates`! run_async (:obj:`bool`, optional): Default setting for the ``run_async`` parameter of handlers and error handlers registered through :meth:`Dispatcher.add_handler` and :meth:`Dispatcher.add_error_handler`. Defaults to :obj:`False`. @@ -54,6 +58,8 @@ class Defaults: Attributes: parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or URLs in your bot's message. + explanation_parse_mode (:obj:`str`): Optional. Alias for :attr:`parse_mode`, used for + the corresponding parameter of :meth:`telegram.Bot.send_poll`. disable_notification (:obj:`bool`): Optional. Sends the message silently. Users will receive a notification with no sound. disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in this @@ -80,7 +86,7 @@ def __init__( disable_web_page_preview: bool = None, # Timeout needs special treatment, since the bot methods have two different # default values for timeout (None and 20s) - timeout: Union[float, DefaultValue] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, quote: bool = None, tzinfo: pytz.BaseTzInfo = pytz.utc, run_async: bool = False, @@ -95,6 +101,26 @@ def __init__( self._tzinfo = tzinfo self._run_async = run_async + # Gather all defaults that actually have a default value + self._api_defaults = {} + for kwarg in ( + 'parse_mode', + 'explanation_parse_mode', + 'disable_notification', + 'disable_web_page_preview', + 'allow_sending_without_reply', + ): + value = getattr(self, kwarg) + if value not in [None, DEFAULT_NONE]: + self._api_defaults[kwarg] = value + # Special casing, as None is a valid default value + if self.timeout != DEFAULT_NONE: + self._api_defaults['timeout'] = self.timeout + + @property + def api_defaults(self) -> Dict[str, Any]: + return self._api_defaults + @property def parse_mode(self) -> Optional[str]: return self._parse_mode @@ -106,6 +132,17 @@ def parse_mode(self, value: object) -> NoReturn: "not have any effect." ) + @property + def explanation_parse_mode(self) -> Optional[str]: + return self._parse_mode + + @explanation_parse_mode.setter + def explanation_parse_mode(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + @property def disable_notification(self) -> Optional[bool]: return self._disable_notification @@ -140,7 +177,7 @@ def allow_sending_without_reply(self, value: object) -> NoReturn: ) @property - def timeout(self) -> Union[float, DefaultValue]: + def timeout(self) -> ODVInput[float]: return self._timeout @timeout.setter diff --git a/telegram/files/animation.py b/telegram/files/animation.py index da636cc70e2..3f90dcc2971 100644 --- a/telegram/files/animation.py +++ b/telegram/files/animation.py @@ -20,7 +20,8 @@ from typing import TYPE_CHECKING, Any, Optional from telegram import PhotoSize, TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -104,7 +105,9 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Animation']: return cls(bot=bot, **data) - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. diff --git a/telegram/files/audio.py b/telegram/files/audio.py index f10ac93342f..bffeacec919 100644 --- a/telegram/files/audio.py +++ b/telegram/files/audio.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Optional from telegram import PhotoSize, TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -108,7 +109,9 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Audio']: return cls(bot=bot, **data) - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. diff --git a/telegram/files/chatphoto.py b/telegram/files/chatphoto.py index 506c05a4320..2a40203c5e2 100644 --- a/telegram/files/chatphoto.py +++ b/telegram/files/chatphoto.py @@ -20,7 +20,8 @@ from typing import TYPE_CHECKING, Any from telegram import TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -85,7 +86,9 @@ def __init__( self.big_file_unique_id, ) - def get_small_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_small_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the small (160x160) chat photo @@ -102,7 +105,9 @@ def get_small_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> file_id=self.small_file_id, timeout=timeout, api_kwargs=api_kwargs ) - def get_big_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_big_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the big (640x640) chat photo diff --git a/telegram/files/document.py b/telegram/files/document.py index 6ce569c6115..e70dd232306 100644 --- a/telegram/files/document.py +++ b/telegram/files/document.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Optional from telegram import PhotoSize, TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -95,7 +96,9 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Document']: return cls(bot=bot, **data) - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. diff --git a/telegram/files/inputmedia.py b/telegram/files/inputmedia.py index 10fc45294ff..501e26a282b 100644 --- a/telegram/files/inputmedia.py +++ b/telegram/files/inputmedia.py @@ -30,8 +30,8 @@ Video, MessageEntity, ) -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue, parse_file_input -from telegram.utils.types import FileInput, JSONDict +from telegram.utils.helpers import DEFAULT_NONE, parse_file_input +from telegram.utils.types import FileInput, JSONDict, ODVInput class InputMedia(TelegramObject): @@ -117,7 +117,7 @@ def __init__( media: Union[FileInput, Animation], thumb: FileInput = None, caption: str = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, width: int = None, height: int = None, duration: int = None, @@ -188,7 +188,7 @@ def __init__( self, media: Union[FileInput, PhotoSize], caption: str = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, filename: str = None, ): @@ -272,7 +272,7 @@ def __init__( height: int = None, duration: int = None, supports_streaming: bool = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, filename: str = None, @@ -368,7 +368,7 @@ def __init__( media: Union[FileInput, Audio], thumb: FileInput = None, caption: str = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, duration: int = None, performer: str = None, title: str = None, @@ -456,7 +456,7 @@ def __init__( media: Union[FileInput, Document], thumb: FileInput = None, caption: str = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: bool = None, caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, filename: str = None, diff --git a/telegram/files/photosize.py b/telegram/files/photosize.py index e704b1f4440..1456a8060a7 100644 --- a/telegram/files/photosize.py +++ b/telegram/files/photosize.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any from telegram import TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -78,7 +79,9 @@ def __init__( self._id_attrs = (self.file_unique_id,) - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. diff --git a/telegram/files/sticker.py b/telegram/files/sticker.py index 3a0ef3c5165..0703b65259a 100644 --- a/telegram/files/sticker.py +++ b/telegram/files/sticker.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, List, Optional, ClassVar from telegram import PhotoSize, TelegramObject, constants -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -115,7 +116,9 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Sticker']: return cls(bot=bot, **data) - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. diff --git a/telegram/files/video.py b/telegram/files/video.py index b26a82a57c8..48d59afc6bf 100644 --- a/telegram/files/video.py +++ b/telegram/files/video.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Optional from telegram import PhotoSize, TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -105,7 +106,9 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Video']: return cls(bot=bot, **data) - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. diff --git a/telegram/files/videonote.py b/telegram/files/videonote.py index f7855dbe0ef..497936ba54a 100644 --- a/telegram/files/videonote.py +++ b/telegram/files/videonote.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Optional, Any from telegram import PhotoSize, TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -94,7 +95,9 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['VideoNote']: return cls(bot=bot, **data) - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. diff --git a/telegram/files/voice.py b/telegram/files/voice.py index d113e0ab8f6..185ab2970e4 100644 --- a/telegram/files/voice.py +++ b/telegram/files/voice.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any from telegram import TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File @@ -78,7 +79,9 @@ def __init__( self._id_attrs = (self.file_unique_id,) - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. diff --git a/telegram/inline/inlinequery.py b/telegram/inline/inlinequery.py index c25b4cfceff..2310465200e 100644 --- a/telegram/inline/inlinequery.py +++ b/telegram/inline/inlinequery.py @@ -22,7 +22,8 @@ from typing import TYPE_CHECKING, Any, Optional, List, Union, Callable, ClassVar from telegram import Location, TelegramObject, User, constants -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, InlineQueryResult @@ -103,7 +104,7 @@ def answer( next_offset: str = None, switch_pm_text: str = None, switch_pm_parameter: str = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, current_offset: str = None, api_kwargs: JSONDict = None, auto_pagination: bool = False, diff --git a/telegram/inline/inlinequeryresult.py b/telegram/inline/inlinequeryresult.py index 2381b2fffff..0280f6c9ea9 100644 --- a/telegram/inline/inlinequeryresult.py +++ b/telegram/inline/inlinequeryresult.py @@ -49,14 +49,6 @@ def __init__(self, type: str, id: str, **_kwargs: Any): self._id_attrs = (self.id,) - @property - def _has_parse_mode(self) -> bool: - return hasattr(self, 'parse_mode') - - @property - def _has_input_message_content(self) -> bool: - return hasattr(self, 'input_message_content') - def to_dict(self) -> JSONDict: data = super().to_dict() diff --git a/telegram/inline/inlinequeryresultaudio.py b/telegram/inline/inlinequeryresultaudio.py index cf40e61496c..91d329e30ab 100644 --- a/telegram/inline/inlinequeryresultaudio.py +++ b/telegram/inline/inlinequeryresultaudio.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -83,7 +84,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultcachedaudio.py b/telegram/inline/inlinequeryresultcachedaudio.py index 43c93e35c26..ed8b4b233d2 100644 --- a/telegram/inline/inlinequeryresultcachedaudio.py +++ b/telegram/inline/inlinequeryresultcachedaudio.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -74,7 +75,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultcacheddocument.py b/telegram/inline/inlinequeryresultcacheddocument.py index 3566471b74a..07a0d5127bc 100644 --- a/telegram/inline/inlinequeryresultcacheddocument.py +++ b/telegram/inline/inlinequeryresultcacheddocument.py @@ -22,7 +22,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -83,7 +84,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultcachedgif.py b/telegram/inline/inlinequeryresultcachedgif.py index fafd687f652..d9ddb4a7a51 100644 --- a/telegram/inline/inlinequeryresultcachedgif.py +++ b/telegram/inline/inlinequeryresultcachedgif.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -80,7 +81,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultcachedmpeg4gif.py b/telegram/inline/inlinequeryresultcachedmpeg4gif.py index 42dbe6553fb..3104eb77286 100644 --- a/telegram/inline/inlinequeryresultcachedmpeg4gif.py +++ b/telegram/inline/inlinequeryresultcachedmpeg4gif.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -80,7 +81,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultcachedphoto.py b/telegram/inline/inlinequeryresultcachedphoto.py index 6735c6d2d98..c3857937b6b 100644 --- a/telegram/inline/inlinequeryresultcachedphoto.py +++ b/telegram/inline/inlinequeryresultcachedphoto.py @@ -22,7 +22,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -84,7 +85,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultcachedvideo.py b/telegram/inline/inlinequeryresultcachedvideo.py index a1866853a54..6e46dc088a5 100644 --- a/telegram/inline/inlinequeryresultcachedvideo.py +++ b/telegram/inline/inlinequeryresultcachedvideo.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -83,7 +84,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultcachedvoice.py b/telegram/inline/inlinequeryresultcachedvoice.py index 0153bc3d713..b99817d1080 100644 --- a/telegram/inline/inlinequeryresultcachedvoice.py +++ b/telegram/inline/inlinequeryresultcachedvoice.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -77,7 +78,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultdocument.py b/telegram/inline/inlinequeryresultdocument.py index f231c8935b3..26328ff47d4 100644 --- a/telegram/inline/inlinequeryresultdocument.py +++ b/telegram/inline/inlinequeryresultdocument.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -97,7 +98,7 @@ def __init__( thumb_url: str = None, thumb_width: int = None, thumb_height: int = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultgif.py b/telegram/inline/inlinequeryresultgif.py index 4d2e3d4b9b1..c1888b5a6c4 100644 --- a/telegram/inline/inlinequeryresultgif.py +++ b/telegram/inline/inlinequeryresultgif.py @@ -22,7 +22,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -97,7 +98,7 @@ def __init__( reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, gif_duration: int = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb_mime_type: str = None, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, diff --git a/telegram/inline/inlinequeryresultmpeg4gif.py b/telegram/inline/inlinequeryresultmpeg4gif.py index 6e49cbf1c3e..9ddd44f4a57 100644 --- a/telegram/inline/inlinequeryresultmpeg4gif.py +++ b/telegram/inline/inlinequeryresultmpeg4gif.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -96,7 +97,7 @@ def __init__( reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, mpeg4_duration: int = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb_mime_type: str = None, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, diff --git a/telegram/inline/inlinequeryresultphoto.py b/telegram/inline/inlinequeryresultphoto.py index fd822316ec8..4f09254d356 100644 --- a/telegram/inline/inlinequeryresultphoto.py +++ b/telegram/inline/inlinequeryresultphoto.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -93,7 +94,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultvideo.py b/telegram/inline/inlinequeryresultvideo.py index 6d86e304994..0245d6fba34 100644 --- a/telegram/inline/inlinequeryresultvideo.py +++ b/telegram/inline/inlinequeryresultvideo.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -105,7 +106,7 @@ def __init__( description: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inlinequeryresultvoice.py b/telegram/inline/inlinequeryresultvoice.py index be47086cc28..a38aff13c98 100644 --- a/telegram/inline/inlinequeryresultvoice.py +++ b/telegram/inline/inlinequeryresultvoice.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Union, Tuple, List from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput if TYPE_CHECKING: from telegram import InputMessageContent, ReplyMarkup @@ -81,7 +82,7 @@ def __init__( caption: str = None, reply_markup: 'ReplyMarkup' = None, input_message_content: 'InputMessageContent' = None, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/inline/inputmessagecontent.py b/telegram/inline/inputmessagecontent.py index 3535100786d..f0b61f04a79 100644 --- a/telegram/inline/inputmessagecontent.py +++ b/telegram/inline/inputmessagecontent.py @@ -29,11 +29,3 @@ class InputMessageContent(TelegramObject): :class:`telegram.InputVenueMessageContent` for more details. """ - - @property - def _has_parse_mode(self) -> bool: - return hasattr(self, 'parse_mode') - - @property - def _has_disable_web_page_preview(self) -> bool: - return hasattr(self, 'disable_web_page_preview') diff --git a/telegram/inline/inputtextmessagecontent.py b/telegram/inline/inputtextmessagecontent.py index 843f8172e8c..4d469613135 100644 --- a/telegram/inline/inputtextmessagecontent.py +++ b/telegram/inline/inputtextmessagecontent.py @@ -21,8 +21,8 @@ from typing import Any, Union, Tuple, List from telegram import InputMessageContent, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE, DefaultValue -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput class InputTextMessageContent(InputMessageContent): @@ -62,8 +62,8 @@ class InputTextMessageContent(InputMessageContent): def __init__( self, message_text: str, - parse_mode: Union[str, DefaultValue] = DEFAULT_NONE, - disable_web_page_preview: Union[bool, DefaultValue] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, **_kwargs: Any, ): diff --git a/telegram/message.py b/telegram/message.py index ff6f3061405..92fc529a15a 100644 --- a/telegram/message.py +++ b/telegram/message.py @@ -55,9 +55,9 @@ from_timestamp, to_timestamp, DEFAULT_NONE, - DefaultValue, + DEFAULT_20, ) -from telegram.utils.types import JSONDict, FileInput +from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput if TYPE_CHECKING: from telegram import ( @@ -605,14 +605,14 @@ def _quote( def reply_text( self, text: str, - parse_mode: str = None, - disable_web_page_preview: bool = None, - disable_notification: bool = False, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, quote: bool = None, ) -> 'Message': @@ -650,13 +650,13 @@ def reply_text( def reply_markdown( self, text: str, - disable_web_page_preview: bool = None, - disable_notification: bool = False, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, quote: bool = None, ) -> 'Message': @@ -704,13 +704,13 @@ def reply_markdown( def reply_markdown_v2( self, text: str, - disable_web_page_preview: bool = None, - disable_notification: bool = False, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, quote: bool = None, ) -> 'Message': @@ -754,13 +754,13 @@ def reply_markdown_v2( def reply_html( self, text: str, - disable_web_page_preview: bool = None, - disable_notification: bool = False, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, quote: bool = None, ) -> 'Message': @@ -806,11 +806,11 @@ def reply_media_group( media: List[ Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] ], - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: bool = None, ) -> List['Message']: """Shortcut for:: @@ -846,13 +846,13 @@ def reply_photo( self, photo: Union[FileInput, 'PhotoSize'], caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, quote: bool = None, @@ -896,14 +896,14 @@ def reply_audio( performer: str = None, title: str = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, quote: bool = None, @@ -949,15 +949,15 @@ def reply_document( document: Union[FileInput, 'Document'], filename: str = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, api_kwargs: JSONDict = None, disable_content_type_detection: bool = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, quote: bool = None, ) -> 'Message': @@ -1003,13 +1003,13 @@ def reply_animation( height: int = None, thumb: FileInput = None, caption: str = None, - parse_mode: str = None, - disable_notification: bool = False, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, quote: bool = None, @@ -1053,12 +1053,12 @@ def reply_animation( def reply_sticker( self, sticker: Union[FileInput, 'Sticker'], - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: bool = None, ) -> 'Message': """Shortcut for:: @@ -1094,17 +1094,17 @@ def reply_video( video: Union[FileInput, 'Video'], duration: int = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, width: int = None, height: int = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: bool = None, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, quote: bool = None, @@ -1151,13 +1151,13 @@ def reply_video_note( video_note: Union[FileInput, 'VideoNote'], duration: int = None, length: int = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: str = None, quote: bool = None, ) -> 'Message': @@ -1198,13 +1198,13 @@ def reply_voice( voice: Union[FileInput, 'Voice'], duration: int = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, quote: bool = None, @@ -1246,17 +1246,17 @@ def reply_location( self, latitude: float = None, longitude: float = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, location: Location = None, live_period: int = None, api_kwargs: JSONDict = None, horizontal_accuracy: float = None, heading: int = None, proximity_alert_radius: int = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: bool = None, ) -> 'Message': """Shortcut for:: @@ -1300,16 +1300,16 @@ def reply_venue( title: str = None, address: str = None, foursquare_id: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, venue: Venue = None, foursquare_type: str = None, api_kwargs: JSONDict = None, google_place_id: str = None, google_place_type: str = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: bool = None, ) -> 'Message': """Shortcut for:: @@ -1353,14 +1353,14 @@ def reply_contact( phone_number: str = None, first_name: str = None, last_name: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, contact: Contact = None, vcard: str = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: bool = None, ) -> 'Message': """Shortcut for:: @@ -1404,16 +1404,16 @@ def reply_poll( allows_multiple_answers: bool = False, correct_option_id: int = None, is_closed: bool = None, - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, explanation: str = None, - explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE, + explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: int = None, close_date: Union[int, datetime.datetime] = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, quote: bool = None, ) -> 'Message': @@ -1458,13 +1458,13 @@ def reply_poll( def reply_dice( self, - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, emoji: str = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: bool = None, ) -> 'Message': """Shortcut for:: @@ -1498,7 +1498,7 @@ def reply_dice( def reply_chat_action( self, action: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -1523,12 +1523,12 @@ def reply_chat_action( def reply_game( self, game_short_name: str, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'InlineKeyboardMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: bool = None, ) -> 'Message': """Shortcut for:: @@ -1579,15 +1579,15 @@ def reply_invoice( need_email: bool = None, need_shipping_address: bool = None, is_flexible: bool = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'InlineKeyboardMarkup' = None, provider_data: Union[str, object] = None, send_phone_number_to_provider: bool = None, send_email_to_provider: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: bool = None, ) -> 'Message': """Shortcut for:: @@ -1641,8 +1641,8 @@ def reply_invoice( def forward( self, chat_id: Union[int, str], - disable_notification: bool = False, - timeout: float = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> 'Message': """Shortcut for:: @@ -1672,13 +1672,13 @@ def copy( self, chat_id: Union[int, str], caption: str = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - allow_sending_without_reply: bool = False, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> 'MessageId': """Shortcut for:: @@ -1715,13 +1715,13 @@ def reply_copy( from_chat_id: Union[str, int], message_id: Union[str, int], caption: str = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - allow_sending_without_reply: bool = False, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, reply_markup: ReplyMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, quote: bool = None, ) -> 'MessageId': @@ -1766,10 +1766,10 @@ def reply_copy( def edit_text( self, text: str, - parse_mode: str = None, - disable_web_page_preview: bool = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Union['Message', bool]: @@ -1809,8 +1809,8 @@ def edit_caption( self, caption: str = None, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, - parse_mode: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Union['Message', bool]: @@ -1850,7 +1850,7 @@ def edit_media( self, media: 'InputMedia' = None, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union['Message', bool]: """Shortcut for:: @@ -1886,7 +1886,7 @@ def edit_media( def edit_reply_markup( self, reply_markup: Optional['InlineKeyboardMarkup'] = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union['Message', bool]: """Shortcut for:: @@ -1923,7 +1923,7 @@ def edit_live_location( longitude: float = None, location: Location = None, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, horizontal_accuracy: float = None, heading: int = None, @@ -1966,7 +1966,7 @@ def edit_live_location( def stop_live_location( self, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union['Message', bool]: """Shortcut for:: @@ -2003,7 +2003,7 @@ def set_game_score( score: int, force: bool = None, disable_edit_message: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Union['Message', bool]: """Shortcut for:: @@ -2039,7 +2039,7 @@ def set_game_score( def get_game_high_scores( self, user_id: Union[int, str], - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> List['GameHighScore']: """Shortcut for:: @@ -2071,7 +2071,7 @@ def get_game_high_scores( def delete( self, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -2097,7 +2097,7 @@ def delete( def stop_poll( self, reply_markup: InlineKeyboardMarkup = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Poll: """Shortcut for:: @@ -2124,8 +2124,8 @@ def stop_poll( def pin( self, - disable_notification: bool = None, - timeout: float = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -2151,7 +2151,7 @@ def pin( def unpin( self, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: diff --git a/telegram/passport/passportfile.py b/telegram/passport/passportfile.py index 7933e6b6d9c..2506a80e945 100644 --- a/telegram/passport/passportfile.py +++ b/telegram/passport/passportfile.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, List, Optional from telegram import TelegramObject -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot, File, FileCredentials @@ -103,7 +104,9 @@ def de_list_decrypted( for i, passport_file in enumerate(data) ] - def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': """ Wrapper over :attr:`telegram.Bot.get_file`. Will automatically assign the correct credentials to the returned :class:`telegram.File` if originating from diff --git a/telegram/payment/precheckoutquery.py b/telegram/payment/precheckoutquery.py index 40ec79d31f7..60ea90ca0c0 100644 --- a/telegram/payment/precheckoutquery.py +++ b/telegram/payment/precheckoutquery.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Optional from telegram import OrderInfo, TelegramObject, User -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot @@ -106,7 +107,7 @@ def answer( # pylint: disable=C0103 self, ok: bool, error_message: str = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: diff --git a/telegram/payment/shippingquery.py b/telegram/payment/shippingquery.py index 1d06cf11ca2..df57a6b7ac9 100644 --- a/telegram/payment/shippingquery.py +++ b/telegram/payment/shippingquery.py @@ -21,7 +21,8 @@ from typing import TYPE_CHECKING, Any, Optional, List from telegram import ShippingAddress, TelegramObject, User, ShippingOption -from telegram.utils.types import JSONDict +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput if TYPE_CHECKING: from telegram import Bot @@ -88,7 +89,7 @@ def answer( # pylint: disable=C0103 ok: bool, shipping_options: List[ShippingOption] = None, error_message: str = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: diff --git a/telegram/user.py b/telegram/user.py index e0e6642978e..1db9d7a0983 100644 --- a/telegram/user.py +++ b/telegram/user.py @@ -22,9 +22,13 @@ from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple from telegram import TelegramObject, constants -from telegram.utils.helpers import mention_html as util_mention_html, DefaultValue, DEFAULT_NONE +from telegram.utils.helpers import ( + mention_html as util_mention_html, + DEFAULT_NONE, + DEFAULT_20, +) from telegram.utils.helpers import mention_markdown as util_mention_markdown -from telegram.utils.types import JSONDict, FileInput +from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput if TYPE_CHECKING: from telegram import ( @@ -151,7 +155,7 @@ def get_profile_photos( self, offset: int = None, limit: int = 100, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> Optional['UserProfilePhotos']: """ @@ -218,8 +222,8 @@ def mention_html(self, name: str = None) -> str: def pin_message( self, message_id: Union[str, int], - disable_notification: bool = None, - timeout: float = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -244,7 +248,7 @@ def pin_message( def unpin_message( self, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, message_id: Union[str, int] = None, ) -> bool: @@ -269,7 +273,7 @@ def unpin_message( def unpin_all_messages( self, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -294,14 +298,14 @@ def unpin_all_messages( def send_message( self, text: str, - parse_mode: str = None, - disable_web_page_preview: bool = None, - disable_notification: bool = False, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> 'Message': """Shortcut for:: @@ -332,13 +336,13 @@ def send_photo( self, photo: Union[FileInput, 'PhotoSize'], caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -372,11 +376,11 @@ def send_media_group( media: List[ Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] ], - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> List['Message']: """Shortcut for:: @@ -405,14 +409,14 @@ def send_audio( performer: str = None, title: str = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -448,7 +452,7 @@ def send_audio( def send_chat_action( self, action: str, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> bool: """Shortcut for:: @@ -476,14 +480,14 @@ def send_contact( phone_number: str = None, first_name: str = None, last_name: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, contact: 'Contact' = None, vcard: str = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -512,13 +516,13 @@ def send_contact( def send_dice( self, - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, emoji: str = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -546,15 +550,15 @@ def send_document( document: Union[FileInput, 'Document'], filename: str = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, api_kwargs: JSONDict = None, disable_content_type_detection: bool = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> 'Message': """Shortcut for:: @@ -587,12 +591,12 @@ def send_document( def send_game( self, game_short_name: str, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'InlineKeyboardMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -633,15 +637,15 @@ def send_invoice( need_email: bool = None, need_shipping_address: bool = None, is_flexible: bool = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'InlineKeyboardMarkup' = None, provider_data: Union[str, object] = None, send_phone_number_to_provider: bool = None, send_email_to_provider: bool = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -686,17 +690,17 @@ def send_location( self, latitude: float = None, longitude: float = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, location: 'Location' = None, live_period: int = None, api_kwargs: JSONDict = None, horizontal_accuracy: float = None, heading: int = None, proximity_alert_radius: int = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -733,13 +737,13 @@ def send_animation( height: int = None, thumb: FileInput = None, caption: str = None, - parse_mode: str = None, - disable_notification: bool = False, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -775,12 +779,12 @@ def send_animation( def send_sticker( self, sticker: Union[FileInput, 'Sticker'], - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -808,17 +812,17 @@ def send_video( video: Union[FileInput, 'Video'], duration: int = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, width: int = None, height: int = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: bool = None, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -859,16 +863,16 @@ def send_venue( title: str = None, address: str = None, foursquare_id: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, venue: 'Venue' = None, foursquare_type: str = None, api_kwargs: JSONDict = None, google_place_id: str = None, google_place_type: str = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, ) -> 'Message': """Shortcut for:: @@ -904,13 +908,13 @@ def send_video_note( video_note: Union[FileInput, 'VideoNote'], duration: int = None, length: int = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, + timeout: DVInput[float] = DEFAULT_20, thumb: FileInput = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: str = None, ) -> 'Message': """Shortcut for:: @@ -943,13 +947,13 @@ def send_voice( voice: Union[FileInput, 'Voice'], duration: int = None, caption: str = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = 20, - parse_mode: str = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, ) -> 'Message': @@ -989,16 +993,16 @@ def send_poll( allows_multiple_answers: bool = False, correct_option_id: int = None, is_closed: bool = None, - disable_notification: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, explanation: str = None, - explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE, + explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: int = None, close_date: Union[int, datetime] = None, api_kwargs: JSONDict = None, - allow_sending_without_reply: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> 'Message': """Shortcut for:: @@ -1038,13 +1042,13 @@ def send_copy( from_chat_id: Union[str, int], message_id: Union[str, int], caption: str = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - allow_sending_without_reply: bool = False, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> 'MessageId': """Shortcut for:: @@ -1077,13 +1081,13 @@ def copy_message( chat_id: Union[int, str], message_id: Union[str, int], caption: str = None, - parse_mode: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: bool = False, + disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: Union[int, str] = None, - allow_sending_without_reply: bool = False, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, reply_markup: 'ReplyMarkup' = None, - timeout: float = None, + timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None, ) -> 'MessageId': """Shortcut for:: diff --git a/telegram/utils/helpers.py b/telegram/utils/helpers.py index 993f5834b9b..6ee67794654 100644 --- a/telegram/utils/helpers.py +++ b/telegram/utils/helpers.py @@ -38,6 +38,9 @@ Type, cast, IO, + TypeVar, + Generic, + overload, ) from telegram.utils.types import JSONDict, FileInput @@ -494,7 +497,11 @@ def decode_user_chat_data_from_json(data: str) -> DefaultDict[int, Dict[object, return tmp -class DefaultValue: +DVType = TypeVar('DVType', bound=object) +OT = TypeVar('OT', bound=object) + + +class DefaultValue(Generic[DVType]): """Wrapper for immutable default arguments that allows to check, if the default value was set explicitly. Usage:: @@ -531,6 +538,9 @@ def f(arg=DefaultOne): if value: ... + ``repr(DefaultValue(value))`` returns ``repr(value)`` and ``str(DefaultValue(value))`` returns + ``f'DefaultValue({value})'``. + Args: value (:obj:`obj`): The value of the default argument @@ -539,15 +549,51 @@ def f(arg=DefaultOne): """ - def __init__(self, value: object = None): + def __init__(self, value: DVType = None): self.value = value def __bool__(self) -> bool: return bool(self.value) + @overload + @staticmethod + def get_value(obj: 'DefaultValue[OT]') -> OT: + ... + + @overload + @staticmethod + def get_value(obj: OT) -> OT: + ... + + @staticmethod + def get_value(obj: Union[OT, 'DefaultValue[OT]']) -> OT: + """ + Shortcut for:: + + return obj.value if isinstance(obj, DefaultValue) else obj + + Args: + obj (:obj:`object`): The object to process + + Returns: + Same type as input, or the value of the input: The value + """ + return obj.value if isinstance(obj, DefaultValue) else obj # type: ignore[return-value] + + # This is mostly here for readability during debugging + def __str__(self) -> str: + return f'DefaultValue({self.value})' + + # This is here to have the default instances nicely rendered in the docs + def __repr__(self) -> str: + return repr(self.value) + DEFAULT_NONE: DefaultValue = DefaultValue(None) """:class:`DefaultValue`: Default :obj:`None`""" DEFAULT_FALSE: DefaultValue = DefaultValue(False) """:class:`DefaultValue`: Default :obj:`False`""" + +DEFAULT_20: DefaultValue = DefaultValue(20) +""":class:`DefaultValue`: Default :obj:`20`""" diff --git a/telegram/utils/types.py b/telegram/utils/types.py index 9a0a50e78f6..1ab5f4df2fc 100644 --- a/telegram/utils/types.py +++ b/telegram/utils/types.py @@ -22,6 +22,7 @@ if TYPE_CHECKING: from telegram import InputFile + from telegram.utils.helpers import DefaultValue FileLike = Union[IO, 'InputFile'] """Either an open file handler or a :class:`telegram.InputFile`.""" @@ -36,6 +37,14 @@ ConversationDict = Dict[Tuple[int, ...], Optional[object]] """Dicts as maintained by the :class:`telegram.ext.ConversationHandler`.""" +DVType = TypeVar('DVType') +ODVInput = Optional[Union['DefaultValue[DVType]', DVType]] +"""Generic type for bot method parameters which can have defaults. ``ODVInput[type]`` is the same +as ``Optional[Union[DefaultValue, type]]``.""" +DVInput = Union['DefaultValue[DVType]', DVType] +"""Generic type for bot method parameters which can have defaults. ``DVInput[type]`` is the same +as ``Union[DefaultValue, type]``.""" + RT = TypeVar("RT") SLT = Union[RT, List[RT], Tuple[RT, ...]] """Single instance or list/tuple of instances.""" diff --git a/tests/conftest.py b/tests/conftest.py index f7d58c06b03..621bc9af2b0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. import datetime +import functools import inspect import os import re @@ -24,7 +25,7 @@ from queue import Queue from threading import Thread, Event from time import sleep -from typing import Callable, List, Dict +from typing import Callable, List, Iterable, Any import pytest import pytz @@ -41,9 +42,12 @@ ShippingQuery, PreCheckoutQuery, ChosenInlineResult, + File, + ChatPermissions, ) from telegram.ext import Dispatcher, JobQueue, Updater, MessageFilter, Defaults, UpdateFilter from telegram.error import BadRequest +from telegram.utils.helpers import DefaultValue, DEFAULT_NONE from tests.bots import get_bot @@ -386,66 +390,236 @@ def check_shortcut_signature( expected_args.discard('self') args_check = expected_args == effective_shortcut_args + if not args_check: + raise Exception(f'Expected arguments {expected_args}, got {effective_shortcut_args}') # TODO: Also check annotation of return type. Would currently be a hassle b/c typing doesn't # resolve `ForwardRef('Type')` to `Type`. For now we rely on MyPy, which probably allows the # shortcuts to return more specific types than the bot method, but it's only annotations after # all - annotation_check = True for kwarg in effective_shortcut_args: if bot_sig.parameters[kwarg].annotation != shortcut_sig.parameters[kwarg].annotation: if isinstance(bot_sig.parameters[kwarg].annotation, type): if bot_sig.parameters[kwarg].annotation.__name__ != str( shortcut_sig.parameters[kwarg].annotation ): - print( - f'Expected {bot_sig.parameters[kwarg].annotation}, but ' - f'got {shortcut_sig.parameters[kwarg].annotation}' + raise Exception( + f'For argument {kwarg} I expected {bot_sig.parameters[kwarg].annotation}, ' + f'but got {shortcut_sig.parameters[kwarg].annotation}' ) - annotation_check = False - break else: - print( - f'Expected {bot_sig.parameters[kwarg].annotation}, but ' + raise Exception( + f'For argument {kwarg} I expected {bot_sig.parameters[kwarg].annotation}, but ' f'got {shortcut_sig.parameters[kwarg].annotation}' ) - annotation_check = False - break bot_method_sig = inspect.signature(bot_method) shortcut_sig = inspect.signature(shortcut) - default_check = all( - shortcut_sig.parameters[arg].default == bot_method_sig.parameters[arg].default - for arg in expected_args - ) + for arg in expected_args: + if not shortcut_sig.parameters[arg].default == bot_method_sig.parameters[arg].default: + raise Exception( + f'Default for argument {arg} does not match the default of the Bot method.' + ) - return args_check and annotation_check and default_check + return True def check_shortcut_call( - kwargs: Dict[str, object], - bot_method: Callable, + shortcut_method: Callable, + bot: Bot, + bot_method_name: str, + skip_params: Iterable[str] = None, + shortcut_kwargs: Iterable[str] = None, ) -> bool: """ Checks that a shortcut passes all the existing arguments to the underlying bot method. Use as:: - send_message = message.bot.send_message + assert check_shortcut_call(message.reply_text, message.bot, 'send_message') + + Args: + shortcut_method: The shortcut method, e.g. `message.reply_text` + bot: The bot + bot_method_name: The bot methods name, e.g. `'send_message'` + skip_params: Parameters that are allowed to be missing, e.g. `['inline_message_id']` + shortcut_kwargs: The kwargs passed by the shortcut directly, e.g. ``chat_id`` + + Returns: + :obj:`bool` + """ + if not skip_params: + skip_params = set() + if not shortcut_kwargs: + shortcut_kwargs = set() + + orig_bot_method = getattr(bot, bot_method_name) + bot_signature = inspect.signature(orig_bot_method) + expected_args = set(bot_signature.parameters.keys()) - {'self'} - set(skip_params) + positional_args = { + name for name, param in bot_signature.parameters.items() if param.default == param.empty + } + ignored_args = positional_args | set(shortcut_kwargs) + + shortcut_signature = inspect.signature(shortcut_method) + # auto_pagination: Special casing for InlineQuery.answer + kwargs = {name: name for name in shortcut_signature.parameters if name != 'auto_pagination'} + + def make_assertion(**kw): + # name == value makes sure that + # a) we receive non-None input for all parameters + # b) we receive the correct input for each kwarg + received_kwargs = { + name for name, value in kw.items() if name in ignored_args or value == name + } + if not received_kwargs == expected_args: + raise Exception( + f'{orig_bot_method.__name__} did not receive correct value for the parameters ' + f'{expected_args - received_kwargs}' + ) + + if bot_method_name == 'get_file': + # This is here mainly for PassportFile.get_file, which calls .set_credentials on the + # return value + return File(file_id='result', file_unique_id='result') + return True - def make_assertion(*_, **kwargs): - return check_shortcut_call(send_message, kwargs) + setattr(bot, bot_method_name, make_assertion) + try: + shortcut_method(**kwargs) + except Exception as exc: + raise exc + finally: + setattr(bot, bot_method_name, orig_bot_method) + + return True - monkeypatch.setattr(message.bot, 'send_message', make_assertion) - assert message.reply_text('foobar') +def check_defaults_handling( + method: Callable, + bot: Bot, + return_value=None, +) -> bool: + """ + Checks that tg.ext.Defaults are handled correctly. Args: - kwargs: The kwargs passed to the bot method by the shortcut - bot_method: The bot method, e.g. :meth:`telegram.Bot.send_message` + method: The shortcut/bot_method + bot: The bot + return_value: Optional. The return value of Bot._post that the method expects. Defaults to + None. get_file is automatically handled. - Returns: - :obj:`bool` """ - bot_signature = inspect.signature(bot_method) - expected_args = set(bot_signature.parameters.keys()).difference(['self']) - return expected_args == set(kwargs.keys()) + def build_kwargs(signature: inspect.Signature, default_kwargs, dfv: Any = DEFAULT_NONE): + kws = {} + for name, param in signature.parameters.items(): + # For required params we need to pass something + if param.default == param.empty: + # Some special casing + if name == 'permissions': + kws[name] = ChatPermissions() + elif name in ['prices', 'media', 'results', 'commands', 'errors']: + kws[name] = [] + elif name == 'ok': + kws['ok'] = False + kws['error_message'] = 'error' + else: + kws[name] = True + # pass values for params that can have defaults only if we don't want to use the + # standard default + elif name in default_kwargs: + if dfv != DEFAULT_NONE: + kws[name] = dfv + # Some special casing for methods that have "exactly one of the optionals" type args + elif name in ['location', 'contact', 'venue', 'inline_message_id']: + kws[name] = True + return kws + + shortcut_signature = inspect.signature(method) + kwargs_need_default = [ + kwarg + for kwarg, value in shortcut_signature.parameters.items() + if isinstance(value.default, DefaultValue) + ] + # shortcut_signature.parameters['timeout'] is of type DefaultValue + method_timeout = shortcut_signature.parameters['timeout'].default.value + + default_kwarg_names = kwargs_need_default + # special case explanation_parse_mode of Bot.send_poll: + if 'explanation_parse_mode' in default_kwarg_names: + default_kwarg_names.remove('explanation_parse_mode') + + defaults_no_custom_defaults = Defaults() + defaults_custom_defaults = Defaults( + **{kwarg: 'custom_default' for kwarg in default_kwarg_names} + ) + + expected_return_values = [None, []] if return_value is None else [return_value] + + def make_assertion(_, data, timeout=DEFAULT_NONE, df_value=DEFAULT_NONE): + expected_timeout = method_timeout if df_value == DEFAULT_NONE else df_value + if timeout != expected_timeout: + pytest.fail(f'Got value {timeout} for "timeout", expected {expected_timeout}') + + for arg in (dkw for dkw in kwargs_need_default if dkw != 'timeout'): + # 'None' should not be passed along to Telegram + if df_value in [None, DEFAULT_NONE]: + if arg in data: + pytest.fail( + f'Got value {data[arg]} for argument {arg}, expected it to be absent' + ) + else: + value = data.get(arg, '`not passed at all`') + if value != df_value: + pytest.fail(f'Got value {value} for argument {arg} instead of {df_value}') + + if method.__name__ in ['get_file', 'get_small_file', 'get_big_file']: + # This is here mainly for PassportFile.get_file, which calls .set_credentials on the + # return value + out = File(file_id='result', file_unique_id='result') + nonlocal expected_return_values + expected_return_values = [out] + return out.to_dict() + # Otherwise return None by default, as TGObject.de_json/list(None) in [None, []] + # That way we can check what gets passed to Request.post without having to actually + # make a request + # Some methods expect specific output, so we allow to customize that + return return_value + + orig_post = bot.request.post + try: + for default_value, defaults in [ + (DEFAULT_NONE, defaults_no_custom_defaults), + ('custom_default', defaults_custom_defaults), + ]: + bot.defaults = defaults + # 1: test that we get the correct default value, if we don't specify anything + kwargs = build_kwargs( + shortcut_signature, + kwargs_need_default, + ) + assertion_callback = functools.partial(make_assertion, df_value=default_value) + setattr(bot.request, 'post', assertion_callback) + assert method(**kwargs) in expected_return_values + + # 2: test that we get the manually passed non-None value + kwargs = build_kwargs(shortcut_signature, kwargs_need_default, dfv='non-None-value') + assertion_callback = functools.partial(make_assertion, df_value='non-None-value') + setattr(bot.request, 'post', assertion_callback) + assert method(**kwargs) in expected_return_values + + # 3: test that we get the manually passed None value + kwargs = build_kwargs( + shortcut_signature, + kwargs_need_default, + dfv=None, + ) + assertion_callback = functools.partial(make_assertion, df_value=None) + setattr(bot.request, 'post', assertion_callback) + assert method(**kwargs) in expected_return_values + except Exception as exc: + raise exc + finally: + setattr(bot.request, 'post', orig_post) + bot.defaults = None + + return True diff --git a/tests/test_animation.py b/tests/test_animation.py index 6f16097cffa..279f4c9012e 100644 --- a/tests/test_animation.py +++ b/tests/test_animation.py @@ -26,7 +26,7 @@ from telegram import PhotoSize, Animation, Voice, TelegramError, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown -from tests.conftest import check_shortcut_call, check_shortcut_signature +from tests.conftest import check_shortcut_call, check_shortcut_signature, check_defaults_handling @pytest.fixture(scope='function') @@ -199,7 +199,6 @@ def test_send_animation_local_files(self, monkeypatch, bot, chat_id): def make_assertion(_, data, *args, **kwargs): nonlocal test_flag - print(data.get('animation'), expected) test_flag = data.get('animation') == expected and data.get('thumb') == expected monkeypatch.setattr(bot, '_post', make_assertion) @@ -309,14 +308,14 @@ def test_error_send_without_required_args(self, bot, chat_id): bot.send_animation(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, animation): - get_file = animation.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == animation.file_id and check_shortcut_call(kwargs, get_file) + return kwargs['file_id'] == animation.file_id assert check_shortcut_signature(Animation.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(animation.get_file, animation.bot, 'get_file') + assert check_defaults_handling(animation.get_file, animation.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(animation.bot, 'get_file', make_assertion) assert animation.get_file() def test_equality(self): diff --git a/tests/test_audio.py b/tests/test_audio.py index 43963affc90..e187b096b11 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -24,7 +24,7 @@ from telegram import Audio, TelegramError, Voice, MessageEntity, Bot from telegram.utils.helpers import escape_markdown -from tests.conftest import check_shortcut_call, check_shortcut_signature +from tests.conftest import check_shortcut_call, check_shortcut_signature, check_defaults_handling @pytest.fixture(scope='function') @@ -282,14 +282,14 @@ def test_error_send_without_required_args(self, bot, chat_id): bot.send_audio(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, audio): - get_file = audio.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == audio.file_id and check_shortcut_call(kwargs, get_file) + return kwargs['file_id'] == audio.file_id assert check_shortcut_signature(Audio.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(audio.get_file, audio.bot, 'get_file') + assert check_defaults_handling(audio.get_file, audio.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(audio.bot, 'get_file', make_assertion) assert audio.get_file() def test_equality(self, audio): diff --git a/tests/test_bot.py b/tests/test_bot.py index d8cb9618df0..5def9fabc5f 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -16,6 +16,7 @@ # # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. +import inspect import time import datetime as dtm from pathlib import Path @@ -47,7 +48,7 @@ from telegram.constants import MAX_INLINE_QUERY_RESULTS from telegram.error import BadRequest, InvalidToken, NetworkError, RetryAfter from telegram.utils.helpers import from_timestamp, escape_markdown, to_timestamp -from tests.conftest import expect_bad_request +from tests.conftest import expect_bad_request, check_defaults_handling from tests.bots import FALLBACKS @@ -177,6 +178,40 @@ def test_to_dict(self, bot): if bot.last_name: assert to_dict_bot["last_name"] == bot.last_name + @pytest.mark.parametrize( + 'bot_method_name', + argvalues=[ + name + for name, _ in inspect.getmembers(Bot, predicate=inspect.isfunction) + if not name.startswith('_') + and name + not in [ + 'de_json', + 'de_list', + 'to_dict', + 'to_json', + 'parse_data', + 'get_updates', + 'getUpdates', + ] + ], + ) + def test_defaults_handling(self, bot_method_name, bot): + """ + Here we check that the bot methods handle tg.ext.Defaults correctly. As for most defaults, + we can't really check the effect, we just check if we're passing the correct kwargs to + Request.post. As bot method tests a scattered across the different test files, we do + this here in one place. + + The same test is also run for all the shortcuts (Message.reply_text) etc in the + corresponding tests. + + Finally, there are some tests for Defaults.{parse_mode, quote, allow_sending_without_reply} + at the appropriate places, as those are the only things we can actually check. + """ + bot_method = getattr(bot, bot_method_name) + assert check_defaults_handling(bot_method, bot) + @flaky(3, 1) @pytest.mark.timeout(10) def test_forward_message(self, bot, chat_id, message): @@ -1790,8 +1825,8 @@ def test_copy_message_without_reply(self, bot, chat_id, media_message): 'default_bot', [ ({'parse_mode': ParseMode.HTML, 'allow_sending_without_reply': True}), - ({'parse_mode': False, 'allow_sending_without_reply': True}), - ({'parse_mode': False, 'allow_sending_without_reply': False}), + ({'parse_mode': None, 'allow_sending_without_reply': True}), + ({'parse_mode': None, 'allow_sending_without_reply': False}), ], indirect=['default_bot'], ) diff --git a/tests/test_callbackcontext.py b/tests/test_callbackcontext.py index 3b2cec90ad8..8018b0ce0d4 100644 --- a/tests/test_callbackcontext.py +++ b/tests/test_callbackcontext.py @@ -143,7 +143,7 @@ def test_data_assignment(self, cdp): callback_context = CallbackContext.from_update(update, cdp) with pytest.raises(AttributeError): - callback_context.chat_data = {"test": 123} + callback_context.bot_data = {"test": 123} with pytest.raises(AttributeError): callback_context.user_data = {} with pytest.raises(AttributeError): diff --git a/tests/test_callbackquery.py b/tests/test_callbackquery.py index 0582d032c2b..7ea3ca85748 100644 --- a/tests/test_callbackquery.py +++ b/tests/test_callbackquery.py @@ -20,10 +20,10 @@ import pytest from telegram import CallbackQuery, User, Message, Chat, Audio, Bot -from tests.conftest import check_shortcut_signature, check_shortcut_call +from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling -@pytest.fixture(scope='class', params=['message', 'inline']) +@pytest.fixture(scope='function', params=['message', 'inline']) def callback_query(bot, request): cbq = CallbackQuery( TestCallbackQuery.id_, @@ -50,6 +50,18 @@ class TestCallbackQuery: inline_message_id = 'inline_message_id' game_short_name = 'the_game' + @staticmethod + def skip_params(callback_query: CallbackQuery): + if callback_query.inline_message_id: + return {'message_id', 'chat_id'} + return {'inline_message_id'} + + @staticmethod + def shortcut_kwargs(callback_query: CallbackQuery): + if not callback_query.inline_message_id: + return {'message_id', 'chat_id'} + return {'inline_message_id'} + @staticmethod def check_passed_ids(callback_query: CallbackQuery, kwargs): if callback_query.inline_message_id: @@ -97,28 +109,26 @@ def test_to_dict(self, callback_query): assert callback_query_dict['game_short_name'] == callback_query.game_short_name def test_answer(self, monkeypatch, callback_query): - answer_callback_query = callback_query.bot.answer_callback_query - def make_assertion(*_, **kwargs): - return kwargs['callback_query_id'] == callback_query.id and check_shortcut_call( - kwargs, answer_callback_query - ) + return kwargs['callback_query_id'] == callback_query.id assert check_shortcut_signature( CallbackQuery.answer, Bot.answer_callback_query, ['callback_query_id'], [] ) + assert check_shortcut_call( + callback_query.answer, callback_query.bot, 'answer_callback_query' + ) + assert check_defaults_handling(callback_query.answer, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'answer_callback_query', make_assertion) # TODO: PEP8 assert callback_query.answer() def test_edit_message_text(self, monkeypatch, callback_query): - edit_message_text = callback_query.bot.edit_message_text - def make_assertion(*_, **kwargs): text = kwargs['text'] == 'test' ids = self.check_passed_ids(callback_query, kwargs) - return ids and text and check_shortcut_call(kwargs, edit_message_text) + return ids and text assert check_shortcut_signature( CallbackQuery.edit_message_text, @@ -126,18 +136,24 @@ def make_assertion(*_, **kwargs): ['inline_message_id', 'message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.edit_message_text, + callback_query.bot, + 'edit_message_text', + skip_params=self.skip_params(callback_query), + shortcut_kwargs=self.shortcut_kwargs(callback_query), + ) + assert check_defaults_handling(callback_query.edit_message_text, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'edit_message_text', make_assertion) assert callback_query.edit_message_text(text='test') assert callback_query.edit_message_text('test') def test_edit_message_caption(self, monkeypatch, callback_query): - edit_message_caption = callback_query.bot.edit_message_caption - def make_assertion(*_, **kwargs): caption = kwargs['caption'] == 'new caption' ids = self.check_passed_ids(callback_query, kwargs) - return ids and caption and check_shortcut_call(kwargs, edit_message_caption) + return ids and caption assert check_shortcut_signature( CallbackQuery.edit_message_caption, @@ -145,18 +161,24 @@ def make_assertion(*_, **kwargs): ['inline_message_id', 'message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.edit_message_caption, + callback_query.bot, + 'edit_message_caption', + skip_params=self.skip_params(callback_query), + shortcut_kwargs=self.shortcut_kwargs(callback_query), + ) + assert check_defaults_handling(callback_query.edit_message_caption, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'edit_message_caption', make_assertion) assert callback_query.edit_message_caption(caption='new caption') assert callback_query.edit_message_caption('new caption') def test_edit_message_reply_markup(self, monkeypatch, callback_query): - edit_message_reply_markup = callback_query.bot.edit_message_reply_markup - def make_assertion(*_, **kwargs): reply_markup = kwargs['reply_markup'] == [['1', '2']] ids = self.check_passed_ids(callback_query, kwargs) - return ids and reply_markup and check_shortcut_call(kwargs, edit_message_reply_markup) + return ids and reply_markup assert check_shortcut_signature( CallbackQuery.edit_message_reply_markup, @@ -164,18 +186,26 @@ def make_assertion(*_, **kwargs): ['inline_message_id', 'message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.edit_message_reply_markup, + callback_query.bot, + 'edit_message_reply_markup', + skip_params=self.skip_params(callback_query), + shortcut_kwargs=self.shortcut_kwargs(callback_query), + ) + assert check_defaults_handling( + callback_query.edit_message_reply_markup, callback_query.bot + ) monkeypatch.setattr(callback_query.bot, 'edit_message_reply_markup', make_assertion) assert callback_query.edit_message_reply_markup(reply_markup=[['1', '2']]) assert callback_query.edit_message_reply_markup([['1', '2']]) def test_edit_message_media(self, monkeypatch, callback_query): - edit_message_media = callback_query.bot.edit_message_media - def make_assertion(*_, **kwargs): message_media = kwargs.get('media') == [['1', '2']] ids = self.check_passed_ids(callback_query, kwargs) - return ids and message_media and check_shortcut_call(kwargs, edit_message_media) + return ids and message_media assert check_shortcut_signature( CallbackQuery.edit_message_media, @@ -183,24 +213,25 @@ def make_assertion(*_, **kwargs): ['inline_message_id', 'message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.edit_message_media, + callback_query.bot, + 'edit_message_media', + skip_params=self.skip_params(callback_query), + shortcut_kwargs=self.shortcut_kwargs(callback_query), + ) + assert check_defaults_handling(callback_query.edit_message_media, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'edit_message_media', make_assertion) assert callback_query.edit_message_media(media=[['1', '2']]) assert callback_query.edit_message_media([['1', '2']]) def test_edit_message_live_location(self, monkeypatch, callback_query): - edit_message_live_location = callback_query.bot.edit_message_live_location - def make_assertion(*_, **kwargs): latitude = kwargs.get('latitude') == 1 longitude = kwargs.get('longitude') == 2 ids = self.check_passed_ids(callback_query, kwargs) - return ( - ids - and latitude - and longitude - and check_shortcut_call(kwargs, edit_message_live_location) - ) + return ids and latitude and longitude assert check_shortcut_signature( CallbackQuery.edit_message_live_location, @@ -208,17 +239,25 @@ def make_assertion(*_, **kwargs): ['inline_message_id', 'message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.edit_message_live_location, + callback_query.bot, + 'edit_message_live_location', + skip_params=self.skip_params(callback_query), + shortcut_kwargs=self.shortcut_kwargs(callback_query), + ) + assert check_defaults_handling( + callback_query.edit_message_live_location, callback_query.bot + ) monkeypatch.setattr(callback_query.bot, 'edit_message_live_location', make_assertion) assert callback_query.edit_message_live_location(latitude=1, longitude=2) assert callback_query.edit_message_live_location(1, 2) def test_stop_message_live_location(self, monkeypatch, callback_query): - stop_message_live_location = callback_query.bot.stop_message_live_location - def make_assertion(*_, **kwargs): ids = self.check_passed_ids(callback_query, kwargs) - return ids and check_shortcut_call(kwargs, stop_message_live_location) + return ids assert check_shortcut_signature( CallbackQuery.stop_message_live_location, @@ -226,18 +265,26 @@ def make_assertion(*_, **kwargs): ['inline_message_id', 'message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.stop_message_live_location, + callback_query.bot, + 'stop_message_live_location', + skip_params=self.skip_params(callback_query), + shortcut_kwargs=self.shortcut_kwargs(callback_query), + ) + assert check_defaults_handling( + callback_query.stop_message_live_location, callback_query.bot + ) monkeypatch.setattr(callback_query.bot, 'stop_message_live_location', make_assertion) assert callback_query.stop_message_live_location() def test_set_game_score(self, monkeypatch, callback_query): - set_game_score = callback_query.bot.set_game_score - def make_assertion(*_, **kwargs): user_id = kwargs.get('user_id') == 1 score = kwargs.get('score') == 2 ids = self.check_passed_ids(callback_query, kwargs) - return ids and user_id and score and check_shortcut_call(kwargs, set_game_score) + return ids and user_id and score assert check_shortcut_signature( CallbackQuery.set_game_score, @@ -245,18 +292,24 @@ def make_assertion(*_, **kwargs): ['inline_message_id', 'message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.set_game_score, + callback_query.bot, + 'set_game_score', + skip_params=self.skip_params(callback_query), + shortcut_kwargs=self.shortcut_kwargs(callback_query), + ) + assert check_defaults_handling(callback_query.set_game_score, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'set_game_score', make_assertion) assert callback_query.set_game_score(user_id=1, score=2) assert callback_query.set_game_score(1, 2) def test_get_game_high_scores(self, monkeypatch, callback_query): - get_game_high_scores = callback_query.bot.get_game_high_scores - def make_assertion(*_, **kwargs): user_id = kwargs.get('user_id') == 1 ids = self.check_passed_ids(callback_query, kwargs) - return ids and user_id and check_shortcut_call(kwargs, get_game_high_scores) + return ids and user_id assert check_shortcut_signature( CallbackQuery.get_game_high_scores, @@ -264,20 +317,27 @@ def make_assertion(*_, **kwargs): ['inline_message_id', 'message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.get_game_high_scores, + callback_query.bot, + 'get_game_high_scores', + skip_params=self.skip_params(callback_query), + shortcut_kwargs=self.shortcut_kwargs(callback_query), + ) + assert check_defaults_handling(callback_query.get_game_high_scores, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'get_game_high_scores', make_assertion) assert callback_query.get_game_high_scores(user_id=1) assert callback_query.get_game_high_scores(1) def test_delete_message(self, monkeypatch, callback_query): - delete_message = callback_query.bot.delete_message if callback_query.inline_message_id: pytest.skip("Can't delete inline messages") def make_assertion(*args, **kwargs): id_ = kwargs['chat_id'] == callback_query.message.chat_id message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and check_shortcut_call(kwargs, delete_message) + return id_ and message assert check_shortcut_signature( CallbackQuery.delete_message, @@ -285,19 +345,20 @@ def make_assertion(*args, **kwargs): ['message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.delete_message, callback_query.bot, 'delete_message' + ) + assert check_defaults_handling(callback_query.delete_message, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'delete_message', make_assertion) assert callback_query.delete_message() def test_pin_message(self, monkeypatch, callback_query): - pin_message = callback_query.bot.pin_chat_message if callback_query.inline_message_id: pytest.skip("Can't pin inline messages") def make_assertion(*args, **kwargs): - return kwargs['chat_id'] == callback_query.message.chat_id and check_shortcut_call( - kwargs, pin_message - ) + return kwargs['chat_id'] == callback_query.message.chat_id assert check_shortcut_signature( CallbackQuery.pin_message, @@ -305,19 +366,20 @@ def make_assertion(*args, **kwargs): ['message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.pin_message, callback_query.bot, 'pin_chat_message' + ) + assert check_defaults_handling(callback_query.pin_message, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'pin_chat_message', make_assertion) assert callback_query.pin_message() def test_unpin_message(self, monkeypatch, callback_query): - unpin_message = callback_query.bot.unpin_chat_message if callback_query.inline_message_id: pytest.skip("Can't unpin inline messages") def make_assertion(*args, **kwargs): - return kwargs['chat_id'] == callback_query.message.chat_id and check_shortcut_call( - kwargs, unpin_message - ) + return kwargs['chat_id'] == callback_query.message.chat_id assert check_shortcut_signature( CallbackQuery.unpin_message, @@ -325,12 +387,18 @@ def make_assertion(*args, **kwargs): ['message_id', 'chat_id'], [], ) + assert check_shortcut_call( + callback_query.unpin_message, + callback_query.bot, + 'unpin_chat_message', + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(callback_query.unpin_message, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'unpin_chat_message', make_assertion) assert callback_query.unpin_message() def test_copy_message(self, monkeypatch, callback_query): - copy_message = callback_query.bot.copy_message if callback_query.inline_message_id: pytest.skip("Can't copy inline messages") @@ -338,7 +406,7 @@ def make_assertion(*args, **kwargs): id_ = kwargs['from_chat_id'] == callback_query.message.chat_id chat_id = kwargs['chat_id'] == 1 message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and chat_id and check_shortcut_call(kwargs, copy_message) + return id_ and message and chat_id assert check_shortcut_signature( CallbackQuery.copy_message, @@ -346,6 +414,8 @@ def make_assertion(*args, **kwargs): ['message_id', 'from_chat_id'], [], ) + assert check_shortcut_call(callback_query.copy_message, callback_query.bot, 'copy_message') + assert check_defaults_handling(callback_query.copy_message, callback_query.bot) monkeypatch.setattr(callback_query.bot, 'copy_message', make_assertion) assert callback_query.copy_message(1) diff --git a/tests/test_chat.py b/tests/test_chat.py index e8e95748d05..5d313cf1898 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -21,7 +21,7 @@ from telegram import Chat, ChatAction, ChatPermissions, ChatLocation, Location, Bot from telegram import User -from tests.conftest import check_shortcut_signature, check_shortcut_call +from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling @pytest.fixture(scope='class') @@ -126,153 +126,144 @@ def test_full_name(self): assert chat.full_name is None def test_send_action(self, monkeypatch, chat): - send_chat_action = chat.bot.send_chat_action - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == chat.id action = kwargs['action'] == ChatAction.TYPING - return id_ and action and check_shortcut_call(kwargs, send_chat_action) + return id_ and action - assert check_shortcut_signature( - Chat.send_chat_action, Bot.send_chat_action, ['chat_id'], [] - ) + assert check_shortcut_signature(chat.send_action, Bot.send_chat_action, ['chat_id'], []) + assert check_shortcut_call(chat.send_action, chat.bot, 'send_chat_action') + assert check_defaults_handling(chat.send_action, chat.bot) monkeypatch.setattr(chat.bot, 'send_chat_action', make_assertion) assert chat.send_action(action=ChatAction.TYPING) - assert chat.send_chat_action(action=ChatAction.TYPING) + assert chat.send_action(action=ChatAction.TYPING) def test_leave(self, monkeypatch, chat): - leave_chat = chat.bot.leave_chat - def make_assertion(*_, **kwargs): - return kwargs['chat_id'] == chat.id and check_shortcut_call(kwargs, leave_chat) + return kwargs['chat_id'] == chat.id assert check_shortcut_signature(Chat.leave, Bot.leave_chat, ['chat_id'], []) + assert check_shortcut_call(chat.leave, chat.bot, 'leave_chat') + assert check_defaults_handling(chat.leave, chat.bot) monkeypatch.setattr(chat.bot, 'leave_chat', make_assertion) assert chat.leave() def test_get_administrators(self, monkeypatch, chat): - get_chat_administrators = chat.bot.get_chat_administrators - def make_assertion(*_, **kwargs): - return kwargs['chat_id'] == chat.id and check_shortcut_call( - kwargs, get_chat_administrators - ) + return kwargs['chat_id'] == chat.id assert check_shortcut_signature( Chat.get_administrators, Bot.get_chat_administrators, ['chat_id'], [] ) + assert check_shortcut_call(chat.get_administrators, chat.bot, 'get_chat_administrators') + assert check_defaults_handling(chat.get_administrators, chat.bot) monkeypatch.setattr(chat.bot, 'get_chat_administrators', make_assertion) assert chat.get_administrators() def test_get_members_count(self, monkeypatch, chat): - get_chat_members_count = chat.bot.get_chat_members_count - def make_assertion(*_, **kwargs): - return kwargs['chat_id'] == chat.id and check_shortcut_call( - kwargs, get_chat_members_count - ) + return kwargs['chat_id'] == chat.id assert check_shortcut_signature( Chat.get_members_count, Bot.get_chat_members_count, ['chat_id'], [] ) + assert check_shortcut_call(chat.get_members_count, chat.bot, 'get_chat_members_count') + assert check_defaults_handling(chat.get_members_count, chat.bot) monkeypatch.setattr(chat.bot, 'get_chat_members_count', make_assertion) assert chat.get_members_count() def test_get_member(self, monkeypatch, chat): - get_chat_member = chat.bot.get_chat_member - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == chat.id user_id = kwargs['user_id'] == 42 - return chat_id and user_id and check_shortcut_call(kwargs, get_chat_member) + return chat_id and user_id assert check_shortcut_signature(Chat.get_member, Bot.get_chat_member, ['chat_id'], []) + assert check_shortcut_call(chat.get_member, chat.bot, 'get_chat_member') + assert check_defaults_handling(chat.get_member, chat.bot) monkeypatch.setattr(chat.bot, 'get_chat_member', make_assertion) assert chat.get_member(user_id=42) def test_kick_member(self, monkeypatch, chat): - kick_chat_member = chat.bot.kick_chat_member - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == chat.id user_id = kwargs['user_id'] == 42 until = kwargs['until_date'] == 43 - return chat_id and user_id and until and check_shortcut_call(kwargs, kick_chat_member) + return chat_id and user_id and until assert check_shortcut_signature(Chat.kick_member, Bot.kick_chat_member, ['chat_id'], []) + assert check_shortcut_call(chat.kick_member, chat.bot, 'kick_chat_member') + assert check_defaults_handling(chat.kick_member, chat.bot) monkeypatch.setattr(chat.bot, 'kick_chat_member', make_assertion) assert chat.kick_member(user_id=42, until_date=43) @pytest.mark.parametrize('only_if_banned', [True, False, None]) def test_unban_member(self, monkeypatch, chat, only_if_banned): - unban_chat_member = chat.bot.unban_chat_member - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == chat.id user_id = kwargs['user_id'] == 42 o_i_b = kwargs.get('only_if_banned', None) == only_if_banned - return chat_id and user_id and o_i_b and check_shortcut_call(kwargs, unban_chat_member) + return chat_id and user_id and o_i_b assert check_shortcut_signature(Chat.unban_member, Bot.unban_chat_member, ['chat_id'], []) + assert check_shortcut_call(chat.unban_member, chat.bot, 'unban_chat_member') + assert check_defaults_handling(chat.unban_member, chat.bot) monkeypatch.setattr(chat.bot, 'unban_chat_member', make_assertion) assert chat.unban_member(user_id=42, only_if_banned=only_if_banned) @pytest.mark.parametrize('is_anonymous', [True, False, None]) def test_promote_member(self, monkeypatch, chat, is_anonymous): - promote_chat_member = chat.bot.promote_chat_member - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == chat.id user_id = kwargs['user_id'] == 42 o_i_b = kwargs.get('is_anonymous', None) == is_anonymous - return ( - chat_id and user_id and o_i_b and check_shortcut_call(kwargs, promote_chat_member) - ) + return chat_id and user_id and o_i_b assert check_shortcut_signature( Chat.promote_member, Bot.promote_chat_member, ['chat_id'], [] ) + assert check_shortcut_call(chat.promote_member, chat.bot, 'promote_chat_member') + assert check_defaults_handling(chat.promote_member, chat.bot) monkeypatch.setattr(chat.bot, 'promote_chat_member', make_assertion) assert chat.promote_member(user_id=42, is_anonymous=is_anonymous) def test_restrict_member(self, monkeypatch, chat): - restrict_chat_member = chat.bot.restrict_chat_member permissions = ChatPermissions(True, False, True, False, True, False, True, False) def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == chat.id user_id = kwargs['user_id'] == 42 o_i_b = kwargs.get('permissions', None) == permissions - return ( - chat_id and user_id and o_i_b and check_shortcut_call(kwargs, restrict_chat_member) - ) + return chat_id and user_id and o_i_b assert check_shortcut_signature( Chat.restrict_member, Bot.restrict_chat_member, ['chat_id'], [] ) + assert check_shortcut_call(chat.restrict_member, chat.bot, 'restrict_chat_member') + assert check_defaults_handling(chat.restrict_member, chat.bot) monkeypatch.setattr(chat.bot, 'restrict_chat_member', make_assertion) assert chat.restrict_member(user_id=42, permissions=permissions) def test_set_permissions(self, monkeypatch, chat): - set_chat_permissions = chat.bot.set_chat_permissions - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == chat.id permissions = kwargs['permissions'] == self.permissions - return chat_id and permissions and check_shortcut_call(kwargs, set_chat_permissions) + return chat_id and permissions assert check_shortcut_signature( Chat.set_permissions, Bot.set_chat_permissions, ['chat_id'], [] ) + assert check_shortcut_call(chat.set_permissions, chat.bot, 'set_chat_permissions') + assert check_defaults_handling(chat.set_permissions, chat.bot) monkeypatch.setattr(chat.bot, 'set_chat_permissions', make_assertion) assert chat.set_permissions(permissions=self.permissions) @@ -288,173 +279,133 @@ def make_assertion(*_, **kwargs): assert chat.set_administrator_custom_title(user_id=42, custom_title='custom_title') def test_pin_message(self, monkeypatch, chat): - pin_chat_message = chat.bot.pin_chat_message - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['message_id'] == 42 - and check_shortcut_call(kwargs, pin_chat_message) - ) + return kwargs['chat_id'] == chat.id and kwargs['message_id'] == 42 assert check_shortcut_signature(Chat.pin_message, Bot.pin_chat_message, ['chat_id'], []) + assert check_shortcut_call(chat.pin_message, chat.bot, 'pin_chat_message') + assert check_defaults_handling(chat.pin_message, chat.bot) monkeypatch.setattr(chat.bot, 'pin_chat_message', make_assertion) assert chat.pin_message(message_id=42) def test_unpin_message(self, monkeypatch, chat): - unpin_chat_message = chat.bot.unpin_chat_message - def make_assertion(*_, **kwargs): - return kwargs['chat_id'] == chat.id and check_shortcut_call(kwargs, unpin_chat_message) + return kwargs['chat_id'] == chat.id assert check_shortcut_signature( Chat.unpin_message, Bot.unpin_chat_message, ['chat_id'], [] ) + assert check_shortcut_call(chat.unpin_message, chat.bot, 'unpin_chat_message') + assert check_defaults_handling(chat.unpin_message, chat.bot) monkeypatch.setattr(chat.bot, 'unpin_chat_message', make_assertion) assert chat.unpin_message() def test_unpin_all_messages(self, monkeypatch, chat): - unpin_all_chat_messages = chat.bot.unpin_all_chat_messages - def make_assertion(*_, **kwargs): - return kwargs['chat_id'] == chat.id and check_shortcut_call( - kwargs, unpin_all_chat_messages - ) + return kwargs['chat_id'] == chat.id assert check_shortcut_signature( Chat.unpin_all_messages, Bot.unpin_all_chat_messages, ['chat_id'], [] ) + assert check_shortcut_call(chat.unpin_all_messages, chat.bot, 'unpin_all_chat_messages') + assert check_defaults_handling(chat.unpin_all_messages, chat.bot) monkeypatch.setattr(chat.bot, 'unpin_all_chat_messages', make_assertion) assert chat.unpin_all_messages() def test_instance_method_send_message(self, monkeypatch, chat): - send_message = chat.bot.send_message - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['text'] == 'test' - and check_shortcut_call(kwargs, send_message) - ) + return kwargs['chat_id'] == chat.id and kwargs['text'] == 'test' assert check_shortcut_signature(Chat.send_message, Bot.send_message, ['chat_id'], []) + assert check_shortcut_call(chat.send_message, chat.bot, 'send_message') + assert check_defaults_handling(chat.send_message, chat.bot) monkeypatch.setattr(chat.bot, 'send_message', make_assertion) assert chat.send_message(text='test') def test_instance_method_send_media_group(self, monkeypatch, chat): - send_media_group = chat.bot.send_media_group - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['media'] == 'test_media_group' - and check_shortcut_call(kwargs, send_media_group) - ) + return kwargs['chat_id'] == chat.id and kwargs['media'] == 'test_media_group' assert check_shortcut_signature( Chat.send_media_group, Bot.send_media_group, ['chat_id'], [] ) + assert check_shortcut_call(chat.send_media_group, chat.bot, 'send_media_group') + assert check_defaults_handling(chat.send_media_group, chat.bot) monkeypatch.setattr(chat.bot, 'send_media_group', make_assertion) assert chat.send_media_group(media='test_media_group') def test_instance_method_send_photo(self, monkeypatch, chat): - send_photo = chat.bot.send_photo - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['photo'] == 'test_photo' - and check_shortcut_call(kwargs, send_photo) - ) + return kwargs['chat_id'] == chat.id and kwargs['photo'] == 'test_photo' assert check_shortcut_signature(Chat.send_photo, Bot.send_photo, ['chat_id'], []) + assert check_shortcut_call(chat.send_photo, chat.bot, 'send_photo') + assert check_defaults_handling(chat.send_photo, chat.bot) monkeypatch.setattr(chat.bot, 'send_photo', make_assertion) assert chat.send_photo(photo='test_photo') def test_instance_method_send_contact(self, monkeypatch, chat): - send_contact = chat.bot.send_contact - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['phone_number'] == 'test_contact' - and check_shortcut_call(kwargs, send_contact) - ) + return kwargs['chat_id'] == chat.id and kwargs['phone_number'] == 'test_contact' assert check_shortcut_signature(Chat.send_contact, Bot.send_contact, ['chat_id'], []) + assert check_shortcut_call(chat.send_contact, chat.bot, 'send_contact') + assert check_defaults_handling(chat.send_contact, chat.bot) monkeypatch.setattr(chat.bot, 'send_contact', make_assertion) assert chat.send_contact(phone_number='test_contact') def test_instance_method_send_audio(self, monkeypatch, chat): - send_audio = chat.bot.send_audio - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['audio'] == 'test_audio' - and check_shortcut_call(kwargs, send_audio) - ) + return kwargs['chat_id'] == chat.id and kwargs['audio'] == 'test_audio' assert check_shortcut_signature(Chat.send_audio, Bot.send_audio, ['chat_id'], []) + assert check_shortcut_call(chat.send_audio, chat.bot, 'send_audio') + assert check_defaults_handling(chat.send_audio, chat.bot) monkeypatch.setattr(chat.bot, 'send_audio', make_assertion) assert chat.send_audio(audio='test_audio') def test_instance_method_send_document(self, monkeypatch, chat): - send_document = chat.bot.send_document - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['document'] == 'test_document' - and check_shortcut_call(kwargs, send_document) - ) + return kwargs['chat_id'] == chat.id and kwargs['document'] == 'test_document' assert check_shortcut_signature(Chat.send_document, Bot.send_document, ['chat_id'], []) + assert check_shortcut_call(chat.send_document, chat.bot, 'send_document') + assert check_defaults_handling(chat.send_document, chat.bot) monkeypatch.setattr(chat.bot, 'send_document', make_assertion) assert chat.send_document(document='test_document') def test_instance_method_send_dice(self, monkeypatch, chat): - send_dice = chat.bot.send_dice - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['emoji'] == 'test_dice' - and check_shortcut_call(kwargs, send_dice) - ) + return kwargs['chat_id'] == chat.id and kwargs['emoji'] == 'test_dice' assert check_shortcut_signature(Chat.send_dice, Bot.send_dice, ['chat_id'], []) + assert check_shortcut_call(chat.send_dice, chat.bot, 'send_dice') + assert check_defaults_handling(chat.send_dice, chat.bot) monkeypatch.setattr(chat.bot, 'send_dice', make_assertion) assert chat.send_dice(emoji='test_dice') def test_instance_method_send_game(self, monkeypatch, chat): - send_game = chat.bot.send_game - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['game_short_name'] == 'test_game' - and check_shortcut_call(kwargs, send_game) - ) + return kwargs['chat_id'] == chat.id and kwargs['game_short_name'] == 'test_game' assert check_shortcut_signature(Chat.send_game, Bot.send_game, ['chat_id'], []) + assert check_shortcut_call(chat.send_game, chat.bot, 'send_game') + assert check_defaults_handling(chat.send_game, chat.bot) monkeypatch.setattr(chat.bot, 'send_game', make_assertion) assert chat.send_game(game_short_name='test_game') def test_instance_method_send_invoice(self, monkeypatch, chat): - send_invoice = chat.bot.send_invoice - def make_assertion(*_, **kwargs): title = kwargs['title'] == 'title' description = kwargs['description'] == 'description' @@ -472,11 +423,11 @@ def make_assertion(*_, **kwargs): and currency and prices ) - return ( - kwargs['chat_id'] == chat.id and args and check_shortcut_call(kwargs, send_invoice) - ) + return kwargs['chat_id'] == chat.id and args assert check_shortcut_signature(Chat.send_invoice, Bot.send_invoice, ['chat_id'], []) + assert check_shortcut_call(chat.send_invoice, chat.bot, 'send_invoice') + assert check_defaults_handling(chat.send_invoice, chat.bot) monkeypatch.setattr(chat.bot, 'send_invoice', make_assertion) assert chat.send_invoice( @@ -490,159 +441,117 @@ def make_assertion(*_, **kwargs): ) def test_instance_method_send_location(self, monkeypatch, chat): - send_location = chat.bot.send_location - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['latitude'] == 'test_location' - and check_shortcut_call(kwargs, send_location) - ) + return kwargs['chat_id'] == chat.id and kwargs['latitude'] == 'test_location' assert check_shortcut_signature(Chat.send_location, Bot.send_location, ['chat_id'], []) + assert check_shortcut_call(chat.send_location, chat.bot, 'send_location') + assert check_defaults_handling(chat.send_location, chat.bot) monkeypatch.setattr(chat.bot, 'send_location', make_assertion) assert chat.send_location(latitude='test_location') def test_instance_method_send_sticker(self, monkeypatch, chat): - send_sticker = chat.bot.send_sticker - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['sticker'] == 'test_sticker' - and check_shortcut_call(kwargs, send_sticker) - ) + return kwargs['chat_id'] == chat.id and kwargs['sticker'] == 'test_sticker' assert check_shortcut_signature(Chat.send_sticker, Bot.send_sticker, ['chat_id'], []) + assert check_shortcut_call(chat.send_sticker, chat.bot, 'send_sticker') + assert check_defaults_handling(chat.send_sticker, chat.bot) monkeypatch.setattr(chat.bot, 'send_sticker', make_assertion) assert chat.send_sticker(sticker='test_sticker') def test_instance_method_send_venue(self, monkeypatch, chat): - send_venue = chat.bot.send_venue - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['title'] == 'test_venue' - and check_shortcut_call(kwargs, send_venue) - ) + return kwargs['chat_id'] == chat.id and kwargs['title'] == 'test_venue' assert check_shortcut_signature(Chat.send_venue, Bot.send_venue, ['chat_id'], []) + assert check_shortcut_call(chat.send_venue, chat.bot, 'send_venue') + assert check_defaults_handling(chat.send_venue, chat.bot) monkeypatch.setattr(chat.bot, 'send_venue', make_assertion) assert chat.send_venue(title='test_venue') def test_instance_method_send_video(self, monkeypatch, chat): - send_video = chat.bot.send_video - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['video'] == 'test_video' - and check_shortcut_call(kwargs, send_video) - ) + return kwargs['chat_id'] == chat.id and kwargs['video'] == 'test_video' assert check_shortcut_signature(Chat.send_video, Bot.send_video, ['chat_id'], []) + assert check_shortcut_call(chat.send_video, chat.bot, 'send_video') + assert check_defaults_handling(chat.send_video, chat.bot) monkeypatch.setattr(chat.bot, 'send_video', make_assertion) assert chat.send_video(video='test_video') def test_instance_method_send_video_note(self, monkeypatch, chat): - send_video_note = chat.bot.send_video_note - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['video_note'] == 'test_video_note' - and check_shortcut_call(kwargs, send_video_note) - ) + return kwargs['chat_id'] == chat.id and kwargs['video_note'] == 'test_video_note' assert check_shortcut_signature(Chat.send_video_note, Bot.send_video_note, ['chat_id'], []) + assert check_shortcut_call(chat.send_video_note, chat.bot, 'send_video_note') + assert check_defaults_handling(chat.send_video_note, chat.bot) monkeypatch.setattr(chat.bot, 'send_video_note', make_assertion) assert chat.send_video_note(video_note='test_video_note') def test_instance_method_send_voice(self, monkeypatch, chat): - send_voice = chat.bot.send_voice - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['voice'] == 'test_voice' - and check_shortcut_call(kwargs, send_voice) - ) + return kwargs['chat_id'] == chat.id and kwargs['voice'] == 'test_voice' assert check_shortcut_signature(Chat.send_voice, Bot.send_voice, ['chat_id'], []) + assert check_shortcut_call(chat.send_voice, chat.bot, 'send_voice') + assert check_defaults_handling(chat.send_voice, chat.bot) monkeypatch.setattr(chat.bot, 'send_voice', make_assertion) assert chat.send_voice(voice='test_voice') def test_instance_method_send_animation(self, monkeypatch, chat): - send_animation = chat.bot.send_animation - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['animation'] == 'test_animation' - and check_shortcut_call(kwargs, send_animation) - ) + return kwargs['chat_id'] == chat.id and kwargs['animation'] == 'test_animation' assert check_shortcut_signature(Chat.send_animation, Bot.send_animation, ['chat_id'], []) + assert check_shortcut_call(chat.send_animation, chat.bot, 'send_animation') + assert check_defaults_handling(chat.send_animation, chat.bot) monkeypatch.setattr(chat.bot, 'send_animation', make_assertion) assert chat.send_animation(animation='test_animation') def test_instance_method_send_poll(self, monkeypatch, chat): - send_poll = chat.bot.send_poll - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == chat.id - and kwargs['question'] == 'test_poll' - and check_shortcut_call(kwargs, send_poll) - ) + return kwargs['chat_id'] == chat.id and kwargs['question'] == 'test_poll' assert check_shortcut_signature(Chat.send_poll, Bot.send_poll, ['chat_id'], []) + assert check_shortcut_call(chat.send_poll, chat.bot, 'send_poll') + assert check_defaults_handling(chat.send_poll, chat.bot) monkeypatch.setattr(chat.bot, 'send_poll', make_assertion) assert chat.send_poll(question='test_poll', options=[1, 2]) def test_instance_method_send_copy(self, monkeypatch, chat): - copy_message = chat.bot.copy_message - def make_assertion(*_, **kwargs): from_chat_id = kwargs['from_chat_id'] == 'test_copy' message_id = kwargs['message_id'] == 42 chat_id = kwargs['chat_id'] == chat.id - return ( - from_chat_id - and message_id - and chat_id - and check_shortcut_call(kwargs, copy_message) - ) + return from_chat_id and message_id and chat_id assert check_shortcut_signature(Chat.send_copy, Bot.copy_message, ['chat_id'], []) + assert check_shortcut_call(chat.copy_message, chat.bot, 'copy_message') + assert check_defaults_handling(chat.copy_message, chat.bot) monkeypatch.setattr(chat.bot, 'copy_message', make_assertion) assert chat.send_copy(from_chat_id='test_copy', message_id=42) def test_instance_method_copy_message(self, monkeypatch, chat): - copy_message = chat.bot.copy_message - def make_assertion(*_, **kwargs): from_chat_id = kwargs['from_chat_id'] == chat.id message_id = kwargs['message_id'] == 42 chat_id = kwargs['chat_id'] == 'test_copy' - return ( - from_chat_id - and message_id - and chat_id - and check_shortcut_call(kwargs, copy_message) - ) + return from_chat_id and message_id and chat_id assert check_shortcut_signature(Chat.copy_message, Bot.copy_message, ['from_chat_id'], []) + assert check_shortcut_call(chat.copy_message, chat.bot, 'copy_message') + assert check_defaults_handling(chat.copy_message, chat.bot) monkeypatch.setattr(chat.bot, 'copy_message', make_assertion) assert chat.copy_message(chat_id='test_copy', message_id=42) diff --git a/tests/test_chatphoto.py b/tests/test_chatphoto.py index 64203c3d7ab..cb9fd16f70a 100644 --- a/tests/test_chatphoto.py +++ b/tests/test_chatphoto.py @@ -22,7 +22,12 @@ from flaky import flaky from telegram import ChatPhoto, Voice, TelegramError, Bot -from tests.conftest import expect_bad_request, check_shortcut_call, check_shortcut_signature +from tests.conftest import ( + expect_bad_request, + check_shortcut_call, + check_shortcut_signature, + check_defaults_handling, +) @pytest.fixture(scope='function') @@ -125,29 +130,25 @@ def test_error_send_without_required_args(self, bot, super_group_id): bot.set_chat_photo(chat_id=super_group_id) def test_get_small_file_instance_method(self, monkeypatch, chat_photo): - get_small_file = chat_photo.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == chat_photo.small_file_id and check_shortcut_call( - kwargs, get_small_file - ) + return kwargs['file_id'] == chat_photo.small_file_id assert check_shortcut_signature(ChatPhoto.get_small_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(chat_photo.get_small_file, chat_photo.bot, 'get_file') + assert check_defaults_handling(chat_photo.get_small_file, chat_photo.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(chat_photo.bot, 'get_file', make_assertion) assert chat_photo.get_small_file() def test_get_big_file_instance_method(self, monkeypatch, chat_photo): - get_big_file = chat_photo.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == chat_photo.big_file_id and check_shortcut_call( - kwargs, get_big_file - ) + return kwargs['file_id'] == chat_photo.big_file_id assert check_shortcut_signature(ChatPhoto.get_big_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(chat_photo.get_big_file, chat_photo.bot, 'get_file') + assert check_defaults_handling(chat_photo.get_big_file, chat_photo.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(chat_photo.bot, 'get_file', make_assertion) assert chat_photo.get_big_file() def test_equality(self): diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 9ff81a00cb9..b12029cc8b1 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -29,6 +29,8 @@ def test_data_assignment(self, cdp): with pytest.raises(AttributeError): defaults.parse_mode = True + with pytest.raises(AttributeError): + defaults.explanation_parse_mode = True with pytest.raises(AttributeError): defaults.disable_notification = True with pytest.raises(AttributeError): diff --git a/tests/test_document.py b/tests/test_document.py index b72668cb94c..37de5dc6bb1 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -25,7 +25,7 @@ from telegram import Document, PhotoSize, TelegramError, Voice, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown -from tests.conftest import check_shortcut_signature, check_shortcut_call +from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling @pytest.fixture(scope='function') @@ -298,14 +298,14 @@ def test_error_send_without_required_args(self, bot, chat_id): bot.send_document(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, document): - get_file = document.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == document.file_id and check_shortcut_call(kwargs, get_file) + return kwargs['file_id'] == document.file_id assert check_shortcut_signature(Document.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(document.get_file, document.bot, 'get_file') + assert check_defaults_handling(document.get_file, document.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(document.bot, 'get_file', make_assertion) assert document.get_file() def test_equality(self, document): diff --git a/tests/test_error.py b/tests/test_error.py index 7a0c2eab477..02273e519af 100644 --- a/tests/test_error.py +++ b/tests/test_error.py @@ -115,7 +115,6 @@ def test_conflict(self): ], ) def test_errors_pickling(self, exception, attributes): - print(exception) pickled = pickle.dumps(exception) unpickled = pickle.loads(pickled) assert type(unpickled) is type(exception) diff --git a/tests/test_filters.py b/tests/test_filters.py index 1cfa69dd6bd..f8d95edad45 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -547,7 +547,7 @@ def test_filters_document_type(self, update): assert not Filters.document.audio(update) update.message.document.mime_type = ( - "application/vnd.openxmlformats-officedocument." "wordprocessingml.document" + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) assert Filters.document.docx(update) assert Filters.document.application(update) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index a736bb24a6a..b95588ab27f 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -17,12 +17,11 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. import os -import subprocess -import sys import time import datetime as dtm from importlib import reload from pathlib import Path +from unittest import mock import pytest @@ -37,6 +36,8 @@ # sample time specification values categorised into absolute / delta / time-of-day +from tests.conftest import env_var_2_bool + ABSOLUTE_TIME_SPECS = [ dtm.datetime.now(tz=dtm.timezone(dtm.timedelta(hours=-7))), dtm.datetime.utcnow(), @@ -49,28 +50,41 @@ RELATIVE_TIME_SPECS = DELTA_TIME_SPECS + TIME_OF_DAY_TIME_SPECS TIME_SPECS = ABSOLUTE_TIME_SPECS + RELATIVE_TIME_SPECS +""" +This part is here for ptb-raw, where we don't have pytz (unless the user installs it) +Because imports in pytest are intricate, we just run -# This is here for ptb-raw, where we don't have pytz (unless the user installs it) -@pytest.fixture(scope='function', params=[True, False]) -def pytz_install(request): - skip = not os.getenv('GITHUB_ACTIONS', False) - reason = 'Un/installing pytz slows tests down, so we just do that in CI' + pytest -k test_helpers.py - if not request.param: - if skip: - pytest.skip(reason) - subprocess.check_call([sys.executable, "-m", "pip", "uninstall", "pytz", "-y"]) - del sys.modules['pytz'] - reload(helpers) - yield - if not request.param: - if skip: - pytest.skip(reason) - subprocess.check_call([sys.executable, "-m", "pip", "install", "pytz"]) +with the TEST_NO_PYTZ environment variable set in addition to the regular test suite. +Because actually uninstalling pytz would lead to errors in the test suite we just mock the +import to raise the expected exception. + +Note that a fixture that just does this for every test that needs it is a nice idea, but for some +reason makes test_updater.py hang indefinitely on GitHub Actions (at least when Hinrich tried that) +""" +TEST_NO_PYTZ = env_var_2_bool(os.getenv('TEST_NO_PYTZ', False)) + +if TEST_NO_PYTZ: + orig_import = __import__ + + def import_mock(module_name, *args, **kwargs): + if module_name == 'pytz': + raise ModuleNotFoundError('We are testing without pytz here') + return orig_import(module_name, *args, **kwargs) + + with mock.patch('builtins.__import__', side_effect=import_mock): reload(helpers) class TestHelpers: + def test_helpers_utc(self): + # Here we just test, that we got the correct UTC variant + if TEST_NO_PYTZ: + assert helpers.UTC is helpers.DTM_UTC + else: + assert helpers.UTC is not helpers.DTM_UTC + def test_escape_markdown(self): test_str = '*bold*, _italic_, `code`, [text_link](http://github.com/)' expected_str = r'\*bold\*, \_italic\_, \`code\`, \[text\_link](http://github.com/)' @@ -108,14 +122,14 @@ def test_markdown_invalid_version(self): with pytest.raises(ValueError): helpers.escape_markdown('abc', version=-1) - def test_to_float_timestamp_absolute_naive(self, pytz_install): + def test_to_float_timestamp_absolute_naive(self): """Conversion from timezone-naive datetime to timestamp. Naive datetimes should be assumed to be in UTC. """ datetime = dtm.datetime(2019, 11, 11, 0, 26, 16, 10 ** 5) assert helpers.to_float_timestamp(datetime) == 1573431976.1 - def test_to_float_timestamp_absolute_naive_no_pytz(self, monkeypatch, pytz_install): + def test_to_float_timestamp_absolute_naive_no_pytz(self, monkeypatch): """Conversion from timezone-naive datetime to timestamp. Naive datetimes should be assumed to be in UTC. """ @@ -146,7 +160,7 @@ def test_to_float_timestamp_delta(self, time_spec): delta = time_spec.total_seconds() if hasattr(time_spec, 'total_seconds') else time_spec assert helpers.to_float_timestamp(time_spec, reference_t) == reference_t + delta - def test_to_float_timestamp_time_of_day(self, pytz_install): + def test_to_float_timestamp_time_of_day(self): """Conversion from time-of-day specification to timestamp""" hour, hour_delta = 12, 1 ref_t = _datetime_to_float_timestamp(dtm.datetime(1970, 1, 1, hour=hour)) @@ -173,7 +187,7 @@ def test_to_float_timestamp_time_of_day_timezone(self, timezone): ) @pytest.mark.parametrize('time_spec', RELATIVE_TIME_SPECS, ids=str) - def test_to_float_timestamp_default_reference(self, time_spec, pytz_install): + def test_to_float_timestamp_default_reference(self, time_spec): """The reference timestamp for relative time specifications should default to now""" now = time.time() assert helpers.to_float_timestamp(time_spec) == pytest.approx( @@ -185,7 +199,7 @@ def test_to_float_timestamp_error(self): helpers.to_float_timestamp(Defaults()) @pytest.mark.parametrize('time_spec', TIME_SPECS, ids=str) - def test_to_timestamp(self, time_spec, pytz_install): + def test_to_timestamp(self, time_spec): # delegate tests to `to_float_timestamp` assert helpers.to_timestamp(time_spec) == int(helpers.to_float_timestamp(time_spec)) @@ -196,7 +210,7 @@ def test_to_timestamp_none(self): def test_from_timestamp_none(self): assert helpers.from_timestamp(None) is None - def test_from_timestamp_naive(self, pytz_install): + def test_from_timestamp_naive(self): datetime = dtm.datetime(2019, 11, 11, 0, 26, 16, tzinfo=None) assert helpers.from_timestamp(1573431976, tzinfo=None) == datetime diff --git a/tests/test_inlinequery.py b/tests/test_inlinequery.py index 5f6bb9a9b87..ab2fb6281e6 100644 --- a/tests/test_inlinequery.py +++ b/tests/test_inlinequery.py @@ -20,7 +20,7 @@ import pytest from telegram import User, Location, InlineQuery, Update, Bot -from tests.conftest import check_shortcut_signature, check_shortcut_call +from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling @pytest.fixture(scope='class') @@ -69,16 +69,14 @@ def test_to_dict(self, inline_query): assert inline_query_dict['offset'] == inline_query.offset def test_answer(self, monkeypatch, inline_query): - answer_inline_query = inline_query.bot.answer_inline_query - def make_assertion(*_, **kwargs): - return kwargs['inline_query_id'] == inline_query.id and check_shortcut_call( - kwargs, answer_inline_query - ) + return kwargs['inline_query_id'] == inline_query.id assert check_shortcut_signature( InlineQuery.answer, Bot.answer_inline_query, ['inline_query_id'], ['auto_pagination'] ) + assert check_shortcut_call(inline_query.answer, inline_query.bot, 'answer_inline_query') + assert check_defaults_handling(inline_query.answer, inline_query.bot) monkeypatch.setattr(inline_query.bot, 'answer_inline_query', make_assertion) assert inline_query.answer(results=[]) diff --git a/tests/test_inputmedia.py b/tests/test_inputmedia.py index ef2e1cd426b..62152007439 100644 --- a/tests/test_inputmedia.py +++ b/tests/test_inputmedia.py @@ -30,6 +30,7 @@ InputMediaAudio, InputMediaDocument, MessageEntity, + ParseMode, ) # noinspection PyUnresolvedReferences @@ -551,3 +552,80 @@ def test_edit_message_media_new_file(self, bot, chat_id, media_group, thumb_file chat_id=cid, message_id=mid, media=InputMediaPhoto(thumb_file) ) assert isinstance(new_message, Message) + + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize( + 'default_bot', [{'parse_mode': ParseMode.HTML}], indirect=True, ids=['HTML-Bot'] + ) + @pytest.mark.parametrize('media_type', ['animation', 'document', 'audio', 'photo', 'video']) + def test_edit_message_media_default_parse_mode( + self, + chat_id, + default_bot, + media_type, + animation, # noqa: F811 + document, # noqa: F811 + audio, # noqa: F811 + photo, # noqa: F811 + video, # noqa: F811 + ): + html_caption = 'bold italic code' + markdown_caption = '*bold* _italic_ `code`' + test_caption = 'bold italic code' + test_entities = [ + MessageEntity(MessageEntity.BOLD, 0, 4), + MessageEntity(MessageEntity.ITALIC, 5, 6), + MessageEntity(MessageEntity.CODE, 12, 4), + ] + + def build_media(parse_mode, med_type): + kwargs = {} + if parse_mode != ParseMode.HTML: + kwargs['parse_mode'] = parse_mode + kwargs['caption'] = markdown_caption + else: + kwargs['caption'] = html_caption + + if med_type == 'animation': + return InputMediaAnimation(animation, **kwargs) + if med_type == 'document': + return InputMediaDocument(document, **kwargs) + if med_type == 'audio': + return InputMediaAudio(audio, **kwargs) + if med_type == 'photo': + return InputMediaPhoto(photo, **kwargs) + if med_type == 'video': + return InputMediaVideo(video, **kwargs) + + message = default_bot.send_photo(chat_id, photo) + + message = default_bot.edit_message_media( + message.chat_id, + message.message_id, + media=build_media(parse_mode=ParseMode.HTML, med_type=media_type), + ) + assert message.caption == test_caption + assert message.caption_entities == test_entities + + # Remove caption to avoid "Message not changed" + message.edit_caption() + + message = default_bot.edit_message_media( + message.chat_id, + message.message_id, + media=build_media(parse_mode=ParseMode.MARKDOWN_V2, med_type=media_type), + ) + assert message.caption == test_caption + assert message.caption_entities == test_entities + + # Remove caption to avoid "Message not changed" + message.edit_caption() + + message = default_bot.edit_message_media( + message.chat_id, + message.message_id, + media=build_media(parse_mode=None, med_type=media_type), + ) + assert message.caption == markdown_caption + assert message.caption_entities == [] diff --git a/tests/test_message.py b/tests/test_message.py index 542a80e4348..2959f81d678 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -50,7 +50,7 @@ ChatAction, ) from telegram.ext import Defaults -from tests.conftest import check_shortcut_signature, check_shortcut_call +from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling from tests.test_passport import RAW_PASSPORT_DATA @@ -638,8 +638,6 @@ def test_effective_attachment(self, message_params): assert message_params.effective_attachment == item def test_reply_text(self, monkeypatch, message): - send_message = message.bot.send_message - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id text = kwargs['text'] == 'test' @@ -647,11 +645,13 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and text and reply and check_shortcut_call(kwargs, send_message) + return id_ and text and reply assert check_shortcut_signature( Message.reply_text, Bot.send_message, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_text, message.bot, 'send_message') + assert check_defaults_handling(message.reply_text, message.bot) monkeypatch.setattr(message.bot, 'send_message', make_assertion) assert message.reply_text('test') @@ -659,7 +659,6 @@ def make_assertion(*_, **kwargs): assert message.reply_text('test', reply_to_message_id=message.message_id, quote=True) def test_reply_markdown(self, monkeypatch, message): - send_message = message.bot.send_message test_md_string = ( r'Test for <*bold*, _ita_\__lic_, `code`, ' '[links](http://github.com/ab_), ' @@ -675,13 +674,13 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return all([cid, markdown_text, reply, markdown_enabled]) and check_shortcut_call( - kwargs, send_message - ) + return all([cid, markdown_text, reply, markdown_enabled]) assert check_shortcut_signature( Message.reply_markdown, Bot.send_message, ['chat_id', 'parse_mode'], ['quote'] ) + assert check_shortcut_call(message.reply_text, message.bot, 'send_message') + assert check_defaults_handling(message.reply_text, message.bot) text_markdown = self.test_message.text_markdown assert text_markdown == test_md_string @@ -694,7 +693,6 @@ def make_assertion(*_, **kwargs): ) def test_reply_markdown_v2(self, monkeypatch, message): - send_message = message.bot.send_message test_md_string = ( r'__Test__ for <*bold*, _ita\_lic_, `\\\`code`, ' '[links](http://github.com/abc\\\\\\)def), ' @@ -711,13 +709,13 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return all([cid, markdown_text, reply, markdown_enabled]) and check_shortcut_call( - kwargs, send_message - ) + return all([cid, markdown_text, reply, markdown_enabled]) assert check_shortcut_signature( Message.reply_markdown_v2, Bot.send_message, ['chat_id', 'parse_mode'], ['quote'] ) + assert check_shortcut_call(message.reply_text, message.bot, 'send_message') + assert check_defaults_handling(message.reply_text, message.bot) text_markdown = self.test_message_v2.text_markdown_v2 assert text_markdown == test_md_string @@ -732,7 +730,6 @@ def make_assertion(*_, **kwargs): ) def test_reply_html(self, monkeypatch, message): - send_message = message.bot.send_message test_html_string = ( 'Test for <bold, ita_lic, ' r'\`code, ' @@ -751,13 +748,13 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return all([cid, html_text, reply, html_enabled]) and check_shortcut_call( - kwargs, send_message - ) + return all([cid, html_text, reply, html_enabled]) assert check_shortcut_signature( Message.reply_html, Bot.send_message, ['chat_id', 'parse_mode'], ['quote'] ) + assert check_shortcut_call(message.reply_text, message.bot, 'send_message') + assert check_defaults_handling(message.reply_text, message.bot) text_html = self.test_message_v2.text_html assert text_html == test_html_string @@ -770,8 +767,6 @@ def make_assertion(*_, **kwargs): ) def test_reply_media_group(self, monkeypatch, message): - send_media_group = message.bot.send_media_group - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id media = kwargs['media'] == 'reply_media_group' @@ -779,19 +774,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and media and reply and check_shortcut_call(kwargs, send_media_group) + return id_ and media and reply assert check_shortcut_signature( Message.reply_media_group, Bot.send_media_group, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_media_group, message.bot, 'send_media_group') + assert check_defaults_handling(message.reply_media_group, message.bot) monkeypatch.setattr(message.bot, 'send_media_group', make_assertion) assert message.reply_media_group(media='reply_media_group') assert message.reply_media_group(media='reply_media_group', quote=True) def test_reply_photo(self, monkeypatch, message): - send_photo = message.bot.send_photo - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id photo = kwargs['photo'] == 'test_photo' @@ -799,19 +794,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and photo and reply and check_shortcut_call(kwargs, send_photo) + return id_ and photo and reply assert check_shortcut_signature( Message.reply_photo, Bot.send_photo, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_photo, message.bot, 'send_photo') + assert check_defaults_handling(message.reply_photo, message.bot) monkeypatch.setattr(message.bot, 'send_photo', make_assertion) assert message.reply_photo(photo='test_photo') assert message.reply_photo(photo='test_photo', quote=True) def test_reply_audio(self, monkeypatch, message): - send_audio = message.bot.send_audio - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id audio = kwargs['audio'] == 'test_audio' @@ -819,19 +814,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and audio and reply and check_shortcut_call(kwargs, send_audio) + return id_ and audio and reply assert check_shortcut_signature( Message.reply_audio, Bot.send_audio, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_audio, message.bot, 'send_audio') + assert check_defaults_handling(message.reply_audio, message.bot) monkeypatch.setattr(message.bot, 'send_audio', make_assertion) assert message.reply_audio(audio='test_audio') assert message.reply_audio(audio='test_audio', quote=True) def test_reply_document(self, monkeypatch, message): - send_document = message.bot.send_document - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id document = kwargs['document'] == 'test_document' @@ -839,19 +834,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and document and reply and check_shortcut_call(kwargs, send_document) + return id_ and document and reply assert check_shortcut_signature( Message.reply_document, Bot.send_document, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_document, message.bot, 'send_document') + assert check_defaults_handling(message.reply_document, message.bot) monkeypatch.setattr(message.bot, 'send_document', make_assertion) assert message.reply_document(document='test_document') assert message.reply_document(document='test_document', quote=True) def test_reply_animation(self, monkeypatch, message): - send_animation = message.bot.send_animation - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id animation = kwargs['animation'] == 'test_animation' @@ -859,19 +854,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and animation and reply and check_shortcut_call(kwargs, send_animation) + return id_ and animation and reply assert check_shortcut_signature( Message.reply_animation, Bot.send_animation, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_animation, message.bot, 'send_animation') + assert check_defaults_handling(message.reply_animation, message.bot) monkeypatch.setattr(message.bot, 'send_animation', make_assertion) assert message.reply_animation(animation='test_animation') assert message.reply_animation(animation='test_animation', quote=True) def test_reply_sticker(self, monkeypatch, message): - send_sticker = message.bot.send_sticker - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id sticker = kwargs['sticker'] == 'test_sticker' @@ -879,19 +874,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and sticker and reply and check_shortcut_call(kwargs, send_sticker) + return id_ and sticker and reply assert check_shortcut_signature( Message.reply_sticker, Bot.send_sticker, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_sticker, message.bot, 'send_sticker') + assert check_defaults_handling(message.reply_sticker, message.bot) monkeypatch.setattr(message.bot, 'send_sticker', make_assertion) assert message.reply_sticker(sticker='test_sticker') assert message.reply_sticker(sticker='test_sticker', quote=True) def test_reply_video(self, monkeypatch, message): - send_video = message.bot.send_video - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id video = kwargs['video'] == 'test_video' @@ -899,19 +894,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and video and reply and check_shortcut_call(kwargs, send_video) + return id_ and video and reply assert check_shortcut_signature( Message.reply_video, Bot.send_video, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_video, message.bot, 'send_video') + assert check_defaults_handling(message.reply_video, message.bot) monkeypatch.setattr(message.bot, 'send_video', make_assertion) assert message.reply_video(video='test_video') assert message.reply_video(video='test_video', quote=True) def test_reply_video_note(self, monkeypatch, message): - send_video_note = message.bot.send_video_note - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id video_note = kwargs['video_note'] == 'test_video_note' @@ -919,19 +914,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and video_note and reply and check_shortcut_call(kwargs, send_video_note) + return id_ and video_note and reply assert check_shortcut_signature( Message.reply_video_note, Bot.send_video_note, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_video_note, message.bot, 'send_video_note') + assert check_defaults_handling(message.reply_video_note, message.bot) monkeypatch.setattr(message.bot, 'send_video_note', make_assertion) assert message.reply_video_note(video_note='test_video_note') assert message.reply_video_note(video_note='test_video_note', quote=True) def test_reply_voice(self, monkeypatch, message): - send_voice = message.bot.send_voice - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id voice = kwargs['voice'] == 'test_voice' @@ -939,19 +934,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and voice and reply and check_shortcut_call(kwargs, send_voice) + return id_ and voice and reply assert check_shortcut_signature( Message.reply_voice, Bot.send_voice, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_voice, message.bot, 'send_voice') + assert check_defaults_handling(message.reply_voice, message.bot) monkeypatch.setattr(message.bot, 'send_voice', make_assertion) assert message.reply_voice(voice='test_voice') assert message.reply_voice(voice='test_voice', quote=True) def test_reply_location(self, monkeypatch, message): - send_location = message.bot.send_location - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id location = kwargs['location'] == 'test_location' @@ -959,19 +954,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and location and reply and check_shortcut_call(kwargs, send_location) + return id_ and location and reply assert check_shortcut_signature( Message.reply_location, Bot.send_location, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_location, message.bot, 'send_location') + assert check_defaults_handling(message.reply_location, message.bot) monkeypatch.setattr(message.bot, 'send_location', make_assertion) assert message.reply_location(location='test_location') assert message.reply_location(location='test_location', quote=True) def test_reply_venue(self, monkeypatch, message): - send_venue = message.bot.send_venue - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id venue = kwargs['venue'] == 'test_venue' @@ -979,19 +974,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and venue and reply and check_shortcut_call(kwargs, send_venue) + return id_ and venue and reply assert check_shortcut_signature( Message.reply_venue, Bot.send_venue, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_venue, message.bot, 'send_venue') + assert check_defaults_handling(message.reply_venue, message.bot) monkeypatch.setattr(message.bot, 'send_venue', make_assertion) assert message.reply_venue(venue='test_venue') assert message.reply_venue(venue='test_venue', quote=True) def test_reply_contact(self, monkeypatch, message): - send_contact = message.bot.send_contact - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id contact = kwargs['contact'] == 'test_contact' @@ -999,19 +994,19 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and contact and reply and check_shortcut_call(kwargs, send_contact) + return id_ and contact and reply assert check_shortcut_signature( Message.reply_contact, Bot.send_contact, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_contact, message.bot, 'send_contact') + assert check_defaults_handling(message.reply_contact, message.bot) monkeypatch.setattr(message.bot, 'send_contact', make_assertion) assert message.reply_contact(contact='test_contact') assert message.reply_contact(contact='test_contact', quote=True) def test_reply_poll(self, monkeypatch, message): - send_poll = message.bot.send_poll - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id question = kwargs['question'] == 'test_poll' @@ -1020,19 +1015,17 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return ( - id_ and question and options and reply and check_shortcut_call(kwargs, send_poll) - ) + return id_ and question and options and reply assert check_shortcut_signature(Message.reply_poll, Bot.send_poll, ['chat_id'], ['quote']) + assert check_shortcut_call(message.reply_poll, message.bot, 'send_poll') + assert check_defaults_handling(message.reply_poll, message.bot) monkeypatch.setattr(message.bot, 'send_poll', make_assertion) assert message.reply_poll(question='test_poll', options=['1', '2', '3']) assert message.reply_poll(question='test_poll', quote=True, options=['1', '2', '3']) def test_reply_dice(self, monkeypatch, message): - send_dice = message.bot.send_dice - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id contact = kwargs['disable_notification'] is True @@ -1040,48 +1033,46 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and contact and reply and check_shortcut_call(kwargs, send_dice) + return id_ and contact and reply assert check_shortcut_signature(Message.reply_dice, Bot.send_dice, ['chat_id'], ['quote']) + assert check_shortcut_call(message.reply_dice, message.bot, 'send_dice') + assert check_defaults_handling(message.reply_dice, message.bot) monkeypatch.setattr(message.bot, 'send_dice', make_assertion) assert message.reply_dice(disable_notification=True) assert message.reply_dice(disable_notification=True, quote=True) def test_reply_action(self, monkeypatch, message: Message): - send_chat_action = message.bot.send_chat_action - def make_assertion(*_, **kwargs): id_ = kwargs['chat_id'] == message.chat_id action = kwargs['action'] == ChatAction.TYPING - return id_ and action and check_shortcut_call(kwargs, send_chat_action) + return id_ and action assert check_shortcut_signature( Message.reply_chat_action, Bot.send_chat_action, ['chat_id'], [] ) + assert check_shortcut_call(message.reply_chat_action, message.bot, 'send_chat_action') + assert check_defaults_handling(message.reply_chat_action, message.bot) monkeypatch.setattr(message.bot, 'send_chat_action', make_assertion) assert message.reply_chat_action(action=ChatAction.TYPING) def test_reply_game(self, monkeypatch, message: Message): - send_game = message.bot.send_game - def make_assertion(*_, **kwargs): return ( - kwargs['chat_id'] == message.chat_id - and kwargs['game_short_name'] == 'test_game' - and check_shortcut_call(kwargs, send_game) + kwargs['chat_id'] == message.chat_id and kwargs['game_short_name'] == 'test_game' ) assert check_shortcut_signature(Message.reply_game, Bot.send_game, ['chat_id'], ['quote']) + assert check_shortcut_call(message.reply_game, message.bot, 'send_game') + assert check_defaults_handling(message.reply_game, message.bot) monkeypatch.setattr(message.bot, 'send_game', make_assertion) assert message.reply_game(game_short_name='test_game') assert message.reply_game(game_short_name='test_game', quote=True) def test_reply_invoice(self, monkeypatch, message: Message): - send_invoice = message.bot.send_invoice - def make_assertion(*_, **kwargs): title = kwargs['title'] == 'title' description = kwargs['description'] == 'description' @@ -1099,15 +1090,13 @@ def make_assertion(*_, **kwargs): and currency and prices ) - return ( - kwargs['chat_id'] == message.chat_id - and args - and check_shortcut_call(kwargs, send_invoice) - ) + return kwargs['chat_id'] == message.chat_id and args assert check_shortcut_signature( Message.reply_invoice, Bot.send_invoice, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.reply_invoice, message.bot, 'send_invoice') + assert check_defaults_handling(message.reply_invoice, message.bot) monkeypatch.setattr(message.bot, 'send_invoice', make_assertion) assert message.reply_invoice( @@ -1132,24 +1121,18 @@ def make_assertion(*_, **kwargs): @pytest.mark.parametrize('disable_notification', [False, True]) def test_forward(self, monkeypatch, message, disable_notification): - forward_message = message.bot.forward_message - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == 123456 from_chat = kwargs['from_chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id notification = kwargs['disable_notification'] == disable_notification - return ( - chat_id - and from_chat - and message_id - and notification - and check_shortcut_call(kwargs, forward_message) - ) + return chat_id and from_chat and message_id and notification assert check_shortcut_signature( Message.forward, Bot.forward_message, ['from_chat_id', 'message_id'], [] ) + assert check_shortcut_call(message.forward, message.bot, 'forward_message') + assert check_defaults_handling(message.forward, message.bot) monkeypatch.setattr(message.bot, 'forward_message', make_assertion) assert message.forward(123456, disable_notification=disable_notification) @@ -1158,7 +1141,6 @@ def make_assertion(*_, **kwargs): @pytest.mark.parametrize('disable_notification', [True, False]) def test_copy(self, monkeypatch, message, disable_notification): keyboard = [[1, 2]] - copy_message = message.bot.copy_message def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == 123456 @@ -1169,18 +1151,13 @@ def make_assertion(*_, **kwargs): reply_markup = kwargs['reply_markup'] is keyboard else: reply_markup = True - return ( - chat_id - and from_chat - and message_id - and notification - and reply_markup - and check_shortcut_call(kwargs, copy_message) - ) + return chat_id and from_chat and message_id and notification and reply_markup assert check_shortcut_signature( Message.copy, Bot.copy_message, ['from_chat_id', 'message_id'], [] ) + assert check_shortcut_call(message.copy, message.bot, 'copy_message') + assert check_defaults_handling(message.copy, message.bot) monkeypatch.setattr(message.bot, 'copy_message', make_assertion) assert message.copy(123456, disable_notification=disable_notification) @@ -1192,7 +1169,6 @@ def make_assertion(*_, **kwargs): @pytest.mark.parametrize('disable_notification', [True, False]) def test_reply_copy(self, monkeypatch, message, disable_notification): keyboard = [[1, 2]] - copy_message = message.bot.copy_message def make_assertion(*_, **kwargs): chat_id = kwargs['from_chat_id'] == 123456 @@ -1207,19 +1183,13 @@ def make_assertion(*_, **kwargs): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return ( - chat_id - and from_chat - and message_id - and notification - and reply_markup - and reply - and check_shortcut_call(kwargs, copy_message) - ) + return chat_id and from_chat and message_id and notification and reply_markup and reply assert check_shortcut_signature( Message.reply_copy, Bot.copy_message, ['chat_id'], ['quote'] ) + assert check_shortcut_call(message.copy, message.bot, 'copy_message') + assert check_defaults_handling(message.copy, message.bot) monkeypatch.setattr(message.bot, 'copy_message', make_assertion) assert message.reply_copy(123456, 456789, disable_notification=disable_notification) @@ -1238,15 +1208,11 @@ def make_assertion(*_, **kwargs): ) def test_edit_text(self, monkeypatch, message): - edit_message_text = message.bot.edit_message_text - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id text = kwargs['text'] == 'test' - return ( - chat_id and message_id and text and check_shortcut_call(kwargs, edit_message_text) - ) + return chat_id and message_id and text assert check_shortcut_signature( Message.edit_text, @@ -1254,23 +1220,24 @@ def make_assertion(*_, **kwargs): ['chat_id', 'message_id', 'inline_message_id'], [], ) + assert check_shortcut_call( + message.edit_text, + message.bot, + 'edit_message_text', + skip_params=['inline_message_id'], + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(message.edit_text, message.bot) monkeypatch.setattr(message.bot, 'edit_message_text', make_assertion) assert message.edit_text(text='test') def test_edit_caption(self, monkeypatch, message): - edit_message_caption = message.bot.edit_message_caption - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id caption = kwargs['caption'] == 'new caption' - return ( - chat_id - and message_id - and caption - and check_shortcut_call(kwargs, edit_message_caption) - ) + return chat_id and message_id and caption assert check_shortcut_signature( Message.edit_caption, @@ -1278,23 +1245,24 @@ def make_assertion(*_, **kwargs): ['chat_id', 'message_id', 'inline_message_id'], [], ) + assert check_shortcut_call( + message.edit_caption, + message.bot, + 'edit_message_caption', + skip_params=['inline_message_id'], + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(message.edit_caption, message.bot) monkeypatch.setattr(message.bot, 'edit_message_caption', make_assertion) assert message.edit_caption(caption='new caption') def test_edit_media(self, monkeypatch, message): - edit_message_media = message.bot.edit_message_media - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id media = kwargs['media'] == 'my_media' - return ( - chat_id - and message_id - and media - and check_shortcut_call(kwargs, edit_message_media) - ) + return chat_id and message_id and media assert check_shortcut_signature( Message.edit_media, @@ -1302,23 +1270,24 @@ def make_assertion(*_, **kwargs): ['chat_id', 'message_id', 'inline_message_id'], [], ) + assert check_shortcut_call( + message.edit_media, + message.bot, + 'edit_message_media', + skip_params=['inline_message_id'], + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(message.edit_media, message.bot) monkeypatch.setattr(message.bot, 'edit_message_media', make_assertion) assert message.edit_media('my_media') def test_edit_reply_markup(self, monkeypatch, message): - edit_message_reply_markup = message.bot.edit_message_reply_markup - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id reply_markup = kwargs['reply_markup'] == [['1', '2']] - return ( - chat_id - and message_id - and reply_markup - and check_shortcut_call(kwargs, edit_message_reply_markup) - ) + return chat_id and message_id and reply_markup assert check_shortcut_signature( Message.edit_reply_markup, @@ -1326,25 +1295,25 @@ def make_assertion(*_, **kwargs): ['chat_id', 'message_id', 'inline_message_id'], [], ) + assert check_shortcut_call( + message.edit_reply_markup, + message.bot, + 'edit_message_reply_markup', + skip_params=['inline_message_id'], + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(message.edit_reply_markup, message.bot) monkeypatch.setattr(message.bot, 'edit_message_reply_markup', make_assertion) assert message.edit_reply_markup(reply_markup=[['1', '2']]) def test_edit_live_location(self, monkeypatch, message): - edit_message_live_location = message.bot.edit_message_live_location - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id latitude = kwargs['latitude'] == 1 longitude = kwargs['longitude'] == 2 - return ( - chat_id - and message_id - and longitude - and latitude - and check_shortcut_call(kwargs, edit_message_live_location) - ) + return chat_id and message_id and longitude and latitude assert check_shortcut_signature( Message.edit_live_location, @@ -1352,19 +1321,23 @@ def make_assertion(*_, **kwargs): ['chat_id', 'message_id', 'inline_message_id'], [], ) + assert check_shortcut_call( + message.edit_live_location, + message.bot, + 'edit_message_live_location', + skip_params=['inline_message_id'], + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(message.edit_live_location, message.bot) monkeypatch.setattr(message.bot, 'edit_message_live_location', make_assertion) assert message.edit_live_location(latitude=1, longitude=2) def test_stop_live_location(self, monkeypatch, message): - stop_message_live_location = message.bot.stop_message_live_location - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return ( - chat_id and message_id and check_shortcut_call(kwargs, stop_message_live_location) - ) + return chat_id and message_id assert check_shortcut_signature( Message.stop_live_location, @@ -1372,25 +1345,25 @@ def make_assertion(*_, **kwargs): ['chat_id', 'message_id', 'inline_message_id'], [], ) + assert check_shortcut_call( + message.stop_live_location, + message.bot, + 'stop_message_live_location', + skip_params=['inline_message_id'], + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(message.stop_live_location, message.bot) monkeypatch.setattr(message.bot, 'stop_message_live_location', make_assertion) assert message.stop_live_location() def test_set_game_score(self, monkeypatch, message): - set_game_score = message.bot.set_game_score - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id user_id = kwargs['user_id'] == 1 score = kwargs['score'] == 2 - return ( - chat_id - and message_id - and user_id - and score - and check_shortcut_call(kwargs, set_game_score) - ) + return chat_id and message_id and user_id and score assert check_shortcut_signature( Message.set_game_score, @@ -1398,23 +1371,24 @@ def make_assertion(*_, **kwargs): ['chat_id', 'message_id', 'inline_message_id'], [], ) + assert check_shortcut_call( + message.set_game_score, + message.bot, + 'set_game_score', + skip_params=['inline_message_id'], + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(message.set_game_score, message.bot) monkeypatch.setattr(message.bot, 'set_game_score', make_assertion) assert message.set_game_score(user_id=1, score=2) def test_get_game_high_scores(self, monkeypatch, message): - get_game_high_scores = message.bot.get_game_high_scores - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id user_id = kwargs['user_id'] == 1 - return ( - chat_id - and message_id - and user_id - and check_shortcut_call(kwargs, get_game_high_scores) - ) + return chat_id and message_id and user_id assert check_shortcut_signature( Message.get_game_high_scores, @@ -1422,66 +1396,79 @@ def make_assertion(*_, **kwargs): ['chat_id', 'message_id', 'inline_message_id'], [], ) + assert check_shortcut_call( + message.get_game_high_scores, + message.bot, + 'get_game_high_scores', + skip_params=['inline_message_id'], + shortcut_kwargs=['message_id', 'chat_id'], + ) + assert check_defaults_handling(message.get_game_high_scores, message.bot) monkeypatch.setattr(message.bot, 'get_game_high_scores', make_assertion) assert message.get_game_high_scores(user_id=1) def test_delete(self, monkeypatch, message): - delete_message = message.bot.delete_message - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id and check_shortcut_call(kwargs, delete_message) + return chat_id and message_id assert check_shortcut_signature( Message.delete, Bot.delete_message, ['chat_id', 'message_id'], [] ) + assert check_shortcut_call(message.delete, message.bot, 'delete_message') + assert check_defaults_handling(message.delete, message.bot) monkeypatch.setattr(message.bot, 'delete_message', make_assertion) assert message.delete() def test_stop_poll(self, monkeypatch, message): - stop_poll = message.bot.stop_poll - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id and check_shortcut_call(kwargs, stop_poll) + return chat_id and message_id assert check_shortcut_signature( Message.stop_poll, Bot.stop_poll, ['chat_id', 'message_id'], [] ) + assert check_shortcut_call(message.stop_poll, message.bot, 'stop_poll') + assert check_defaults_handling(message.stop_poll, message.bot) monkeypatch.setattr(message.bot, 'stop_poll', make_assertion) assert message.stop_poll() def test_pin(self, monkeypatch, message): - pin_chat_message = message.bot.pin_chat_message - def make_assertion(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id and check_shortcut_call(kwargs, pin_chat_message) + return chat_id and message_id assert check_shortcut_signature( Message.pin, Bot.pin_chat_message, ['chat_id', 'message_id'], [] ) + assert check_shortcut_call(message.pin, message.bot, 'pin_chat_message') + assert check_defaults_handling(message.pin, message.bot) monkeypatch.setattr(message.bot, 'pin_chat_message', make_assertion) assert message.pin() def test_unpin(self, monkeypatch, message): - unpin_chat_message = message.bot.unpin_chat_message - def make_assertion(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id and check_shortcut_call(kwargs, unpin_chat_message) + return chat_id and message_id assert check_shortcut_signature( Message.unpin, Bot.unpin_chat_message, ['chat_id', 'message_id'], [] ) + assert check_shortcut_call( + message.unpin, + message.bot, + 'unpin_chat_message', + shortcut_kwargs=['chat_id', 'message_id'], + ) + assert check_defaults_handling(message.unpin, message.bot) monkeypatch.setattr(message.bot, 'unpin_chat_message', make_assertion) assert message.unpin() diff --git a/tests/test_passportfile.py b/tests/test_passportfile.py index ac9af58d7f5..0a4af5d6c9e 100644 --- a/tests/test_passportfile.py +++ b/tests/test_passportfile.py @@ -20,7 +20,7 @@ import pytest from telegram import PassportFile, PassportElementError, Bot, File -from tests.conftest import check_shortcut_signature, check_shortcut_call +from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling @pytest.fixture(scope='class') @@ -56,16 +56,14 @@ def test_to_dict(self, passport_file): assert passport_file_dict['file_date'] == passport_file.file_date def test_get_file_instance_method(self, monkeypatch, passport_file): - get_file = passport_file.bot.get_file - def make_assertion(*_, **kwargs): - result = kwargs['file_id'] == passport_file.file_id and check_shortcut_call( - kwargs, get_file - ) + result = kwargs['file_id'] == passport_file.file_id # we need to be a bit hacky here, b/c PF.get_file needs Bot.get_file to return a File return File(file_id=result, file_unique_id=result) assert check_shortcut_signature(PassportFile.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(passport_file.get_file, passport_file.bot, 'get_file') + assert check_defaults_handling(passport_file.get_file, passport_file.bot) monkeypatch.setattr(passport_file.bot, 'get_file', make_assertion) assert passport_file.get_file().file_id == 'True' diff --git a/tests/test_photo.py b/tests/test_photo.py index 9969dc5f1cb..f00c226fcfb 100644 --- a/tests/test_photo.py +++ b/tests/test_photo.py @@ -25,7 +25,12 @@ from telegram import Sticker, TelegramError, PhotoSize, InputFile, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown -from tests.conftest import expect_bad_request, check_shortcut_call, check_shortcut_signature +from tests.conftest import ( + expect_bad_request, + check_shortcut_call, + check_shortcut_signature, + check_defaults_handling, +) @pytest.fixture(scope='function') @@ -465,14 +470,14 @@ def test_error_without_required_args(self, bot, chat_id): bot.send_photo(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, photo): - get_file = photo.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == photo.file_id and check_shortcut_call(kwargs, get_file) + return kwargs['file_id'] == photo.file_id assert check_shortcut_signature(PhotoSize.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(photo.get_file, photo.bot, 'get_file') + assert check_defaults_handling(photo.get_file, photo.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(photo.bot, 'get_file', make_assertion) assert photo.get_file() def test_equality(self, photo): diff --git a/tests/test_precheckoutquery.py b/tests/test_precheckoutquery.py index d594a2f5a04..6f70fb9ff23 100644 --- a/tests/test_precheckoutquery.py +++ b/tests/test_precheckoutquery.py @@ -20,7 +20,7 @@ import pytest from telegram import Update, User, PreCheckoutQuery, OrderInfo, Bot -from tests.conftest import check_shortcut_call, check_shortcut_signature +from tests.conftest import check_shortcut_call, check_shortcut_signature, check_defaults_handling @pytest.fixture(scope='class') @@ -80,16 +80,18 @@ def test_to_dict(self, pre_checkout_query): assert pre_checkout_query_dict['order_info'] == pre_checkout_query.order_info.to_dict() def test_answer(self, monkeypatch, pre_checkout_query): - answer_pre_checkout_query = pre_checkout_query.bot.answer_pre_checkout_query - def make_assertion(*_, **kwargs): - return kwargs[ - 'pre_checkout_query_id' - ] == pre_checkout_query.id and check_shortcut_call(kwargs, answer_pre_checkout_query) + return kwargs['pre_checkout_query_id'] == pre_checkout_query.id assert check_shortcut_signature( PreCheckoutQuery.answer, Bot.answer_pre_checkout_query, ['pre_checkout_query_id'], [] ) + assert check_shortcut_call( + pre_checkout_query.answer, + pre_checkout_query.bot, + 'answer_pre_checkout_query', + ) + assert check_defaults_handling(pre_checkout_query.answer, pre_checkout_query.bot) monkeypatch.setattr(pre_checkout_query.bot, 'answer_pre_checkout_query', make_assertion) assert pre_checkout_query.answer(ok=True) diff --git a/tests/test_shippingquery.py b/tests/test_shippingquery.py index 49b75523013..98cf0e01b97 100644 --- a/tests/test_shippingquery.py +++ b/tests/test_shippingquery.py @@ -20,7 +20,7 @@ import pytest from telegram import Update, User, ShippingAddress, ShippingQuery, Bot -from tests.conftest import check_shortcut_call, check_shortcut_signature +from tests.conftest import check_shortcut_call, check_shortcut_signature, check_defaults_handling @pytest.fixture(scope='class') @@ -65,16 +65,16 @@ def test_to_dict(self, shipping_query): assert shipping_query_dict['shipping_address'] == shipping_query.shipping_address.to_dict() def test_answer(self, monkeypatch, shipping_query): - answer_shipping_query = shipping_query.bot.answer_shipping_query - def make_assertion(*_, **kwargs): - return kwargs['shipping_query_id'] == shipping_query.id and check_shortcut_call( - kwargs, answer_shipping_query - ) + return kwargs['shipping_query_id'] == shipping_query.id assert check_shortcut_signature( ShippingQuery.answer, Bot.answer_shipping_query, ['shipping_query_id'], [] ) + assert check_shortcut_call( + shipping_query.answer, shipping_query.bot, 'answer_shipping_query' + ) + assert check_defaults_handling(shipping_query.answer, shipping_query.bot) monkeypatch.setattr(shipping_query.bot, 'answer_shipping_query', make_assertion) assert shipping_query.answer(ok=True) diff --git a/tests/test_sticker.py b/tests/test_sticker.py index 3d8e3abac63..80dad9af63b 100644 --- a/tests/test_sticker.py +++ b/tests/test_sticker.py @@ -25,7 +25,7 @@ from telegram import Sticker, PhotoSize, TelegramError, StickerSet, Audio, MaskPosition, Bot from telegram.error import BadRequest -from tests.conftest import check_shortcut_call, check_shortcut_signature +from tests.conftest import check_shortcut_call, check_shortcut_signature, check_defaults_handling @pytest.fixture(scope='function') @@ -505,14 +505,14 @@ def make_assertion(_, data, *args, **kwargs): assert test_flag def test_get_file_instance_method(self, monkeypatch, sticker): - get_file = sticker.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == sticker.file_id and check_shortcut_call(kwargs, get_file) + return kwargs['file_id'] == sticker.file_id assert check_shortcut_signature(Sticker.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(sticker.get_file, sticker.bot, 'get_file') + assert check_defaults_handling(sticker.get_file, sticker.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(sticker.bot, 'get_file', make_assertion) assert sticker.get_file() def test_equality(self): diff --git a/tests/test_user.py b/tests/test_user.py index ce18d2c01ca..30b32c85ef7 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -20,7 +20,7 @@ from telegram import Update, User, Bot from telegram.utils.helpers import escape_markdown -from tests.conftest import check_shortcut_signature, check_shortcut_call +from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling @pytest.fixture(scope='function') @@ -129,197 +129,159 @@ def test_link(self, user): assert user.link is None def test_instance_method_get_profile_photos(self, monkeypatch, user): - get_profile_photos = user.bot.get_user_profile_photos - def make_assertion(*_, **kwargs): - return kwargs['user_id'] == user.id and check_shortcut_call(kwargs, get_profile_photos) + return kwargs['user_id'] == user.id assert check_shortcut_signature( User.get_profile_photos, Bot.get_user_profile_photos, ['user_id'], [] ) + assert check_shortcut_call(user.get_profile_photos, user.bot, 'get_user_profile_photos') + assert check_defaults_handling(user.get_profile_photos, user.bot) monkeypatch.setattr(user.bot, 'get_user_profile_photos', make_assertion) assert user.get_profile_photos() def test_instance_method_pin_message(self, monkeypatch, user): - pin_message = user.bot.pin_chat_message - def make_assertion(*_, **kwargs): - return kwargs['chat_id'] == user.id and check_shortcut_call(kwargs, pin_message) + return kwargs['chat_id'] == user.id assert check_shortcut_signature(User.pin_message, Bot.pin_chat_message, ['chat_id'], []) + assert check_shortcut_call(user.pin_message, user.bot, 'pin_chat_message') + assert check_defaults_handling(user.pin_message, user.bot) monkeypatch.setattr(user.bot, 'pin_chat_message', make_assertion) assert user.pin_message(1) def test_instance_method_unpin_message(self, monkeypatch, user): - unpin_message = user.bot.unpin_chat_message - def make_assertion(*_, **kwargs): - return kwargs['chat_id'] == user.id and check_shortcut_call(kwargs, unpin_message) + return kwargs['chat_id'] == user.id assert check_shortcut_signature( User.unpin_message, Bot.unpin_chat_message, ['chat_id'], [] ) + assert check_shortcut_call(user.unpin_message, user.bot, 'unpin_chat_message') + assert check_defaults_handling(user.unpin_message, user.bot) monkeypatch.setattr(user.bot, 'unpin_chat_message', make_assertion) assert user.unpin_message() def test_instance_method_unpin_all_messages(self, monkeypatch, user): - unpin_all_messages = user.bot.unpin_all_chat_messages - def make_assertion(*_, **kwargs): - return kwargs['chat_id'] == user.id and check_shortcut_call(kwargs, unpin_all_messages) + return kwargs['chat_id'] == user.id assert check_shortcut_signature( User.unpin_all_messages, Bot.unpin_all_chat_messages, ['chat_id'], [] ) + assert check_shortcut_call(user.unpin_all_messages, user.bot, 'unpin_all_chat_messages') + assert check_defaults_handling(user.unpin_all_messages, user.bot) monkeypatch.setattr(user.bot, 'unpin_all_chat_messages', make_assertion) assert user.unpin_all_messages() def test_instance_method_send_message(self, monkeypatch, user): - send_message = user.bot.send_message - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['text'] == 'test' - and check_shortcut_call(kwargs, send_message) - ) + return kwargs['chat_id'] == user.id and kwargs['text'] == 'test' assert check_shortcut_signature(User.send_message, Bot.send_message, ['chat_id'], []) + assert check_shortcut_call(user.send_message, user.bot, 'send_message') + assert check_defaults_handling(user.send_message, user.bot) monkeypatch.setattr(user.bot, 'send_message', make_assertion) assert user.send_message('test') def test_instance_method_send_photo(self, monkeypatch, user): - send_photo = user.bot.send_photo - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['photo'] == 'test_photo' - and check_shortcut_call(kwargs, send_photo) - ) + return kwargs['chat_id'] == user.id and kwargs['photo'] == 'test_photo' assert check_shortcut_signature(User.send_photo, Bot.send_photo, ['chat_id'], []) + assert check_shortcut_call(user.send_photo, user.bot, 'send_photo') + assert check_defaults_handling(user.send_photo, user.bot) monkeypatch.setattr(user.bot, 'send_photo', make_assertion) assert user.send_photo('test_photo') def test_instance_method_send_media_group(self, monkeypatch, user): - send_media_group = user.bot.send_media_group - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['media'] == 'test_media_group' - and check_shortcut_call(kwargs, send_media_group) - ) + return kwargs['chat_id'] == user.id and kwargs['media'] == 'test_media_group' assert check_shortcut_signature( User.send_media_group, Bot.send_media_group, ['chat_id'], [] ) + assert check_shortcut_call(user.send_media_group, user.bot, 'send_media_group') + assert check_defaults_handling(user.send_media_group, user.bot) monkeypatch.setattr(user.bot, 'send_media_group', make_assertion) assert user.send_media_group('test_media_group') def test_instance_method_send_audio(self, monkeypatch, user): - send_audio = user.bot.send_audio - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['audio'] == 'test_audio' - and check_shortcut_call(kwargs, send_audio) - ) + return kwargs['chat_id'] == user.id and kwargs['audio'] == 'test_audio' assert check_shortcut_signature(User.send_audio, Bot.send_audio, ['chat_id'], []) + assert check_shortcut_call(user.send_audio, user.bot, 'send_audio') + assert check_defaults_handling(user.send_audio, user.bot) monkeypatch.setattr(user.bot, 'send_audio', make_assertion) assert user.send_audio('test_audio') def test_instance_method_send_chat_action(self, monkeypatch, user): - send_chat_action = user.bot.send_chat_action - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['action'] == 'test_chat_action' - and check_shortcut_call(kwargs, send_chat_action) - ) + return kwargs['chat_id'] == user.id and kwargs['action'] == 'test_chat_action' assert check_shortcut_signature( User.send_chat_action, Bot.send_chat_action, ['chat_id'], [] ) + assert check_shortcut_call(user.send_chat_action, user.bot, 'send_chat_action') + assert check_defaults_handling(user.send_chat_action, user.bot) monkeypatch.setattr(user.bot, 'send_chat_action', make_assertion) assert user.send_chat_action('test_chat_action') def test_instance_method_send_contact(self, monkeypatch, user): - send_contact = user.bot.send_contact - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['phone_number'] == 'test_contact' - and check_shortcut_call(kwargs, send_contact) - ) + return kwargs['chat_id'] == user.id and kwargs['phone_number'] == 'test_contact' assert check_shortcut_signature(User.send_contact, Bot.send_contact, ['chat_id'], []) + assert check_shortcut_call(user.send_contact, user.bot, 'send_contact') + assert check_defaults_handling(user.send_contact, user.bot) monkeypatch.setattr(user.bot, 'send_contact', make_assertion) assert user.send_contact(phone_number='test_contact') def test_instance_method_send_dice(self, monkeypatch, user): - send_dice = user.bot.send_dice - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['emoji'] == 'test_dice' - and check_shortcut_call(kwargs, send_dice) - ) + return kwargs['chat_id'] == user.id and kwargs['emoji'] == 'test_dice' assert check_shortcut_signature(User.send_dice, Bot.send_dice, ['chat_id'], []) + assert check_shortcut_call(user.send_dice, user.bot, 'send_dice') + assert check_defaults_handling(user.send_dice, user.bot) monkeypatch.setattr(user.bot, 'send_dice', make_assertion) assert user.send_dice(emoji='test_dice') def test_instance_method_send_document(self, monkeypatch, user): - send_document = user.bot.send_document - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['document'] == 'test_document' - and check_shortcut_call(kwargs, send_document) - ) + return kwargs['chat_id'] == user.id and kwargs['document'] == 'test_document' assert check_shortcut_signature(User.send_document, Bot.send_document, ['chat_id'], []) + assert check_shortcut_call(user.send_document, user.bot, 'send_document') + assert check_defaults_handling(user.send_document, user.bot) monkeypatch.setattr(user.bot, 'send_document', make_assertion) assert user.send_document('test_document') def test_instance_method_send_game(self, monkeypatch, user): - send_game = user.bot.send_game - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['game_short_name'] == 'test_game' - and check_shortcut_call(kwargs, send_game) - ) + return kwargs['chat_id'] == user.id and kwargs['game_short_name'] == 'test_game' assert check_shortcut_signature(User.send_game, Bot.send_game, ['chat_id'], []) + assert check_shortcut_call(user.send_game, user.bot, 'send_game') + assert check_defaults_handling(user.send_game, user.bot) monkeypatch.setattr(user.bot, 'send_game', make_assertion) assert user.send_game(game_short_name='test_game') def test_instance_method_send_invoice(self, monkeypatch, user): - send_invoice = user.bot.send_invoice - def make_assertion(*_, **kwargs): title = kwargs['title'] == 'title' description = kwargs['description'] == 'description' @@ -337,11 +299,11 @@ def make_assertion(*_, **kwargs): and currency and prices ) - return ( - kwargs['chat_id'] == user.id and args and check_shortcut_call(kwargs, send_invoice) - ) + return kwargs['chat_id'] == user.id and args assert check_shortcut_signature(User.send_invoice, Bot.send_invoice, ['chat_id'], []) + assert check_shortcut_call(user.send_invoice, user.bot, 'send_invoice') + assert check_defaults_handling(user.send_invoice, user.bot) monkeypatch.setattr(user.bot, 'send_invoice', make_assertion) assert user.send_invoice( @@ -355,151 +317,117 @@ def make_assertion(*_, **kwargs): ) def test_instance_method_send_location(self, monkeypatch, user): - send_location = user.bot.send_location - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['latitude'] == 'test_location' - and check_shortcut_call(kwargs, send_location) - ) + return kwargs['chat_id'] == user.id and kwargs['latitude'] == 'test_location' assert check_shortcut_signature(User.send_location, Bot.send_location, ['chat_id'], []) + assert check_shortcut_call(user.send_location, user.bot, 'send_location') + assert check_defaults_handling(user.send_location, user.bot) monkeypatch.setattr(user.bot, 'send_location', make_assertion) assert user.send_location('test_location') def test_instance_method_send_sticker(self, monkeypatch, user): - send_sticker = user.bot.send_sticker - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['sticker'] == 'test_sticker' - and check_shortcut_call(kwargs, send_sticker) - ) + return kwargs['chat_id'] == user.id and kwargs['sticker'] == 'test_sticker' assert check_shortcut_signature(User.send_sticker, Bot.send_sticker, ['chat_id'], []) + assert check_shortcut_call(user.send_sticker, user.bot, 'send_sticker') + assert check_defaults_handling(user.send_sticker, user.bot) monkeypatch.setattr(user.bot, 'send_sticker', make_assertion) assert user.send_sticker('test_sticker') def test_instance_method_send_video(self, monkeypatch, user): - send_video = user.bot.send_video - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['video'] == 'test_video' - and check_shortcut_call(kwargs, send_video) - ) + return kwargs['chat_id'] == user.id and kwargs['video'] == 'test_video' assert check_shortcut_signature(User.send_video, Bot.send_video, ['chat_id'], []) + assert check_shortcut_call(user.send_video, user.bot, 'send_video') + assert check_defaults_handling(user.send_video, user.bot) monkeypatch.setattr(user.bot, 'send_video', make_assertion) assert user.send_video('test_video') def test_instance_method_send_venue(self, monkeypatch, user): - send_venue = user.bot.send_venue - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['title'] == 'test_venue' - and check_shortcut_call(kwargs, send_venue) - ) + return kwargs['chat_id'] == user.id and kwargs['title'] == 'test_venue' assert check_shortcut_signature(User.send_venue, Bot.send_venue, ['chat_id'], []) + assert check_shortcut_call(user.send_venue, user.bot, 'send_venue') + assert check_defaults_handling(user.send_venue, user.bot) monkeypatch.setattr(user.bot, 'send_venue', make_assertion) assert user.send_venue(title='test_venue') def test_instance_method_send_video_note(self, monkeypatch, user): - send_video_note = user.bot.send_video_note - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['video_note'] == 'test_video_note' - and check_shortcut_call(kwargs, send_video_note) - ) + return kwargs['chat_id'] == user.id and kwargs['video_note'] == 'test_video_note' assert check_shortcut_signature(User.send_video_note, Bot.send_video_note, ['chat_id'], []) + assert check_shortcut_call(user.send_video_note, user.bot, 'send_video_note') + assert check_defaults_handling(user.send_video_note, user.bot) monkeypatch.setattr(user.bot, 'send_video_note', make_assertion) assert user.send_video_note('test_video_note') def test_instance_method_send_voice(self, monkeypatch, user): - send_voice = user.bot.send_voice - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['voice'] == 'test_voice' - and check_shortcut_call(kwargs, send_voice) - ) + return kwargs['chat_id'] == user.id and kwargs['voice'] == 'test_voice' assert check_shortcut_signature(User.send_voice, Bot.send_voice, ['chat_id'], []) + assert check_shortcut_call(user.send_voice, user.bot, 'send_voice') + assert check_defaults_handling(user.send_voice, user.bot) monkeypatch.setattr(user.bot, 'send_voice', make_assertion) assert user.send_voice('test_voice') def test_instance_method_send_animation(self, monkeypatch, user): - send_animation = user.bot.send_animation - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['animation'] == 'test_animation' - and check_shortcut_call(kwargs, send_animation) - ) + return kwargs['chat_id'] == user.id and kwargs['animation'] == 'test_animation' assert check_shortcut_signature(User.send_animation, Bot.send_animation, ['chat_id'], []) + assert check_shortcut_call(user.send_animation, user.bot, 'send_animation') + assert check_defaults_handling(user.send_animation, user.bot) monkeypatch.setattr(user.bot, 'send_animation', make_assertion) assert user.send_animation('test_animation') def test_instance_method_send_poll(self, monkeypatch, user): - send_poll = user.bot.send_poll - def make_assertion(*_, **kwargs): - return ( - kwargs['chat_id'] == user.id - and kwargs['question'] == 'test_poll' - and check_shortcut_call(kwargs, send_poll) - ) + return kwargs['chat_id'] == user.id and kwargs['question'] == 'test_poll' assert check_shortcut_signature(User.send_poll, Bot.send_poll, ['chat_id'], []) + assert check_shortcut_call(user.send_poll, user.bot, 'send_poll') + assert check_defaults_handling(user.send_poll, user.bot) monkeypatch.setattr(user.bot, 'send_poll', make_assertion) assert user.send_poll(question='test_poll', options=[1, 2]) def test_instance_method_send_copy(self, monkeypatch, user): - send_copy = user.bot.copy_message - def make_assertion(*_, **kwargs): user_id = kwargs['chat_id'] == user.id message_id = kwargs['message_id'] == 'message_id' from_chat_id = kwargs['from_chat_id'] == 'from_chat_id' - return ( - from_chat_id and message_id and user_id and check_shortcut_call(kwargs, send_copy) - ) + return from_chat_id and message_id and user_id assert check_shortcut_signature(User.send_copy, Bot.copy_message, ['chat_id'], []) + assert check_shortcut_call(user.copy_message, user.bot, 'copy_message') + assert check_defaults_handling(user.copy_message, user.bot) monkeypatch.setattr(user.bot, 'copy_message', make_assertion) assert user.send_copy(from_chat_id='from_chat_id', message_id='message_id') def test_instance_method_copy_message(self, monkeypatch, user): - copy_message = user.bot.copy_message - def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == 'chat_id' message_id = kwargs['message_id'] == 'message_id' user_id = kwargs['from_chat_id'] == user.id - return chat_id and message_id and user_id and check_shortcut_call(kwargs, copy_message) + return chat_id and message_id and user_id assert check_shortcut_signature(User.copy_message, Bot.copy_message, ['from_chat_id'], []) + assert check_shortcut_call(user.copy_message, user.bot, 'copy_message') + assert check_defaults_handling(user.copy_message, user.bot) monkeypatch.setattr(user.bot, 'copy_message', make_assertion) assert user.copy_message(chat_id='chat_id', message_id='message_id') diff --git a/tests/test_video.py b/tests/test_video.py index ec9f486a8d3..1cfd9e04084 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -25,7 +25,7 @@ from telegram import Video, TelegramError, Voice, PhotoSize, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown -from tests.conftest import check_shortcut_call, check_shortcut_signature +from tests.conftest import check_shortcut_call, check_shortcut_signature, check_defaults_handling @pytest.fixture(scope='function') @@ -330,14 +330,14 @@ def test_error_without_required_args(self, bot, chat_id): bot.send_video(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, video): - get_file = video.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == video.file_id and check_shortcut_call(kwargs, get_file) + return kwargs['file_id'] == video.file_id assert check_shortcut_signature(Video.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(video.get_file, video.bot, 'get_file') + assert check_defaults_handling(video.get_file, video.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(video.bot, 'get_file', make_assertion) assert video.get_file() def test_equality(self, video): diff --git a/tests/test_videonote.py b/tests/test_videonote.py index e93c3e879d1..9cae229e334 100644 --- a/tests/test_videonote.py +++ b/tests/test_videonote.py @@ -24,7 +24,7 @@ from telegram import VideoNote, TelegramError, Voice, PhotoSize, Bot from telegram.error import BadRequest -from tests.conftest import check_shortcut_call, check_shortcut_signature +from tests.conftest import check_shortcut_call, check_shortcut_signature, check_defaults_handling @pytest.fixture(scope='function') @@ -228,16 +228,14 @@ def test_error_without_required_args(self, bot, chat_id): bot.send_video_note(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, video_note): - get_file = video_note.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == video_note.file_id and check_shortcut_call( - kwargs, get_file - ) + return kwargs['file_id'] == video_note.file_id assert check_shortcut_signature(VideoNote.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(video_note.get_file, video_note.bot, 'get_file') + assert check_defaults_handling(video_note.get_file, video_note.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(video_note.bot, 'get_file', make_assertion) assert video_note.get_file() def test_equality(self, video_note): diff --git a/tests/test_voice.py b/tests/test_voice.py index 6ff2bd269e5..5c9384dfaa3 100644 --- a/tests/test_voice.py +++ b/tests/test_voice.py @@ -25,7 +25,7 @@ from telegram import Audio, Voice, TelegramError, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown -from tests.conftest import check_shortcut_call, check_shortcut_signature +from tests.conftest import check_shortcut_call, check_shortcut_signature, check_defaults_handling @pytest.fixture(scope='function') @@ -284,14 +284,14 @@ def test_error_without_required_args(self, bot, chat_id): bot.sendVoice(chat_id) def test_get_file_instance_method(self, monkeypatch, voice): - get_file = voice.bot.get_file - def make_assertion(*_, **kwargs): - return kwargs['file_id'] == voice.file_id and check_shortcut_call(kwargs, get_file) + return kwargs['file_id'] == voice.file_id assert check_shortcut_signature(Voice.get_file, Bot.get_file, ['file_id'], []) + assert check_shortcut_call(voice.get_file, voice.bot, 'get_file') + assert check_defaults_handling(voice.get_file, voice.bot) - monkeypatch.setattr('telegram.Bot.get_file', make_assertion) + monkeypatch.setattr(voice.bot, 'get_file', make_assertion) assert voice.get_file() def test_equality(self, voice):