Skip to content

Add Internal Helper for Deserializing Subclasses #4358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions telegram/_botcommandscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,7 @@ def de_json(
The Telegram object.

"""
data = cls._parse_data(data)

if not data:
return None

_class_mapping: Dict[str, Type[BotCommandScope]] = {
class_mapping: Dict[str, Type[BotCommandScope]] = {
cls.DEFAULT: BotCommandScopeDefault,
cls.ALL_PRIVATE_CHATS: BotCommandScopeAllPrivateChats,
cls.ALL_GROUP_CHATS: BotCommandScopeAllGroupChats,
Expand All @@ -117,9 +112,9 @@ def de_json(
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)
return cls._de_json_subclasses(
data=data, bot=bot, base_class=BotCommandScope, class_mapping=class_mapping
)


class BotCommandScopeDefault(BotCommandScope):
Expand Down
41 changes: 17 additions & 24 deletions telegram/_chatbackground.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,15 @@ def de_json(
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
) -> Optional["BackgroundFill"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)

if not data:
return None

_class_mapping: Dict[str, Type[BackgroundFill]] = {
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)
return cls._de_json_subclasses(
data=data, bot=bot, class_mapping=class_mapping, base_class=BackgroundFill
)


class BackgroundFillSolid(BackgroundFill):
Expand Down Expand Up @@ -273,28 +267,27 @@ def de_json(
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
) -> Optional["BackgroundType"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)

if not data:
return None

_class_mapping: Dict[str, Type[BackgroundType]] = {
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"] = BackgroundFill.de_json(data.get("fill"), bot)
def preprocess_data(data_: JSONDict) -> None:
if "fill" in data_:
data_["fill"] = BackgroundFill.de_json(data_.get("fill"), bot)

if "document" in data:
data["document"] = Document.de_json(data.get("document"), bot)
if "document" in data_:
data_["document"] = Document.de_json(data_.get("document"), bot)

return super().de_json(data=data, bot=bot)
return cls._de_json_subclasses(
data=data,
bot=bot,
class_mapping=class_mapping,
base_class=BackgroundType,
preprocess_data=preprocess_data,
)


class BackgroundTypeFill(BackgroundType):
Expand Down
26 changes: 13 additions & 13 deletions telegram/_chatboost.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,24 +114,24 @@ def de_json(
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
) -> Optional["ChatBoostSource"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)

if not data:
return None

_class_mapping: Dict[str, Type[ChatBoostSource]] = {
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"] = User.de_json(data.get("user"), bot)

return super().de_json(data=data, bot=bot)
def preprocess_data(data_: JSONDict) -> None:
if "user" in data_:
data_["user"] = User.de_json(data_.get("user"), bot)

return cls._de_json_subclasses(
data=data,
bot=bot,
class_mapping=class_mapping,
base_class=ChatBoostSource,
preprocess_data=preprocess_data,
discriminator="source",
)


class ChatBoostSourcePremium(ChatBoostSource):
Expand Down
42 changes: 23 additions & 19 deletions telegram/_chatmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,7 @@ def de_json(
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
) -> Optional["ChatMember"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)

if not data:
return None

_class_mapping: Dict[str, Type[ChatMember]] = {
class_mapping: Dict[str, Type[ChatMember]] = {
cls.OWNER: ChatMemberOwner,
cls.ADMINISTRATOR: ChatMemberAdministrator,
cls.MEMBER: ChatMemberMember,
Expand All @@ -122,23 +117,32 @@ def de_json(
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)
def preprocess_data(data_: JSONDict) -> Optional[ChatMemberRestricted]:
data_["user"] = User.de_json(data_.get("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["user"] = User.de_json(data.get("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_["until_date"], tzinfo=loc_tzinfo)

data["until_date"] = from_timestamp(data["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(cls, ChatMemberRestricted)._de_json(
data=data_, bot=bot, api_kwargs=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 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 None

return super().de_json(data=data, bot=bot)
return cls._de_json_subclasses(
data=data,
bot=bot,
class_mapping=class_mapping,
preprocess_data=preprocess_data,
discriminator="status",
base_class=ChatMember,
)


class ChatMemberOwner(ChatMember):
Expand Down
20 changes: 8 additions & 12 deletions telegram/_menubutton.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,19 @@ def de_json(
The Telegram object.

"""
data = cls._parse_data(data)

if data is None:
return None

if not data and cls is MenuButton:
return None

_class_mapping: Dict[str, Type[MenuButton]] = {
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)
return cls._de_json_subclasses(
data=data,
bot=bot,
class_mapping=class_mapping,
base_class=MenuButton,
allow_empty_data=(MenuButtonCommands, MenuButtonDefault),
)

COMMANDS: Final[str] = constants.MenuButtonType.COMMANDS
""":const:`telegram.constants.MenuButtonType.COMMANDS`"""
Expand Down
34 changes: 17 additions & 17 deletions telegram/_messageorigin.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,33 +100,33 @@ def de_json(
"""Converts JSON data to the appropriate :class:`MessageOrigin` object, i.e. takes
care of selecting the correct subclass.
"""
data = cls._parse_data(data)

if not data:
return None

_class_mapping: Dict[str, Type[MessageOrigin]] = {
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)
def preprocess_data(data_: JSONDict) -> None:
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"] = User.de_json(data.get("sender_user"), bot)
if "sender_user" in data_:
data_["sender_user"] = User.de_json(data_.get("sender_user"), bot)

if "sender_chat" in data:
data["sender_chat"] = Chat.de_json(data.get("sender_chat"), bot)
if "sender_chat" in data_:
data_["sender_chat"] = Chat.de_json(data_.get("sender_chat"), bot)

if "chat" in data:
data["chat"] = Chat.de_json(data.get("chat"), bot)
if "chat" in data_:
data_["chat"] = Chat.de_json(data_.get("chat"), bot)

return super().de_json(data=data, bot=bot)
return cls._de_json_subclasses(
data=data,
bot=bot,
class_mapping=class_mapping,
base_class=MessageOrigin,
preprocess_data=preprocess_data,
)


class MessageOriginUser(MessageOrigin):
Expand Down
17 changes: 4 additions & 13 deletions telegram/_paidmedia.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,15 @@ def de_json(
The Telegram object.

"""
data = cls._parse_data(data)

if data is None:
return None

if not data and cls is PaidMedia:
return None

_class_mapping: Dict[str, Type[PaidMedia]] = {
class_mapping: Dict[str, Type[PaidMedia]] = {
cls.PREVIEW: PaidMediaPreview,
cls.PHOTO: PaidMediaPhoto,
cls.VIDEO: PaidMediaVideo,
}

if cls is PaidMedia 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)
return cls._de_json_subclasses(
data=data, bot=bot, class_mapping=class_mapping, base_class=PaidMedia
)


class PaidMediaPreview(PaidMedia):
Expand Down
35 changes: 12 additions & 23 deletions telegram/_payment/stars.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,15 @@ def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None) -> None:
def de_json(
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
) -> Optional["RevenueWithdrawalState"]:
data = cls._parse_data(data)

if not data:
return None

_class_mapping: Dict[str, Type[RevenueWithdrawalState]] = {
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)
return cls._de_json_subclasses(
data=data, bot=bot, class_mapping=class_mapping, base_class=RevenueWithdrawalState
)


class RevenueWithdrawalStatePending(RevenueWithdrawalState):
Expand Down Expand Up @@ -233,25 +227,20 @@ def de_json(
The Telegram object.

"""
data = cls._parse_data(data)

if data is None:
return None

if not data and cls is TransactionPartner:
return None

_class_mapping: Dict[str, Type[TransactionPartner]] = {
class_mapping: Dict[str, Type[TransactionPartner]] = {
cls.FRAGMENT: TransactionPartnerFragment,
cls.USER: TransactionPartnerUser,
cls.OTHER: TransactionPartnerOther,
cls.TELEGRAM_ADS: TransactionPartnerTelegramAds,
}

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)
return cls._de_json_subclasses(
data=data,
bot=bot,
class_mapping=class_mapping,
base_class=TransactionPartner,
allow_empty_data=(TransactionPartnerOther,),
)


class TransactionPartnerFragment(TransactionPartner):
Expand Down
Loading
Loading