Skip to content
2 changes: 1 addition & 1 deletion telegram/_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8205,7 +8205,7 @@ async def create_invoice_link(
api_kwargs=api_kwargs,
)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict: # skipcq: PYL-W0613
"""See :meth:`telegram.TelegramObject.to_dict`."""
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}

Expand Down
4 changes: 2 additions & 2 deletions telegram/_chatinvitelink.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatInviteLi

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["expire_date"] = to_timestamp(self.expire_date)

Expand Down
4 changes: 2 additions & 2 deletions telegram/_chatjoinrequest.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatJoinRequ

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["date"] = to_timestamp(self.date)

Expand Down
4 changes: 2 additions & 2 deletions telegram/_chatmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatMember"]

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

if data.get("until_date", False):
data["until_date"] = to_timestamp(data["until_date"])
Expand Down
4 changes: 2 additions & 2 deletions telegram/_chatmemberupdated.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatMemberUp

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

# Required
data["date"] = to_timestamp(self.date)
Expand Down
4 changes: 2 additions & 2 deletions telegram/_files/inputmedia.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ def __init__(
self.caption_entities = caption_entities
self.parse_mode = parse_mode

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

if self.caption_entities:
data["caption_entities"] = [ce.to_dict() for ce in self.caption_entities]
Expand Down
4 changes: 2 additions & 2 deletions telegram/_files/sticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["StickerSet"]

return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["stickers"] = [s.to_dict() for s in data.get("stickers")] # type: ignore[union-attr]

Expand Down
4 changes: 2 additions & 2 deletions telegram/_games/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Game"]:

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["photo"] = [p.to_dict() for p in self.photo]
if self.text_entities:
Expand Down
4 changes: 2 additions & 2 deletions telegram/_inline/inlinekeyboardmarkup.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ def __init__(

self._id_attrs = (self.inline_keyboard,)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["inline_keyboard"] = []
for inline_keyboard in self.inline_keyboard:
Expand Down
4 changes: 2 additions & 2 deletions telegram/_inline/inlinequeryresult.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ def __init__(self, type: str, id: str, *, api_kwargs: JSONDict = None):

self._id_attrs = (self.id,)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

# pylint: disable=no-member
if (
Expand Down
4 changes: 2 additions & 2 deletions telegram/_inline/inputinvoicemessagecontent.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,9 @@ def __hash__(self) -> int:
)
)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["prices"] = [price.to_dict() for price in self.prices]

Expand Down
4 changes: 2 additions & 2 deletions telegram/_inline/inputtextmessagecontent.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ def __init__(

self._id_attrs = (self.message_text,)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

if self.entities:
data["entities"] = [ce.to_dict() for ce in self.entities]
Expand Down
4 changes: 2 additions & 2 deletions telegram/_menubutton.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MenuButtonWe

return super().de_json(data=data, bot=bot) # type: ignore[return-value]

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)
data["web_app"] = self.web_app.to_dict()
return data

Expand Down
4 changes: 2 additions & 2 deletions telegram/_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,9 +718,9 @@ def effective_attachment(

return self._effective_attachment # type: ignore[return-value]

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

# Required
data["date"] = to_timestamp(self.date)
Expand Down
12 changes: 6 additions & 6 deletions telegram/_passport/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,9 +404,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["SecureValue"

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().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]
Expand Down Expand Up @@ -450,9 +450,9 @@ 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) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

del data["file_hash"]
del data["hash"]
Expand All @@ -479,9 +479,9 @@ 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) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

del data["data_hash"]
del data["hash"]
Expand Down
4 changes: 2 additions & 2 deletions telegram/_passport/encryptedpassportelement.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,9 @@ def de_json_decrypted(

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

if self.files:
data["files"] = [p.to_dict() for p in self.files]
Expand Down
4 changes: 2 additions & 2 deletions telegram/_passport/passportdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["PassportData

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["data"] = [e.to_dict() for e in self.data]

Expand Down
4 changes: 2 additions & 2 deletions telegram/_payment/shippingoption.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ def __init__(

self._id_attrs = (self.id,)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["prices"] = [p.to_dict() for p in self.prices]

Expand Down
4 changes: 2 additions & 2 deletions telegram/_poll.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Poll"]:

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["options"] = [x.to_dict() for x in self.options]
if self.explanation_entities:
Expand Down
4 changes: 2 additions & 2 deletions telegram/_replykeyboardmarkup.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ def __init__(

self._id_attrs = (self.keyboard,)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["keyboard"] = []
for row in self.keyboard:
Expand Down
47 changes: 25 additions & 22 deletions telegram/_telegramobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import inspect
import json
from copy import deepcopy
from itertools import chain
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type, TypeVar, Union

from telegram._utils.types import JSONDict
Expand Down Expand Up @@ -160,37 +161,32 @@ def _get_attrs(

Args:
include_private (:obj:`bool`): Whether the result should include private variables.
recursive (:obj:`bool`): If :obj:`True`, will convert any TelegramObjects (if found) in
the attributes to a dictionary. Else, preserves it as an object itself.
recursive (:obj:`bool`): If :obj:`True`, will convert any ``TelegramObjects`` (if
found) in the attributes to a dictionary. Else, preserves it as an object itself.
remove_bot (:obj:`bool`): Whether the bot should be included in the result.

Returns:
:obj:`dict`: A dict where the keys are attribute names and values are their values.
"""
data = {}

if not recursive:
try:
# __dict__ has attrs from superclasses, so no need to put in the for loop below
data.update(self.__dict__)
except AttributeError:
pass
# We want to get all attributes for the class, using self.__slots__ only includes the
# attributes used by that class itself, and not its superclass(es). Hence, we get its MRO
# and then get their attributes. The `[:-1]` slice excludes the `object` class
for cls in self.__class__.__mro__[:-1]:
for key in cls.__slots__: # type: ignore[attr-defined]
if not include_private and key.startswith("_"):
continue

value = getattr(self, key, None)
if value is not None:
if recursive and hasattr(value, "to_dict"):
data[key] = value.to_dict() # pylint: disable=no-member
else:
data[key] = value
elif not recursive:
all_slots = (s for c in self.__class__.__mro__[:-1] for s in c.__slots__) # type: ignore
# chain the class's slots with the user defined subclass __dict__ (class has no slots)
for key in chain(self.__dict__, all_slots) if hasattr(self, "__dict__") else all_slots:
if not include_private and key.startswith("_"):
continue

value = getattr(self, key, None)
if value is not None:
if recursive and hasattr(value, "to_dict"):
data[key] = value.to_dict(recursive=True) # pylint: disable=no-member
else:
data[key] = value
elif not recursive:
data[key] = value

if recursive and data.get("from_user"):
data["from"] = data.pop("from_user", None)
Expand Down Expand Up @@ -279,16 +275,23 @@ def to_json(self) -> str:
"""
return json.dumps(self.to_dict())

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""Gives representation of object as :obj:`dict`.

.. versionchanged:: 20.0
Now includes all entries of :attr:`api_kwargs`.

Args:
recursive (:obj:`bool`, optional): If :obj:`True`, will convert any TelegramObjects
(if found) in the attributes to a dictionary. Else, preserves it as an object
itself. Defaults to :obj:`True`.

.. versionadded:: 20.0

Returns:
:obj:`dict`
"""
out = self._get_attrs(recursive=True)
out = self._get_attrs(recursive=recursive)
out.update(out.pop("api_kwargs", {})) # type: ignore[call-overload]
return out

Expand Down
4 changes: 2 additions & 2 deletions telegram/_userprofilephotos.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["UserProfileP

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

data["photos"] = []
for photo in self.photos:
Expand Down
8 changes: 4 additions & 4 deletions telegram/_videochat.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ def de_json(
data["users"] = User.de_list(data.get("users", []), bot)
return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

if self.users is not None:
data["users"] = [u.to_dict() for u in self.users]
Expand Down Expand Up @@ -176,9 +176,9 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["VideoChatSch

return super().de_json(data=data, bot=bot)

def to_dict(self) -> JSONDict:
def to_dict(self, recursive: bool = True) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data = super().to_dict(recursive=recursive)

# Required
data["start_date"] = to_timestamp(self.start_date)
Expand Down
Loading