From e54c6a04dea90d10efd358a3abe41a7fc0617282 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Mon, 14 Nov 2022 01:58:41 +0530 Subject: [PATCH] Handle Lists and Tuples and Datetimes Directly in `TelegramObject.to_dict` (#3353) --- telegram/_bot.py | 4 +-- telegram/_chatinvitelink.py | 10 +------ telegram/_chatjoinrequest.py | 10 +------ telegram/_chatmember.py | 11 +------- telegram/_chatmemberupdated.py | 11 +------- telegram/_files/inputmedia.py | 9 ------ telegram/_files/sticker.py | 8 ------ telegram/_games/game.py | 10 ------- telegram/_inline/inlinekeyboardmarkup.py | 10 ------- telegram/_inline/inlinequeryresult.py | 15 ---------- .../_inline/inputinvoicemessagecontent.py | 8 ------ telegram/_inline/inputtextmessagecontent.py | 9 ------ telegram/_menubutton.py | 6 ---- telegram/_message.py | 26 +---------------- telegram/_passport/credentials.py | 27 ------------------ .../_passport/encryptedpassportelement.py | 11 -------- telegram/_passport/passportdata.py | 8 ------ telegram/_payment/shippingoption.py | 8 ------ telegram/_poll.py | 13 +-------- telegram/_replykeyboardmarkup.py | 9 ------ telegram/_telegramobject.py | 28 +++++++++++++++++++ telegram/_userprofilephotos.py | 10 ------- telegram/_videochat.py | 19 +------------ tests/test_bot.py | 11 +++++--- tests/test_callbackquery.py | 4 ++- tests/test_chatinvitelink.py | 2 +- tests/test_chatmember.py | 3 ++ tests/test_message.py | 12 ++++++-- tests/test_telegramobject.py | 4 +-- tests/test_update.py | 3 +- 30 files changed, 65 insertions(+), 254 deletions(-) diff --git a/telegram/_bot.py b/telegram/_bot.py index ec2b7a14b..bd6ae67d6 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -3665,7 +3665,7 @@ class Bot(TelegramObject, AbstractAsyncContextManager): if inline_message_id: data["inline_message_id"] = inline_message_id if entities: - data["entities"] = [me.to_dict() for me in entities] + data["entities"] = [me.to_dict(recursive=True) for me in entities] return await self._send_message( "editMessageText", @@ -5085,7 +5085,7 @@ class Bot(TelegramObject, AbstractAsyncContextManager): data: JSONDict = {"shipping_query_id": shipping_query_id, "ok": ok} if shipping_options is not None: - data["shipping_options"] = [option.to_dict() for option in shipping_options] + data["shipping_options"] = [option.to_dict(True) for option in shipping_options] if error_message is not None: data["error_message"] = error_message diff --git a/telegram/_chatinvitelink.py b/telegram/_chatinvitelink.py index f0ff6543c..de7208dda 100644 --- a/telegram/_chatinvitelink.py +++ b/telegram/_chatinvitelink.py @@ -22,7 +22,7 @@ from typing import TYPE_CHECKING, Optional from telegram._telegramobject import TelegramObject from telegram._user import User -from telegram._utils.datetime import from_timestamp, to_timestamp +from telegram._utils.datetime import from_timestamp from telegram._utils.types import JSONDict if TYPE_CHECKING: @@ -150,11 +150,3 @@ class ChatInviteLink(TelegramObject): data["expire_date"] = from_timestamp(data.get("expire_date", None)) return super().de_json(data=data, bot=bot) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["expire_date"] = to_timestamp(self.expire_date) - - return data diff --git a/telegram/_chatjoinrequest.py b/telegram/_chatjoinrequest.py index 2869df129..2fbcfb966 100644 --- a/telegram/_chatjoinrequest.py +++ b/telegram/_chatjoinrequest.py @@ -24,7 +24,7 @@ from telegram._chat import Chat from telegram._chatinvitelink import ChatInviteLink from telegram._telegramobject import TelegramObject from telegram._user import User -from telegram._utils.datetime import from_timestamp, to_timestamp +from telegram._utils.datetime import from_timestamp from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._utils.types import JSONDict, ODVInput @@ -103,14 +103,6 @@ class ChatJoinRequest(TelegramObject): return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["date"] = to_timestamp(self.date) - - return data - async def approve( self, *, diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index 01b40f7e1..69d0a00cd 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, ClassVar, Dict, Optional, Type from telegram import constants from telegram._telegramobject import TelegramObject from telegram._user import User -from telegram._utils.datetime import from_timestamp, to_timestamp +from telegram._utils.datetime import from_timestamp from telegram._utils.types import JSONDict if TYPE_CHECKING: @@ -123,15 +123,6 @@ class ChatMember(TelegramObject): return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - if data.get("until_date", False): - data["until_date"] = to_timestamp(data["until_date"]) - - return data - class ChatMemberOwner(ChatMember): """ diff --git a/telegram/_chatmemberupdated.py b/telegram/_chatmemberupdated.py index e0abc5f03..39344d702 100644 --- a/telegram/_chatmemberupdated.py +++ b/telegram/_chatmemberupdated.py @@ -25,7 +25,7 @@ from telegram._chatinvitelink import ChatInviteLink from telegram._chatmember import ChatMember from telegram._telegramobject import TelegramObject from telegram._user import User -from telegram._utils.datetime import from_timestamp, to_timestamp +from telegram._utils.datetime import from_timestamp from telegram._utils.types import JSONDict if TYPE_CHECKING: @@ -122,15 +122,6 @@ class ChatMemberUpdated(TelegramObject): return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - # Required - data["date"] = to_timestamp(self.date) - - return data - def _get_attribute_difference(self, attribute: str) -> Tuple[object, object]: try: old = self.old_chat_member[attribute] diff --git a/telegram/_files/inputmedia.py b/telegram/_files/inputmedia.py index 3174aca58..c6c65ca32 100644 --- a/telegram/_files/inputmedia.py +++ b/telegram/_files/inputmedia.py @@ -90,15 +90,6 @@ class InputMedia(TelegramObject): self.caption_entities = caption_entities self.parse_mode = parse_mode - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - if self.caption_entities: - data["caption_entities"] = [ce.to_dict() for ce in self.caption_entities] - - return data - @staticmethod def _parse_thumb_input(thumb: Optional[FileInput]) -> Optional[Union[str, InputFile]]: # We use local_mode=True because we don't have access to the actual setting and want diff --git a/telegram/_files/sticker.py b/telegram/_files/sticker.py index 64e42c340..5c3e81d11 100644 --- a/telegram/_files/sticker.py +++ b/telegram/_files/sticker.py @@ -282,14 +282,6 @@ class StickerSet(TelegramObject): return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["stickers"] = [s.to_dict() for s in data.get("stickers")] # type: ignore[union-attr] - - return data - class MaskPosition(TelegramObject): """This object describes the position on faces where a mask should be placed by default. diff --git a/telegram/_games/game.py b/telegram/_games/game.py index 91d31b17e..91047e84b 100644 --- a/telegram/_games/game.py +++ b/telegram/_games/game.py @@ -117,16 +117,6 @@ class Game(TelegramObject): return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["photo"] = [p.to_dict() for p in self.photo] - if self.text_entities: - data["text_entities"] = [x.to_dict() for x in self.text_entities] - - return data - def parse_text_entity(self, entity: MessageEntity) -> str: """Returns the text from a given :class:`telegram.MessageEntity`. diff --git a/telegram/_inline/inlinekeyboardmarkup.py b/telegram/_inline/inlinekeyboardmarkup.py index 52c398288..5ee25ecf3 100644 --- a/telegram/_inline/inlinekeyboardmarkup.py +++ b/telegram/_inline/inlinekeyboardmarkup.py @@ -68,16 +68,6 @@ class InlineKeyboardMarkup(TelegramObject): self._id_attrs = (self.inline_keyboard,) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["inline_keyboard"] = [] - for inline_keyboard in self.inline_keyboard: - data["inline_keyboard"].append([x.to_dict() for x in inline_keyboard]) - - return data - @classmethod def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["InlineKeyboardMarkup"]: """See :meth:`telegram.TelegramObject.de_json`.""" diff --git a/telegram/_inline/inlinequeryresult.py b/telegram/_inline/inlinequeryresult.py index 7ccf3c00b..e6ce5fc92 100644 --- a/telegram/_inline/inlinequeryresult.py +++ b/telegram/_inline/inlinequeryresult.py @@ -53,18 +53,3 @@ class InlineQueryResult(TelegramObject): self.id = str(id) # pylint: disable=invalid-name self._id_attrs = (self.id,) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - # pylint: disable=no-member - if ( - hasattr(self, "caption_entities") - and self.caption_entities # type: ignore[attr-defined] - ): - data["caption_entities"] = [ - ce.to_dict() for ce in self.caption_entities # type: ignore[attr-defined] - ] - - return data diff --git a/telegram/_inline/inputinvoicemessagecontent.py b/telegram/_inline/inputinvoicemessagecontent.py index fbc7f3c33..ce65c7171 100644 --- a/telegram/_inline/inputinvoicemessagecontent.py +++ b/telegram/_inline/inputinvoicemessagecontent.py @@ -228,14 +228,6 @@ class InputInvoiceMessageContent(InputMessageContent): ) ) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["prices"] = [price.to_dict() for price in self.prices] - - return data - @classmethod def de_json( cls, data: Optional[JSONDict], bot: "Bot" diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 71c220830..c106cb2d6 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -83,12 +83,3 @@ class InputTextMessageContent(InputMessageContent): self.disable_web_page_preview = disable_web_page_preview self._id_attrs = (self.message_text,) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - if self.entities: - data["entities"] = [ce.to_dict() for ce in self.entities] - - return data diff --git a/telegram/_menubutton.py b/telegram/_menubutton.py index 2c28ed742..4a7a84c05 100644 --- a/telegram/_menubutton.py +++ b/telegram/_menubutton.py @@ -161,12 +161,6 @@ class MenuButtonWebApp(MenuButton): return super().de_json(data=data, bot=bot) # type: ignore[return-value] - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - data["web_app"] = self.web_app.to_dict() - return data - class MenuButtonDefault(MenuButton): """Describes that no specific value for the menu button was set. diff --git a/telegram/_message.py b/telegram/_message.py index 86d40a1a3..60a14b3f3 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -47,7 +47,7 @@ from telegram._poll import Poll from telegram._proximityalerttriggered import ProximityAlertTriggered from telegram._telegramobject import TelegramObject from telegram._user import User -from telegram._utils.datetime import from_timestamp, to_timestamp +from telegram._utils.datetime import from_timestamp from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue from telegram._utils.types import DVInput, FileInput, JSONDict, ODVInput, ReplyMarkup from telegram._videochat import ( @@ -719,30 +719,6 @@ class Message(TelegramObject): return self._effective_attachment # type: ignore[return-value] - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - # Required - data["date"] = to_timestamp(self.date) - # Optionals - if self.forward_date: - data["forward_date"] = to_timestamp(self.forward_date) - if self.edit_date: - data["edit_date"] = to_timestamp(self.edit_date) - if self.photo: - data["photo"] = [p.to_dict() for p in self.photo] - if self.entities: - data["entities"] = [e.to_dict() for e in self.entities] - if self.caption_entities: - data["caption_entities"] = [e.to_dict() for e in self.caption_entities] - if self.new_chat_photo: - data["new_chat_photo"] = [p.to_dict() for p in self.new_chat_photo] - if self.new_chat_members: - data["new_chat_members"] = [u.to_dict() for u in self.new_chat_members] - - return data - def _quote(self, quote: Optional[bool], reply_to_message_id: Optional[int]) -> Optional[int]: """Modify kwargs for replying with or without quoting.""" if reply_to_message_id is not None: diff --git a/telegram/_passport/credentials.py b/telegram/_passport/credentials.py index 0d3e5244c..2d21440dc 100644 --- a/telegram/_passport/credentials.py +++ b/telegram/_passport/credentials.py @@ -404,15 +404,6 @@ class SecureValue(TelegramObject): return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["files"] = [p.to_dict() for p in self.files] # type: ignore[union-attr] - data["translation"] = [p.to_dict() for p in self.translation] # type: ignore[union-attr] - - return data - class _CredentialsBase(TelegramObject): """Base class for DataCredentials and FileCredentials.""" @@ -450,15 +441,6 @@ class DataCredentials(_CredentialsBase): def __init__(self, data_hash: str, secret: str, *, api_kwargs: JSONDict = None): super().__init__(hash=data_hash, secret=secret, api_kwargs=api_kwargs) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - del data["file_hash"] - del data["hash"] - - return data - class FileCredentials(_CredentialsBase): """ @@ -478,12 +460,3 @@ class FileCredentials(_CredentialsBase): def __init__(self, file_hash: str, secret: str, *, api_kwargs: JSONDict = None): super().__init__(hash=file_hash, secret=secret, api_kwargs=api_kwargs) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - del data["data_hash"] - del data["hash"] - - return data diff --git a/telegram/_passport/encryptedpassportelement.py b/telegram/_passport/encryptedpassportelement.py index 54281b7b8..5b460c134 100644 --- a/telegram/_passport/encryptedpassportelement.py +++ b/telegram/_passport/encryptedpassportelement.py @@ -244,14 +244,3 @@ class EncryptedPassportElement(TelegramObject): ) return super().de_json(data=data, bot=bot) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - if self.files: - data["files"] = [p.to_dict() for p in self.files] - if self.translation: - data["translation"] = [p.to_dict() for p in self.translation] - - return data diff --git a/telegram/_passport/passportdata.py b/telegram/_passport/passportdata.py index fbfafce21..f4508a1b8 100644 --- a/telegram/_passport/passportdata.py +++ b/telegram/_passport/passportdata.py @@ -81,14 +81,6 @@ class PassportData(TelegramObject): return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["data"] = [e.to_dict() for e in self.data] - - return data - @property def decrypted_data(self) -> List[EncryptedPassportElement]: """ diff --git a/telegram/_payment/shippingoption.py b/telegram/_payment/shippingoption.py index c21c4d534..667cb82f6 100644 --- a/telegram/_payment/shippingoption.py +++ b/telegram/_payment/shippingoption.py @@ -64,11 +64,3 @@ class ShippingOption(TelegramObject): self.prices = prices self._id_attrs = (self.id,) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["prices"] = [p.to_dict() for p in self.prices] - - return data diff --git a/telegram/_poll.py b/telegram/_poll.py index 5ed9a1b1c..8a8854854 100644 --- a/telegram/_poll.py +++ b/telegram/_poll.py @@ -27,7 +27,7 @@ from telegram._messageentity import MessageEntity from telegram._telegramobject import TelegramObject from telegram._user import User from telegram._utils import enum -from telegram._utils.datetime import from_timestamp, to_timestamp +from telegram._utils.datetime import from_timestamp from telegram._utils.types import JSONDict if TYPE_CHECKING: @@ -228,17 +228,6 @@ class Poll(TelegramObject): return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["options"] = [x.to_dict() for x in self.options] - if self.explanation_entities: - data["explanation_entities"] = [e.to_dict() for e in self.explanation_entities] - data["close_date"] = to_timestamp(data.get("close_date")) - - return data - def parse_explanation_entity(self, entity: MessageEntity) -> str: """Returns the text from a given :class:`telegram.MessageEntity`. diff --git a/telegram/_replykeyboardmarkup.py b/telegram/_replykeyboardmarkup.py index c122670ee..97deeae3f 100644 --- a/telegram/_replykeyboardmarkup.py +++ b/telegram/_replykeyboardmarkup.py @@ -119,15 +119,6 @@ class ReplyKeyboardMarkup(TelegramObject): self._id_attrs = (self.keyboard,) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["keyboard"] = [] - for row in self.keyboard: - data["keyboard"].append([button.to_dict() for button in row]) - return data - @classmethod def from_button( cls, diff --git a/telegram/_telegramobject.py b/telegram/_telegramobject.py index 40a408be4..de132940f 100644 --- a/telegram/_telegramobject.py +++ b/telegram/_telegramobject.py @@ -17,12 +17,14 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. """Base class for Telegram Objects.""" +import datetime import inspect import json from copy import deepcopy from itertools import chain from typing import TYPE_CHECKING, Dict, List, Optional, Set, Sized, Tuple, Type, TypeVar, Union +from telegram._utils.datetime import to_timestamp from telegram._utils.types import JSONDict from telegram._utils.warnings import warn @@ -327,6 +329,32 @@ class TelegramObject: :obj:`dict` """ out = self._get_attrs(recursive=recursive) + + # Now we should convert TGObjects to dicts inside objects such as sequences, and convert + # datetimes to timestamps. This mostly eliminates the need for subclasses to override + # `to_dict` + for key, value in out.items(): + if isinstance(value, (tuple, list)) and value: + val = [] # empty list to append our converted values to + for item in value: + if hasattr(item, "to_dict"): + val.append(item.to_dict(recursive=recursive)) + # This branch is useful for e.g. List[List[PhotoSize|KeyboardButton]] + elif isinstance(item, (tuple, list)): + val.append( + [ + i.to_dict(recursive=recursive) if hasattr(i, "to_dict") else i + for i in item + ] + ) + else: # if it's not a TGObject, just append it. E.g. [TGObject, 2] + val.append(item) + out[key] = val + + elif isinstance(value, datetime.datetime): + out[key] = to_timestamp(value) + + # Effectively "unpack" api_kwargs into `out`: out.update(out.pop("api_kwargs", {})) # type: ignore[call-overload] return out diff --git a/telegram/_userprofilephotos.py b/telegram/_userprofilephotos.py index ee0e8ad35..244c89fa2 100644 --- a/telegram/_userprofilephotos.py +++ b/telegram/_userprofilephotos.py @@ -69,15 +69,5 @@ class UserProfilePhotos(TelegramObject): return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - data["photos"] = [] - for photo in self.photos: - data["photos"].append([x.to_dict() for x in photo]) - - return data - def __hash__(self) -> int: return hash(tuple(tuple(p for p in photo) for photo in self.photos)) diff --git a/telegram/_videochat.py b/telegram/_videochat.py index 41bc25c64..60a0ab4ff 100644 --- a/telegram/_videochat.py +++ b/telegram/_videochat.py @@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, List, Optional from telegram._telegramobject import TelegramObject from telegram._user import User -from telegram._utils.datetime import from_timestamp, to_timestamp +from telegram._utils.datetime import from_timestamp from telegram._utils.types import JSONDict if TYPE_CHECKING: @@ -121,14 +121,6 @@ class VideoChatParticipantsInvited(TelegramObject): data["users"] = User.de_list(data.get("users", []), bot) return super().de_json(data=data, bot=bot) - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - if self.users is not None: - data["users"] = [u.to_dict() for u in self.users] - return data - def __hash__(self) -> int: return hash(None) if self.users is None else hash(tuple(self.users)) @@ -175,12 +167,3 @@ class VideoChatScheduled(TelegramObject): data["start_date"] = from_timestamp(data["start_date"]) return super().de_json(data=data, bot=bot) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict(recursive=recursive) - - # Required - data["start_date"] = to_timestamp(self.start_date) - - return data diff --git a/tests/test_bot.py b/tests/test_bot.py index 51945506d..c9d36db55 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -1714,7 +1714,7 @@ class TestBot: message=Message( 1, from_user=User(1, "", False), - date=None, + date=dtm.datetime.utcnow(), chat=Chat(1, ""), text="Webhook", ), @@ -2997,7 +2997,10 @@ class TestBot: ) message = Message( - 1, None, None, reply_markup=bot.callback_data_cache.process_keyboard(reply_markup) + 1, + dtm.datetime.utcnow(), + None, + reply_markup=bot.callback_data_cache.process_keyboard(reply_markup), ) # We do to_dict -> de_json to make sure those aren't the same objects message.pinned_message = Message.de_json(message.to_dict(), bot) @@ -3008,7 +3011,7 @@ class TestBot: **{ message_type: Message( 1, - None, + dtm.datetime.utcnow(), None, pinned_message=message, reply_to_message=Message.de_json(message.to_dict(), bot), @@ -3075,7 +3078,7 @@ class TestBot: reply_markup = bot.callback_data_cache.process_keyboard(reply_markup) message = Message( 1, - None, + dtm.datetime.utcnow(), None, reply_markup=reply_markup, via_bot=bot.bot if self_sender else User(1, "first", False), diff --git a/tests/test_callbackquery.py b/tests/test_callbackquery.py index b2a06f7d0..29b9b0974 100644 --- a/tests/test_callbackquery.py +++ b/tests/test_callbackquery.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. +from datetime import datetime + import pytest from telegram import Audio, Bot, CallbackQuery, Chat, Message, User @@ -45,7 +47,7 @@ class TestCallbackQuery: id_ = "id" from_user = User(1, "test_user", False) chat_instance = "chat_instance" - message = Message(3, None, Chat(4, "private"), from_user=User(5, "bot", False)) + message = Message(3, datetime.utcnow(), Chat(4, "private"), from_user=User(5, "bot", False)) data = "data" inline_message_id = "inline_message_id" game_short_name = "the_game" diff --git a/tests/test_chatinvitelink.py b/tests/test_chatinvitelink.py index d1c8de3ad..1f940d39a 100644 --- a/tests/test_chatinvitelink.py +++ b/tests/test_chatinvitelink.py @@ -47,7 +47,7 @@ def invite_link(creator): class TestChatInviteLink: link = "thisialink" - creates_join_request = (False,) + creates_join_request = False primary = True revoked = False expire_date = datetime.datetime.now(datetime.timezone.utc) diff --git a/tests/test_chatmember.py b/tests/test_chatmember.py index 2e6248087..f2a1d0854 100644 --- a/tests/test_chatmember.py +++ b/tests/test_chatmember.py @@ -223,6 +223,9 @@ class TestChatMemberTypes: assert chat_member_dict["status"] == chat_member_type.status assert chat_member_dict["user"] == chat_member_type.user.to_dict() + for slot in chat_member_type.__slots__: # additional verification for the optional args + assert getattr(chat_member_type, slot) == chat_member_dict[slot] + def test_equality(self, chat_member_type): a = ChatMember(status="status", user=CMDefaults.user) b = ChatMember(status="status", user=CMDefaults.user) diff --git a/tests/test_message.py b/tests/test_message.py index c9aca3572..3ad03e386 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -80,7 +80,11 @@ def message(bot): "forward_from_message_id": 101, "forward_date": datetime.utcnow(), }, - {"reply_to_message": Message(50, None, None, None)}, + { + "reply_to_message": Message( + 50, datetime.utcnow(), Chat(13, "channel"), User(9, "i", False) + ) + }, {"edit_date": datetime.utcnow()}, { "text": "a text message", @@ -124,7 +128,11 @@ def message(bot): {"message_auto_delete_timer_changed": MessageAutoDeleteTimerChanged(42)}, {"migrate_to_chat_id": -12345}, {"migrate_from_chat_id": -54321}, - {"pinned_message": Message(7, None, None, None)}, + { + "pinned_message": Message( + 7, datetime.utcnow(), Chat(13, "channel"), User(9, "i", False) + ) + }, {"invoice": Invoice("my invoice", "invoice", "start", "EUR", 243)}, { "successful_payment": SuccessfulPayment( diff --git a/tests/test_telegramobject.py b/tests/test_telegramobject.py index e636a0068..5eb248200 100644 --- a/tests/test_telegramobject.py +++ b/tests/test_telegramobject.py @@ -238,9 +238,9 @@ class TestTelegramObject: with pytest.raises(RuntimeError): unpickled.get_bot() # There should be no bot when we pickle TGObjects - assert unpickled.chat == chat + assert unpickled.chat == chat, f"{unpickled.chat._id_attrs} != {chat._id_attrs}" assert unpickled.from_user == user - assert unpickled.date == date + assert unpickled.date == date, f"{unpickled.date} != {date}" assert unpickled.photo[0] == photo def test_pickle_apply_api_kwargs(self, bot): diff --git a/tests/test_update.py b/tests/test_update.py index 2cd765863..20cce556e 100644 --- a/tests/test_update.py +++ b/tests/test_update.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 time +from datetime import datetime import pytest @@ -39,7 +40,7 @@ from telegram import ( ) from telegram._utils.datetime import from_timestamp -message = Message(1, None, Chat(1, ""), from_user=User(1, "", False), text="Text") +message = Message(1, datetime.utcnow(), Chat(1, ""), from_user=User(1, "", False), text="Text") chat_member_updated = ChatMemberUpdated( Chat(1, "chat"), User(1, "", False),