Compare commits

...

14 Commits

Author SHA1 Message Date
Harshil c913056701 Rename import 2026-06-09 22:43:24 -04:00
Harshil dec28a232c Remove de_json depr test 2026-06-09 21:35:28 -04:00
Harshil 37ddf8cc16 Merge master and fix conflicts, and remove de_json's 2026-06-09 21:28:38 -04:00
Harshil b5cfa4f902 Remove redundant _de_json in Message 2026-03-31 04:20:37 -07:00
Harshil 40e9bdf94f Update changelog 2026-03-31 03:28:30 -07:00
Harshil 42dcd86fd2 Run ruff formatter and linter 2026-03-31 02:03:25 -07:00
Harshil f49f9a7d02 I'm happy enough with this implementation 2026-03-31 02:03:25 -07:00
Harshil 116aa08a93 WIP: Do some perf improvements 2026-03-31 02:03:25 -07:00
Harshil 65777a737c Remove print statements for benchmark 2026-03-31 02:03:24 -07:00
Harshil 50d9d63c11 WIP: Remove extraneous cls field 2026-03-31 02:03:24 -07:00
Harshil 4e0410aa14 WIP: Fix tests
All changes in this commit were done by Opus 4.6, some of which I'm not happy with, so that will be changed
2026-03-31 02:03:24 -07:00
Harshil 21a66b7e1b WIP: Flesh out the implementation a little more
Some tests are still failing
2026-03-31 02:03:24 -07:00
harshil21 d0d7e19b4f Add chango fragment for PR #5186 2026-03-29 13:59:35 +00:00
Harshil bb3138cc9c WIP: Start centralizing de_json 2026-03-29 06:56:22 -07:00
72 changed files with 505 additions and 2398 deletions
@@ -0,0 +1,5 @@
other = "Centralize `de_json` into `TelegramObject`"
[[pull_requests]]
uid = "5186"
author_uids = ["harshil21"]
closes_threads = []
+1 -13
View File
@@ -19,16 +19,12 @@
"""This module contains an object that represents a Telegram Bot Access Settings."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class BotAccessSettings(TelegramObject):
"""
@@ -67,11 +63,3 @@ class BotAccessSettings(TelegramObject):
self._id_attrs = (self.is_access_restricted, self.added_users)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BotAccessSettings":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["added_users"] = de_list_optional(data.get("added_users"), User, bot)
return super().de_json(data=data, bot=bot)
+14 -37
View File
@@ -19,16 +19,13 @@
# pylint: disable=redefined-builtin
"""This module contains objects representing Telegram bot command scopes."""
from typing import TYPE_CHECKING, Final
from typing import ClassVar, Final
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class BotCommandScope(TelegramObject):
"""Base class for objects that represent the scope to which bot commands are applied.
@@ -62,6 +59,19 @@ class BotCommandScope(TelegramObject):
__slots__ = ("type",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"default": "BotCommandScopeDefault",
"all_private_chats": "BotCommandScopeAllPrivateChats",
"all_group_chats": "BotCommandScopeAllGroupChats",
"all_chat_administrators": "BotCommandScopeAllChatAdministrators",
"chat": "BotCommandScopeChat",
"chat_administrators": "BotCommandScopeChatAdministrators",
"chat_member": "BotCommandScopeChatMember",
},
)
DEFAULT: Final[str] = constants.BotCommandScopeType.DEFAULT
""":const:`telegram.constants.BotCommandScopeType.DEFAULT`"""
ALL_PRIVATE_CHATS: Final[str] = constants.BotCommandScopeType.ALL_PRIVATE_CHATS
@@ -84,39 +94,6 @@ class BotCommandScope(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BotCommandScope":
"""Converts JSON data to the appropriate :class:`BotCommandScope` object, i.e. takes
care of selecting the correct subclass.
Args:
data (dict[:obj:`str`, ...]): The JSON data.
bot (:class:`telegram.Bot`, optional): The bot associated with this object. Defaults to
:obj:`None`, in which case shortcut methods will not be available.
.. versionchanged:: 21.4
:paramref:`bot` is now optional and defaults to :obj:`None`
Returns:
The Telegram object.
"""
data = cls._parse_data(data)
_class_mapping: dict[str, type[BotCommandScope]] = {
cls.DEFAULT: BotCommandScopeDefault,
cls.ALL_PRIVATE_CHATS: BotCommandScopeAllPrivateChats,
cls.ALL_GROUP_CHATS: BotCommandScopeAllGroupChats,
cls.ALL_CHAT_ADMINISTRATORS: BotCommandScopeAllChatAdministrators,
cls.CHAT: BotCommandScopeChat,
cls.CHAT_ADMINISTRATORS: BotCommandScopeChatAdministrators,
cls.CHAT_MEMBER: BotCommandScopeChatMember,
}
if cls is BotCommandScope and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
return super().de_json(data=data, bot=bot)
class BotCommandScopeDefault(BotCommandScope):
"""Represents the default scope of bot commands. Default commands are used if no commands with
+2 -59
View File
@@ -25,24 +25,19 @@ from typing import TYPE_CHECKING
from zoneinfo import ZoneInfo
from telegram._chat import Chat
from telegram._files.location import Location
from telegram._files.sticker import Sticker
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import (
de_json_optional,
de_list_optional,
parse_sequence_arg,
)
from telegram._utils.datetime import (
extract_tzinfo_from_defaults,
from_timestamp,
get_zone_info,
)
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
from telegram._files.location import Location
from telegram._user import User
class BusinessBotRights(TelegramObject):
@@ -266,20 +261,6 @@ class BusinessConnection(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BusinessConnection":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
data["user"] = de_json_optional(data.get("user"), User, bot)
data["rights"] = de_json_optional(data.get("rights"), BusinessBotRights, bot)
return super().de_json(data=data, bot=bot)
class BusinessMessagesDeleted(TelegramObject):
"""
@@ -333,15 +314,6 @@ class BusinessMessagesDeleted(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BusinessMessagesDeleted":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
return super().de_json(data=data, bot=bot)
class BusinessIntro(TelegramObject):
"""
@@ -387,15 +359,6 @@ class BusinessIntro(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BusinessIntro":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
return super().de_json(data=data, bot=bot)
class BusinessLocation(TelegramObject):
"""
@@ -436,15 +399,6 @@ class BusinessLocation(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BusinessLocation":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["location"] = de_json_optional(data.get("location"), Location, bot)
return super().de_json(data=data, bot=bot)
class BusinessOpeningHoursInterval(TelegramObject):
"""
@@ -678,14 +632,3 @@ class BusinessOpeningHours(TelegramObject):
return True
return False
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BusinessOpeningHours":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["opening_hours"] = de_list_optional(
data.get("opening_hours"), BusinessOpeningHoursInterval, bot
)
return super().de_json(data=data, bot=bot)
-12
View File
@@ -27,13 +27,11 @@ from telegram._inputchecklist import InputChecklist
from telegram._message import MaybeInaccessibleMessage, Message
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput, TimePeriod
if TYPE_CHECKING:
from telegram import (
Bot,
GameHighScore,
InlineKeyboardMarkup,
InputMedia,
@@ -153,16 +151,6 @@ class CallbackQuery(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "CallbackQuery":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
data["message"] = de_json_optional(data.get("message"), Message, bot)
return super().de_json(data=data, bot=bot)
async def answer(
self,
text: str | None = None,
+21 -53
View File
@@ -19,18 +19,15 @@
"""This module contains objects related to chat backgrounds."""
from collections.abc import Sequence
from typing import TYPE_CHECKING, Final
from typing import ClassVar, Final
from telegram import constants
from telegram._files.document import Document
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class BackgroundFill(TelegramObject):
"""Base class for Telegram BackgroundFill Objects. It can be one of:
@@ -57,6 +54,15 @@ class BackgroundFill(TelegramObject):
__slots__ = ("type",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"solid": "BackgroundFillSolid",
"gradient": "BackgroundFillGradient",
"freeform_gradient": "BackgroundFillFreeformGradient",
},
)
SOLID: Final[constants.BackgroundFillType] = constants.BackgroundFillType.SOLID
""":const:`telegram.constants.BackgroundFillType.SOLID`"""
GRADIENT: Final[constants.BackgroundFillType] = constants.BackgroundFillType.GRADIENT
@@ -79,22 +85,6 @@ class BackgroundFill(TelegramObject):
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BackgroundFill":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
_class_mapping: dict[str, type[BackgroundFill]] = {
cls.SOLID: BackgroundFillSolid,
cls.GRADIENT: BackgroundFillGradient,
cls.FREEFORM_GRADIENT: BackgroundFillFreeformGradient,
}
if cls is BackgroundFill and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
return super().de_json(data=data, bot=bot)
class BackgroundFillSolid(BackgroundFill):
"""
@@ -243,6 +233,16 @@ class BackgroundType(TelegramObject):
__slots__ = ("type",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"fill": "BackgroundTypeFill",
"wallpaper": "BackgroundTypeWallpaper",
"pattern": "BackgroundTypePattern",
"chat_theme": "BackgroundTypeChatTheme",
},
)
FILL: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.FILL
""":const:`telegram.constants.BackgroundTypeType.FILL`"""
WALLPAPER: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.WALLPAPER
@@ -265,29 +265,6 @@ class BackgroundType(TelegramObject):
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "BackgroundType":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
_class_mapping: dict[str, type[BackgroundType]] = {
cls.FILL: BackgroundTypeFill,
cls.WALLPAPER: BackgroundTypeWallpaper,
cls.PATTERN: BackgroundTypePattern,
cls.CHAT_THEME: BackgroundTypeChatTheme,
}
if cls is BackgroundType and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
if "fill" in data:
data["fill"] = de_json_optional(data.get("fill"), BackgroundFill, bot)
if "document" in data:
data["document"] = de_json_optional(data.get("document"), Document, bot)
return super().de_json(data=data, bot=bot)
class BackgroundTypeFill(BackgroundType):
"""
@@ -522,12 +499,3 @@ class ChatBackground(TelegramObject):
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatBackground":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["type"] = de_json_optional(data.get("type"), BackgroundType, bot)
return super().de_json(data=data, bot=bot)
+11 -68
View File
@@ -20,20 +20,16 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING, Final
from typing import ClassVar, Final
from telegram import constants
from telegram._chat import Chat
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class ChatBoostAdded(TelegramObject):
"""
@@ -94,6 +90,15 @@ class ChatBoostSource(TelegramObject):
__slots__ = ("source",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"source",
{
"premium": "ChatBoostSourcePremium",
"gift_code": "ChatBoostSourceGiftCode",
"giveaway": "ChatBoostSourceGiveaway",
},
)
PREMIUM: Final[str] = constants.ChatBoostSources.PREMIUM
""":const:`telegram.constants.ChatBoostSources.PREMIUM`"""
GIFT_CODE: Final[str] = constants.ChatBoostSources.GIFT_CODE
@@ -110,25 +115,6 @@ class ChatBoostSource(TelegramObject):
self._id_attrs = (self.source,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatBoostSource":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
_class_mapping: dict[str, type[ChatBoostSource]] = {
cls.PREMIUM: ChatBoostSourcePremium,
cls.GIFT_CODE: ChatBoostSourceGiftCode,
cls.GIVEAWAY: ChatBoostSourceGiveaway,
}
if cls is ChatBoostSource and data.get("source") in _class_mapping:
return _class_mapping[data.pop("source")].de_json(data=data, bot=bot)
if "user" in data:
data["user"] = de_json_optional(data.get("user"), User, bot)
return super().de_json(data=data, bot=bot)
class ChatBoostSourcePremium(ChatBoostSource):
"""
@@ -285,18 +271,6 @@ class ChatBoost(TelegramObject):
self._id_attrs = (self.boost_id, self.add_date, self.expiration_date, self.source)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatBoost":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["source"] = de_json_optional(data.get("source"), ChatBoostSource, bot)
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["add_date"] = from_timestamp(data.get("add_date"), tzinfo=loc_tzinfo)
data["expiration_date"] = from_timestamp(data.get("expiration_date"), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
class ChatBoostUpdated(TelegramObject):
"""This object represents a boost added to a chat or changed.
@@ -332,16 +306,6 @@ class ChatBoostUpdated(TelegramObject):
self._id_attrs = (self.chat.id, self.boost)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatBoostUpdated":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["boost"] = de_json_optional(data.get("boost"), ChatBoost, bot)
return super().de_json(data=data, bot=bot)
class ChatBoostRemoved(TelegramObject):
"""
@@ -386,18 +350,6 @@ class ChatBoostRemoved(TelegramObject):
self._id_attrs = (self.chat, self.boost_id, self.remove_date, self.source)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatBoostRemoved":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["source"] = de_json_optional(data.get("source"), ChatBoostSource, bot)
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["remove_date"] = from_timestamp(data.get("remove_date"), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
class UserChatBoosts(TelegramObject):
"""This object represents a list of boosts added to a chat by a user.
@@ -429,12 +381,3 @@ class UserChatBoosts(TelegramObject):
self._id_attrs = (self.boosts,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UserChatBoosts":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["boosts"] = de_list_optional(data.get("boosts"), ChatBoost, bot)
return super().de_json(data=data, bot=bot)
+1 -54
View File
@@ -34,20 +34,16 @@ from telegram._reaction import ReactionType
from telegram._uniquegift import UniqueGiftColors
from telegram._userrating import UserRating
from telegram._utils.argumentparsing import (
de_json_optional,
de_list_optional,
parse_sequence_arg,
to_timedelta,
)
from telegram._utils.datetime import (
extract_tzinfo_from_defaults,
from_timestamp,
get_timedelta_value,
)
from telegram._utils.types import JSONDict, TimePeriod
if TYPE_CHECKING:
from telegram import Bot, BusinessIntro, BusinessLocation, BusinessOpeningHours, Message
from telegram import BusinessIntro, BusinessLocation, BusinessOpeningHours, Message
class ChatFullInfo(_ChatBase):
@@ -623,52 +619,3 @@ class ChatFullInfo(_ChatBase):
return get_timedelta_value(
self._message_auto_delete_time, attribute="message_auto_delete_time"
)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatFullInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["emoji_status_expiration_date"] = from_timestamp(
data.get("emoji_status_expiration_date"), tzinfo=loc_tzinfo
)
data["photo"] = de_json_optional(data.get("photo"), ChatPhoto, bot)
data["accepted_gift_types"] = de_json_optional(
data.get("accepted_gift_types"), AcceptedGiftTypes, bot
)
from telegram import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
BusinessIntro,
BusinessLocation,
BusinessOpeningHours,
Message,
)
data["pinned_message"] = de_json_optional(data.get("pinned_message"), Message, bot)
data["permissions"] = de_json_optional(data.get("permissions"), ChatPermissions, bot)
data["location"] = de_json_optional(data.get("location"), ChatLocation, bot)
data["available_reactions"] = de_list_optional(
data.get("available_reactions"), ReactionType, bot
)
data["birthdate"] = de_json_optional(data.get("birthdate"), Birthdate, bot)
data["personal_chat"] = de_json_optional(data.get("personal_chat"), Chat, bot)
data["business_intro"] = de_json_optional(data.get("business_intro"), BusinessIntro, bot)
data["business_location"] = de_json_optional(
data.get("business_location"), BusinessLocation, bot
)
data["business_opening_hours"] = de_json_optional(
data.get("business_opening_hours"), BusinessOpeningHours, bot
)
data["parent_chat"] = de_json_optional(data.get("parent_chat"), Chat, bot)
data["rating"] = de_json_optional(data.get("rating"), UserRating, bot)
data["unique_gift_colors"] = de_json_optional(
data.get("unique_gift_colors"), UniqueGiftColors, bot
)
data["first_profile_audio"] = de_json_optional(data.get("first_profile_audio"), Audio, bot)
return super().de_json(data=data, bot=bot)
+2 -23
View File
@@ -19,21 +19,13 @@
"""This module contains an object that represents an invite link for a chat."""
import datetime as dtm
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional, to_timedelta
from telegram._utils.datetime import (
extract_tzinfo_from_defaults,
from_timestamp,
get_timedelta_value,
)
from telegram._utils.argumentparsing import to_timedelta
from telegram._utils.datetime import get_timedelta_value
from telegram._utils.types import JSONDict, TimePeriod
if TYPE_CHECKING:
from telegram import Bot
class ChatInviteLink(TelegramObject):
"""This object represents an invite link for a chat.
@@ -191,16 +183,3 @@ class ChatInviteLink(TelegramObject):
@property
def subscription_period(self) -> int | dtm.timedelta | None:
return get_timedelta_value(self._subscription_period, attribute="subscription_period")
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatInviteLink":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["creator"] = de_json_optional(data.get("creator"), User, bot)
data["expire_date"] = from_timestamp(data.get("expire_date", None), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
-21
View File
@@ -19,20 +19,14 @@
"""This module contains an object that represents a Telegram ChatJoinRequest."""
import datetime as dtm
from typing import TYPE_CHECKING
from telegram._chat import Chat
from telegram._chatinvitelink import ChatInviteLink
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING:
from telegram import Bot
class ChatJoinRequest(TelegramObject):
"""This object represents a join request sent to a chat.
@@ -130,21 +124,6 @@ class ChatJoinRequest(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatJoinRequest":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo)
data["invite_link"] = de_json_optional(data.get("invite_link"), ChatInviteLink, bot)
return super().de_json(data=data, bot=bot)
async def approve(
self,
*,
+1 -14
View File
@@ -18,17 +18,13 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a location to which a chat is connected."""
from typing import TYPE_CHECKING, Final
from typing import Final
from telegram import constants
from telegram._files.location import Location
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class ChatLocation(TelegramObject):
"""This object represents a location to which a chat is connected.
@@ -68,15 +64,6 @@ class ChatLocation(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatLocation":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["location"] = de_json_optional(data.get("location"), Location, bot)
return super().de_json(data=data, bot=bot)
MIN_ADDRESS: Final[int] = constants.LocationLimit.MIN_CHAT_LOCATION_ADDRESS
""":const:`telegram.constants.LocationLimit.MIN_CHAT_LOCATION_ADDRESS`
+15 -38
View File
@@ -19,19 +19,14 @@
"""This module contains an object that represents a Telegram ChatMember."""
import datetime as dtm
from typing import TYPE_CHECKING, Final
from typing import ClassVar, Final
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class ChatMember(TelegramObject):
"""Base class for Telegram ChatMember Objects.
@@ -77,6 +72,18 @@ class ChatMember(TelegramObject):
__slots__ = ("status", "user")
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"status",
{
"creator": "ChatMemberOwner",
"administrator": "ChatMemberAdministrator",
"member": "ChatMemberMember",
"restricted": "ChatMemberRestricted",
"left": "ChatMemberLeft",
"kicked": "ChatMemberBanned",
},
)
ADMINISTRATOR: Final[str] = constants.ChatMemberStatus.ADMINISTRATOR
""":const:`telegram.constants.ChatMemberStatus.ADMINISTRATOR`"""
OWNER: Final[str] = constants.ChatMemberStatus.OWNER
@@ -106,38 +113,6 @@ class ChatMember(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatMember":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
_class_mapping: dict[str, type[ChatMember]] = {
cls.OWNER: ChatMemberOwner,
cls.ADMINISTRATOR: ChatMemberAdministrator,
cls.MEMBER: ChatMemberMember,
cls.RESTRICTED: ChatMemberRestricted,
cls.LEFT: ChatMemberLeft,
cls.BANNED: ChatMemberBanned,
}
if cls is ChatMember and data.get("status") in _class_mapping:
return _class_mapping[data.pop("status")].de_json(data=data, bot=bot)
data["user"] = de_json_optional(data.get("user"), User, bot)
if "until_date" in data:
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["until_date"] = from_timestamp(data.get("until_date"), tzinfo=loc_tzinfo)
# This is a deprecated field that TG still returns for backwards compatibility
# Let's filter it out to speed up the de-json process
if cls is ChatMemberRestricted and data.get("can_send_media_messages") is not None:
api_kwargs = {"can_send_media_messages": data.pop("can_send_media_messages")}
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
return super().de_json(data=data, bot=bot)
class ChatMemberOwner(ChatMember):
"""
@@ -611,6 +586,8 @@ class ChatMemberRestricted(ChatMember):
"until_date",
)
__REMOVED_API_FIELDS__: ClassVar[frozenset[str]] = frozenset({"can_send_media_messages"})
def __init__(
self,
user: User,
-23
View File
@@ -19,20 +19,14 @@
"""This module contains an object that represents a Telegram ChatMemberUpdated."""
import datetime as dtm
from typing import TYPE_CHECKING
from telegram._chat import Chat
from telegram._chatinvitelink import ChatInviteLink
from telegram._chatmember import ChatMember
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class ChatMemberUpdated(TelegramObject):
"""This object represents changes in the status of a chat member.
@@ -142,23 +136,6 @@ class ChatMemberUpdated(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatMemberUpdated":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
data["old_chat_member"] = de_json_optional(data.get("old_chat_member"), ChatMember, bot)
data["new_chat_member"] = de_json_optional(data.get("new_chat_member"), ChatMember, bot)
data["invite_link"] = de_json_optional(data.get("invite_link"), ChatInviteLink, bot)
return super().de_json(data=data, bot=bot)
def _get_attribute_difference(self, attribute: str) -> tuple[object, object]:
try:
old = self.old_chat_member[attribute]
-24
View File
@@ -18,16 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a chat owner change in the chat."""
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class ChatOwnerChanged(TelegramObject):
"""This object represents a service message about an ownership change in the chat.
@@ -60,15 +54,6 @@ class ChatOwnerChanged(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatOwnerChanged":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["new_owner"] = de_json_optional(data.get("new_owner"), User, bot)
return super().de_json(data=data, bot=bot)
class ChatOwnerLeft(TelegramObject):
"""This object represents a service message about the chat owner leaving the chat.
@@ -102,12 +87,3 @@ class ChatOwnerLeft(TelegramObject):
self._id_attrs = (self.new_owner,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatOwnerLeft":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["new_owner"] = de_json_optional(data.get("new_owner"), User, bot)
return super().de_json(data=data, bot=bot)
+6 -18
View File
@@ -18,14 +18,9 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram ChatPermission."""
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class ChatPermissions(TelegramObject):
"""Describes actions that a non-administrator user is allowed to take in a chat.
@@ -178,6 +173,12 @@ class ChatPermissions(TelegramObject):
"can_send_voice_notes",
)
__REMOVED_API_FIELDS__ = frozenset(
{
"can_send_media_messages",
}
)
def __init__(
self,
can_send_messages: bool | None = None,
@@ -260,16 +261,3 @@ class ChatPermissions(TelegramObject):
.. versionadded:: 20.0
"""
return cls(*(False,) * len(cls.__slots__))
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatPermissions":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
api_kwargs = {}
# This is a deprecated field that TG still returns for backwards compatibility
# Let's filter it out to speed up the de-json process
if data.get("can_send_media_messages") is not None:
api_kwargs["can_send_media_messages"] = data.pop("can_send_media_messages")
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
+5 -61
View File
@@ -20,20 +20,18 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING
from telegram._chat import Chat
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.entities import parse_message_entities, parse_message_entity
from telegram._utils.types import JSONDict
from telegram.constants import ZERO_DATE
if TYPE_CHECKING:
from telegram import Bot, Message
from telegram import Message
class ChecklistTask(TelegramObject):
@@ -112,25 +110,6 @@ class ChecklistTask(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChecklistTask":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
if (date := data.get("completion_date")) == 0:
data["completion_date"] = ZERO_DATE
else:
data["completion_date"] = from_timestamp(date, tzinfo=loc_tzinfo)
data["completed_by_user"] = de_json_optional(data.get("completed_by_user"), User, bot)
data["completed_by_chat"] = de_json_optional(data.get("completed_by_chat"), Chat, bot)
data["text_entities"] = de_list_optional(data.get("text_entities"), MessageEntity, bot)
return super().de_json(data=data, bot=bot)
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`text`
from a given :class:`telegram.MessageEntity` of :attr:`text_entities`.
@@ -231,16 +210,6 @@ class Checklist(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Checklist":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["title_entities"] = de_list_optional(data.get("title_entities"), MessageEntity, bot)
data["tasks"] = de_list_optional(data.get("tasks"), ChecklistTask, bot)
return super().de_json(data=data, bot=bot)
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`title`
from a given :class:`telegram.MessageEntity` of :attr:`title_entities`.
@@ -321,7 +290,7 @@ class ChecklistTasksDone(TelegramObject):
def __init__(
self,
checklist_message: Optional["Message"] = None,
checklist_message: "Message | None" = None,
marked_as_done_task_ids: Sequence[int] | None = None,
marked_as_not_done_task_ids: Sequence[int] | None = None,
*,
@@ -338,18 +307,6 @@ class ChecklistTasksDone(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChecklistTasksDone":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# needs to be imported here to avoid circular import issues
from telegram import Message # pylint: disable=import-outside-toplevel # noqa: PLC0415
data["checklist_message"] = de_json_optional(data.get("checklist_message"), Message, bot)
return super().de_json(data=data, bot=bot)
class ChecklistTasksAdded(TelegramObject):
"""
@@ -380,7 +337,7 @@ class ChecklistTasksAdded(TelegramObject):
def __init__(
self,
tasks: Sequence[ChecklistTask],
checklist_message: Optional["Message"] = None,
checklist_message: "Message | None" = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -391,16 +348,3 @@ class ChecklistTasksAdded(TelegramObject):
self._id_attrs = (self.tasks,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChecklistTasksAdded":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# needs to be imported here to avoid circular import issues
from telegram import Message # pylint: disable=import-outside-toplevel # noqa: PLC0415
data["checklist_message"] = de_json_optional(data.get("checklist_message"), Message, bot)
data["tasks"] = ChecklistTask.de_list(data.get("tasks", []), bot)
return super().de_json(data=data, bot=bot)
+1 -15
View File
@@ -21,14 +21,12 @@
from typing import TYPE_CHECKING
from telegram._files.location import Location
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
from telegram._files.location import Location
class ChosenInlineResult(TelegramObject):
@@ -91,15 +89,3 @@ class ChosenInlineResult(TelegramObject):
self._id_attrs = (self.result_id,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChosenInlineResult":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Required
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
# Optionals
data["location"] = de_json_optional(data.get("location"), Location, bot)
return super().de_json(data=data, bot=bot)
-15
View File
@@ -18,16 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the DirectMessagesTopic class."""
from typing import TYPE_CHECKING, Optional
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram._bot import Bot
class DirectMessagesTopic(TelegramObject):
"""
@@ -75,12 +69,3 @@ class DirectMessagesTopic(TelegramObject):
self._id_attrs = (self.topic_id, self.user)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "DirectMessagesTopic":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["user"] = de_json_optional(data.get("user"), User, bot)
return super().de_json(data=data, bot=bot)
-1
View File
@@ -48,7 +48,6 @@ class _BaseMedium(TelegramObject):
Can't be used to download or reuse the file.
file_size (:obj:`int`): Optional. File size.
"""
__slots__ = ("file_id", "file_size", "file_unique_id")
+6 -22
View File
@@ -18,16 +18,12 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Common base class for media objects with thumbnails"""
from typing import TYPE_CHECKING, TypeVar
from typing import TypeVar
from telegram._files._basemedium import _BaseMedium
from telegram._files.photosize import PhotoSize
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
# pylint: disable=invalid-name
ThumbedMT_co = TypeVar("ThumbedMT_co", bound="_BaseThumbedMedium", covariant=True)
@@ -63,6 +59,11 @@ class _BaseThumbedMedium(_BaseMedium):
"""
__slots__ = ("thumbnail",)
__REMOVED_API_FIELDS__ = frozenset(
{
"thumb",
}
)
def __init__(
self,
@@ -81,20 +82,3 @@ class _BaseThumbedMedium(_BaseMedium):
)
self.thumbnail: PhotoSize | None = thumbnail
@classmethod
def de_json(cls: type[ThumbedMT_co], data: JSONDict, bot: "Bot | None" = None) -> ThumbedMT_co:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# In case this wasn't already done by the subclass
if not isinstance(data.get("thumbnail"), PhotoSize):
data["thumbnail"] = de_json_optional(data.get("thumbnail"), PhotoSize, bot)
api_kwargs = {}
# This is a deprecated field that TG still returns for backwards compatibility
# Let's filter it out to speed up the de-json process
if data.get("thumb") is not None:
api_kwargs["thumb"] = data.pop("thumb")
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
+1 -12
View File
@@ -23,14 +23,12 @@ from typing import TYPE_CHECKING
from telegram._files._basemedium import _BaseMedium
from telegram._files.photosize import PhotoSize
from telegram._utils.argumentparsing import de_list_optional, parse_sequence_arg, to_timedelta
from telegram._utils.argumentparsing import parse_sequence_arg, to_timedelta
from telegram._utils.types import JSONDict, TimePeriod
if TYPE_CHECKING:
import datetime as dtm
from telegram import Bot
class LivePhoto(_BaseMedium):
"""
@@ -108,12 +106,3 @@ class LivePhoto(_BaseMedium):
# Optional
self.photo: Sequence[PhotoSize] | None = parse_sequence_arg(photo)
self.mime_type: str | None = mime_type
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "LivePhoto":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
return super().de_json(data=data, bot=bot)
+8 -37
View File
@@ -23,15 +23,14 @@ from typing import TYPE_CHECKING, Final
from telegram import constants
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.file import File
from telegram._files.photosize import PhotoSize
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
from telegram._files.file import File
class Sticker(_BaseThumbedMedium):
@@ -144,6 +143,11 @@ class Sticker(_BaseThumbedMedium):
"type",
"width",
)
__REMOVED_API_FIELDS__ = frozenset(
{
"thumb",
}
)
def __init__(
self,
@@ -194,23 +198,6 @@ class Sticker(_BaseThumbedMedium):
CUSTOM_EMOJI: Final[str] = constants.StickerType.CUSTOM_EMOJI
""":const:`telegram.constants.StickerType.CUSTOM_EMOJI`"""
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Sticker":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["thumbnail"] = de_json_optional(data.get("thumbnail"), PhotoSize, bot)
data["mask_position"] = de_json_optional(data.get("mask_position"), MaskPosition, bot)
data["premium_animation"] = de_json_optional(data.get("premium_animation"), File, bot)
api_kwargs = {}
# This is a deprecated field that TG still returns for backwards compatibility
# Let's filter it out to speed up the de-json process
if data.get("thumb") is not None:
api_kwargs["thumb"] = data.pop("thumb")
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
class StickerSet(TelegramObject):
"""This object represents a sticker set.
@@ -281,6 +268,7 @@ class StickerSet(TelegramObject):
"thumbnail",
"title",
)
__REMOVED_API_FIELDS__ = frozenset({"contains_masks", "is_animated", "is_video", "thumb"})
def __init__(
self,
@@ -303,23 +291,6 @@ class StickerSet(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "StickerSet":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["thumbnail"] = de_json_optional(data.get("thumbnail"), PhotoSize, bot)
data["stickers"] = de_list_optional(data.get("stickers"), Sticker, bot)
api_kwargs: JSONDict = {}
# These are deprecated fields that TG still returns for backwards compatibility
# Let's filter them out to speed up the de-json process
for deprecated_field in ("contains_masks", "thumb", "is_animated", "is_video"):
if deprecated_field in data:
api_kwargs[deprecated_field] = data.pop(deprecated_field)
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
class MaskPosition(TelegramObject):
"""This object describes the position on faces where a mask should be placed by default.
-15
View File
@@ -18,16 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Venue."""
from typing import TYPE_CHECKING
from telegram._files.location import Location
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class Venue(TelegramObject):
"""This object represents a venue.
@@ -102,12 +96,3 @@ class Venue(TelegramObject):
self._id_attrs = (self.location, self.title)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Venue":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["location"] = de_json_optional(data.get("location"), Location, bot)
return super().de_json(data=data, bot=bot)
+1 -15
View File
@@ -20,18 +20,14 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.photosize import PhotoSize
from telegram._files.videoquality import VideoQuality
from telegram._utils.argumentparsing import de_list_optional, parse_sequence_arg, to_timedelta
from telegram._utils.argumentparsing import parse_sequence_arg, to_timedelta
from telegram._utils.datetime import get_timedelta_value
from telegram._utils.types import JSONDict, TimePeriod
if TYPE_CHECKING:
from telegram import Bot
class Video(_BaseThumbedMedium):
"""This object represents a video file.
@@ -167,13 +163,3 @@ class Video(_BaseThumbedMedium):
@property
def start_timestamp(self) -> dtm.timedelta | None | int:
return get_timedelta_value(self._start_timestamp, attribute="start_timestamp")
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Video":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["cover"] = de_list_optional(data.get("cover"), PhotoSize, bot)
data["qualities"] = de_list_optional(data.get("qualities"), VideoQuality, bot)
return super().de_json(data=data, bot=bot)
+1 -16
View File
@@ -19,19 +19,15 @@
"""This module contains an object that represents a Telegram Game."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._files.animation import Animation
from telegram._files.photosize import PhotoSize
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.strings import TextEncoding
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class Game(TelegramObject):
"""
@@ -124,17 +120,6 @@ class Game(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Game":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
data["text_entities"] = de_list_optional(data.get("text_entities"), MessageEntity, bot)
data["animation"] = de_json_optional(data.get("animation"), Animation, bot)
return super().de_json(data=data, bot=bot)
def parse_text_entity(self, entity: MessageEntity) -> str:
"""Returns the text from a given :class:`telegram.MessageEntity`.
-15
View File
@@ -18,16 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram GameHighScore."""
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class GameHighScore(TelegramObject):
"""This object represents one row of the high scores table for a game.
@@ -60,12 +54,3 @@ class GameHighScore(TelegramObject):
self._id_attrs = (self.position, self.user, self.score)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "GameHighScore":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["user"] = de_json_optional(data.get("user"), User, bot)
return super().de_json(data=data, bot=bot)
+1 -33
View File
@@ -20,19 +20,15 @@
"""This module contains classes related to gifs sent by bots."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._chat import Chat
from telegram._files.sticker import Sticker
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.entities import parse_message_entities, parse_message_entity
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class GiftBackground(TelegramObject):
"""This object describes the background of a gift.
@@ -228,16 +224,6 @@ class Gift(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Gift":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
data["publisher_chat"] = de_json_optional(data.get("publisher_chat"), Chat, bot)
data["background"] = de_json_optional(data.get("background"), GiftBackground, bot)
return super().de_json(data=data, bot=bot)
class Gifts(TelegramObject):
"""This object represent a list of gifts.
@@ -270,14 +256,6 @@ class Gifts(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Gifts":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["gifts"] = de_list_optional(data.get("gifts"), Gift, bot)
return super().de_json(data=data, bot=bot)
class GiftInfo(TelegramObject):
"""Describes a service message about a regular gift that was sent or received.
@@ -385,16 +363,6 @@ class GiftInfo(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "GiftInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["gift"] = de_json_optional(data.get("gift"), Gift, bot)
data["entities"] = de_list_optional(data.get("entities"), MessageEntity, bot)
return super().de_json(data=data, bot=bot)
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`text`
from a given :class:`telegram.MessageEntity` of :attr:`entities`.
+2 -48
View File
@@ -25,12 +25,11 @@ from typing import TYPE_CHECKING
from telegram._chat import Chat
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot, Message
from telegram import Message
class Giveaway(TelegramObject):
@@ -137,21 +136,6 @@ class Giveaway(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Giveaway":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["chats"] = de_list_optional(data.get("chats"), Chat, bot)
data["winners_selection_date"] = from_timestamp(
data.get("winners_selection_date"), tzinfo=loc_tzinfo
)
return super().de_json(data=data, bot=bot)
class GiveawayCreated(TelegramObject):
"""This object represents a service message about the creation of a scheduled giveaway.
@@ -292,22 +276,6 @@ class GiveawayWinners(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "GiveawayWinners":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["winners"] = de_list_optional(data.get("winners"), User, bot)
data["winners_selection_date"] = from_timestamp(
data.get("winners_selection_date"), tzinfo=loc_tzinfo
)
return super().de_json(data=data, bot=bot)
class GiveawayCompleted(TelegramObject):
"""This object represents a service message about the completion of a giveaway without public
@@ -363,17 +331,3 @@ class GiveawayCompleted(TelegramObject):
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "GiveawayCompleted":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Unfortunately, this needs to be here due to cyclic imports
from telegram._message import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
Message,
)
data["giveaway_message"] = de_json_optional(data.get("giveaway_message"), Message, bot)
return super().de_json(data=data, bot=bot)
+1 -20
View File
@@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram InlineKeyboardButton."""
from typing import TYPE_CHECKING, Final
from typing import Final
from telegram import constants
from telegram._copytextbutton import CopyTextButton
@@ -26,13 +26,9 @@ from telegram._games.callbackgame import CallbackGame
from telegram._loginurl import LoginUrl
from telegram._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
from telegram._webappinfo import WebAppInfo
if TYPE_CHECKING:
from telegram import Bot
class InlineKeyboardButton(TelegramObject):
"""This object represents one button of an inline keyboard.
@@ -344,21 +340,6 @@ class InlineKeyboardButton(TelegramObject):
self.icon_custom_emoji_id,
)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "InlineKeyboardButton":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["login_url"] = de_json_optional(data.get("login_url"), LoginUrl, bot)
data["web_app"] = de_json_optional(data.get("web_app"), WebAppInfo, bot)
data["callback_game"] = de_json_optional(data.get("callback_game"), CallbackGame, bot)
data["switch_inline_query_chosen_chat"] = de_json_optional(
data.get("switch_inline_query_chosen_chat"), SwitchInlineQueryChosenChat, bot
)
data["copy_text"] = de_json_optional(data.get("copy_text"), CopyTextButton, bot)
return super().de_json(data=data, bot=bot)
def update_callback_data(self, callback_data: str | object) -> None:
"""
Sets :attr:`callback_data` to the passed object. Intended to be used by
@@ -19,16 +19,12 @@
"""This module contains an object that represents a Telegram InlineKeyboardMarkup."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton
from telegram._telegramobject import TelegramObject
from telegram._utils.markup import check_keyboard_type
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class InlineKeyboardMarkup(TelegramObject):
"""
@@ -91,21 +87,6 @@ class InlineKeyboardMarkup(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "InlineKeyboardMarkup":
"""See :meth:`telegram.TelegramObject.de_json`."""
keyboard = []
for row in data["inline_keyboard"]:
tmp = []
for col in row:
btn = InlineKeyboardButton.de_json(col, bot)
if btn:
tmp.append(btn)
keyboard.append(tmp)
return cls(keyboard)
@classmethod
def from_button(cls, button: InlineKeyboardButton, **kwargs: object) -> "InlineKeyboardMarkup":
"""Shortcut for::
+2 -13
View File
@@ -23,16 +23,15 @@ from collections.abc import Callable, Sequence
from typing import TYPE_CHECKING, Final
from telegram import constants
from telegram._files.location import Location
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput, TimePeriod
if TYPE_CHECKING:
from telegram import Bot, InlineQueryResult
from telegram import InlineQueryResult
from telegram._files.location import Location
class InlineQuery(TelegramObject):
@@ -132,16 +131,6 @@ class InlineQuery(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "InlineQuery":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
data["location"] = de_json_optional(data.get("location"), Location, bot)
return super().de_json(data=data, bot=bot)
async def answer(
self,
results: (
@@ -18,17 +18,13 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the class that represent a Telegram InlineQueryResultsButton."""
from typing import TYPE_CHECKING, Final
from typing import Final
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
from telegram._webappinfo import WebAppInfo
if TYPE_CHECKING:
from telegram import Bot
class InlineQueryResultsButton(TelegramObject):
"""This object represents a button to be shown above inline query results. You **must** use
@@ -98,14 +94,6 @@ class InlineQueryResultsButton(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "InlineQueryResultsButton":
"""See :meth:`telegram.TelegramObject.de_json`."""
data["web_app"] = de_json_optional(data.get("web_app"), WebAppInfo, bot)
return super().de_json(data=data, bot=bot)
MIN_START_PARAMETER_LENGTH: Final[int] = (
constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH
)
@@ -19,16 +19,12 @@
"""This module contains a class that represents a Telegram InputInvoiceMessageContent."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._inline.inputmessagecontent import InputMessageContent
from telegram._payment.labeledprice import LabeledPrice
from telegram._utils.argumentparsing import de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class InputInvoiceMessageContent(InputMessageContent):
"""
@@ -254,12 +250,3 @@ class InputInvoiceMessageContent(InputMessageContent):
self.currency,
self.prices,
)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "InputInvoiceMessageContent":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["prices"] = de_list_optional(data.get("prices"), LabeledPrice, bot)
return super().de_json(data=data, bot=bot)
@@ -19,15 +19,10 @@
"""This module contains an object that represents a Telegram Prepared inline Message."""
import datetime as dtm
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class PreparedInlineMessage(TelegramObject):
"""Describes an inline message to be sent by a user of a Mini App.
@@ -66,14 +61,3 @@ class PreparedInlineMessage(TelegramObject):
self._id_attrs = (self.id,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PreparedInlineMessage":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["expiration_date"] = from_timestamp(data.get("expiration_date"), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
+6 -33
View File
@@ -18,8 +18,6 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram KeyboardButton."""
from typing import TYPE_CHECKING
from telegram._keyboardbuttonpolltype import KeyboardButtonPollType
from telegram._keyboardbuttonrequest import (
KeyboardButtonRequestChat,
@@ -27,13 +25,9 @@ from telegram._keyboardbuttonrequest import (
KeyboardButtonRequestUsers,
)
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
from telegram._webappinfo import WebAppInfo
if TYPE_CHECKING:
from telegram import Bot
class KeyboardButton(TelegramObject):
"""
@@ -201,6 +195,12 @@ class KeyboardButton(TelegramObject):
"web_app",
)
__REMOVED_API_FIELDS__ = frozenset(
{
"request_user",
}
)
def __init__(
self,
text: str,
@@ -244,30 +244,3 @@ class KeyboardButton(TelegramObject):
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "KeyboardButton":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["request_poll"] = de_json_optional(
data.get("request_poll"), KeyboardButtonPollType, bot
)
data["request_users"] = de_json_optional(
data.get("request_users"), KeyboardButtonRequestUsers, bot
)
data["request_chat"] = de_json_optional(
data.get("request_chat"), KeyboardButtonRequestChat, bot
)
data["web_app"] = de_json_optional(data.get("web_app"), WebAppInfo, bot)
data["request_managed_bot"] = de_json_optional(
data.get("request_managed_bot"), KeyboardButtonRequestManagedBot, bot
)
api_kwargs = {}
# This is a deprecated field that TG still returns for backwards compatibility
# Let's filter it out to speed up the de-json process
if request_user := data.get("request_user"):
api_kwargs = {"request_user": request_user}
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
-20
View File
@@ -18,16 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains two objects to request chats/users."""
from typing import TYPE_CHECKING
from telegram._chatadministratorrights import ChatAdministratorRights
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class KeyboardButtonRequestUsers(TelegramObject):
"""This object defines the criteria used to request a suitable user. The identifier of the
@@ -255,20 +249,6 @@ class KeyboardButtonRequestChat(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "KeyboardButtonRequestChat":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["user_administrator_rights"] = de_json_optional(
data.get("user_administrator_rights"), ChatAdministratorRights, bot
)
data["bot_administrator_rights"] = de_json_optional(
data.get("bot_administrator_rights"), ChatAdministratorRights, bot
)
return super().de_json(data=data, bot=bot)
class KeyboardButtonRequestManagedBot(TelegramObject):
"""
-24
View File
@@ -18,17 +18,12 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects that represent managed bots in the Telegram Bot API."""
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.types import (
JSONDict,
)
if TYPE_CHECKING:
from telegram import Bot
class ManagedBotCreated(TelegramObject):
"""
@@ -61,15 +56,6 @@ class ManagedBotCreated(TelegramObject):
self._id_attrs = (self.bot,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ManagedBotCreated":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data=data)
data["bot"] = User.de_json(data=data["bot"], bot=bot)
return super().de_json(data=data, bot=bot)
class ManagedBotUpdated(TelegramObject):
"""
@@ -111,13 +97,3 @@ class ManagedBotUpdated(TelegramObject):
self.bot,
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ManagedBotUpdated":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data=data)
data["user"] = User.de_json(data=data["user"], bot=bot)
data["bot"] = User.de_json(data=data["bot"], bot=bot)
return super().de_json(data=data, bot=bot)
+10 -43
View File
@@ -18,18 +18,14 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects related to Telegram menu buttons."""
from typing import TYPE_CHECKING, Final
from typing import ClassVar, Final
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
from telegram._webappinfo import WebAppInfo
if TYPE_CHECKING:
from telegram import Bot
class MenuButton(TelegramObject):
"""This object describes the bot's menu button in a private chat. It should be one of
@@ -57,6 +53,15 @@ class MenuButton(TelegramObject):
__slots__ = ("type",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"commands": "MenuButtonCommands",
"web_app": "MenuButtonWebApp",
"default": "MenuButtonDefault",
},
)
def __init__(
self,
type: str,
@@ -70,35 +75,6 @@ class MenuButton(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "MenuButton":
"""Converts JSON data to the appropriate :class:`MenuButton` object, i.e. takes
care of selecting the correct subclass.
Args:
data (dict[:obj:`str`, ...]): The JSON data.
bot (:class:`telegram.Bot`, optional): The bot associated with this object. Defaults to
:obj:`None`, in which case shortcut methods will not be available.
.. versionchanged:: 21.4
:paramref:`bot` is now optional and defaults to :obj:`None`
Returns:
The Telegram object.
"""
data = cls._parse_data(data)
_class_mapping: dict[str, type[MenuButton]] = {
cls.COMMANDS: MenuButtonCommands,
cls.WEB_APP: MenuButtonWebApp,
cls.DEFAULT: MenuButtonDefault,
}
if cls is MenuButton and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data, bot=bot)
return super().de_json(data=data, bot=bot)
COMMANDS: Final[str] = constants.MenuButtonType.COMMANDS
""":const:`telegram.constants.MenuButtonType.COMMANDS`"""
WEB_APP: Final[str] = constants.MenuButtonType.WEB_APP
@@ -165,15 +141,6 @@ class MenuButtonWebApp(MenuButton):
self._id_attrs = (self.type, self.text, self.web_app)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "MenuButtonWebApp":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["web_app"] = de_json_optional(data.get("web_app"), WebAppInfo, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class MenuButtonDefault(MenuButton):
"""Describes that no specific value for the menu button was set.
+23 -239
View File
@@ -23,7 +23,7 @@ import datetime as dtm
import re
from collections.abc import Sequence
from html import escape
from typing import TYPE_CHECKING, TypedDict
from typing import TYPE_CHECKING, ClassVar, TypedDict
from telegram._chat import Chat
from telegram._chatbackground import ChatBackground
@@ -75,8 +75,8 @@ from telegram._story import Story
from telegram._telegramobject import TelegramObject
from telegram._uniquegift import UniqueGiftInfo
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp, to_timestamp
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.datetime import to_timestamp
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
from telegram._utils.entities import parse_message_entities, parse_message_entity
from telegram._utils.strings import TextEncoding
@@ -202,31 +202,20 @@ class MaybeInaccessibleMessage(TelegramObject):
return self.date != ZERO_DATE
@classmethod
def _de_json(
def de_json(
cls,
data: JSONDict | None,
data: JSONDict,
bot: "Bot | None" = None,
api_kwargs: JSONDict | None = None,
) -> "MaybeInaccessibleMessage | None":
) -> "MaybeInaccessibleMessage":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Dispatch *before* the plan runs so that the raw ``date`` value is still
# an integer and can be compared to 0.
if cls is MaybeInaccessibleMessage:
if data["date"] == 0:
data = cls._parse_data(data)
if data.get("date") == 0:
return InaccessibleMessage.de_json(data=data, bot=bot)
return Message.de_json(data=data, bot=bot)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
# this is to include the Literal from InaccessibleMessage
if data["date"] == 0:
data["date"] = ZERO_DATE
else:
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
return super().de_json(data=data, bot=bot)
class InaccessibleMessage(MaybeInaccessibleMessage):
@@ -264,6 +253,18 @@ class InaccessibleMessage(MaybeInaccessibleMessage):
class Message(MaybeInaccessibleMessage):
__REMOVED_API_FIELDS__: ClassVar[frozenset[str]] = frozenset(
{
"user_shared",
"forward_from",
"forward_from_chat",
"forward_from_message_id",
"forward_signature",
"forward_sender_name",
"forward_date",
}
)
# fmt: off
"""This object represents a message.
@@ -1610,223 +1611,6 @@ class Message(MaybeInaccessibleMessage):
return baselink
return None
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Message":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
data["sender_chat"] = de_json_optional(data.get("sender_chat"), Chat, bot)
data["entities"] = de_list_optional(data.get("entities"), MessageEntity, bot)
data["caption_entities"] = de_list_optional(
data.get("caption_entities"), MessageEntity, bot
)
data["reply_to_message"] = de_json_optional(data.get("reply_to_message"), Message, bot)
data["edit_date"] = from_timestamp(data.get("edit_date"), tzinfo=loc_tzinfo)
data["audio"] = de_json_optional(data.get("audio"), Audio, bot)
data["document"] = de_json_optional(data.get("document"), Document, bot)
data["animation"] = de_json_optional(data.get("animation"), Animation, bot)
data["game"] = de_json_optional(data.get("game"), Game, bot)
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
data["story"] = de_json_optional(data.get("story"), Story, bot)
data["video"] = de_json_optional(data.get("video"), Video, bot)
data["voice"] = de_json_optional(data.get("voice"), Voice, bot)
data["video_note"] = de_json_optional(data.get("video_note"), VideoNote, bot)
data["contact"] = de_json_optional(data.get("contact"), Contact, bot)
data["location"] = de_json_optional(data.get("location"), Location, bot)
data["venue"] = de_json_optional(data.get("venue"), Venue, bot)
data["new_chat_members"] = de_list_optional(data.get("new_chat_members"), User, bot)
data["left_chat_member"] = de_json_optional(data.get("left_chat_member"), User, bot)
data["new_chat_photo"] = de_list_optional(data.get("new_chat_photo"), PhotoSize, bot)
data["message_auto_delete_timer_changed"] = de_json_optional(
data.get("message_auto_delete_timer_changed"), MessageAutoDeleteTimerChanged, bot
)
data["pinned_message"] = de_json_optional(
data.get("pinned_message"), MaybeInaccessibleMessage, bot
)
data["invoice"] = de_json_optional(data.get("invoice"), Invoice, bot)
data["successful_payment"] = de_json_optional(
data.get("successful_payment"), SuccessfulPayment, bot
)
data["passport_data"] = de_json_optional(data.get("passport_data"), PassportData, bot)
data["poll"] = de_json_optional(data.get("poll"), Poll, bot)
data["dice"] = de_json_optional(data.get("dice"), Dice, bot)
data["via_bot"] = de_json_optional(data.get("via_bot"), User, bot)
data["proximity_alert_triggered"] = de_json_optional(
data.get("proximity_alert_triggered"), ProximityAlertTriggered, bot
)
data["reply_markup"] = de_json_optional(
data.get("reply_markup"), InlineKeyboardMarkup, bot
)
data["video_chat_scheduled"] = de_json_optional(
data.get("video_chat_scheduled"), VideoChatScheduled, bot
)
data["video_chat_started"] = de_json_optional(
data.get("video_chat_started"), VideoChatStarted, bot
)
data["video_chat_ended"] = de_json_optional(
data.get("video_chat_ended"), VideoChatEnded, bot
)
data["video_chat_participants_invited"] = de_json_optional(
data.get("video_chat_participants_invited"), VideoChatParticipantsInvited, bot
)
data["web_app_data"] = de_json_optional(data.get("web_app_data"), WebAppData, bot)
data["forum_topic_closed"] = de_json_optional(
data.get("forum_topic_closed"), ForumTopicClosed, bot
)
data["forum_topic_created"] = de_json_optional(
data.get("forum_topic_created"), ForumTopicCreated, bot
)
data["forum_topic_reopened"] = de_json_optional(
data.get("forum_topic_reopened"), ForumTopicReopened, bot
)
data["forum_topic_edited"] = de_json_optional(
data.get("forum_topic_edited"), ForumTopicEdited, bot
)
data["general_forum_topic_hidden"] = de_json_optional(
data.get("general_forum_topic_hidden"), GeneralForumTopicHidden, bot
)
data["general_forum_topic_unhidden"] = de_json_optional(
data.get("general_forum_topic_unhidden"), GeneralForumTopicUnhidden, bot
)
data["write_access_allowed"] = de_json_optional(
data.get("write_access_allowed"), WriteAccessAllowed, bot
)
data["users_shared"] = de_json_optional(data.get("users_shared"), UsersShared, bot)
data["chat_shared"] = de_json_optional(data.get("chat_shared"), ChatShared, bot)
data["chat_background_set"] = de_json_optional(
data.get("chat_background_set"), ChatBackground, bot
)
data["paid_media"] = de_json_optional(data.get("paid_media"), PaidMediaInfo, bot)
data["refunded_payment"] = de_json_optional(
data.get("refunded_payment"), RefundedPayment, bot
)
data["gift"] = de_json_optional(data.get("gift"), GiftInfo, bot)
data["unique_gift"] = de_json_optional(data.get("unique_gift"), UniqueGiftInfo, bot)
data["paid_message_price_changed"] = de_json_optional(
data.get("paid_message_price_changed"), PaidMessagePriceChanged, bot
)
# Unfortunately, this needs to be here due to cyclic imports
from telegram._giveaway import ( # pylint: disable=C0415 # noqa: PLC0415
Giveaway,
GiveawayCompleted,
GiveawayCreated,
GiveawayWinners,
)
from telegram._messageorigin import ( # pylint: disable=C0415 # noqa: PLC0415
MessageOrigin,
)
from telegram._reply import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
ExternalReplyInfo,
TextQuote,
)
from telegram._suggestedpost import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
SuggestedPostApprovalFailed,
SuggestedPostApproved,
SuggestedPostDeclined,
SuggestedPostInfo,
SuggestedPostPaid,
SuggestedPostRefunded,
)
data["giveaway"] = de_json_optional(data.get("giveaway"), Giveaway, bot)
data["giveaway_completed"] = de_json_optional(
data.get("giveaway_completed"), GiveawayCompleted, bot
)
data["giveaway_created"] = de_json_optional(
data.get("giveaway_created"), GiveawayCreated, bot
)
data["giveaway_winners"] = de_json_optional(
data.get("giveaway_winners"), GiveawayWinners, bot
)
data["link_preview_options"] = de_json_optional(
data.get("link_preview_options"), LinkPreviewOptions, bot
)
data["external_reply"] = de_json_optional(
data.get("external_reply"), ExternalReplyInfo, bot
)
data["quote"] = de_json_optional(data.get("quote"), TextQuote, bot)
data["forward_origin"] = de_json_optional(data.get("forward_origin"), MessageOrigin, bot)
data["reply_to_story"] = de_json_optional(data.get("reply_to_story"), Story, bot)
data["boost_added"] = de_json_optional(data.get("boost_added"), ChatBoostAdded, bot)
data["sender_business_bot"] = de_json_optional(data.get("sender_business_bot"), User, bot)
data["direct_message_price_changed"] = de_json_optional(
data.get("direct_message_price_changed"), DirectMessagePriceChanged, bot
)
data["checklist"] = de_json_optional(data.get("checklist"), Checklist, bot)
data["checklist_tasks_done"] = de_json_optional(
data.get("checklist_tasks_done"), ChecklistTasksDone, bot
)
data["checklist_tasks_added"] = de_json_optional(
data.get("checklist_tasks_added"), ChecklistTasksAdded, bot
)
data["direct_messages_topic"] = de_json_optional(
data.get("direct_messages_topic"), DirectMessagesTopic, bot
)
data["suggested_post_declined"] = de_json_optional(
data.get("suggested_post_declined"), SuggestedPostDeclined, bot
)
data["suggested_post_paid"] = de_json_optional(
data.get("suggested_post_paid"), SuggestedPostPaid, bot
)
data["suggested_post_refunded"] = de_json_optional(
data.get("suggested_post_refunded"), SuggestedPostRefunded, bot
)
data["suggested_post_info"] = de_json_optional(
data.get("suggested_post_info"), SuggestedPostInfo, bot
)
data["suggested_post_approved"] = de_json_optional(
data.get("suggested_post_approved"), SuggestedPostApproved, bot
)
data["suggested_post_approval_failed"] = de_json_optional(
data.get("suggested_post_approval_failed"), SuggestedPostApprovalFailed, bot
)
data["gift_upgrade_sent"] = de_json_optional(data.get("gift_upgrade_sent"), GiftInfo, bot)
data["chat_owner_changed"] = de_json_optional(
data.get("chat_owner_changed"), ChatOwnerChanged, bot
)
data["chat_owner_left"] = de_json_optional(data.get("chat_owner_left"), ChatOwnerLeft, bot)
data["poll_option_added"] = de_json_optional(
data.get("poll_option_added"), PollOptionAdded, bot
)
data["poll_option_deleted"] = de_json_optional(
data.get("poll_option_deleted"), PollOptionDeleted, bot
)
data["managed_bot_created"] = de_json_optional(
data.get("managed_bot_created"), ManagedBotCreated, bot
)
data["guest_bot_caller_user"] = de_json_optional(
data.get("guest_bot_caller_user"), User, bot
)
data["guest_bot_caller_chat"] = de_json_optional(
data.get("guest_bot_caller_chat"), Chat, bot
)
data["live_photo"] = de_json_optional(data.get("live_photo"), LivePhoto, bot)
api_kwargs = {}
# This is a deprecated field that TG still returns for backwards compatibility
# Let's filter it out to speed up the de-json process
for key in (
"user_shared",
"forward_from",
"forward_from_chat",
"forward_from_message_id",
"forward_signature",
"forward_sender_name",
"forward_date",
):
if entry := data.get(key):
api_kwargs = {key: entry}
return super()._de_json( # type: ignore[return-value]
data=data, bot=bot, api_kwargs=api_kwargs
)
@property
def effective_attachment(
self,
+1 -19
View File
@@ -22,20 +22,15 @@ import copy
import datetime as dtm
import itertools
from collections.abc import Sequence
from typing import TYPE_CHECKING, Final
from typing import Final
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.strings import TextEncoding
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
_SEM = Sequence["MessageEntity"]
@@ -183,19 +178,6 @@ class MessageEntity(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "MessageEntity":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["user"] = de_json_optional(data.get("user"), User, bot)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["unix_time"] = from_timestamp(data.get("unix_time"), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
@staticmethod
def adjust_message_entities_to_utf_16(text: str, entities: _SEM) -> _SEM:
"""Utility functionality for converting the offset and length of entities from
+11 -36
View File
@@ -19,20 +19,15 @@
"""This module contains the classes that represent Telegram MessageOigin."""
import datetime as dtm
from typing import TYPE_CHECKING, Final
from typing import ClassVar, Final
from telegram import constants
from telegram._chat import Chat
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class MessageOrigin(TelegramObject):
"""
@@ -68,6 +63,16 @@ class MessageOrigin(TelegramObject):
"type",
)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"user": "MessageOriginUser",
"hidden_user": "MessageOriginHiddenUser",
"chat": "MessageOriginChat",
"channel": "MessageOriginChannel",
},
)
USER: Final[str] = constants.MessageOriginType.USER
""":const:`telegram.constants.MessageOriginType.USER`"""
HIDDEN_USER: Final[str] = constants.MessageOriginType.HIDDEN_USER
@@ -95,36 +100,6 @@ class MessageOrigin(TelegramObject):
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "MessageOrigin":
"""Converts JSON data to the appropriate :class:`MessageOrigin` object, i.e. takes
care of selecting the correct subclass.
"""
data = cls._parse_data(data)
_class_mapping: dict[str, type[MessageOrigin]] = {
cls.USER: MessageOriginUser,
cls.HIDDEN_USER: MessageOriginHiddenUser,
cls.CHAT: MessageOriginChat,
cls.CHANNEL: MessageOriginChannel,
}
if cls is MessageOrigin and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
if "sender_user" in data:
data["sender_user"] = de_json_optional(data.get("sender_user"), User, bot)
if "sender_chat" in data:
data["sender_chat"] = de_json_optional(data.get("sender_chat"), Chat, bot)
if "chat" in data:
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
return super().de_json(data=data, bot=bot)
class MessageOriginUser(MessageOrigin):
"""
+1 -37
View File
@@ -20,19 +20,14 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._chat import Chat
from telegram._reaction import ReactionCount, ReactionType
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class MessageReactionCountUpdated(TelegramObject):
"""This class represents reaction changes on a message with anonymous reactions.
@@ -86,20 +81,6 @@ class MessageReactionCountUpdated(TelegramObject):
self._id_attrs = (self.chat, self.message_id, self.date, self.reactions)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "MessageReactionCountUpdated":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["reactions"] = de_list_optional(data.get("reactions"), ReactionCount, bot)
return super().de_json(data=data, bot=bot)
class MessageReactionUpdated(TelegramObject):
"""This class represents a change of a reaction on a message performed by a user.
@@ -181,20 +162,3 @@ class MessageReactionUpdated(TelegramObject):
self.new_reaction,
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "MessageReactionUpdated":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["old_reaction"] = de_list_optional(data.get("old_reaction"), ReactionType, bot)
data["new_reaction"] = de_list_optional(data.get("new_reaction"), ReactionType, bot)
data["user"] = de_json_optional(data.get("user"), User, bot)
data["actor_chat"] = de_json_optional(data.get("actor_chat"), Chat, bot)
return super().de_json(data=data, bot=bot)
+10 -67
View File
@@ -20,7 +20,7 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING, Final
from typing import ClassVar, Final
from telegram import constants
from telegram._gifts import Gift
@@ -29,14 +29,10 @@ from telegram._telegramobject import TelegramObject
from telegram._uniquegift import UniqueGift
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.entities import parse_message_entities, parse_message_entity
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class OwnedGift(TelegramObject):
"""This object describes a gift received and owned by a user or a chat. Currently, it
@@ -64,6 +60,14 @@ class OwnedGift(TelegramObject):
UNIQUE: Final[str] = constants.OwnedGiftType.UNIQUE
""":const:`telegram.constants.OwnedGiftType.UNIQUE`"""
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"regular": "OwnedGiftRegular",
"unique": "OwnedGiftUnique",
},
)
def __init__(
self,
type: str, # pylint: disable=redefined-builtin
@@ -76,31 +80,6 @@ class OwnedGift(TelegramObject):
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "OwnedGift":
"""Converts JSON data to the appropriate :class:`OwnedGift` object, i.e. takes
care of selecting the correct subclass.
Args:
data (dict[:obj:`str`, ...]): The JSON data.
bot (:class:`telegram.Bot`, optional): The bot associated with this object.
Returns:
The Telegram object.
"""
data = cls._parse_data(data)
_class_mapping: dict[str, type[OwnedGift]] = {
cls.REGULAR: OwnedGiftRegular,
cls.UNIQUE: OwnedGiftUnique,
}
if cls is OwnedGift and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
return super().de_json(data=data, bot=bot)
class OwnedGifts(TelegramObject):
"""Contains the list of gifts received and owned by a user or a chat.
@@ -146,14 +125,6 @@ class OwnedGifts(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "OwnedGifts":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["gifts"] = de_list_optional(data.get("gifts"), OwnedGift, bot)
return super().de_json(data=data, bot=bot)
class OwnedGiftRegular(OwnedGift):
"""Describes a regular gift owned by a user or a chat.
@@ -286,19 +257,6 @@ class OwnedGiftRegular(OwnedGift):
self._id_attrs = (self.type, self.gift, self.send_date)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "OwnedGiftRegular":
"""See :meth:`telegram.OwnedGift.de_json`."""
data = cls._parse_data(data)
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo)
data["sender_user"] = de_json_optional(data.get("sender_user"), User, bot)
data["gift"] = de_json_optional(data.get("gift"), Gift, bot)
data["entities"] = de_list_optional(data.get("entities"), MessageEntity, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`text`
from a given :class:`telegram.MessageEntity` of :attr:`entities`.
@@ -438,18 +396,3 @@ class OwnedGiftUnique(OwnedGift):
self.next_transfer_date: dtm.datetime | None = next_transfer_date
self._id_attrs = (self.type, self.gift, self.send_date)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "OwnedGiftUnique":
"""See :meth:`telegram.OwnedGift.de_json`."""
data = cls._parse_data(data)
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo)
data["sender_user"] = de_json_optional(data.get("sender_user"), User, bot)
data["gift"] = de_json_optional(data.get("gift"), UniqueGift, bot)
data["next_transfer_date"] = from_timestamp(
data.get("next_transfer_date"), tzinfo=loc_tzinfo
)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
+13 -71
View File
@@ -20,18 +20,14 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING, Final
from typing import TYPE_CHECKING, ClassVar, Final
from telegram import constants
from telegram._files.livephoto import LivePhoto
from telegram._files.photosize import PhotoSize
from telegram._files.video import Video
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import (
de_json_optional,
de_list_optional,
parse_sequence_arg,
to_timedelta,
)
@@ -39,7 +35,8 @@ from telegram._utils.datetime import get_timedelta_value
from telegram._utils.types import JSONDict, TimePeriod
if TYPE_CHECKING:
from telegram import Bot
from telegram._files.photosize import PhotoSize
from telegram._user import User
class PaidMedia(TelegramObject):
@@ -63,6 +60,16 @@ class PaidMedia(TelegramObject):
__slots__ = ("type",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"preview": "PaidMediaPreview",
"photo": "PaidMediaPhoto",
"video": "PaidMediaVideo",
"live_photo": "PaidMediaLivePhoto",
},
)
PREVIEW: Final[str] = constants.PaidMediaType.PREVIEW
""":const:`telegram.constants.PaidMediaType.PREVIEW`"""
PHOTO: Final[str] = constants.PaidMediaType.PHOTO
@@ -84,36 +91,6 @@ class PaidMedia(TelegramObject):
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PaidMedia":
"""Converts JSON data to the appropriate :class:`PaidMedia` object, i.e. takes
care of selecting the correct subclass.
Args:
data (dict[:obj:`str`, ...]): The JSON data.
bot (:class:`telegram.Bot`, optional): The bot associated with this object.
Returns:
The Telegram object.
"""
data = cls._parse_data(data)
_class_mapping: dict[str, type[PaidMedia]] = {
cls.PREVIEW: PaidMediaPreview,
cls.PHOTO: PaidMediaPhoto,
cls.VIDEO: PaidMediaVideo,
cls.LIVE_PHOTO: PaidMediaLivePhoto,
}
if cls is PaidMedia and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
if "duration" in data:
data["duration"] = dtm.timedelta(seconds=s) if (s := data.get("duration")) else None
return super().de_json(data=data, bot=bot)
class PaidMediaPreview(PaidMedia):
"""The paid media isn't available before the payment.
@@ -206,13 +183,6 @@ class PaidMediaPhoto(PaidMedia):
self._id_attrs = (self.type, self.photo)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PaidMediaPhoto":
data = cls._parse_data(data)
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class PaidMediaVideo(PaidMedia):
"""
@@ -247,13 +217,6 @@ class PaidMediaVideo(PaidMedia):
self._id_attrs = (self.type, self.video)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PaidMediaVideo":
data = cls._parse_data(data)
data["video"] = de_json_optional(data.get("video"), Video, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class PaidMediaLivePhoto(PaidMedia):
"""
@@ -288,13 +251,6 @@ class PaidMediaLivePhoto(PaidMedia):
self.live_photo: LivePhoto = live_photo
self._id_attrs = (self.type, self.live_photo)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PaidMediaLivePhoto":
data = cls._parse_data(data)
data["live_photo"] = de_json_optional(data.get("live_photo"), LivePhoto, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class PaidMediaInfo(TelegramObject):
"""
@@ -332,13 +288,6 @@ class PaidMediaInfo(TelegramObject):
self._id_attrs = (self.star_count, self.paid_media)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PaidMediaInfo":
data = cls._parse_data(data)
data["paid_media"] = de_list_optional(data.get("paid_media"), PaidMedia, bot)
return super().de_json(data=data, bot=bot)
class PaidMediaPurchased(TelegramObject):
"""This object contains information about a paid media purchase.
@@ -375,10 +324,3 @@ class PaidMediaPurchased(TelegramObject):
self._id_attrs = (self.from_user, self.paid_media_payload)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PaidMediaPurchased":
data = cls._parse_data(data)
data["from_user"] = User.de_json(data=data.pop("from"), bot=bot)
return super().de_json(data=data, bot=bot)
+2 -53
View File
@@ -20,7 +20,7 @@
import json
from base64 import b64decode
from collections.abc import Sequence
from typing import TYPE_CHECKING, no_type_check
from typing import no_type_check
try:
from cryptography.hazmat.backends import default_backend
@@ -39,14 +39,11 @@ except ImportError:
CRYPTO_INSTALLED = False
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.strings import TextEncoding
from telegram._utils.types import JSONDict
from telegram.error import PassportDecryptionError
if TYPE_CHECKING:
from telegram import Bot
@no_type_check
def decrypt(secret, hash, data):
@@ -233,15 +230,6 @@ class Credentials(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Credentials":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["secure_data"] = de_json_optional(data.get("secure_data"), SecureData, bot)
return super().de_json(data=data, bot=bot)
class SecureData(TelegramObject):
"""
@@ -340,31 +328,6 @@ class SecureData(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "SecureData":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["temporary_registration"] = de_json_optional(
data.get("temporary_registration"), SecureValue, bot
)
data["passport_registration"] = de_json_optional(
data.get("passport_registration"), SecureValue, bot
)
data["rental_agreement"] = de_json_optional(data.get("rental_agreement"), SecureValue, bot)
data["bank_statement"] = de_json_optional(data.get("bank_statement"), SecureValue, bot)
data["utility_bill"] = de_json_optional(data.get("utility_bill"), SecureValue, bot)
data["address"] = de_json_optional(data.get("address"), SecureValue, bot)
data["identity_card"] = de_json_optional(data.get("identity_card"), SecureValue, bot)
data["driver_license"] = de_json_optional(data.get("driver_license"), SecureValue, bot)
data["internal_passport"] = de_json_optional(
data.get("internal_passport"), SecureValue, bot
)
data["passport"] = de_json_optional(data.get("passport"), SecureValue, bot)
data["personal_details"] = de_json_optional(data.get("personal_details"), SecureValue, bot)
return super().de_json(data=data, bot=bot)
class SecureValue(TelegramObject):
"""
@@ -445,20 +408,6 @@ class SecureValue(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "SecureValue":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["data"] = de_json_optional(data.get("data"), DataCredentials, bot)
data["front_side"] = de_json_optional(data.get("front_side"), FileCredentials, bot)
data["reverse_side"] = de_json_optional(data.get("reverse_side"), FileCredentials, bot)
data["selfie"] = de_json_optional(data.get("selfie"), FileCredentials, bot)
data["files"] = de_list_optional(data.get("files"), FileCredentials, bot)
data["translation"] = de_list_optional(data.get("translation"), FileCredentials, bot)
return super().de_json(data=data, bot=bot)
class _CredentialsBase(TelegramObject):
"""Base class for DataCredentials and FileCredentials."""
@@ -27,9 +27,7 @@ from telegram._passport.passportfile import PassportFile
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import (
de_json_decrypted_optional,
de_json_optional,
de_list_decrypted_optional,
de_list_optional,
parse_sequence_arg,
)
from telegram._utils.types import JSONDict
@@ -195,19 +193,6 @@ class EncryptedPassportElement(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "EncryptedPassportElement":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["files"] = de_list_optional(data.get("files"), PassportFile, bot) or None
data["front_side"] = de_json_optional(data.get("front_side"), PassportFile, bot)
data["reverse_side"] = de_json_optional(data.get("reverse_side"), PassportFile, bot)
data["selfie"] = de_json_optional(data.get("selfie"), PassportFile, bot)
data["translation"] = de_list_optional(data.get("translation"), PassportFile, bot) or None
return super().de_json(data=data, bot=bot)
@classmethod
def de_json_decrypted(
cls, data: JSONDict, bot: "Bot | None", credentials: "Credentials"
+2 -12
View File
@@ -24,11 +24,11 @@ from typing import TYPE_CHECKING
from telegram._passport.credentials import EncryptedCredentials
from telegram._passport.encryptedpassportelement import EncryptedPassportElement
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot, Credentials
from telegram import Credentials
class PassportData(TelegramObject):
@@ -82,16 +82,6 @@ class PassportData(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PassportData":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["data"] = de_list_optional(data.get("data"), EncryptedPassportElement, bot)
data["credentials"] = de_json_optional(data.get("credentials"), EncryptedCredentials, bot)
return super().de_json(data=data, bot=bot)
@property
def decrypted_data(self) -> tuple[EncryptedPassportElement, ...]:
"""
-12
View File
@@ -22,7 +22,6 @@ import datetime as dtm
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
@@ -98,17 +97,6 @@ class PassportFile(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PassportFile":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["file_date"] = from_timestamp(data.get("file_date"), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
@classmethod
def de_json_decrypted(
cls, data: JSONDict, bot: "Bot | None", credentials: "FileCredentials"
-17
View File
@@ -18,16 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram OrderInfo."""
from typing import TYPE_CHECKING
from telegram._payment.shippingaddress import ShippingAddress
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class OrderInfo(TelegramObject):
"""This object represents information about an order.
@@ -70,14 +64,3 @@ class OrderInfo(TelegramObject):
self._id_attrs = (self.name, self.phone_number, self.email, self.shipping_address)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "OrderInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["shipping_address"] = de_json_optional(
data.get("shipping_address"), ShippingAddress, bot
)
return super().de_json(data=data, bot=bot)
-16
View File
@@ -18,18 +18,12 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram PreCheckoutQuery."""
from typing import TYPE_CHECKING
from telegram._payment.orderinfo import OrderInfo
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING:
from telegram import Bot
class PreCheckoutQuery(TelegramObject):
"""This object contains information about an incoming pre-checkout query.
@@ -110,16 +104,6 @@ class PreCheckoutQuery(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PreCheckoutQuery":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
data["order_info"] = de_json_optional(data.get("order_info"), OrderInfo, bot)
return super().de_json(data=data, bot=bot)
async def answer(
self,
ok: bool,
-14
View File
@@ -24,12 +24,10 @@ from typing import TYPE_CHECKING
from telegram._payment.shippingaddress import ShippingAddress
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING:
from telegram import Bot
from telegram._payment.shippingoption import ShippingOption
@@ -78,18 +76,6 @@ class ShippingQuery(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ShippingQuery":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
data["shipping_address"] = de_json_optional(
data.get("shipping_address"), ShippingAddress, bot
)
return super().de_json(data=data, bot=bot)
async def answer(
self,
ok: bool,
+2 -14
View File
@@ -20,14 +20,12 @@
from typing import TYPE_CHECKING
from telegram._chat import Chat
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
from telegram._chat import Chat
from telegram._user import User
class AffiliateInfo(TelegramObject):
@@ -105,13 +103,3 @@ class AffiliateInfo(TelegramObject):
self.nanostar_amount,
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "AffiliateInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["affiliate_user"] = de_json_optional(data.get("affiliate_user"), User, bot)
data["affiliate_chat"] = de_json_optional(data.get("affiliate_chat"), Chat, bot)
return super().de_json(data=data, bot=bot)
@@ -20,17 +20,13 @@
"""This module contains the classes for Telegram Stars Revenue Withdrawals."""
import datetime as dtm
from typing import TYPE_CHECKING, Final
from typing import ClassVar, Final
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class RevenueWithdrawalState(TelegramObject):
"""This object describes the state of a revenue withdrawal operation. Currently, it can be one
@@ -54,6 +50,15 @@ class RevenueWithdrawalState(TelegramObject):
__slots__ = ("type",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"pending": "RevenueWithdrawalStatePending",
"succeeded": "RevenueWithdrawalStateSucceeded",
"failed": "RevenueWithdrawalStateFailed",
},
)
PENDING: Final[str] = constants.RevenueWithdrawalStateType.PENDING
""":const:`telegram.constants.RevenueWithdrawalStateType.PENDING`"""
SUCCEEDED: Final[str] = constants.RevenueWithdrawalStateType.SUCCEEDED
@@ -68,32 +73,6 @@ class RevenueWithdrawalState(TelegramObject):
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "RevenueWithdrawalState":
"""Converts JSON data to the appropriate :class:`RevenueWithdrawalState` object, i.e. takes
care of selecting the correct subclass.
Args:
data (dict[:obj:`str`, ...]): The JSON data.
bot (:class:`telegram.Bot`): The bot associated with this object.
Returns:
The Telegram object.
"""
data = cls._parse_data(data)
_class_mapping: dict[str, type[RevenueWithdrawalState]] = {
cls.PENDING: RevenueWithdrawalStatePending,
cls.SUCCEEDED: RevenueWithdrawalStateSucceeded,
cls.FAILED: RevenueWithdrawalStateFailed,
}
if cls is RevenueWithdrawalState and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
return super().de_json(data=data, bot=bot)
class RevenueWithdrawalStatePending(RevenueWithdrawalState):
"""The withdrawal is in progress.
@@ -150,19 +129,6 @@ class RevenueWithdrawalStateSucceeded(RevenueWithdrawalState):
self.date,
)
@classmethod
def de_json(
cls, data: JSONDict, bot: "Bot | None" = None
) -> "RevenueWithdrawalStateSucceeded":
"""See :meth:`telegram.RevenueWithdrawalState.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class RevenueWithdrawalStateFailed(RevenueWithdrawalState):
"""The withdrawal failed and the transaction was refunded.
@@ -21,18 +21,13 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
from .transactionpartner import TransactionPartner
if TYPE_CHECKING:
from telegram import Bot
class StarTransaction(TelegramObject):
"""Describes a Telegram Star transaction.
@@ -114,20 +109,6 @@ class StarTransaction(TelegramObject):
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "StarTransaction":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo)
data["source"] = de_json_optional(data.get("source"), TransactionPartner, bot)
data["receiver"] = de_json_optional(data.get("receiver"), TransactionPartner, bot)
return super().de_json(data=data, bot=bot)
class StarTransactions(TelegramObject):
"""
@@ -155,11 +136,3 @@ class StarTransactions(TelegramObject):
self._id_attrs = (self.transactions,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "StarTransactions":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["transactions"] = de_list_optional(data.get("transactions"), StarTransaction, bot)
return super().de_json(data=data, bot=bot)
@@ -20,30 +20,28 @@
"""This module contains the classes for Telegram Stars transaction partners."""
from collections.abc import Sequence
from typing import TYPE_CHECKING, Final
from typing import TYPE_CHECKING, ClassVar, Final
from telegram import constants
from telegram._chat import Chat
from telegram._gifts import Gift
from telegram._paidmedia import PaidMedia
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import (
de_json_optional,
de_list_optional,
parse_sequence_arg,
to_timedelta,
)
from telegram._utils.types import JSONDict, TimePeriod
from .affiliateinfo import AffiliateInfo
from .revenuewithdrawalstate import RevenueWithdrawalState
if TYPE_CHECKING:
import datetime as dtm
from telegram import Bot
from telegram._user import User
from .revenuewithdrawalstate import RevenueWithdrawalState
class TransactionPartner(TelegramObject):
@@ -75,6 +73,19 @@ class TransactionPartner(TelegramObject):
__slots__ = ("type",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"affiliate_program": "TransactionPartnerAffiliateProgram",
"chat": "TransactionPartnerChat",
"fragment": "TransactionPartnerFragment",
"other": "TransactionPartnerOther",
"telegram_ads": "TransactionPartnerTelegramAds",
"telegram_api": "TransactionPartnerTelegramApi",
"user": "TransactionPartnerUser",
},
)
AFFILIATE_PROGRAM: Final[str] = constants.TransactionPartnerType.AFFILIATE_PROGRAM
""":const:`telegram.constants.TransactionPartnerType.AFFILIATE_PROGRAM`
@@ -103,36 +114,6 @@ class TransactionPartner(TelegramObject):
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "TransactionPartner":
"""Converts JSON data to the appropriate :class:`TransactionPartner` object, i.e. takes
care of selecting the correct subclass.
Args:
data (dict[:obj:`str`, ...]): The JSON data.
bot (:class:`telegram.Bot`): The bot associated with this object.
Returns:
The Telegram object.
"""
data = cls._parse_data(data)
_class_mapping: dict[str, type[TransactionPartner]] = {
cls.AFFILIATE_PROGRAM: TransactionPartnerAffiliateProgram,
cls.CHAT: TransactionPartnerChat,
cls.FRAGMENT: TransactionPartnerFragment,
cls.USER: TransactionPartnerUser,
cls.TELEGRAM_ADS: TransactionPartnerTelegramAds,
cls.TELEGRAM_API: TransactionPartnerTelegramApi,
cls.OTHER: TransactionPartnerOther,
}
if cls is TransactionPartner and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
return super().de_json(data=data, bot=bot)
class TransactionPartnerAffiliateProgram(TransactionPartner):
"""Describes the affiliate program that issued the affiliate commission received via this
@@ -177,17 +158,6 @@ class TransactionPartnerAffiliateProgram(TransactionPartner):
self.commission_per_mille,
)
@classmethod
def de_json(
cls, data: JSONDict, bot: "Bot | None" = None
) -> "TransactionPartnerAffiliateProgram":
"""See :meth:`telegram.TransactionPartner.de_json`."""
data = cls._parse_data(data)
data["sponsor_user"] = de_json_optional(data.get("sponsor_user"), User, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class TransactionPartnerChat(TransactionPartner):
"""Describes a transaction with a chat.
@@ -232,16 +202,6 @@ class TransactionPartnerChat(TransactionPartner):
self.chat,
)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "TransactionPartnerChat":
"""See :meth:`telegram.TransactionPartner.de_json`."""
data = cls._parse_data(data)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["gift"] = de_json_optional(data.get("gift"), Gift, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class TransactionPartnerFragment(TransactionPartner):
"""Describes a withdrawal transaction with Fragment.
@@ -272,17 +232,6 @@ class TransactionPartnerFragment(TransactionPartner):
with self._unfrozen():
self.withdrawal_state: RevenueWithdrawalState | None = withdrawal_state
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "TransactionPartnerFragment":
"""See :meth:`telegram.TransactionPartner.de_json`."""
data = cls._parse_data(data)
data["withdrawal_state"] = de_json_optional(
data.get("withdrawal_state"), RevenueWithdrawalState, bot
)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class TransactionPartnerUser(TransactionPartner):
"""Describes a transaction with a user.
@@ -448,18 +397,6 @@ class TransactionPartnerUser(TransactionPartner):
self.transaction_type,
)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "TransactionPartnerUser":
"""See :meth:`telegram.TransactionPartner.de_json`."""
data = cls._parse_data(data)
data["user"] = de_json_optional(data.get("user"), User, bot)
data["affiliate"] = de_json_optional(data.get("affiliate"), AffiliateInfo, bot)
data["paid_media"] = de_list_optional(data.get("paid_media"), PaidMedia, bot)
data["gift"] = de_json_optional(data.get("gift"), Gift, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
class TransactionPartnerOther(TransactionPartner):
"""Describes a transaction with an unknown partner.
@@ -19,17 +19,11 @@
"""This module contains an object that represents a Telegram SuccessfulPayment."""
import datetime as dtm
from typing import TYPE_CHECKING
from telegram._payment.orderinfo import OrderInfo
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class SuccessfulPayment(TelegramObject):
"""This object contains basic information about a successful payment.
@@ -140,19 +134,3 @@ class SuccessfulPayment(TelegramObject):
self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "SuccessfulPayment":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["order_info"] = de_json_optional(data.get("order_info"), OrderInfo, bot)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["subscription_expiration_date"] = from_timestamp(
data.get("subscription_expiration_date"), tzinfo=loc_tzinfo
)
return super().de_json(data=data, bot=bot)
+3 -135
View File
@@ -38,16 +38,10 @@ from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import (
de_json_optional,
de_list_optional,
parse_sequence_arg,
to_timedelta,
)
from telegram._utils.datetime import (
extract_tzinfo_from_defaults,
from_timestamp,
get_timedelta_value,
)
from telegram._utils.datetime import get_timedelta_value
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.entities import parse_message_entities, parse_message_entity
from telegram._utils.types import JSONDict, ODVInput, TimePeriod
@@ -55,7 +49,8 @@ from telegram._utils.warnings import warn
from telegram.warnings import PTBDeprecationWarning
if TYPE_CHECKING:
from telegram import Bot, InputPollOptionMedia, MaybeInaccessibleMessage
from telegram._files.inputmedia import InputPollOptionMedia
from telegram._message import MaybeInaccessibleMessage
class PollMedia(TelegramObject):
@@ -155,23 +150,6 @@ class PollMedia(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PollMedia":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["animation"] = de_json_optional(data.get("animation"), Animation, bot)
data["audio"] = de_json_optional(data.get("audio"), Audio, bot)
data["document"] = de_json_optional(data.get("document"), Document, bot)
data["live_photo"] = de_json_optional(data.get("live_photo"), LivePhoto, bot)
data["location"] = de_json_optional(data.get("location"), Location, bot)
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
data["venue"] = de_json_optional(data.get("venue"), Venue, bot)
data["video"] = de_json_optional(data.get("video"), Video, bot)
return super().de_json(data=data, bot=bot)
class InputPollOption(TelegramObject):
"""
@@ -234,30 +212,6 @@ class InputPollOption(TelegramObject):
self._freeze()
# tags: deprecated NEXT.VERSION
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "InputPollOption":
"""See :meth:`telegram.TelegramObject.de_json`. The :paramref:`media` field will
not be included for deserialization.
.. deprecated:: NEXT.VERSION
This class is input only and will be removed in the next version.
"""
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"`InputPollOption.de_json` is deprecated. This class is input only and will be "
"removed in the next version. The `media` field will not be included for "
"deserialization.",
),
stacklevel=2,
)
data = cls._parse_data(data)
data["text_entities"] = de_list_optional(data.get("text_entities"), MessageEntity, bot)
return super().de_json(data=data, bot=bot)
class PollOption(TelegramObject):
"""
@@ -377,22 +331,6 @@ class PollOption(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PollOption":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["text_entities"] = de_list_optional(data.get("text_entities"), MessageEntity, bot)
data["added_by_user"] = de_json_optional(data.get("added_by_user"), User, bot)
data["added_by_chat"] = de_json_optional(data.get("added_by_chat"), Chat, bot)
data["addition_date"] = from_timestamp(data.get("addition_date"), tzinfo=loc_tzinfo)
data["media"] = de_json_optional(data.get("media"), PollMedia, bot)
return super().de_json(data=data, bot=bot)
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`text`
from a given :class:`telegram.MessageEntity` of :attr:`text_entities`.
@@ -542,16 +480,6 @@ class PollAnswer(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PollAnswer":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["user"] = de_json_optional(data.get("user"), User, bot)
data["voter_chat"] = de_json_optional(data.get("voter_chat"), Chat, bot)
return super().de_json(data=data, bot=bot)
class PollOptionAdded(TelegramObject):
"""
@@ -607,24 +535,6 @@ class PollOptionAdded(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PollOptionAdded":
"""See :meth:`telegram.TelegramObject.de_json`."""
from telegram._message import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
MaybeInaccessibleMessage,
)
data = cls._parse_data(data)
data["poll_message"] = de_json_optional(
data.get("poll_message"), MaybeInaccessibleMessage, bot
)
data["option_text_entities"] = de_list_optional(
data.get("option_text_entities"), MessageEntity, bot
)
return super().de_json(data=data, bot=bot)
def parse_option_text_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`option_text`
from a given :class:`telegram.MessageEntity` of :attr:`option_text_entities`.
@@ -722,24 +632,6 @@ class PollOptionDeleted(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "PollOptionDeleted":
"""See :meth:`telegram.TelegramObject.de_json`."""
from telegram._message import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
MaybeInaccessibleMessage,
)
data = cls._parse_data(data)
data["poll_message"] = de_json_optional(
data.get("poll_message"), MaybeInaccessibleMessage, bot
)
data["option_text_entities"] = de_list_optional(
data.get("option_text_entities"), MessageEntity, bot
)
return super().de_json(data=data, bot=bot)
def parse_option_text_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`option_text`
from a given :class:`telegram.MessageEntity` of :attr:`option_text_entities`.
@@ -1067,30 +959,6 @@ class Poll(TelegramObject):
def open_period(self) -> int | dtm.timedelta | None:
return get_timedelta_value(self._open_period, attribute="open_period")
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Poll":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["options"] = de_list_optional(data.get("options"), PollOption, bot)
data["explanation_entities"] = de_list_optional(
data.get("explanation_entities"), MessageEntity, bot
)
data["close_date"] = from_timestamp(data.get("close_date"), tzinfo=loc_tzinfo)
data["question_entities"] = de_list_optional(
data.get("question_entities"), MessageEntity, bot
)
data["description_entities"] = de_list_optional(
data.get("description_entities"), MessageEntity, bot
)
data["media"] = de_json_optional(data.get("media"), PollMedia, bot)
data["explanation_media"] = de_json_optional(data.get("explanation_media"), PollMedia, bot)
return super().de_json(data=data, bot=bot)
def parse_explanation_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`explanation` from a given :class:`telegram.MessageEntity` of
:attr:`explanation_entities`.
-16
View File
@@ -18,16 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Proximity Alert."""
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class ProximityAlertTriggered(TelegramObject):
"""
@@ -67,13 +61,3 @@ class ProximityAlertTriggered(TelegramObject):
self._id_attrs = (self.traveler, self.watcher, self.distance)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ProximityAlertTriggered":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["traveler"] = de_json_optional(data.get("traveler"), User, bot)
data["watcher"] = de_json_optional(data.get("watcher"), User, bot)
return super().de_json(data=data, bot=bot)
+10 -30
View File
@@ -19,17 +19,13 @@
# pylint: disable=redefined-builtin
"""This module contains objects that represents a Telegram ReactionType."""
from typing import TYPE_CHECKING, Final, Literal
from typing import ClassVar, Final, Literal
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class ReactionType(TelegramObject):
"""Base class for Telegram ReactionType Objects.
@@ -54,6 +50,15 @@ class ReactionType(TelegramObject):
__slots__ = ("type",)
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = (
"type",
{
"emoji": "ReactionTypeEmoji",
"custom_emoji": "ReactionTypeCustomEmoji",
"paid": "ReactionTypePaid",
},
)
EMOJI: Final[constants.ReactionType] = constants.ReactionType.EMOJI
""":const:`telegram.constants.ReactionType.EMOJI`"""
CUSTOM_EMOJI: Final[constants.ReactionType] = constants.ReactionType.CUSTOM_EMOJI
@@ -76,22 +81,6 @@ class ReactionType(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ReactionType":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
_class_mapping: dict[str, type[ReactionType]] = {
cls.EMOJI: ReactionTypeEmoji,
cls.CUSTOM_EMOJI: ReactionTypeCustomEmoji,
cls.PAID: ReactionTypePaid,
}
if cls is ReactionType and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data, bot)
return super().de_json(data=data, bot=bot)
class ReactionTypeEmoji(ReactionType):
"""
@@ -220,12 +209,3 @@ class ReactionCount(TelegramObject):
self.total_count,
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ReactionCount":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["type"] = de_json_optional(data.get("type"), ReactionType, bot)
return super().de_json(data=data, bot=bot)
+3 -60
View File
@@ -26,10 +26,8 @@ from telegram._checklists import Checklist
from telegram._dice import Dice
from telegram._files.animation import Animation
from telegram._files.audio import Audio
from telegram._files.contact import Contact
from telegram._files.document import Document
from telegram._files.livephoto import LivePhoto
from telegram._files.location import Location
from telegram._files.photosize import PhotoSize
from telegram._files.sticker import Sticker
from telegram._files.venue import Venue
@@ -46,12 +44,13 @@ from telegram._payment.invoice import Invoice
from telegram._poll import Poll
from telegram._story import Story
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING:
from telegram import Bot
from telegram._files.contact import Contact
from telegram._files.location import Location
class ExternalReplyInfo(TelegramObject):
@@ -271,42 +270,6 @@ class ExternalReplyInfo(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ExternalReplyInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["origin"] = de_json_optional(data.get("origin"), MessageOrigin, bot)
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
data["link_preview_options"] = de_json_optional(
data.get("link_preview_options"), LinkPreviewOptions, bot
)
data["animation"] = de_json_optional(data.get("animation"), Animation, bot)
data["audio"] = de_json_optional(data.get("audio"), Audio, bot)
data["document"] = de_json_optional(data.get("document"), Document, bot)
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
data["story"] = de_json_optional(data.get("story"), Story, bot)
data["video"] = de_json_optional(data.get("video"), Video, bot)
data["video_note"] = de_json_optional(data.get("video_note"), VideoNote, bot)
data["voice"] = de_json_optional(data.get("voice"), Voice, bot)
data["contact"] = de_json_optional(data.get("contact"), Contact, bot)
data["dice"] = de_json_optional(data.get("dice"), Dice, bot)
data["game"] = de_json_optional(data.get("game"), Game, bot)
data["giveaway"] = de_json_optional(data.get("giveaway"), Giveaway, bot)
data["giveaway_winners"] = de_json_optional(
data.get("giveaway_winners"), GiveawayWinners, bot
)
data["invoice"] = de_json_optional(data.get("invoice"), Invoice, bot)
data["location"] = de_json_optional(data.get("location"), Location, bot)
data["poll"] = de_json_optional(data.get("poll"), Poll, bot)
data["venue"] = de_json_optional(data.get("venue"), Venue, bot)
data["paid_media"] = de_json_optional(data.get("paid_media"), PaidMediaInfo, bot)
data["checklist"] = de_json_optional(data.get("checklist"), Checklist, bot)
data["live_photo"] = de_json_optional(data.get("live_photo"), LivePhoto, bot)
return super().de_json(data=data, bot=bot)
class TextQuote(TelegramObject):
"""
@@ -372,15 +335,6 @@ class TextQuote(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "TextQuote":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["entities"] = de_list_optional(data.get("entities"), MessageEntity, bot)
return super().de_json(data=data, bot=bot)
class ReplyParameters(TelegramObject):
"""
@@ -502,14 +456,3 @@ class ReplyParameters(TelegramObject):
self._id_attrs = (self.message_id,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ReplyParameters":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["quote_entities"] = tuple(
de_list_optional(data.get("quote_entities"), MessageEntity, bot)
)
return super().de_json(data=data, bot=bot)
+7 -36
View File
@@ -19,17 +19,13 @@
"""This module contains two objects used for request chats/users service messages."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._files.photosize import PhotoSize
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_list_optional, parse_sequence_arg
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
from telegram._utils.usernames import get_full_name, get_link, get_name
if TYPE_CHECKING:
from telegram._bot import Bot
class UsersShared(TelegramObject):
"""
@@ -70,6 +66,12 @@ class UsersShared(TelegramObject):
__slots__ = ("request_id", "users")
__REMOVED_API_FIELDS__ = frozenset(
{
"user_ids",
}
)
def __init__(
self,
request_id: int,
@@ -85,21 +87,6 @@ class UsersShared(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UsersShared":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["users"] = de_list_optional(data.get("users"), SharedUser, bot)
api_kwargs = {}
# This is a deprecated field that TG still returns for backwards compatibility
# Let's filter it out to speed up the de-json process
if user_ids := data.get("user_ids"):
api_kwargs = {"user_ids": user_ids}
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
class ChatShared(TelegramObject):
"""
@@ -171,14 +158,6 @@ class ChatShared(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "ChatShared":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
return super().de_json(data=data, bot=bot)
@property
def link(self) -> str | None:
""":obj:`str`: Convenience property. If :attr:`username` is available, returns a t.me link
@@ -281,11 +260,3 @@ class SharedUser(TelegramObject):
.. versionadded:: 22.4
"""
return get_link(self)
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "SharedUser":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
return super().de_json(data=data, bot=bot)
-13
View File
@@ -18,16 +18,11 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object related to a Telegram Story."""
from typing import TYPE_CHECKING
from telegram._chat import Chat
from telegram._telegramobject import TelegramObject
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput, TimePeriod
if TYPE_CHECKING:
from telegram import Bot
class Story(TelegramObject):
"""
@@ -71,14 +66,6 @@ class Story(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Story":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["chat"] = Chat.de_json(data.get("chat", {}), bot)
return super().de_json(data=data, bot=bot)
async def repost(
self,
business_connection_id: str,
+1 -95
View File
@@ -19,20 +19,15 @@
"""This module contains objects related to Telegram suggested posts."""
import datetime as dtm
from typing import TYPE_CHECKING, Final, Optional
from typing import Final
from telegram import constants
from telegram._message import Message
from telegram._payment.stars.staramount import StarAmount
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class SuggestedPostPrice(TelegramObject):
"""
@@ -141,20 +136,6 @@ class SuggestedPostParameters(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostParameters":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["price"] = de_json_optional(data.get("price"), SuggestedPostPrice, bot)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
class SuggestedPostInfo(TelegramObject):
"""
@@ -223,19 +204,6 @@ class SuggestedPostInfo(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["price"] = de_json_optional(data.get("price"), SuggestedPostPrice, bot)
data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
class SuggestedPostDeclined(TelegramObject):
"""
@@ -281,17 +249,6 @@ class SuggestedPostDeclined(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostDeclined":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["suggested_post_message"] = de_json_optional(
data.get("suggested_post_message"), Message, bot
)
return super().de_json(data=data, bot=bot)
class SuggestedPostPaid(TelegramObject):
"""
@@ -363,18 +320,6 @@ class SuggestedPostPaid(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostPaid":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["suggested_post_message"] = de_json_optional(
data.get("suggested_post_message"), Message, bot
)
data["star_amount"] = de_json_optional(data.get("star_amount"), StarAmount, bot)
return super().de_json(data=data, bot=bot)
class SuggestedPostRefunded(TelegramObject):
"""
@@ -430,17 +375,6 @@ class SuggestedPostRefunded(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostRefunded":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["suggested_post_message"] = de_json_optional(
data.get("suggested_post_message"), Message, bot
)
return super().de_json(data=data, bot=bot)
class SuggestedPostApproved(TelegramObject):
"""
@@ -496,22 +430,6 @@ class SuggestedPostApproved(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostApproved":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo)
data["price"] = de_json_optional(data.get("price"), SuggestedPostPrice, bot)
data["suggested_post_message"] = de_json_optional(
data.get("suggested_post_message"), Message, bot
)
return super().de_json(data=data, bot=bot)
class SuggestedPostApprovalFailed(TelegramObject):
"""
@@ -559,15 +477,3 @@ class SuggestedPostApprovalFailed(TelegramObject):
self._id_attrs = (self.price, self.suggested_post_message)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostApprovalFailed":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["price"] = de_json_optional(data.get("price"), SuggestedPostPrice, bot)
data["suggested_post_message"] = de_json_optional(
data.get("suggested_post_message"), Message, bot
)
return super().de_json(data=data, bot=bot)
+219 -8
View File
@@ -20,25 +20,84 @@
import contextlib
import datetime as dtm
import importlib
import inspect
import json
from collections.abc import Iterator, Mapping, Sized
from collections.abc import Iterator, Mapping, Sequence, Sized
from contextlib import contextmanager
from copy import deepcopy
from itertools import chain
from types import MappingProxyType
from typing import TYPE_CHECKING, Any, ClassVar, TypeVar, cast
from types import MappingProxyType, UnionType
from typing import TYPE_CHECKING, Any, ClassVar, TypeVar, cast, get_args, get_origin
from telegram._utils.datetime import to_timestamp
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp, to_timestamp
from telegram._utils.defaultvalue import DefaultValue
from telegram._utils.types import JSONDict
from telegram._utils.warnings import warn
if TYPE_CHECKING:
from collections.abc import Callable
from telegram import Bot
Tele_co = TypeVar("Tele_co", bound="TelegramObject", covariant=True)
Tele = TypeVar("Tele", bound="TelegramObject")
_DATETIME_FIELD = object() # sentinel value to mark datetime fields in the de_json plan
def _telegram_ns() -> dict[str, object]:
"""Return the full ``telegram`` package namespace for annotation resolution."""
return vars(importlib.import_module("telegram"))
def _unwrap_optional(ann: object) -> object:
"""``X | None`` → ``X``. Any other annotation is returned unchanged."""
if isinstance(ann, UnionType):
non_none = [a for a in ann.__args__ if a is not type(None)] # pylint: disable=unidiomatic-typecheck
if len(non_none) == 1:
return non_none[0]
return ann
def _make_seq_transform(
item_type: object,
globalns: dict[str, object],
tg_ns: dict[str, object],
) -> "Callable[[object, Bot | None], object] | None":
"""Recursively build a ``(value, bot) → transformed_value`` lambda for a Sequence item type.
Args:
item_type: The unwrapped type annotation of the items in the Sequence.
globalns: The global namespace for evaluating string annotations.
tg_ns: The telegram namespace for evaluating string annotations.
Returns:
- :obj:`None` if the item type does not require any transformation.
- a lambda (value, bot) -> transformation
"""
# inspect.signature does not resolve forward refs in Sequence's despite eval_str=True for some
# reason:
if isinstance(item_type, str):
item_type = eval(item_type, globalns, tg_ns) # pylint: disable=eval-used # noqa: S307
item_origin = get_origin(item_type)
if item_origin is Sequence:
inner_args = get_args(item_type)
if not inner_args:
return None
inner_fn = _make_seq_transform(inner_args[0], globalns, tg_ns)
if inner_fn is None:
return None
return lambda v, b, _f=inner_fn: ( # type: ignore[misc]
[_f(row, b) for row in v] if isinstance(v, list) else v
)
if isinstance(item_type, type) and issubclass(item_type, TelegramObject):
return lambda v, b, _c=item_type: ( # type: ignore[misc]
_c.de_list(v, b) if isinstance(v, list) else v
)
return None
class TelegramObject:
@@ -88,6 +147,31 @@ class TelegramObject:
# unless it's overridden
__INIT_PARAMS_CHECK: type["TelegramObject"] | None = None
# Per-class de_json plan built once by _build_plan().
# Maps parameter name → transform target:
# _DATETIME_FIELD sentinel → from_timestamp(value, tzinfo)
# TelegramObject subclass → cls.de_json(value, bot)
# callable(value, bot) → Sequence transform (from _make_seq_transform)
__DE_JSON_PLAN__: ClassVar[dict[str, Any]] = {}
# Forward-compatibility: names of Sequence-typed __init__ params.
# If the Telegram API stops sending a field that PTB's __init__ still
# requires (i.e. the API made it optional), _de_json defaults sequences
# to () and everything else to None so the library doesn't crash.
__DE_JSON_COMPAT__: ClassVar[frozenset[str]] = frozenset()
# Subclasses may declare field names that Telegram still returns for backwards
# compatibility but that are no longer part of the PTB model. Those fields will
# be intercepted by de_json and forwarded into api_kwargs before construction.
__REMOVED_API_FIELDS__: ClassVar[frozenset[str]] = frozenset()
# Delegator base classes (e.g. TransactionPartner) may define a dispatch mapping to route
# de_json to the correct subclass.
# Format: (dispatch_key, {value: "ClassName", ...}).
# The dispatch_key is the JSON field name (e.g. "type", "source", "status").
# The values are class name strings, e.g. "TransactionPartnerChat".
__DE_JSON_DISPATCH__: ClassVar[tuple[str, dict[str, str]] | None] = None
def __init__(self, *, api_kwargs: JSONDict | None = None) -> None:
# Setting _frozen to `False` here means that classes without arguments still need to
# implement __init__. However, with `True` would mean increased usage of
@@ -385,6 +469,74 @@ class TelegramObject:
"""
return data.copy()
@classmethod
def _build_plan(cls) -> dict[str, Any]:
"""Build the de_json transformation plan from ``__init__`` type annotations.
Called once per class on the first :meth:`de_json` invocation. By that time
every module is fully loaded so forward-reference resolution always succeeds.
The resulting ``dict`` maps parameter names to their transform targets.
Four kinds of transforms are recognised:
* ``datetime`` fields :func:`~telegram._utils.datetime.from_timestamp`
* ``TelegramObject`` fields ``TargetCls.de_json(...)``
* ``Sequence[TelegramObject]`` fields ``TargetCls.de_list(...)``
* ``Sequence[Sequence[TelegramObject]]`` fields nested de_list
"""
init_fn = cls.__dict__.get("__init__")
if init_fn is None:
# No own __init__: inherit the nearest ancestor's plan. This is true for e.g. Chat
parent = cast("type[TelegramObject]", cls.__mro__[1])
if "__DE_JSON_PLAN__" not in parent.__dict__:
parent._build_plan() # pylint: disable=protected-access, no-member
cls.__DE_JSON_PLAN__ = parent.__DE_JSON_PLAN__ # pylint: disable=no-member
cls.__DE_JSON_COMPAT__ = parent.__DE_JSON_COMPAT__ # pylint: disable=no-member
return cls.__DE_JSON_PLAN__
plan: dict[str, Any] = {}
seq_fields: set[str] = set()
globalns: dict[str, object] = getattr(init_fn, "__globals__", {})
tg_ns = _telegram_ns()
sig = inspect.signature(init_fn, eval_str=True, globals=globalns, locals=tg_ns)
for name, param in sig.parameters.items():
if name in ("self", "api_kwargs") or param.kind in (
param.VAR_POSITIONAL,
param.VAR_KEYWORD,
):
continue
ann = param.annotation
inner = _unwrap_optional(ann)
origin = get_origin(inner)
if inner is dtm.datetime:
plan[name] = _DATETIME_FIELD
elif isinstance(inner, type) and issubclass(inner, TelegramObject):
plan[name] = inner
elif origin is Sequence:
args = get_args(inner)
if not args:
continue
fn = _make_seq_transform(args[0], globalns, tg_ns)
if fn is not None:
plan[name] = fn
seq_fields.add(name)
cls.__DE_JSON_PLAN__ = plan
cls.__DE_JSON_COMPAT__ = frozenset(seq_fields)
# Pre-resolve any string class names in the dispatch mapping so that
# de_json() can look up the target class directly without string checks.
if cls.__DE_JSON_DISPATCH__:
_, dispatch_mapping = cls.__DE_JSON_DISPATCH__
for key, value in dispatch_mapping.items():
if isinstance(value, str):
dispatch_mapping[key] = tg_ns[value] # type: ignore[assignment]
return plan
@classmethod
def _de_json(
cls: type[Tele_co],
@@ -396,12 +548,15 @@ class TelegramObject:
try:
obj = cls(**data, api_kwargs=api_kwargs)
except TypeError as exc:
if "__init__() got an unexpected keyword argument" not in str(exc):
exc_str = str(exc)
if (
"unexpected keyword argument" not in exc_str
and "required positional argument" not in exc_str
):
raise
if cls.__INIT_PARAMS_CHECK is not cls:
signature = inspect.signature(cls)
cls.__INIT_PARAMS = set(signature.parameters.keys())
cls.__INIT_PARAMS = set(inspect.signature(cls).parameters.keys())
cls.__INIT_PARAMS_CHECK = cls
api_kwargs = api_kwargs or {}
@@ -409,6 +564,12 @@ class TelegramObject:
for key, value in data.items():
(existing_kwargs if key in cls.__INIT_PARAMS else api_kwargs)[key] = value
# Forward-compat: if the API stopped sending a field PTB requires,
# default sequences to () and everything else to None.
compat = cls.__dict__.get("__DE_JSON_COMPAT__", frozenset())
for key in cls.__INIT_PARAMS - existing_kwargs.keys() - {"self", "api_kwargs"}:
existing_kwargs[key] = () if key in compat else None
obj = cls(api_kwargs=api_kwargs, **existing_kwargs)
obj.set_bot(bot=bot)
@@ -430,7 +591,57 @@ class TelegramObject:
The Telegram object.
"""
return cls._de_json(data=data, bot=bot)
# Build the plan lazily (once per class).
if "__DE_JSON_PLAN__" not in cls.__dict__:
cls._build_plan()
plan = cls.__DE_JSON_PLAN__
# Fast path: no dispatch, no removed fields, empty plan → skip data.copy()
if not plan and not cls.__DE_JSON_DISPATCH__ and not cls.__REMOVED_API_FIELDS__:
return cls._de_json(data=data, bot=bot)
# We'll mutate data below (rename, pop, transform), so copy first.
data = cls._parse_data(data)
# Dispatch to subclass for delegator classes (e.g. TransactionPartner, ChatMember).
if cls.__DE_JSON_DISPATCH__:
dispatch_key, dispatch_mapping = cls.__DE_JSON_DISPATCH__
target_cls: Tele_co = dispatch_mapping.get( # type: ignore[assignment]
data.get(dispatch_key) # type: ignore[arg-type]
)
if target_cls is not None:
data.pop(dispatch_key)
return target_cls.de_json(data=data, bot=bot)
# Move removed/legacy API fields into api_kwargs
api_kwargs: JSONDict | None = None
if cls.__REMOVED_API_FIELDS__:
removed = {f: data.pop(f) for f in cls.__REMOVED_API_FIELDS__ if f in data}
if removed:
api_kwargs = removed
# Rename "from" → "from_user" before the transform loop.
if "from_user" in plan and "from" in data:
data["from_user"] = data.pop("from")
# Let's finally apply the transformations:
if plan:
# Compute tzinfo once for all datetime fields, if any
tz = extract_tzinfo_from_defaults(bot)
for key in data: # Only loop through keys returned by the API
if key in plan and data[key] is not None: # Should we transform this field?
target = plan[key] # The transform target for this field
if target is _DATETIME_FIELD: # timestamp → datetime
if not isinstance(data[key], dtm.datetime): # Avoid retransformations
data[key] = from_timestamp(data[key], tzinfo=tz)
elif isinstance(target, type): # Target is a TelegramObject subclass → de_json
if not isinstance(data[key], target): # Avoid retransformations
data[key] = target.de_json(data[key], bot) # type: ignore[attr-defined]
else:
# Sequence transform callable (e.g. de_list)
data[key] = target(data[key], bot)
return cls._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
@classmethod
def de_list(
+2 -59
View File
@@ -21,20 +21,16 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING, Final
from typing import Final
from telegram import constants
from telegram._chat import Chat
from telegram._files.sticker import Sticker
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class UniqueGiftColors(TelegramObject):
"""This object contains information about the color scheme for a user's name, message replies
@@ -173,15 +169,6 @@ class UniqueGiftModel(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UniqueGiftModel":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
return super().de_json(data=data, bot=bot)
class UniqueGiftSymbol(TelegramObject):
"""This object describes the symbol shown on the pattern of a unique gift.
@@ -228,15 +215,6 @@ class UniqueGiftSymbol(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UniqueGiftSymbol":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
return super().de_json(data=data, bot=bot)
class UniqueGiftBackdropColors(TelegramObject):
"""This object describes the colors of the backdrop of a unique gift.
@@ -333,15 +311,6 @@ class UniqueGiftBackdrop(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UniqueGiftBackdrop":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["colors"] = de_json_optional(data.get("colors"), UniqueGiftBackdropColors, bot)
return super().de_json(data=data, bot=bot)
class UniqueGift(TelegramObject):
"""This object describes a unique gift that was upgraded from a regular gift.
@@ -483,19 +452,6 @@ class UniqueGift(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UniqueGift":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["model"] = de_json_optional(data.get("model"), UniqueGiftModel, bot)
data["symbol"] = de_json_optional(data.get("symbol"), UniqueGiftSymbol, bot)
data["backdrop"] = de_json_optional(data.get("backdrop"), UniqueGiftBackdrop, bot)
data["publisher_chat"] = de_json_optional(data.get("publisher_chat"), Chat, bot)
data["colors"] = de_json_optional(data.get("colors"), UniqueGiftColors, bot)
return super().de_json(data=data, bot=bot)
class UniqueGiftInfo(TelegramObject):
"""Describes a service message about a unique gift that was sent or received.
@@ -627,16 +583,3 @@ class UniqueGiftInfo(TelegramObject):
self._id_attrs = (self.gift, self.origin)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UniqueGiftInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["gift"] = de_json_optional(data.get("gift"), UniqueGift, bot)
data["next_transfer_date"] = from_timestamp(
data.get("next_transfer_date"), tzinfo=loc_tzinfo
)
return super().de_json(data=data, bot=bot)
+1 -59
View File
@@ -36,12 +36,11 @@ from telegram._payment.precheckoutquery import PreCheckoutQuery
from telegram._payment.shippingquery import ShippingQuery
from telegram._poll import Poll, PollAnswer
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
from telegram._utils.warnings import warn
if TYPE_CHECKING:
from telegram import Bot, Chat, User
from telegram import Chat, User
class Update(TelegramObject):
@@ -803,60 +802,3 @@ class Update(TelegramObject):
self._effective_message = message
return message
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "Update":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["message"] = de_json_optional(data.get("message"), Message, bot)
data["edited_message"] = de_json_optional(data.get("edited_message"), Message, bot)
data["inline_query"] = de_json_optional(data.get("inline_query"), InlineQuery, bot)
data["chosen_inline_result"] = de_json_optional(
data.get("chosen_inline_result"), ChosenInlineResult, bot
)
data["callback_query"] = de_json_optional(data.get("callback_query"), CallbackQuery, bot)
data["shipping_query"] = de_json_optional(data.get("shipping_query"), ShippingQuery, bot)
data["pre_checkout_query"] = de_json_optional(
data.get("pre_checkout_query"), PreCheckoutQuery, bot
)
data["channel_post"] = de_json_optional(data.get("channel_post"), Message, bot)
data["edited_channel_post"] = de_json_optional(
data.get("edited_channel_post"), Message, bot
)
data["poll"] = de_json_optional(data.get("poll"), Poll, bot)
data["poll_answer"] = de_json_optional(data.get("poll_answer"), PollAnswer, bot)
data["my_chat_member"] = de_json_optional(
data.get("my_chat_member"), ChatMemberUpdated, bot
)
data["chat_member"] = de_json_optional(data.get("chat_member"), ChatMemberUpdated, bot)
data["chat_join_request"] = de_json_optional(
data.get("chat_join_request"), ChatJoinRequest, bot
)
data["chat_boost"] = de_json_optional(data.get("chat_boost"), ChatBoostUpdated, bot)
data["removed_chat_boost"] = de_json_optional(
data.get("removed_chat_boost"), ChatBoostRemoved, bot
)
data["message_reaction"] = de_json_optional(
data.get("message_reaction"), MessageReactionUpdated, bot
)
data["message_reaction_count"] = de_json_optional(
data.get("message_reaction_count"), MessageReactionCountUpdated, bot
)
data["business_connection"] = de_json_optional(
data.get("business_connection"), BusinessConnection, bot
)
data["business_message"] = de_json_optional(data.get("business_message"), Message, bot)
data["edited_business_message"] = de_json_optional(
data.get("edited_business_message"), Message, bot
)
data["deleted_business_messages"] = de_json_optional(
data.get("deleted_business_messages"), BusinessMessagesDeleted, bot
)
data["purchased_paid_media"] = de_json_optional(
data.get("purchased_paid_media"), PaidMediaPurchased, bot
)
data["managed_bot"] = de_json_optional(data.get("managed_bot"), ManagedBotUpdated, bot)
data["guest_message"] = de_json_optional(data.get("guest_message"), Message, bot)
return super().de_json(data=data, bot=bot)
-13
View File
@@ -19,15 +19,11 @@
"""This module contains an object that represents a Telegram UserProfileAudios."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._files.audio import Audio
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class UserProfileAudios(TelegramObject):
"""
@@ -65,12 +61,3 @@ class UserProfileAudios(TelegramObject):
self._id_attrs = (self.total_count, self.audios)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UserProfileAudios":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["audios"] = Audio.de_list(data.get("audios", []), bot)
return super().de_json(data=data, bot=bot)
-13
View File
@@ -19,15 +19,11 @@
"""This module contains an object that represents a Telegram UserProfilePhotos."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._files.photosize import PhotoSize
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class UserProfilePhotos(TelegramObject):
"""This object represents a user's profile pictures.
@@ -70,12 +66,3 @@ class UserProfilePhotos(TelegramObject):
self._id_attrs = (self.total_count, self.photos)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UserProfilePhotos":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["photos"] = [PhotoSize.de_list(photo, bot) for photo in data["photos"]]
return super().de_json(data=data, bot=bot)
+1 -29
View File
@@ -20,21 +20,13 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import parse_sequence_arg, to_timedelta
from telegram._utils.datetime import (
extract_tzinfo_from_defaults,
from_timestamp,
get_timedelta_value,
)
from telegram._utils.datetime import get_timedelta_value
from telegram._utils.types import JSONDict, TimePeriod
if TYPE_CHECKING:
from telegram import Bot
class VideoChatStarted(TelegramObject):
"""
@@ -146,14 +138,6 @@ class VideoChatParticipantsInvited(TelegramObject):
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "VideoChatParticipantsInvited":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["users"] = User.de_list(data.get("users", []), bot)
return super().de_json(data=data, bot=bot)
class VideoChatScheduled(TelegramObject):
"""This object represents a service message about a video chat scheduled in the chat.
@@ -193,15 +177,3 @@ class VideoChatScheduled(TelegramObject):
self._id_attrs = (self.start_date,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "VideoChatScheduled":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["start_date"] = from_timestamp(data.get("start_date"), tzinfo=loc_tzinfo)
return super().de_json(data=data, bot=bot)
-20
View File
@@ -20,16 +20,11 @@
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class WebhookInfo(TelegramObject):
"""This object represents a Telegram WebhookInfo.
@@ -164,18 +159,3 @@ class WebhookInfo(TelegramObject):
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "WebhookInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
# Get the local timezone from the bot if it has defaults
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["last_error_date"] = from_timestamp(data.get("last_error_date"), tzinfo=loc_tzinfo)
data["last_synchronization_error_date"] = from_timestamp(
data.get("last_synchronization_error_date"), tzinfo=loc_tzinfo
)
return super().de_json(data=data, bot=bot)
+39 -29
View File
@@ -69,11 +69,35 @@ class StickerTestBase:
type = Sticker.REGULAR
custom_emoji_id = "ThisIsSuchACustomEmojiID"
needs_repainting = True
mask_position = MaskPosition(point="forehead", x_shift=0.1, y_shift=-0.1, scale=1.0)
thumbnail = PhotoSize(
file_id="1",
file_unique_id="1",
width=thumb_width,
height=thumb_height,
file_size=thumb_file_size,
)
sticker_file_id = "5a3128a4d2a04750b5b58397f3b5e812"
sticker_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
premium_animation = File("this_is_an_id", "this_is_an_unique_id")
sticker = Sticker(
file_id=sticker_file_id,
file_unique_id=sticker_file_unique_id,
width=width,
height=height,
is_animated=is_animated,
is_video=is_video,
type=type,
emoji=emoji,
file_size=file_size,
mask_position=mask_position,
premium_animation=premium_animation,
custom_emoji_id=custom_emoji_id,
thumbnail=thumbnail,
needs_repainting=needs_repainting,
)
class TestStickerWithoutRequest(StickerTestBase):
@@ -125,22 +149,8 @@ class TestStickerWithoutRequest(StickerTestBase):
assert sticker_dict["type"] == sticker.type
assert sticker_dict["needs_repainting"] == sticker.needs_repainting
def test_de_json(self, offline_bot, sticker):
json_dict = {
"file_id": self.sticker_file_id,
"file_unique_id": self.sticker_file_unique_id,
"width": self.width,
"height": self.height,
"is_animated": self.is_animated,
"is_video": self.is_video,
"thumbnail": sticker.thumbnail.to_dict(),
"emoji": self.emoji,
"file_size": self.file_size,
"premium_animation": self.premium_animation.to_dict(),
"type": self.type,
"custom_emoji_id": self.custom_emoji_id,
"needs_repainting": self.needs_repainting,
}
def test_de_json(self, offline_bot):
json_dict = self.sticker.to_dict()
json_sticker = Sticker.de_json(json_dict, offline_bot)
assert json_sticker.api_kwargs == {}
@@ -152,7 +162,7 @@ class TestStickerWithoutRequest(StickerTestBase):
assert json_sticker.is_video == self.is_video
assert json_sticker.emoji == self.emoji
assert json_sticker.file_size == self.file_size
assert json_sticker.thumbnail == sticker.thumbnail
assert json_sticker.thumbnail == self.thumbnail
assert json_sticker.premium_animation == self.premium_animation
assert json_sticker.type == self.type
assert json_sticker.custom_emoji_id == self.custom_emoji_id
@@ -494,6 +504,13 @@ class StickerSetTestBase:
sticker_type = Sticker.REGULAR
contains_masks = True
thumbnail = PhotoSize("thumb_file_id", "thumb_file_un_id", 100, 100, False)
sticker_set = StickerSet(
name,
title=title,
stickers=stickers,
sticker_type=sticker_type,
thumbnail=thumbnail,
)
class TestStickerSetWithoutRequest(StickerSetTestBase):
@@ -503,22 +520,15 @@ class TestStickerSetWithoutRequest(StickerSetTestBase):
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
def test_de_json(self, offline_bot, sticker):
name = f"test_by_{offline_bot.username}"
json_dict = {
"name": name,
"title": self.title,
"stickers": [x.to_dict() for x in self.stickers],
"thumbnail": sticker.thumbnail.to_dict(),
"sticker_type": self.sticker_type,
"contains_masks": self.contains_masks,
}
def test_de_json(self, offline_bot):
json_dict = self.sticker_set.to_dict()
json_dict["contains_masks"] = self.contains_masks
sticker_set = StickerSet.de_json(json_dict, offline_bot)
assert sticker_set.name == name
assert sticker_set.name == self.name
assert sticker_set.title == self.title
assert sticker_set.stickers == tuple(self.stickers)
assert sticker_set.thumbnail == sticker.thumbnail
assert sticker_set.thumbnail == self.thumbnail
assert sticker_set.sticker_type == self.sticker_type
assert sticker_set.api_kwargs == {"contains_masks": self.contains_masks}
-10
View File
@@ -92,16 +92,6 @@ class TestInputPollOptionWithoutRequest(InputPollOptionTestBase):
assert input_poll_option.text_parse_mode == self.text_parse_mode
assert input_poll_option.text_entities == tuple(self.text_entities)
def test_de_json_deprecated(self, recwarn):
InputPollOption.de_json({"text": self.text}, None)
assert len(recwarn) == 1
assert "`InputPollOption.de_json` is deprecated" in str(recwarn[0].message)
assert "The `media` field will not be included for deserialization" in str(
recwarn[0].message
)
assert recwarn[0].category is PTBDeprecationWarning
def test_to_dict(self, input_poll_option):
input_poll_option_dict = input_poll_option.to_dict()