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
143 changed files with 1412 additions and 2829 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15.0-beta.2']
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- python-version: '3.14t'
+1 -1
View File
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.15.16'
rev: 'v0.15.15'
hooks:
# Run the linter:
- id: ruff-check
@@ -1,6 +0,0 @@
documentation = "Documentation Improvements"
pull_requests = [
{ uid = "5240", author_uids = ["harshil21", "Poolitzer"] },
{ uid = "5241", author_uids = ["harshil21"] },
]
@@ -1,9 +0,0 @@
other = """Support Python 3.15 Beta
* Python 3.15 free threading is not fully supported yet, as the optional dependency ``cryptography`` is not yet compatible with it.
"""
[[pull_requests]]
uid = "5259"
author_uids = ["harshil21"]
closes_threads = ["5231"]
@@ -1,5 +0,0 @@
other = "Bump Version to 22.8"
[[pull_requests]]
uid = "5262"
author_uids = ["Poolitzer"]
closes_threads = []
@@ -0,0 +1,5 @@
other = "Centralize `de_json` into `TelegramObject`"
[[pull_requests]]
uid = "5186"
author_uids = ["harshil21"]
closes_threads = []
@@ -1,5 +0,0 @@
dependencies = "Update dependency tornado to v6.5.6 [SECURITY]"
[[pull_requests]]
uid = "5264"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -1,5 +0,0 @@
internal = "Update Ruff to v0.15.16"
[[pull_requests]]
uid = "5265"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -1,5 +0,0 @@
bugfixes = "Fixed ``parse_lpo_and_dwpp`` silently overwriting ``link_preview_options`` when ``disable_web_page_preview=False``."
[[pull_requests]]
uid = "5268"
author_uids = ["JSap0914"]
closes_threads = []
@@ -1,5 +0,0 @@
dependencies = "Update dependency tornado to v6.5.7 [SECURITY]"
[[pull_requests]]
uid = "5273"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -1,5 +0,0 @@
dependencies = "Update dependency cryptography to v48.0.1 [SECURITY]"
[[pull_requests]]
uid = "5274"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -83,13 +83,6 @@ get_updates_read_timeout_addition = [
" ``2``.",
]
RAISES_BLOCK = [
"Raises:",
"",
" :class:`telegram.error.TelegramError`",
"",
]
def find_insert_pos_for_kwargs(lines: list[str]) -> int:
"""Finds the correct position to insert the keyword arguments and returns the index."""
@@ -99,13 +92,6 @@ def find_insert_pos_for_kwargs(lines: list[str]) -> int:
return False
def find_insert_pos_for_raises(lines: list[str]) -> int:
"""Finds the correct position to insert the Raises block and returns the index."""
if "Raises:" in lines:
return -1 # Don't insert if there's already a Raises block
return len(lines) # Insert at the end if there's no Raises block
def check_timeout_and_api_kwargs_presence(obj: object) -> int:
"""Checks if the method has timeout and api_kwargs keyword only parameters."""
sig = inspect.signature(obj)
+4 -18
View File
@@ -27,11 +27,9 @@ from sphinx.application import Sphinx
import telegram
import telegram.ext
from docs.auxil.admonition_inserter import AdmonitionInserter
from docs.auxil.bot_insertion import (
RAISES_BLOCK,
from docs.auxil.kwargs_insertion import (
check_timeout_and_api_kwargs_presence,
find_insert_pos_for_kwargs,
find_insert_pos_for_raises,
get_updates_read_timeout_addition,
keyword_args,
media_write_timeout_change,
@@ -87,8 +85,8 @@ def autodoc_process_docstring(
app: Sphinx, what, name: str, obj: object, options, lines: list[str]
):
"""We do the following things:
1) Use this method to automatically insert the Keyword Args, "Shortcuts" admonitions,
and the Raises block, wherever applicable, for the Bot methods.
1) Use this method to automatically insert the Keyword Args and "Shortcuts" admonitions
for the Bot methods.
2) Use this method to automatically insert "Returned in" admonition into classes
that are returned from the Bot methods
@@ -104,15 +102,13 @@ def autodoc_process_docstring(
"""
# 1) Insert the Keyword Args and "Shortcuts" admonitions for the Bot methods
method_name = name.rsplit(".", maxsplit=1)[-1]
method_name = name.rsplit(".", maxsplit=1)[0]
if (
name.startswith("telegram.Bot.")
and what == "method"
and method_name.islower()
and check_timeout_and_api_kwargs_presence(obj)
):
# Logic for inserting keyword args into docstrings:
# -------------------------------------------------
insert_index = find_insert_pos_for_kwargs(lines)
if not insert_index:
raise ValueError(
@@ -138,16 +134,6 @@ def autodoc_process_docstring(
lines[insert_idx:insert_idx] = effective_insert
insert_idx += len(effective_insert)
# Logic for inserting Raises:
# -------------------------------------------------
# We will only insert the Raises block if there isn't already one.
insert_index = find_insert_pos_for_raises(lines)
if insert_index != -1:
lines[insert_index:insert_index] = RAISES_BLOCK
# Logic for inserting "Shortcuts" admonition:
# -------------------------------------------
ADMONITION_INSERTER.insert_admonitions(
obj=typing.cast("collections.abc.Callable", obj),
docstring_lines=lines,
-1
View File
@@ -165,7 +165,6 @@ Available Types
telegram.poll
telegram.pollanswer
telegram.pollmedia
telegram.polloption
telegram.polloptionadded
telegram.polloptiondeleted
telegram.preparedkeyboardbutton
+1 -2
View File
@@ -36,7 +36,6 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
]
dependencies = [
"httpx >=0.27,<0.29",
@@ -134,7 +133,7 @@ docs = [
]
linting = [
"prek",
"ruff==0.15.16",
"ruff==0.15.15",
"mypy==1.20.2",
"pylint==4.0.5"
]
+18 -19
View File
@@ -343,7 +343,19 @@ __all__ = (
"warnings",
)
__lazy_modules__: list[str] = ["constants", "error", "helpers", "request", "warnings"]
from telegram._inputchecklist import InputChecklist, InputChecklistTask
from telegram._payment.stars.staramount import StarAmount
from telegram._payment.stars.startransactions import StarTransaction, StarTransactions
from telegram._payment.stars.transactionpartner import (
TransactionPartner,
TransactionPartnerAffiliateProgram,
TransactionPartnerChat,
TransactionPartnerFragment,
TransactionPartnerOther,
TransactionPartnerTelegramAds,
TransactionPartnerTelegramApi,
TransactionPartnerUser,
)
from . import _version, constants, error, helpers, request, warnings
from ._birthdate import Birthdate
@@ -419,6 +431,11 @@ from ._copytextbutton import CopyTextButton
from ._dice import Dice
from ._directmessagepricechanged import DirectMessagePriceChanged
from ._directmessagestopic import DirectMessagesTopic
from ._files._inputstorycontent import (
InputStoryContent,
InputStoryContentPhoto,
InputStoryContentVideo,
)
from ._files.animation import Animation
from ._files.audio import Audio
from ._files.chatphoto import ChatPhoto
@@ -450,11 +467,6 @@ from ._files.inputprofilephoto import (
InputProfilePhotoStatic,
)
from ._files.inputsticker import InputSticker
from ._files.inputstorycontent import (
InputStoryContent,
InputStoryContentPhoto,
InputStoryContentVideo,
)
from ._files.livephoto import LivePhoto
from ._files.location import Location
from ._files.photosize import PhotoSize
@@ -511,7 +523,6 @@ from ._inline.inputmessagecontent import InputMessageContent
from ._inline.inputtextmessagecontent import InputTextMessageContent
from ._inline.inputvenuemessagecontent import InputVenueMessageContent
from ._inline.preparedinlinemessage import PreparedInlineMessage
from ._inputchecklist import InputChecklist, InputChecklistTask
from ._keyboardbutton import KeyboardButton
from ._keyboardbuttonpolltype import KeyboardButtonPollType
from ._keyboardbuttonrequest import (
@@ -585,18 +596,6 @@ from ._payment.stars.revenuewithdrawalstate import (
RevenueWithdrawalStatePending,
RevenueWithdrawalStateSucceeded,
)
from ._payment.stars.staramount import StarAmount
from ._payment.stars.startransactions import StarTransaction, StarTransactions
from ._payment.stars.transactionpartner import (
TransactionPartner,
TransactionPartnerAffiliateProgram,
TransactionPartnerChat,
TransactionPartnerFragment,
TransactionPartnerOther,
TransactionPartnerTelegramAds,
TransactionPartnerTelegramApi,
TransactionPartnerUser,
)
from ._payment.successfulpayment import SuccessfulPayment
from ._poll import (
InputPollOption,
+621 -45
View File
File diff suppressed because it is too large Load Diff
+2 -14
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):
"""
@@ -37,7 +33,7 @@ class BotAccessSettings(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`is_access_restricted` and :attr:`added_users` are equal.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
is_access_restricted (:obj:`bool`): :obj:`True`, if only selected users can access the bot.
@@ -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,
+4 -4
View File
@@ -1110,7 +1110,7 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_message_draft`.
.. versionchanged:: 22.8
.. versionchanged:: NEXT.VERSION
Bot API 10.0 makes the ``text`` argument optional.
Returns:
@@ -1392,7 +1392,7 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_live_photo`.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
@@ -4155,7 +4155,7 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_message_reaction`.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -4195,7 +4195,7 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_all_message_reactions`.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
+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`
+18 -41
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):
"""
@@ -521,7 +496,7 @@ class ChatMemberRestricted(ChatMember):
can_react_to_messages (:obj:`bool`): :obj:`True`, if the user is allowed to react to
messages.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
tag (:obj:`str`, optional): Tag of the member.
.. versionadded:: 22.7
@@ -582,7 +557,7 @@ class ChatMemberRestricted(ChatMember):
can_react_to_messages (:obj:`bool`): :obj:`True`, if the user is allowed to react to
messages.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
tag (:obj:`str`): Optional. Tag of the member.
.. versionadded:: 22.7
@@ -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,
@@ -632,7 +609,7 @@ class ChatMemberRestricted(ChatMember):
can_send_voice_notes: bool,
can_edit_tag: bool,
tag: str | None = None,
# tags: 22.8
# tags: NEXT.VERSION
# temporarily optional to make it not breaking
can_react_to_messages: bool | None = None,
*,
-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)
+9 -21
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.
@@ -50,7 +45,7 @@ class ChatPermissions(TelegramObject):
.. versionchanged:: 22.7
:attr:`can_edit_tag` is considered as well when comparing objects of
this type in terms of equality.
.. versionchanged:: 22.8
.. versionchanged:: NEXT.VERSION
:attr:`can_react_to_messages` is considered as well when comparing objects of
this type in terms of equality.
@@ -106,7 +101,7 @@ class ChatPermissions(TelegramObject):
can_react_to_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to react
to messages. If omitted, defaults to the value of :attr:`can_send_messages`.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Attributes:
can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text
@@ -155,7 +150,7 @@ class ChatPermissions(TelegramObject):
can_react_to_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to react
to messages. If omitted, defaults to the value of :attr:`can_send_messages`.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
"""
@@ -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)
+33 -33
View File
@@ -176,7 +176,7 @@ class InputPaidMedia(TelegramObject):
LIVE_PHOTO: Final[str] = constants.InputPaidMediaType.LIVE_PHOTO
""":const:`telegram.constants.InputPaidMediaType.LIVE_PHOTO`
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
"""
__slots__ = ("media", "type")
@@ -342,7 +342,7 @@ class InputPaidMediaLivePhoto(InputPaidMedia):
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
@@ -404,8 +404,8 @@ class InputMediaAnimation(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 22.8
.. deprecated:: 22.8
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the animation to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
@@ -441,7 +441,7 @@ class InputMediaAnimation(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: 22.8
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
@@ -494,7 +494,7 @@ class InputMediaAnimation(InputMedia):
height: int | None = None,
duration: TimePeriod | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated 22.8
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
@@ -509,7 +509,7 @@ class InputMediaAnimation(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"22.8",
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -565,8 +565,8 @@ class InputMediaPhoto(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 22.8
.. deprecated:: 22.8
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional ): Caption of the photo to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
@@ -590,7 +590,7 @@ class InputMediaPhoto(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: 22.8
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
@@ -626,7 +626,7 @@ class InputMediaPhoto(InputMedia):
caption: str | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated 22.8
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
@@ -640,7 +640,7 @@ class InputMediaPhoto(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"22.8",
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -693,8 +693,8 @@ class InputMediaVideo(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 22.8
.. deprecated:: 22.8
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the video to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
@@ -738,7 +738,7 @@ class InputMediaVideo(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: 22.8
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
@@ -803,7 +803,7 @@ class InputMediaVideo(InputMedia):
supports_streaming: bool | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated 22.8
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
@@ -820,7 +820,7 @@ class InputMediaVideo(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"22.8",
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -869,7 +869,7 @@ class InputMediaVideo(InputMedia):
class InputMediaLocation(_BaseInputMedia):
"""Represents a location to be sent.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
latitude (:obj:`float`): Latitude of the location.
@@ -905,7 +905,7 @@ class InputMediaLocation(_BaseInputMedia):
class InputMediaVenue(_BaseInputMedia):
"""Represents a venue to be sent.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
latitude (:obj:`float`): Latitude of the location.
@@ -976,7 +976,7 @@ class InputMediaSticker(_BaseInputMedia):
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
@@ -1039,8 +1039,8 @@ class InputMediaAudio(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 22.8
.. deprecated:: 22.8
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the audio to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
@@ -1070,7 +1070,7 @@ class InputMediaAudio(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: 22.8
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
@@ -1111,7 +1111,7 @@ class InputMediaAudio(InputMedia):
performer: str | None = None,
title: str | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated 22.8
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
thumbnail: "FileInput | None" = None,
@@ -1124,7 +1124,7 @@ class InputMediaAudio(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"22.8",
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -1181,8 +1181,8 @@ class InputMediaDocument(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 22.8
.. deprecated:: 22.8
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the document to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
@@ -1207,7 +1207,7 @@ class InputMediaDocument(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: 22.8
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
@@ -1240,7 +1240,7 @@ class InputMediaDocument(InputMedia):
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_content_type_detection: bool | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated 22.8
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
thumbnail: "FileInput | None" = None,
@@ -1253,7 +1253,7 @@ class InputMediaDocument(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"22.8",
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -1285,7 +1285,7 @@ class InputMediaLivePhoto(InputMedia):
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
@@ -1364,7 +1364,7 @@ InputPollMedia: TypeAlias = (
)
"""Type alias for InputPollMedia objects.
versionadded:: 22.8
versionadded:: NEXT.VERSION
"""
InputPollOptionMedia: TypeAlias = (
@@ -1378,5 +1378,5 @@ InputPollOptionMedia: TypeAlias = (
)
"""Type alias for InputPollOptionMedia objects.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
"""
+2 -13
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):
"""
@@ -39,7 +37,7 @@ class LivePhoto(_BaseMedium):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`file_unique_id` is equal.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
file_id (:obj:`str`): Identifier for the video file which can be used to download or reuse
@@ -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)
+2 -16
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.
@@ -105,7 +101,7 @@ class Video(_BaseThumbedMedium):
.. deprecated:: v22.2
|time-period-int-deprecated|
qualities (tuple[:class:`telegram.VideoQuality`]): Optional. List of available qualities
qualities (Sequence[:class:`telegram.VideoQuality`]): Optional. List of available qualities
of the video
.. versionadded:: 22.7
@@ -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)
+8 -35
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):
"""
@@ -130,7 +124,7 @@ class KeyboardButton(TelegramObject):
in the `@BotFather <https://telegram.me/BotFather>` Mini App. Available in private
chats only.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Attributes:
@@ -185,7 +179,7 @@ class KeyboardButton(TelegramObject):
in the `@BotFather <https://telegram.me/BotFather>` Mini App. Available in private
chats only.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
"""
__slots__ = (
@@ -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)
+1 -21
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):
"""
@@ -280,7 +260,7 @@ class KeyboardButtonRequestManagedBot(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`request_id` is equal.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
request_id (:obj:`int`): Signed 32-bit identifier of the request. Must be unique
+2 -26
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):
"""
@@ -38,7 +33,7 @@ class ManagedBotCreated(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`bot` is equal.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
bot (:class:`telegram.User`): Information about the bot. The bot's token can be fetched
@@ -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):
"""
@@ -79,7 +65,7 @@ class ManagedBotUpdated(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`user` and :attr:`bot` are equal.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
user (:class:`telegram.User`): User that created the bot.
@@ -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.
+45 -261
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.
@@ -693,46 +694,46 @@ class Message(MaybeInaccessibleMessage):
.. versionadded:: 22.7
sender_tag (:obj:`str`, optional): Tag or custom title of the sender of the message; for
supergroups only.
supergroups only
.. versionadded:: 22.7
poll_option_added (:class:`telegram.PollOptionAdded`, optional): Service message:
answer option was added to a poll.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
poll_option_deleted (:class:`telegram.PollOptionDeleted`, optional): Service message:
answer option was deleted from a poll.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
reply_to_poll_option_id (:obj:`str`, optional): Persistent
identifier of the specific poll option that is being replied to.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
managed_bot_created (:class:`telegram.ManagedBotCreated`, optional): Service message: user
created a bot that will be managed by the current bot.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
guest_bot_caller_user (:class:`telegram.User`, optional): For a message sent by a guest
bot, this is the user whose original message triggered the bot's response.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
guest_bot_caller_chat (:class:`telegram.Chat`, optional): For a message sent by a guest
bot, this is the chat whose original message triggered the bot's response.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
guest_query_id (:obj:`str`, optional): The unique identifier for the guest query. Use this
identifier with the method :meth:`telegram.Bot.answer_guest_query` to send a response
message. If non-empty, the message belongs to the chat where the guest bot was
summoned, which may not coincide with other existing bot chats sharing the same
identifier.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
live_photo (:class:`telegram.LivePhoto`, optional): Message is a live photo, information
about the live photo. For backward compatibility, when this field is set, the photo
field will also be set.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Attributes:
message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances
@@ -1146,45 +1147,45 @@ class Message(MaybeInaccessibleMessage):
.. versionadded:: 22.7
sender_tag (:obj:`str`): Optional. Tag or custom title of the sender of the message; for
supergroups only.
supergroups only
.. versionadded:: 22.7
poll_option_added (:class:`telegram.PollOptionAdded`): Optional. Service message:
answer option was added to a poll.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
poll_option_deleted (:class:`telegram.PollOptionDeleted`): Optional. Service message:
answer option was deleted from a poll.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
reply_to_poll_option_id (:obj:`str`): Optional. Persistent
identifier of the specific poll option that is being replied to.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
managed_bot_created (:class:`telegram.ManagedBotCreated`): Optional. Service message: user
created a bot that will be managed by the current bot.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
guest_bot_caller_user (:class:`telegram.User`): Optional. For a message sent by a guest
bot, this is the user whose original message triggered the bot's response.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
guest_bot_caller_chat (:class:`telegram.Chat`): Optional. For a message sent by a guest
bot, this is the chat whose original message triggered the bot's response.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
guest_query_id (:obj:`str`): Optional. The unique identifier for the guest query. Use this
identifier with the method :meth:`telegram.Bot.answer_guest_query` to send a response
message. If non-empty, the message belongs to the chat where the guest bot was
summoned, which may not coincide with other existing bot chats sharing the same
identifier.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
live_photo (:class:`telegram.LivePhoto`): Optional. Message is a live photo, information
about the live photo. For backward compatibility, when this field is set, the photo
field will also be set.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
.. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
@@ -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,
@@ -2279,7 +2063,7 @@ class Message(MaybeInaccessibleMessage):
.. versionadded:: 22.6
.. versionchanged:: 22.8
.. versionchanged:: NEXT.VERSION
Bot API 10.0 makes the ``text`` argument optional.
Returns:
@@ -2756,7 +2540,7 @@ class Message(MaybeInaccessibleMessage):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_live_photo`.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Keyword Args:
do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
@@ -5400,7 +5184,7 @@ class Message(MaybeInaccessibleMessage):
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_message_reaction`.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool` On success, :obj:`True` is returned.
@@ -5436,7 +5220,7 @@ class Message(MaybeInaccessibleMessage):
For the documentation of the arguments, please see :meth:`telegram.Bot.answer_guest_query`.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Returns:
:class:`telegram.SentGuestMessage`: On success, a
+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]
+14 -72
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):
"""
@@ -262,7 +225,7 @@ class PaidMediaLivePhoto(PaidMedia):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`live_photo` are equal.
.. versionadded:: 22.8
.. versionadded:: NEXT.VERSION
Args:
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.LIVE_PHOTO`
@@ -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"

Some files were not shown because too many files have changed in this diff Show More