hgjgjgg
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,537 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
# pylint: disable=missing-module-docstring, redefined-builtin
|
|
||||||
import json
|
|
||||||
from base64 import b64decode
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional, no_type_check
|
|
||||||
|
|
||||||
try:
|
|
||||||
from cryptography.hazmat.backends import default_backend
|
|
||||||
from cryptography.hazmat.primitives.asymmetric.padding import MGF1, OAEP
|
|
||||||
from cryptography.hazmat.primitives.ciphers import Cipher
|
|
||||||
from cryptography.hazmat.primitives.ciphers.algorithms import AES
|
|
||||||
from cryptography.hazmat.primitives.ciphers.modes import CBC
|
|
||||||
from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512, Hash
|
|
||||||
|
|
||||||
CRYPTO_INSTALLED = True
|
|
||||||
except ImportError:
|
|
||||||
default_backend = None # type: ignore[assignment]
|
|
||||||
MGF1, OAEP, Cipher, AES, CBC = (None, None, None, None, None) # type: ignore[misc,assignment]
|
|
||||||
SHA1, SHA256, SHA512, Hash = (None, None, None, None) # type: ignore[misc,assignment]
|
|
||||||
|
|
||||||
CRYPTO_INSTALLED = False
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
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):
|
|
||||||
"""
|
|
||||||
Decrypt per telegram docs at https://core.telegram.org/passport.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
secret (:obj:`str` or :obj:`bytes`): The encryption secret, either as bytes or as a
|
|
||||||
base64 encoded string.
|
|
||||||
hash (:obj:`str` or :obj:`bytes`): The hash, either as bytes or as a
|
|
||||||
base64 encoded string.
|
|
||||||
data (:obj:`str` or :obj:`bytes`): The data to decrypt, either as bytes or as a
|
|
||||||
base64 encoded string.
|
|
||||||
file (:obj:`bool`): Force data to be treated as raw data, instead of trying to
|
|
||||||
b64decode it.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:class:`PassportDecryptionError`: Given hash does not match hash of decrypted data.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`bytes`: The decrypted data as bytes.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not CRYPTO_INSTALLED:
|
|
||||||
raise RuntimeError(
|
|
||||||
"To use Telegram Passports, PTB must be installed via `pip install "
|
|
||||||
'"python-telegram-bot[passport]"`.'
|
|
||||||
)
|
|
||||||
# Make a SHA512 hash of secret + update
|
|
||||||
digest = Hash(SHA512(), backend=default_backend())
|
|
||||||
digest.update(secret + hash)
|
|
||||||
secret_hash_hash = digest.finalize()
|
|
||||||
# First 32 chars is our key, next 16 is the initialisation vector
|
|
||||||
key, init_vector = secret_hash_hash[:32], secret_hash_hash[32 : 32 + 16]
|
|
||||||
# Init a AES-CBC cipher and decrypt the data
|
|
||||||
cipher = Cipher(AES(key), CBC(init_vector), backend=default_backend())
|
|
||||||
decryptor = cipher.decryptor()
|
|
||||||
data = decryptor.update(data) + decryptor.finalize()
|
|
||||||
# Calculate SHA256 hash of the decrypted data
|
|
||||||
digest = Hash(SHA256(), backend=default_backend())
|
|
||||||
digest.update(data)
|
|
||||||
data_hash = digest.finalize()
|
|
||||||
# If the newly calculated hash did not match the one telegram gave us
|
|
||||||
if data_hash != hash:
|
|
||||||
# Raise a error that is caught inside telegram.PassportData and transformed into a warning
|
|
||||||
raise PassportDecryptionError(f"Hashes are not equal! {data_hash} != {hash}")
|
|
||||||
# Return data without padding
|
|
||||||
return data[data[0] :]
|
|
||||||
|
|
||||||
|
|
||||||
@no_type_check
|
|
||||||
def decrypt_json(secret, hash, data):
|
|
||||||
"""Decrypts data using secret and hash and then decodes utf-8 string and loads json"""
|
|
||||||
return json.loads(decrypt(secret, hash, data).decode(TextEncoding.UTF_8))
|
|
||||||
|
|
||||||
|
|
||||||
class EncryptedCredentials(TelegramObject):
|
|
||||||
"""Contains data required for decrypting and authenticating EncryptedPassportElement. See the
|
|
||||||
Telegram Passport Documentation for a complete description of the data decryption and
|
|
||||||
authentication processes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`data`, :attr:`hash` and :attr:`secret` are equal.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This object is decrypted only when originating from
|
|
||||||
:attr:`telegram.PassportData.decrypted_credentials`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (:class:`telegram.Credentials` | :obj:`str`): Decrypted data with unique user's
|
|
||||||
nonce, data hashes and secrets used for EncryptedPassportElement decryption and
|
|
||||||
authentication or base64 encrypted data.
|
|
||||||
hash (:obj:`str`): Base64-encoded data hash for data authentication.
|
|
||||||
secret (:obj:`str`): Decrypted or encrypted secret used for decryption.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
data (:class:`telegram.Credentials` | :obj:`str`): Decrypted data with unique user's
|
|
||||||
nonce, data hashes and secrets used for EncryptedPassportElement decryption and
|
|
||||||
authentication or base64 encrypted data.
|
|
||||||
hash (:obj:`str`): Base64-encoded data hash for data authentication.
|
|
||||||
secret (:obj:`str`): Decrypted or encrypted secret used for decryption.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"_decrypted_data",
|
|
||||||
"_decrypted_secret",
|
|
||||||
"data",
|
|
||||||
"hash",
|
|
||||||
"secret",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
data: str,
|
|
||||||
hash: str,
|
|
||||||
secret: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.data: str = data
|
|
||||||
self.hash: str = hash
|
|
||||||
self.secret: str = secret
|
|
||||||
|
|
||||||
self._id_attrs = (self.data, self.hash, self.secret)
|
|
||||||
|
|
||||||
self._decrypted_secret: Optional[bytes] = None
|
|
||||||
self._decrypted_data: Optional[Credentials] = None
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def decrypted_secret(self) -> bytes:
|
|
||||||
"""
|
|
||||||
:obj:`bytes`: Lazily decrypt and return secret.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
|
||||||
private/public key but can also suggest malformed/tampered data.
|
|
||||||
"""
|
|
||||||
if self._decrypted_secret is None:
|
|
||||||
if not CRYPTO_INSTALLED:
|
|
||||||
raise RuntimeError(
|
|
||||||
"To use Telegram Passports, PTB must be installed via `pip install "
|
|
||||||
'"python-telegram-bot[passport]"`.'
|
|
||||||
)
|
|
||||||
# Try decrypting according to step 1 at
|
|
||||||
# https://core.telegram.org/passport#decrypting-data
|
|
||||||
# We make sure to base64 decode the secret first.
|
|
||||||
# Telegram says to use OAEP padding so we do that. The Mask Generation Function
|
|
||||||
# is the default for OAEP, the algorithm is the default for PHP which is what
|
|
||||||
# Telegram's backend servers run.
|
|
||||||
try:
|
|
||||||
self._decrypted_secret = self.get_bot().private_key.decrypt( # type: ignore
|
|
||||||
b64decode(self.secret),
|
|
||||||
OAEP(mgf=MGF1(algorithm=SHA1()), algorithm=SHA1(), label=None), # skipcq
|
|
||||||
)
|
|
||||||
except ValueError as exception:
|
|
||||||
# If decryption fails raise exception
|
|
||||||
raise PassportDecryptionError(exception) from exception
|
|
||||||
return self._decrypted_secret
|
|
||||||
|
|
||||||
@property
|
|
||||||
def decrypted_data(self) -> "Credentials":
|
|
||||||
"""
|
|
||||||
:class:`telegram.Credentials`: Lazily decrypt and return credentials data. This object
|
|
||||||
also contains the user specified nonce as
|
|
||||||
`decrypted_data.nonce`.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
|
||||||
private/public key but can also suggest malformed/tampered data.
|
|
||||||
"""
|
|
||||||
if self._decrypted_data is None:
|
|
||||||
self._decrypted_data = Credentials.de_json(
|
|
||||||
decrypt_json(self.decrypted_secret, b64decode(self.hash), b64decode(self.data)),
|
|
||||||
self.get_bot(),
|
|
||||||
)
|
|
||||||
return self._decrypted_data # type: ignore[return-value]
|
|
||||||
|
|
||||||
|
|
||||||
class Credentials(TelegramObject):
|
|
||||||
"""
|
|
||||||
Attributes:
|
|
||||||
secure_data (:class:`telegram.SecureData`): Credentials for encrypted data
|
|
||||||
nonce (:obj:`str`): Bot-specified nonce
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("nonce", "secure_data")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
secure_data: "SecureData",
|
|
||||||
nonce: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.secure_data: SecureData = secure_data
|
|
||||||
self.nonce: str = nonce
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["Credentials"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["secure_data"] = SecureData.de_json(data.get("secure_data"), bot=bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class SecureData(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents the credentials that were used to decrypt the encrypted data.
|
|
||||||
All fields are optional and depend on fields that were requested.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
personal_details (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
personal details.
|
|
||||||
passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted passport.
|
|
||||||
internal_passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
internal passport.
|
|
||||||
driver_license (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
driver license.
|
|
||||||
identity_card (:class:`telegram.SecureValue`, optional): Credentials for encrypted ID card
|
|
||||||
address (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
residential address.
|
|
||||||
utility_bill (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
utility bill.
|
|
||||||
bank_statement (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
bank statement.
|
|
||||||
rental_agreement (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
rental agreement.
|
|
||||||
passport_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
registration from internal passport.
|
|
||||||
temporary_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
|
||||||
temporary registration.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
personal_details (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
personal details.
|
|
||||||
passport (:class:`telegram.SecureValue`): Optional. Credentials for encrypted passport.
|
|
||||||
internal_passport (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
internal passport.
|
|
||||||
driver_license (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
driver license.
|
|
||||||
identity_card (:class:`telegram.SecureValue`): Optional. Credentials for encrypted ID card
|
|
||||||
address (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
residential address.
|
|
||||||
utility_bill (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
utility bill.
|
|
||||||
bank_statement (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
bank statement.
|
|
||||||
rental_agreement (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
rental agreement.
|
|
||||||
passport_registration (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
registration from internal passport.
|
|
||||||
temporary_registration (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
|
||||||
temporary registration.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"address",
|
|
||||||
"bank_statement",
|
|
||||||
"driver_license",
|
|
||||||
"identity_card",
|
|
||||||
"internal_passport",
|
|
||||||
"passport",
|
|
||||||
"passport_registration",
|
|
||||||
"personal_details",
|
|
||||||
"rental_agreement",
|
|
||||||
"temporary_registration",
|
|
||||||
"utility_bill",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
personal_details: Optional["SecureValue"] = None,
|
|
||||||
passport: Optional["SecureValue"] = None,
|
|
||||||
internal_passport: Optional["SecureValue"] = None,
|
|
||||||
driver_license: Optional["SecureValue"] = None,
|
|
||||||
identity_card: Optional["SecureValue"] = None,
|
|
||||||
address: Optional["SecureValue"] = None,
|
|
||||||
utility_bill: Optional["SecureValue"] = None,
|
|
||||||
bank_statement: Optional["SecureValue"] = None,
|
|
||||||
rental_agreement: Optional["SecureValue"] = None,
|
|
||||||
passport_registration: Optional["SecureValue"] = None,
|
|
||||||
temporary_registration: Optional["SecureValue"] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
# Optionals
|
|
||||||
self.temporary_registration: Optional[SecureValue] = temporary_registration
|
|
||||||
self.passport_registration: Optional[SecureValue] = passport_registration
|
|
||||||
self.rental_agreement: Optional[SecureValue] = rental_agreement
|
|
||||||
self.bank_statement: Optional[SecureValue] = bank_statement
|
|
||||||
self.utility_bill: Optional[SecureValue] = utility_bill
|
|
||||||
self.address: Optional[SecureValue] = address
|
|
||||||
self.identity_card: Optional[SecureValue] = identity_card
|
|
||||||
self.driver_license: Optional[SecureValue] = driver_license
|
|
||||||
self.internal_passport: Optional[SecureValue] = internal_passport
|
|
||||||
self.passport: Optional[SecureValue] = passport
|
|
||||||
self.personal_details: Optional[SecureValue] = personal_details
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["SecureData"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["temporary_registration"] = SecureValue.de_json(
|
|
||||||
data.get("temporary_registration"), bot=bot
|
|
||||||
)
|
|
||||||
data["passport_registration"] = SecureValue.de_json(
|
|
||||||
data.get("passport_registration"), bot=bot
|
|
||||||
)
|
|
||||||
data["rental_agreement"] = SecureValue.de_json(data.get("rental_agreement"), bot=bot)
|
|
||||||
data["bank_statement"] = SecureValue.de_json(data.get("bank_statement"), bot=bot)
|
|
||||||
data["utility_bill"] = SecureValue.de_json(data.get("utility_bill"), bot=bot)
|
|
||||||
data["address"] = SecureValue.de_json(data.get("address"), bot=bot)
|
|
||||||
data["identity_card"] = SecureValue.de_json(data.get("identity_card"), bot=bot)
|
|
||||||
data["driver_license"] = SecureValue.de_json(data.get("driver_license"), bot=bot)
|
|
||||||
data["internal_passport"] = SecureValue.de_json(data.get("internal_passport"), bot=bot)
|
|
||||||
data["passport"] = SecureValue.de_json(data.get("passport"), bot=bot)
|
|
||||||
data["personal_details"] = SecureValue.de_json(data.get("personal_details"), bot=bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class SecureValue(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents the credentials that were used to decrypt the encrypted value.
|
|
||||||
All fields are optional and depend on the type of field.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (:class:`telegram.DataCredentials`, optional): Credentials for encrypted Telegram
|
|
||||||
Passport data. Available for "personal_details", "passport", "driver_license",
|
|
||||||
"identity_card", "identity_passport" and "address" types.
|
|
||||||
front_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted
|
|
||||||
document's front side. Available for "passport", "driver_license", "identity_card"
|
|
||||||
and "internal_passport".
|
|
||||||
reverse_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted
|
|
||||||
document's reverse side. Available for "driver_license" and "identity_card".
|
|
||||||
selfie (:class:`telegram.FileCredentials`, optional): Credentials for encrypted selfie
|
|
||||||
of the user with a document. Can be available for "passport", "driver_license",
|
|
||||||
"identity_card" and "internal_passport".
|
|
||||||
translation (list[:class:`telegram.FileCredentials`], optional): Credentials for an
|
|
||||||
encrypted translation of the document. Available for "passport", "driver_license",
|
|
||||||
"identity_card", "internal_passport", "utility_bill", "bank_statement",
|
|
||||||
"rental_agreement", "passport_registration" and "temporary_registration".
|
|
||||||
files (list[:class:`telegram.FileCredentials`], optional): Credentials for encrypted
|
|
||||||
files. Available for "utility_bill", "bank_statement", "rental_agreement",
|
|
||||||
"passport_registration" and "temporary_registration" types.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
data (:class:`telegram.DataCredentials`): Optional. Credentials for encrypted Telegram
|
|
||||||
Passport data. Available for "personal_details", "passport", "driver_license",
|
|
||||||
"identity_card", "identity_passport" and "address" types.
|
|
||||||
front_side (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted
|
|
||||||
document's front side. Available for "passport", "driver_license", "identity_card"
|
|
||||||
and "internal_passport".
|
|
||||||
reverse_side (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted
|
|
||||||
document's reverse side. Available for "driver_license" and "identity_card".
|
|
||||||
selfie (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted selfie
|
|
||||||
of the user with a document. Can be available for "passport", "driver_license",
|
|
||||||
"identity_card" and "internal_passport".
|
|
||||||
translation (tuple[:class:`telegram.FileCredentials`]): Optional. Credentials for an
|
|
||||||
encrypted translation of the document. Available for "passport", "driver_license",
|
|
||||||
"identity_card", "internal_passport", "utility_bill", "bank_statement",
|
|
||||||
"rental_agreement", "passport_registration" and "temporary_registration".
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|tupleclassattrs|
|
|
||||||
|
|
||||||
files (tuple[:class:`telegram.FileCredentials`]): Optional. Credentials for encrypted
|
|
||||||
files. Available for "utility_bill", "bank_statement", "rental_agreement",
|
|
||||||
"passport_registration" and "temporary_registration" types.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* |tupleclassattrs|
|
|
||||||
* |alwaystuple|
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("data", "files", "front_side", "reverse_side", "selfie", "translation")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
data: Optional["DataCredentials"] = None,
|
|
||||||
front_side: Optional["FileCredentials"] = None,
|
|
||||||
reverse_side: Optional["FileCredentials"] = None,
|
|
||||||
selfie: Optional["FileCredentials"] = None,
|
|
||||||
files: Optional[Sequence["FileCredentials"]] = None,
|
|
||||||
translation: Optional[Sequence["FileCredentials"]] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.data: Optional[DataCredentials] = data
|
|
||||||
self.front_side: Optional[FileCredentials] = front_side
|
|
||||||
self.reverse_side: Optional[FileCredentials] = reverse_side
|
|
||||||
self.selfie: Optional[FileCredentials] = selfie
|
|
||||||
self.files: tuple[FileCredentials, ...] = parse_sequence_arg(files)
|
|
||||||
self.translation: tuple[FileCredentials, ...] = parse_sequence_arg(translation)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["SecureValue"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["data"] = DataCredentials.de_json(data.get("data"), bot=bot)
|
|
||||||
data["front_side"] = FileCredentials.de_json(data.get("front_side"), bot=bot)
|
|
||||||
data["reverse_side"] = FileCredentials.de_json(data.get("reverse_side"), bot=bot)
|
|
||||||
data["selfie"] = FileCredentials.de_json(data.get("selfie"), bot=bot)
|
|
||||||
data["files"] = FileCredentials.de_list(data.get("files"), bot=bot)
|
|
||||||
data["translation"] = FileCredentials.de_list(data.get("translation"), bot=bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class _CredentialsBase(TelegramObject):
|
|
||||||
"""Base class for DataCredentials and FileCredentials."""
|
|
||||||
|
|
||||||
__slots__ = ("data_hash", "file_hash", "hash", "secret")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
hash: str,
|
|
||||||
secret: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.hash: str = hash
|
|
||||||
self.secret: str = secret
|
|
||||||
|
|
||||||
# Aliases just to be sure
|
|
||||||
self.file_hash: str = self.hash
|
|
||||||
self.data_hash: str = self.hash
|
|
||||||
|
|
||||||
|
|
||||||
class DataCredentials(_CredentialsBase):
|
|
||||||
"""
|
|
||||||
These credentials can be used to decrypt encrypted data from the data field in
|
|
||||||
EncryptedPassportData.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data_hash (:obj:`str`): Checksum of encrypted data
|
|
||||||
secret (:obj:`str`): Secret of encrypted data
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
hash (:obj:`str`): Checksum of encrypted data
|
|
||||||
secret (:obj:`str`): Secret of encrypted data
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, data_hash: str, secret: str, *, api_kwargs: Optional[JSONDict] = None):
|
|
||||||
super().__init__(hash=data_hash, secret=secret, api_kwargs=api_kwargs)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class FileCredentials(_CredentialsBase):
|
|
||||||
"""
|
|
||||||
These credentials can be used to decrypt encrypted files from the front_side,
|
|
||||||
reverse_side, selfie and files fields in EncryptedPassportData.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_hash (:obj:`str`): Checksum of encrypted file
|
|
||||||
secret (:obj:`str`): Secret of encrypted file
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
hash (:obj:`str`): Checksum of encrypted file
|
|
||||||
secret (:obj:`str`): Secret of encrypted file
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, file_hash: str, secret: str, *, api_kwargs: Optional[JSONDict] = None):
|
|
||||||
super().__init__(hash=file_hash, secret=secret, api_kwargs=api_kwargs)
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
# pylint: disable=missing-module-docstring
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class PersonalDetails(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents personal details.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
first_name (:obj:`str`): First Name.
|
|
||||||
middle_name (:obj:`str`): Optional. First Name.
|
|
||||||
last_name (:obj:`str`): Last Name.
|
|
||||||
birth_date (:obj:`str`): Date of birth in DD.MM.YYYY format.
|
|
||||||
gender (:obj:`str`): Gender, male or female.
|
|
||||||
country_code (:obj:`str`): Citizenship (ISO 3166-1 alpha-2 country code).
|
|
||||||
residence_country_code (:obj:`str`): Country of residence (ISO 3166-1 alpha-2 country
|
|
||||||
code).
|
|
||||||
first_name_native (:obj:`str`): First Name in the language of the user's country of
|
|
||||||
residence.
|
|
||||||
middle_name_native (:obj:`str`): Optional. Middle Name in the language of the user's
|
|
||||||
country of residence.
|
|
||||||
last_name_native (:obj:`str`): Last Name in the language of the user's country of
|
|
||||||
residence.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
first_name (:obj:`str`): First Name.
|
|
||||||
middle_name (:obj:`str`): Optional. First Name.
|
|
||||||
last_name (:obj:`str`): Last Name.
|
|
||||||
birth_date (:obj:`str`): Date of birth in DD.MM.YYYY format.
|
|
||||||
gender (:obj:`str`): Gender, male or female.
|
|
||||||
country_code (:obj:`str`): Citizenship (ISO 3166-1 alpha-2 country code).
|
|
||||||
residence_country_code (:obj:`str`): Country of residence (ISO 3166-1 alpha-2 country
|
|
||||||
code).
|
|
||||||
first_name_native (:obj:`str`): First Name in the language of the user's country of
|
|
||||||
residence.
|
|
||||||
middle_name_native (:obj:`str`): Optional. Middle Name in the language of the user's
|
|
||||||
country of residence.
|
|
||||||
last_name_native (:obj:`str`): Last Name in the language of the user's country of
|
|
||||||
residence.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"birth_date",
|
|
||||||
"country_code",
|
|
||||||
"first_name",
|
|
||||||
"first_name_native",
|
|
||||||
"gender",
|
|
||||||
"last_name",
|
|
||||||
"last_name_native",
|
|
||||||
"middle_name",
|
|
||||||
"middle_name_native",
|
|
||||||
"residence_country_code",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
first_name: str,
|
|
||||||
last_name: str,
|
|
||||||
birth_date: str,
|
|
||||||
gender: str,
|
|
||||||
country_code: str,
|
|
||||||
residence_country_code: str,
|
|
||||||
first_name_native: Optional[str] = None,
|
|
||||||
last_name_native: Optional[str] = None,
|
|
||||||
middle_name: Optional[str] = None,
|
|
||||||
middle_name_native: Optional[str] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.first_name: str = first_name
|
|
||||||
self.last_name: str = last_name
|
|
||||||
self.middle_name: Optional[str] = middle_name
|
|
||||||
self.birth_date: str = birth_date
|
|
||||||
self.gender: str = gender
|
|
||||||
self.country_code: str = country_code
|
|
||||||
self.residence_country_code: str = residence_country_code
|
|
||||||
self.first_name_native: Optional[str] = first_name_native
|
|
||||||
self.last_name_native: Optional[str] = last_name_native
|
|
||||||
self.middle_name_native: Optional[str] = middle_name_native
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class ResidentialAddress(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents a residential address.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
street_line1 (:obj:`str`): First line for the address.
|
|
||||||
street_line2 (:obj:`str`): Optional. Second line for the address.
|
|
||||||
city (:obj:`str`): City.
|
|
||||||
state (:obj:`str`): Optional. State.
|
|
||||||
country_code (:obj:`str`): ISO 3166-1 alpha-2 country code.
|
|
||||||
post_code (:obj:`str`): Address post code.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
street_line1 (:obj:`str`): First line for the address.
|
|
||||||
street_line2 (:obj:`str`): Optional. Second line for the address.
|
|
||||||
city (:obj:`str`): City.
|
|
||||||
state (:obj:`str`): Optional. State.
|
|
||||||
country_code (:obj:`str`): ISO 3166-1 alpha-2 country code.
|
|
||||||
post_code (:obj:`str`): Address post code.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"city",
|
|
||||||
"country_code",
|
|
||||||
"post_code",
|
|
||||||
"state",
|
|
||||||
"street_line1",
|
|
||||||
"street_line2",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
street_line1: str,
|
|
||||||
street_line2: str,
|
|
||||||
city: str,
|
|
||||||
state: str,
|
|
||||||
country_code: str,
|
|
||||||
post_code: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.street_line1: str = street_line1
|
|
||||||
self.street_line2: str = street_line2
|
|
||||||
self.city: str = city
|
|
||||||
self.state: str = state
|
|
||||||
self.country_code: str = country_code
|
|
||||||
self.post_code: str = post_code
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class IdDocumentData(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents the data of an identity document.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
document_no (:obj:`str`): Document number.
|
|
||||||
expiry_date (:obj:`str`): Optional. Date of expiry, in DD.MM.YYYY format.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
document_no (:obj:`str`): Document number.
|
|
||||||
expiry_date (:obj:`str`): Optional. Date of expiry, in DD.MM.YYYY format.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("document_no", "expiry_date")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
document_no: str,
|
|
||||||
expiry_date: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.document_no: str = document_no
|
|
||||||
self.expiry_date: str = expiry_date
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# flake8: noqa: E501
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram EncryptedPassportElement."""
|
|
||||||
from base64 import b64decode
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional, Union
|
|
||||||
|
|
||||||
from telegram._passport.credentials import decrypt_json
|
|
||||||
from telegram._passport.data import IdDocumentData, PersonalDetails, ResidentialAddress
|
|
||||||
from telegram._passport.passportfile import PassportFile
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot, Credentials
|
|
||||||
|
|
||||||
|
|
||||||
class EncryptedPassportElement(TelegramObject):
|
|
||||||
"""
|
|
||||||
Contains information about documents or other Telegram Passport elements shared with the bot
|
|
||||||
by the user. The data has been automatically decrypted by python-telegram-bot.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`type`, :attr:`data`, :attr:`phone_number`, :attr:`email`,
|
|
||||||
:attr:`files`, :attr:`front_side`, :attr:`reverse_side` and :attr:`selfie` are equal.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This object is decrypted only when originating from
|
|
||||||
:attr:`telegram.PassportData.decrypted_data`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license",
|
|
||||||
"identity_card", "internal_passport", "address", "utility_bill", "bank_statement",
|
|
||||||
"rental_agreement", "passport_registration", "temporary_registration", "phone_number",
|
|
||||||
"email".
|
|
||||||
hash (:obj:`str`): Base64-encoded element hash for using in
|
|
||||||
:class:`telegram.PassportElementErrorUnspecified`.
|
|
||||||
data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \
|
|
||||||
:class:`telegram.ResidentialAddress` | :obj:`str`, optional):
|
|
||||||
Decrypted or encrypted data; available only for "personal_details", "passport",
|
|
||||||
"driver_license", "identity_card", "internal_passport" and "address" types.
|
|
||||||
phone_number (:obj:`str`, optional): User's verified phone number; available only for
|
|
||||||
"phone_number" type.
|
|
||||||
email (:obj:`str`, optional): User's verified email address; available only for "email"
|
|
||||||
type.
|
|
||||||
files (Sequence[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted
|
|
||||||
files with documents provided by the user; available only for "utility_bill",
|
|
||||||
"bank_statement", "rental_agreement", "passport_registration" and
|
|
||||||
"temporary_registration" types.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
|
|
||||||
front_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
|
|
||||||
front side of the document, provided by the user; Available only for "passport",
|
|
||||||
"driver_license", "identity_card" and "internal_passport".
|
|
||||||
reverse_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
|
|
||||||
reverse side of the document, provided by the user; Available only for
|
|
||||||
"driver_license" and "identity_card".
|
|
||||||
selfie (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
|
|
||||||
selfie of the user holding a document, provided by the user; available if requested for
|
|
||||||
"passport", "driver_license", "identity_card" and "internal_passport".
|
|
||||||
translation (Sequence[:class:`telegram.PassportFile`], optional): Array of
|
|
||||||
encrypted/decrypted files with translated versions of documents provided by the user;
|
|
||||||
available if requested requested for "passport", "driver_license", "identity_card",
|
|
||||||
"internal_passport", "utility_bill", "bank_statement", "rental_agreement",
|
|
||||||
"passport_registration" and "temporary_registration" types.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license",
|
|
||||||
"identity_card", "internal_passport", "address", "utility_bill", "bank_statement",
|
|
||||||
"rental_agreement", "passport_registration", "temporary_registration", "phone_number",
|
|
||||||
"email".
|
|
||||||
hash (:obj:`str`): Base64-encoded element hash for using in
|
|
||||||
:class:`telegram.PassportElementErrorUnspecified`.
|
|
||||||
data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \
|
|
||||||
:class:`telegram.ResidentialAddress` | :obj:`str`):
|
|
||||||
Optional. Decrypted or encrypted data; available only for "personal_details",
|
|
||||||
"passport", "driver_license", "identity_card", "internal_passport" and "address" types.
|
|
||||||
phone_number (:obj:`str`): Optional. User's verified phone number; available only for
|
|
||||||
"phone_number" type.
|
|
||||||
email (:obj:`str`): Optional. User's verified email address; available only for "email"
|
|
||||||
type.
|
|
||||||
files (tuple[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted
|
|
||||||
files with documents provided by the user; available only for "utility_bill",
|
|
||||||
"bank_statement", "rental_agreement", "passport_registration" and
|
|
||||||
"temporary_registration" types.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* |tupleclassattrs|
|
|
||||||
* |alwaystuple|
|
|
||||||
|
|
||||||
front_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
|
|
||||||
front side of the document, provided by the user; available only for "passport",
|
|
||||||
"driver_license", "identity_card" and "internal_passport".
|
|
||||||
reverse_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
|
|
||||||
reverse side of the document, provided by the user; available only for "driver_license"
|
|
||||||
and "identity_card".
|
|
||||||
selfie (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
|
|
||||||
selfie of the user holding a document, provided by the user; available if requested for
|
|
||||||
"passport", "driver_license", "identity_card" and "internal_passport".
|
|
||||||
translation (tuple[:class:`telegram.PassportFile`]): Optional. Array of
|
|
||||||
encrypted/decrypted files with translated versions of documents provided by the user;
|
|
||||||
available if requested for "passport", "driver_license", "identity_card",
|
|
||||||
"internal_passport", "utility_bill", "bank_statement", "rental_agreement",
|
|
||||||
"passport_registration" and "temporary_registration" types.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* |tupleclassattrs|
|
|
||||||
* |alwaystuple|
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"data",
|
|
||||||
"email",
|
|
||||||
"files",
|
|
||||||
"front_side",
|
|
||||||
"hash",
|
|
||||||
"phone_number",
|
|
||||||
"reverse_side",
|
|
||||||
"selfie",
|
|
||||||
"translation",
|
|
||||||
"type",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
type: str, # pylint: disable=redefined-builtin
|
|
||||||
hash: str, # pylint: disable=redefined-builtin
|
|
||||||
data: Optional[Union[PersonalDetails, IdDocumentData, ResidentialAddress]] = None,
|
|
||||||
phone_number: Optional[str] = None,
|
|
||||||
email: Optional[str] = None,
|
|
||||||
files: Optional[Sequence[PassportFile]] = None,
|
|
||||||
front_side: Optional[PassportFile] = None,
|
|
||||||
reverse_side: Optional[PassportFile] = None,
|
|
||||||
selfie: Optional[PassportFile] = None,
|
|
||||||
translation: Optional[Sequence[PassportFile]] = None,
|
|
||||||
# TODO: Remove the credentials argument in 22.0 or later
|
|
||||||
credentials: Optional[ # pylint: disable=unused-argument # noqa: ARG002
|
|
||||||
"Credentials"
|
|
||||||
] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
# Required
|
|
||||||
self.type: str = type
|
|
||||||
# Optionals
|
|
||||||
self.data: Optional[Union[PersonalDetails, IdDocumentData, ResidentialAddress]] = data
|
|
||||||
self.phone_number: Optional[str] = phone_number
|
|
||||||
self.email: Optional[str] = email
|
|
||||||
self.files: tuple[PassportFile, ...] = parse_sequence_arg(files)
|
|
||||||
self.front_side: Optional[PassportFile] = front_side
|
|
||||||
self.reverse_side: Optional[PassportFile] = reverse_side
|
|
||||||
self.selfie: Optional[PassportFile] = selfie
|
|
||||||
self.translation: tuple[PassportFile, ...] = parse_sequence_arg(translation)
|
|
||||||
self.hash: str = hash
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.type,
|
|
||||||
self.data,
|
|
||||||
self.phone_number,
|
|
||||||
self.email,
|
|
||||||
self.files,
|
|
||||||
self.front_side,
|
|
||||||
self.reverse_side,
|
|
||||||
self.selfie,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["EncryptedPassportElement"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["files"] = PassportFile.de_list(data.get("files"), bot) or None
|
|
||||||
data["front_side"] = PassportFile.de_json(data.get("front_side"), bot)
|
|
||||||
data["reverse_side"] = PassportFile.de_json(data.get("reverse_side"), bot)
|
|
||||||
data["selfie"] = PassportFile.de_json(data.get("selfie"), bot)
|
|
||||||
data["translation"] = PassportFile.de_list(data.get("translation"), bot) or None
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json_decrypted(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"], credentials: "Credentials"
|
|
||||||
) -> Optional["EncryptedPassportElement"]:
|
|
||||||
"""Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account
|
|
||||||
passport credentials.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (dict[:obj:`str`, ...]): The JSON data.
|
|
||||||
bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object.
|
|
||||||
May be :obj:`None`, in which case shortcut methods will not be available.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.4
|
|
||||||
:paramref:`bot` is now optional and defaults to :obj:`None`
|
|
||||||
|
|
||||||
.. deprecated:: 21.4
|
|
||||||
This argument will be converted to an optional argument in future versions.
|
|
||||||
credentials (:class:`telegram.FileCredentials`): The credentials
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:class:`telegram.EncryptedPassportElement`:
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if data["type"] not in ("phone_number", "email"):
|
|
||||||
secure_data = getattr(credentials.secure_data, data["type"])
|
|
||||||
|
|
||||||
if secure_data.data is not None:
|
|
||||||
# If not already decrypted
|
|
||||||
if not isinstance(data["data"], dict):
|
|
||||||
data["data"] = decrypt_json(
|
|
||||||
b64decode(secure_data.data.secret),
|
|
||||||
b64decode(secure_data.data.hash),
|
|
||||||
b64decode(data["data"]),
|
|
||||||
)
|
|
||||||
if data["type"] == "personal_details":
|
|
||||||
data["data"] = PersonalDetails.de_json(data["data"], bot=bot)
|
|
||||||
elif data["type"] in (
|
|
||||||
"passport",
|
|
||||||
"internal_passport",
|
|
||||||
"driver_license",
|
|
||||||
"identity_card",
|
|
||||||
):
|
|
||||||
data["data"] = IdDocumentData.de_json(data["data"], bot=bot)
|
|
||||||
elif data["type"] == "address":
|
|
||||||
data["data"] = ResidentialAddress.de_json(data["data"], bot=bot)
|
|
||||||
|
|
||||||
data["files"] = (
|
|
||||||
PassportFile.de_list_decrypted(data.get("files"), bot, secure_data.files) or None
|
|
||||||
)
|
|
||||||
data["front_side"] = PassportFile.de_json_decrypted(
|
|
||||||
data.get("front_side"), bot, secure_data.front_side
|
|
||||||
)
|
|
||||||
data["reverse_side"] = PassportFile.de_json_decrypted(
|
|
||||||
data.get("reverse_side"), bot, secure_data.reverse_side
|
|
||||||
)
|
|
||||||
data["selfie"] = PassportFile.de_json_decrypted(
|
|
||||||
data.get("selfie"), bot, secure_data.selfie
|
|
||||||
)
|
|
||||||
data["translation"] = (
|
|
||||||
PassportFile.de_list_decrypted(
|
|
||||||
data.get("translation"), bot, secure_data.translation
|
|
||||||
)
|
|
||||||
or None
|
|
||||||
)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""Contains information about Telegram Passport data shared with the bot by the user."""
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._passport.credentials import EncryptedCredentials
|
|
||||||
from telegram._passport.encryptedpassportelement import EncryptedPassportElement
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot, Credentials
|
|
||||||
|
|
||||||
|
|
||||||
class PassportData(TelegramObject):
|
|
||||||
"""Contains information about Telegram Passport data shared with the bot by the user.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
To be able to decrypt this object, you must pass your ``private_key`` to either
|
|
||||||
:class:`telegram.ext.Updater` or :class:`telegram.Bot`. Decrypted data is then found in
|
|
||||||
:attr:`decrypted_data` and the payload can be found in :attr:`decrypted_credentials`'s
|
|
||||||
attribute :attr:`telegram.Credentials.nonce`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (Sequence[:class:`telegram.EncryptedPassportElement`]): Array with encrypted
|
|
||||||
information about documents and other Telegram Passport elements that was shared with
|
|
||||||
the bot.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
|
|
||||||
credentials (:class:`telegram.EncryptedCredentials`)): Encrypted credentials.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
data (tuple[:class:`telegram.EncryptedPassportElement`]): Array with encrypted
|
|
||||||
information about documents and other Telegram Passport elements that was shared with
|
|
||||||
the bot.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|tupleclassattrs|
|
|
||||||
|
|
||||||
credentials (:class:`telegram.EncryptedCredentials`): Encrypted credentials.
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("_decrypted_data", "credentials", "data")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
data: Sequence[EncryptedPassportElement],
|
|
||||||
credentials: EncryptedCredentials,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
self.data: tuple[EncryptedPassportElement, ...] = parse_sequence_arg(data)
|
|
||||||
self.credentials: EncryptedCredentials = credentials
|
|
||||||
|
|
||||||
self._decrypted_data: Optional[tuple[EncryptedPassportElement]] = None
|
|
||||||
self._id_attrs = tuple([x.type for x in data] + [credentials.hash])
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["PassportData"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["data"] = EncryptedPassportElement.de_list(data.get("data"), bot)
|
|
||||||
data["credentials"] = EncryptedCredentials.de_json(data.get("credentials"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def decrypted_data(self) -> tuple[EncryptedPassportElement, ...]:
|
|
||||||
"""
|
|
||||||
tuple[:class:`telegram.EncryptedPassportElement`]: Lazily decrypt and return information
|
|
||||||
about documents and other Telegram Passport elements which were shared with the bot.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
Returns a tuple instead of a list.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
|
||||||
private/public key but can also suggest malformed/tampered data.
|
|
||||||
"""
|
|
||||||
if self._decrypted_data is None:
|
|
||||||
self._decrypted_data = tuple( # type: ignore[assignment]
|
|
||||||
EncryptedPassportElement.de_json_decrypted(
|
|
||||||
element.to_dict(), self.get_bot(), self.decrypted_credentials
|
|
||||||
)
|
|
||||||
for element in self.data
|
|
||||||
)
|
|
||||||
return self._decrypted_data # type: ignore[return-value]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def decrypted_credentials(self) -> "Credentials":
|
|
||||||
"""
|
|
||||||
:class:`telegram.Credentials`: Lazily decrypt and return credentials that were used
|
|
||||||
to decrypt the data. This object also contains the user specified payload as
|
|
||||||
`decrypted_data.payload`.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
|
||||||
private/public key but can also suggest malformed/tampered data.
|
|
||||||
"""
|
|
||||||
return self.credentials.decrypted_data
|
|
||||||
@@ -1,474 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
# pylint: disable=redefined-builtin
|
|
||||||
"""This module contains the classes that represent Telegram PassportElementError."""
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
from telegram._utils.warnings import warn
|
|
||||||
from telegram.warnings import PTBDeprecationWarning
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementError(TelegramObject):
|
|
||||||
"""Baseclass for the PassportElementError* classes.
|
|
||||||
|
|
||||||
This object represents an error in the Telegram Passport element which was submitted that
|
|
||||||
should be resolved by the user.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`source` and :attr:`type` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
source (:obj:`str`): Error source.
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
source (:obj:`str`): Error source.
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("message", "source", "type")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, source: str, type: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.source: str = str(source)
|
|
||||||
self.type: str = str(type)
|
|
||||||
self.message: str = str(message)
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorDataField(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue in one of the data fields that was provided by the user. The error is
|
|
||||||
considered resolved when the field's value changes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`field_name`, :attr:`data_hash` and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of
|
|
||||||
``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
|
||||||
``"internal_passport"``, ``"address"``.
|
|
||||||
field_name (:obj:`str`): Name of the data field which has the error.
|
|
||||||
data_hash (:obj:`str`): Base64-encoded data hash.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of
|
|
||||||
``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
|
||||||
``"internal_passport"``, ``"address"``.
|
|
||||||
field_name (:obj:`str`): Name of the data field which has the error.
|
|
||||||
data_hash (:obj:`str`): Base64-encoded data hash.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("data_hash", "field_name")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
type: str,
|
|
||||||
field_name: str,
|
|
||||||
data_hash: str,
|
|
||||||
message: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("data", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.field_name: str = field_name
|
|
||||||
self.data_hash: str = data_hash
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.source,
|
|
||||||
self.type,
|
|
||||||
self.field_name,
|
|
||||||
self.data_hash,
|
|
||||||
self.message,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorFile(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue with a document scan. The error is considered resolved when the file with
|
|
||||||
the document scan changes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`file_hash`, and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
|
||||||
``"passport_registration"``, ``"temporary_registration"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded file hash.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
|
||||||
``"passport_registration"``, ``"temporary_registration"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded file hash.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("file_hash",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("file", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.file_hash: str = file_hash
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorFiles(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue with a list of scans. The error is considered resolved when the list of
|
|
||||||
files with the document scans changes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`file_hashes`, and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
|
||||||
``"passport_registration"``, ``"temporary_registration"``.
|
|
||||||
file_hashes (list[:obj:`str`]): List of base64-encoded file hashes.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
|
||||||
``"passport_registration"``, ``"temporary_registration"``.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("_file_hashes",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
type: str,
|
|
||||||
file_hashes: list[str],
|
|
||||||
message: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("files", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self._file_hashes: list[str] = file_hashes
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
|
||||||
|
|
||||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
|
||||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
|
||||||
data = super().to_dict(recursive)
|
|
||||||
data["file_hashes"] = self._file_hashes
|
|
||||||
return data
|
|
||||||
|
|
||||||
@property
|
|
||||||
def file_hashes(self) -> list[str]:
|
|
||||||
"""List of base64-encoded file hashes.
|
|
||||||
|
|
||||||
.. deprecated:: 20.6
|
|
||||||
This attribute will return a tuple instead of a list in future major versions.
|
|
||||||
"""
|
|
||||||
warn(
|
|
||||||
PTBDeprecationWarning(
|
|
||||||
"20.6",
|
|
||||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
|
||||||
" versions.",
|
|
||||||
),
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self._file_hashes
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorFrontSide(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue with the front side of a document. The error is considered resolved when
|
|
||||||
the file with the front side of the document changes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`file_hash`, and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the
|
|
||||||
document.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the
|
|
||||||
document.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("file_hash",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("front_side", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.file_hash: str = file_hash
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorReverseSide(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue with the reverse side of a document. The error is considered resolved when
|
|
||||||
the file with the reverse side of the document changes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`file_hash`, and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"driver_license"``, ``"identity_card"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the
|
|
||||||
document.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"driver_license"``, ``"identity_card"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the
|
|
||||||
document.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("file_hash",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("reverse_side", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.file_hash: str = file_hash
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorSelfie(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue with the selfie with a document. The error is considered resolved when
|
|
||||||
the file with the selfie changes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`file_hash`, and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
|
||||||
``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("file_hash",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("selfie", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.file_hash: str = file_hash
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorTranslationFile(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue with one of the files that constitute the translation of a document.
|
|
||||||
The error is considered resolved when the file changes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`file_hash`, and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
|
||||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
|
||||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
|
||||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded hash of the file.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
|
||||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
|
||||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
|
||||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
|
||||||
file_hash (:obj:`str`): Base64-encoded hash of the file.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("file_hash",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("translation_file", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.file_hash: str = file_hash
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorTranslationFiles(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue with the translated version of a document. The error is considered
|
|
||||||
resolved when a file with the document translation changes.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`file_hashes`, and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
|
||||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
|
||||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
|
||||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
|
||||||
file_hashes (list[:obj:`str`]): List of base64-encoded file hashes.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
|
||||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
|
||||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
|
||||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("_file_hashes",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
type: str,
|
|
||||||
file_hashes: list[str],
|
|
||||||
message: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("translation_files", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self._file_hashes: list[str] = file_hashes
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
|
||||||
|
|
||||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
|
||||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
|
||||||
data = super().to_dict(recursive)
|
|
||||||
data["file_hashes"] = self._file_hashes
|
|
||||||
return data
|
|
||||||
|
|
||||||
@property
|
|
||||||
def file_hashes(self) -> list[str]:
|
|
||||||
"""List of base64-encoded file hashes.
|
|
||||||
|
|
||||||
.. deprecated:: 20.6
|
|
||||||
This attribute will return a tuple instead of a list in future major versions.
|
|
||||||
"""
|
|
||||||
warn(
|
|
||||||
PTBDeprecationWarning(
|
|
||||||
"20.6",
|
|
||||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
|
||||||
" versions. See the stability policy:"
|
|
||||||
" https://docs.python-telegram-bot.org/en/stable/stability_policy.html",
|
|
||||||
),
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self._file_hashes
|
|
||||||
|
|
||||||
|
|
||||||
class PassportElementErrorUnspecified(PassportElementError):
|
|
||||||
"""
|
|
||||||
Represents an issue in an unspecified place. The error is considered resolved when new
|
|
||||||
data is added.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
|
||||||
:attr:`element_hash`, and :attr:`message` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue.
|
|
||||||
element_hash (:obj:`str`): Base64-encoded element hash.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue.
|
|
||||||
element_hash (:obj:`str`): Base64-encoded element hash.
|
|
||||||
message (:obj:`str`): Error message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("element_hash",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, type: str, element_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
# Required
|
|
||||||
super().__init__("unspecified", type, message, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.element_hash: str = element_hash
|
|
||||||
|
|
||||||
self._id_attrs = (self.source, self.type, self.element_hash, self.message)
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Encrypted PassportFile."""
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
|
||||||
from telegram._utils.types import JSONDict, ODVInput
|
|
||||||
from telegram._utils.warnings import warn
|
|
||||||
from telegram.warnings import PTBDeprecationWarning
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot, File, FileCredentials
|
|
||||||
|
|
||||||
|
|
||||||
class PassportFile(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents a file uploaded to Telegram Passport. Currently all Telegram Passport
|
|
||||||
files are in JPEG format when decrypted and don't exceed 10MB.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
|
||||||
or reuse the file.
|
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
|
||||||
is supposed to be the same over time and for different bots.
|
|
||||||
Can't be used to download or reuse the file.
|
|
||||||
file_size (:obj:`int`): File size in bytes.
|
|
||||||
file_date (:obj:`int`): Unix time when the file was uploaded.
|
|
||||||
|
|
||||||
.. deprecated:: 20.6
|
|
||||||
This argument will only accept a datetime instead of an integer in future
|
|
||||||
major versions.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
|
||||||
or reuse the file.
|
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
|
||||||
is supposed to be the same over time and for different bots.
|
|
||||||
Can't be used to download or reuse the file.
|
|
||||||
file_size (:obj:`int`): File size in bytes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"_credentials",
|
|
||||||
"_file_date",
|
|
||||||
"file_id",
|
|
||||||
"file_size",
|
|
||||||
"file_unique_id",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
file_id: str,
|
|
||||||
file_unique_id: str,
|
|
||||||
file_date: int,
|
|
||||||
file_size: int,
|
|
||||||
credentials: Optional["FileCredentials"] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
# Required
|
|
||||||
self.file_id: str = file_id
|
|
||||||
self.file_unique_id: str = file_unique_id
|
|
||||||
self.file_size: int = file_size
|
|
||||||
self._file_date: int = file_date
|
|
||||||
# Optionals
|
|
||||||
|
|
||||||
self._credentials: Optional[FileCredentials] = credentials
|
|
||||||
|
|
||||||
self._id_attrs = (self.file_unique_id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
|
||||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
|
||||||
data = super().to_dict(recursive)
|
|
||||||
data["file_date"] = self._file_date
|
|
||||||
return data
|
|
||||||
|
|
||||||
@property
|
|
||||||
def file_date(self) -> int:
|
|
||||||
""":obj:`int`: Unix time when the file was uploaded.
|
|
||||||
|
|
||||||
.. deprecated:: 20.6
|
|
||||||
This attribute will return a datetime instead of a integer in future major versions.
|
|
||||||
"""
|
|
||||||
warn(
|
|
||||||
PTBDeprecationWarning(
|
|
||||||
"20.6",
|
|
||||||
"The attribute `file_date` will return a datetime instead of an integer in future"
|
|
||||||
" major versions.",
|
|
||||||
),
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self._file_date
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json_decrypted(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"], credentials: "FileCredentials"
|
|
||||||
) -> Optional["PassportFile"]:
|
|
||||||
"""Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account
|
|
||||||
passport credentials.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (dict[:obj:`str`, ...]): The JSON data.
|
|
||||||
bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object.
|
|
||||||
May be :obj:`None`, in which case shortcut methods will not be available.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.4
|
|
||||||
:paramref:`bot` is now optional and defaults to :obj:`None`
|
|
||||||
|
|
||||||
.. deprecated:: 21.4
|
|
||||||
This argument will be converted to an optional argument in future versions.
|
|
||||||
credentials (:class:`telegram.FileCredentials`): The credentials
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:class:`telegram.PassportFile`:
|
|
||||||
|
|
||||||
"""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["credentials"] = credentials
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_list_decrypted(
|
|
||||||
cls,
|
|
||||||
data: Optional[list[JSONDict]],
|
|
||||||
bot: Optional["Bot"],
|
|
||||||
credentials: list["FileCredentials"],
|
|
||||||
) -> tuple[Optional["PassportFile"], ...]:
|
|
||||||
"""Variant of :meth:`telegram.TelegramObject.de_list` that also takes into account
|
|
||||||
passport credentials.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* Returns a tuple instead of a list.
|
|
||||||
* Filters out any :obj:`None` values
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (list[dict[:obj:`str`, ...]]): The JSON data.
|
|
||||||
bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object.
|
|
||||||
May be :obj:`None`, in which case shortcut methods will not be available.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.4
|
|
||||||
:paramref:`bot` is now optional and defaults to :obj:`None`
|
|
||||||
|
|
||||||
.. deprecated:: 21.4
|
|
||||||
This argument will be converted to an optional argument in future versions.
|
|
||||||
credentials (:class:`telegram.FileCredentials`): The credentials
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
tuple[:class:`telegram.PassportFile`]:
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
return ()
|
|
||||||
|
|
||||||
return tuple(
|
|
||||||
obj
|
|
||||||
for obj in (
|
|
||||||
cls.de_json_decrypted(passport_file, bot, credentials[i])
|
|
||||||
for i, passport_file in enumerate(data)
|
|
||||||
)
|
|
||||||
if obj is not None
|
|
||||||
)
|
|
||||||
|
|
||||||
async def get_file(
|
|
||||||
self,
|
|
||||||
*,
|
|
||||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> "File":
|
|
||||||
"""
|
|
||||||
Wrapper over :meth:`telegram.Bot.get_file`. Will automatically assign the correct
|
|
||||||
credentials to the returned :class:`telegram.File` if originating from
|
|
||||||
:attr:`telegram.PassportData.decrypted_data`.
|
|
||||||
|
|
||||||
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:class:`telegram.File`
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:class:`telegram.error.TelegramError`
|
|
||||||
|
|
||||||
"""
|
|
||||||
file = await self.get_bot().get_file(
|
|
||||||
file_id=self.file_id,
|
|
||||||
read_timeout=read_timeout,
|
|
||||||
write_timeout=write_timeout,
|
|
||||||
connect_timeout=connect_timeout,
|
|
||||||
pool_timeout=pool_timeout,
|
|
||||||
api_kwargs=api_kwargs,
|
|
||||||
)
|
|
||||||
if self._credentials:
|
|
||||||
file.set_credentials(self._credentials)
|
|
||||||
return file
|
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,134 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram Invoice."""
|
|
||||||
|
|
||||||
from typing import Final, Optional
|
|
||||||
|
|
||||||
from telegram import constants
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class Invoice(TelegramObject):
|
|
||||||
"""This object contains basic information about an invoice.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`title`, :attr:`description`, :paramref:`start_parameter`,
|
|
||||||
:attr:`currency` and :attr:`total_amount` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
title (:obj:`str`): Product name.
|
|
||||||
description (:obj:`str`): Product description.
|
|
||||||
start_parameter (:obj:`str`): Unique bot deep-linking parameter that can be used to
|
|
||||||
generate this invoice.
|
|
||||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
|
||||||
|tg_stars|.
|
|
||||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer,
|
|
||||||
**not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``.
|
|
||||||
See the ``exp`` parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
title (:obj:`str`): Product name.
|
|
||||||
description (:obj:`str`): Product description.
|
|
||||||
start_parameter (:obj:`str`): Unique bot deep-linking parameter that can be used to
|
|
||||||
generate this invoice.
|
|
||||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
|
||||||
|tg_stars|.
|
|
||||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer,
|
|
||||||
**not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``.
|
|
||||||
See the ``exp`` parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"currency",
|
|
||||||
"description",
|
|
||||||
"start_parameter",
|
|
||||||
"title",
|
|
||||||
"total_amount",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
title: str,
|
|
||||||
description: str,
|
|
||||||
start_parameter: str,
|
|
||||||
currency: str,
|
|
||||||
total_amount: int,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.title: str = title
|
|
||||||
self.description: str = description
|
|
||||||
self.start_parameter: str = start_parameter
|
|
||||||
self.currency: str = currency
|
|
||||||
self.total_amount: int = total_amount
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.title,
|
|
||||||
self.description,
|
|
||||||
self.start_parameter,
|
|
||||||
self.currency,
|
|
||||||
self.total_amount,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
MIN_TITLE_LENGTH: Final[int] = constants.InvoiceLimit.MIN_TITLE_LENGTH
|
|
||||||
""":const:`telegram.constants.InvoiceLimit.MIN_TITLE_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_TITLE_LENGTH: Final[int] = constants.InvoiceLimit.MAX_TITLE_LENGTH
|
|
||||||
""":const:`telegram.constants.InvoiceLimit.MAX_TITLE_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MIN_DESCRIPTION_LENGTH: Final[int] = constants.InvoiceLimit.MIN_DESCRIPTION_LENGTH
|
|
||||||
""":const:`telegram.constants.InvoiceLimit.MIN_DESCRIPTION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_DESCRIPTION_LENGTH: Final[int] = constants.InvoiceLimit.MAX_DESCRIPTION_LENGTH
|
|
||||||
""":const:`telegram.constants.InvoiceLimit.MAX_DESCRIPTION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MIN_PAYLOAD_LENGTH: Final[int] = constants.InvoiceLimit.MIN_PAYLOAD_LENGTH
|
|
||||||
""":const:`telegram.constants.InvoiceLimit.MIN_PAYLOAD_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_PAYLOAD_LENGTH: Final[int] = constants.InvoiceLimit.MAX_PAYLOAD_LENGTH
|
|
||||||
""":const:`telegram.constants.InvoiceLimit.MAX_PAYLOAD_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_TIP_AMOUNTS: Final[int] = constants.InvoiceLimit.MAX_TIP_AMOUNTS
|
|
||||||
""":const:`telegram.constants.InvoiceLimit.MAX_TIP_AMOUNTS`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram LabeledPrice."""
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class LabeledPrice(TelegramObject):
|
|
||||||
"""This object represents a portion of the price for goods or services.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`label` and :attr:`amount` are equal.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
:any:`Payment Bot <examples.paymentbot>`
|
|
||||||
|
|
||||||
Args:
|
|
||||||
label (:obj:`str`): Portion label.
|
|
||||||
amount (:obj:`int`): Price of the product in the smallest units of the currency (integer,
|
|
||||||
**not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``.
|
|
||||||
See the ``exp`` parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
label (:obj:`str`): Portion label.
|
|
||||||
amount (:obj:`int`): Price of the product in the smallest units of the currency (integer,
|
|
||||||
**not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``.
|
|
||||||
See the ``exp`` parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("amount", "label")
|
|
||||||
|
|
||||||
def __init__(self, label: str, amount: int, *, api_kwargs: Optional[JSONDict] = None):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.label: str = label
|
|
||||||
self.amount: int = amount
|
|
||||||
|
|
||||||
self._id_attrs = (self.label, self.amount)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram OrderInfo."""
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._payment.shippingaddress import ShippingAddress
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class OrderInfo(TelegramObject):
|
|
||||||
"""This object represents information about an order.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`name`, :attr:`phone_number`, :attr:`email` and
|
|
||||||
:attr:`shipping_address` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name (:obj:`str`, optional): User name.
|
|
||||||
phone_number (:obj:`str`, optional): User's phone number.
|
|
||||||
email (:obj:`str`, optional): User email.
|
|
||||||
shipping_address (:class:`telegram.ShippingAddress`, optional): User shipping address.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
name (:obj:`str`): Optional. User name.
|
|
||||||
phone_number (:obj:`str`): Optional. User's phone number.
|
|
||||||
email (:obj:`str`): Optional. User email.
|
|
||||||
shipping_address (:class:`telegram.ShippingAddress`): Optional. User shipping address.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("email", "name", "phone_number", "shipping_address")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: Optional[str] = None,
|
|
||||||
phone_number: Optional[str] = None,
|
|
||||||
email: Optional[str] = None,
|
|
||||||
shipping_address: Optional[ShippingAddress] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.name: Optional[str] = name
|
|
||||||
self.phone_number: Optional[str] = phone_number
|
|
||||||
self.email: Optional[str] = email
|
|
||||||
self.shipping_address: Optional[ShippingAddress] = shipping_address
|
|
||||||
|
|
||||||
self._id_attrs = (self.name, self.phone_number, self.email, self.shipping_address)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["OrderInfo"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return cls()
|
|
||||||
|
|
||||||
data["shipping_address"] = ShippingAddress.de_json(data.get("shipping_address"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram PreCheckoutQuery."""
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._payment.orderinfo import OrderInfo
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._user import User
|
|
||||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
|
||||||
from telegram._utils.types import JSONDict, ODVInput
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class PreCheckoutQuery(TelegramObject):
|
|
||||||
"""This object contains information about an incoming pre-checkout query.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`id` is equal.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
id (:obj:`str`): Unique query identifier.
|
|
||||||
from_user (:class:`telegram.User`): User who sent the query.
|
|
||||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
|
||||||
|tg_stars|.
|
|
||||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer,
|
|
||||||
**not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``.
|
|
||||||
See the ``exp`` parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
|
||||||
shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the
|
|
||||||
user.
|
|
||||||
order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
id (:obj:`str`): Unique query identifier.
|
|
||||||
from_user (:class:`telegram.User`): User who sent the query.
|
|
||||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
|
||||||
|tg_stars|.
|
|
||||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer,
|
|
||||||
**not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``.
|
|
||||||
See the ``exp`` parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
|
||||||
shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the
|
|
||||||
user.
|
|
||||||
order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user.
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"currency",
|
|
||||||
"from_user",
|
|
||||||
"id",
|
|
||||||
"invoice_payload",
|
|
||||||
"order_info",
|
|
||||||
"shipping_option_id",
|
|
||||||
"total_amount",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
id: str, # pylint: disable=redefined-builtin
|
|
||||||
from_user: User,
|
|
||||||
currency: str,
|
|
||||||
total_amount: int,
|
|
||||||
invoice_payload: str,
|
|
||||||
shipping_option_id: Optional[str] = None,
|
|
||||||
order_info: Optional[OrderInfo] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.id: str = id
|
|
||||||
self.from_user: User = from_user
|
|
||||||
self.currency: str = currency
|
|
||||||
self.total_amount: int = total_amount
|
|
||||||
self.invoice_payload: str = invoice_payload
|
|
||||||
self.shipping_option_id: Optional[str] = shipping_option_id
|
|
||||||
self.order_info: Optional[OrderInfo] = order_info
|
|
||||||
|
|
||||||
self._id_attrs = (self.id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["PreCheckoutQuery"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
|
||||||
data["order_info"] = OrderInfo.de_json(data.get("order_info"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
async def answer(
|
|
||||||
self,
|
|
||||||
ok: bool,
|
|
||||||
error_message: Optional[str] = None,
|
|
||||||
*,
|
|
||||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> bool:
|
|
||||||
"""Shortcut for::
|
|
||||||
|
|
||||||
await bot.answer_pre_checkout_query(update.pre_checkout_query.id, *args, **kwargs)
|
|
||||||
|
|
||||||
For the documentation of the arguments, please see
|
|
||||||
:meth:`telegram.Bot.answer_pre_checkout_query`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return await self.get_bot().answer_pre_checkout_query(
|
|
||||||
pre_checkout_query_id=self.id,
|
|
||||||
ok=ok,
|
|
||||||
error_message=error_message,
|
|
||||||
read_timeout=read_timeout,
|
|
||||||
write_timeout=write_timeout,
|
|
||||||
connect_timeout=connect_timeout,
|
|
||||||
pool_timeout=pool_timeout,
|
|
||||||
api_kwargs=api_kwargs,
|
|
||||||
)
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram RefundedPayment."""
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class RefundedPayment(TelegramObject):
|
|
||||||
"""This object contains basic information about a refunded payment.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`telegram_payment_charge_id` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Args:
|
|
||||||
currency (:obj:`str`): Three-letter ISO 4217 `currency
|
|
||||||
<https://core.telegram.org/bots/payments#supported-currencies>`_ code, or ``XTR`` for
|
|
||||||
payments in |tg_stars|. Currently, always ``XTR``.
|
|
||||||
total_amount (:obj:`int`): Total refunded price in the *smallest units* of the currency
|
|
||||||
(integer, **not** float/double). For example, for a price of ``US$ 1.45``,
|
|
||||||
``total_amount = 145``. See the *exp* parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
|
||||||
telegram_payment_charge_id (:obj:`str`): Telegram payment identifier.
|
|
||||||
provider_payment_charge_id (:obj:`str`, optional): Provider payment identifier.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
currency (:obj:`str`): Three-letter ISO 4217 `currency
|
|
||||||
<https://core.telegram.org/bots/payments#supported-currencies>`_ code, or ``XTR`` for
|
|
||||||
payments in |tg_stars|. Currently, always ``XTR``.
|
|
||||||
total_amount (:obj:`int`): Total refunded price in the *smallest units* of the currency
|
|
||||||
(integer, **not** float/double). For example, for a price of ``US$ 1.45``,
|
|
||||||
``total_amount = 145``. See the *exp* parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
|
||||||
telegram_payment_charge_id (:obj:`str`): Telegram payment identifier.
|
|
||||||
provider_payment_charge_id (:obj:`str`): Optional. Provider payment identifier.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"currency",
|
|
||||||
"invoice_payload",
|
|
||||||
"provider_payment_charge_id",
|
|
||||||
"telegram_payment_charge_id",
|
|
||||||
"total_amount",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
currency: str,
|
|
||||||
total_amount: int,
|
|
||||||
invoice_payload: str,
|
|
||||||
telegram_payment_charge_id: str,
|
|
||||||
provider_payment_charge_id: Optional[str] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.currency: str = currency
|
|
||||||
self.total_amount: int = total_amount
|
|
||||||
self.invoice_payload: str = invoice_payload
|
|
||||||
self.telegram_payment_charge_id: str = telegram_payment_charge_id
|
|
||||||
# Optional
|
|
||||||
self.provider_payment_charge_id: Optional[str] = provider_payment_charge_id
|
|
||||||
|
|
||||||
self._id_attrs = (self.telegram_payment_charge_id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram ShippingAddress."""
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class ShippingAddress(TelegramObject):
|
|
||||||
"""This object represents a Telegram ShippingAddress.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`country_code`, :attr:`state`, :attr:`city`,
|
|
||||||
:attr:`street_line1`, :attr:`street_line2` and :attr:`post_code` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
country_code (:obj:`str`): ISO 3166-1 alpha-2 country code.
|
|
||||||
state (:obj:`str`): State, if applicable.
|
|
||||||
city (:obj:`str`): City.
|
|
||||||
street_line1 (:obj:`str`): First line for the address.
|
|
||||||
street_line2 (:obj:`str`): Second line for the address.
|
|
||||||
post_code (:obj:`str`): Address post code.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
country_code (:obj:`str`): ISO 3166-1 alpha-2 country code.
|
|
||||||
state (:obj:`str`): State, if applicable.
|
|
||||||
city (:obj:`str`): City.
|
|
||||||
street_line1 (:obj:`str`): First line for the address.
|
|
||||||
street_line2 (:obj:`str`): Second line for the address.
|
|
||||||
post_code (:obj:`str`): Address post code.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"city",
|
|
||||||
"country_code",
|
|
||||||
"post_code",
|
|
||||||
"state",
|
|
||||||
"street_line1",
|
|
||||||
"street_line2",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
country_code: str,
|
|
||||||
state: str,
|
|
||||||
city: str,
|
|
||||||
street_line1: str,
|
|
||||||
street_line2: str,
|
|
||||||
post_code: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.country_code: str = country_code
|
|
||||||
self.state: str = state
|
|
||||||
self.city: str = city
|
|
||||||
self.street_line1: str = street_line1
|
|
||||||
self.street_line2: str = street_line2
|
|
||||||
self.post_code: str = post_code
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.country_code,
|
|
||||||
self.state,
|
|
||||||
self.city,
|
|
||||||
self.street_line1,
|
|
||||||
self.street_line2,
|
|
||||||
self.post_code,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram ShippingOption."""
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import LabeledPrice
|
|
||||||
|
|
||||||
|
|
||||||
class ShippingOption(TelegramObject):
|
|
||||||
"""This object represents one shipping option.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`id` is equal.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
:any:`Payment Bot <examples.paymentbot>`
|
|
||||||
|
|
||||||
Args:
|
|
||||||
id (:obj:`str`): Shipping option identifier.
|
|
||||||
title (:obj:`str`): Option title.
|
|
||||||
prices (Sequence[:class:`telegram.LabeledPrice`]): List of price portions.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
id (:obj:`str`): Shipping option identifier.
|
|
||||||
title (:obj:`str`): Option title.
|
|
||||||
prices (tuple[:class:`telegram.LabeledPrice`]): List of price portions.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|tupleclassattrs|
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("id", "prices", "title")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
id: str, # pylint: disable=redefined-builtin
|
|
||||||
title: str,
|
|
||||||
prices: Sequence["LabeledPrice"],
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
self.id: str = id
|
|
||||||
self.title: str = title
|
|
||||||
self.prices: tuple[LabeledPrice, ...] = parse_sequence_arg(prices)
|
|
||||||
|
|
||||||
self._id_attrs = (self.id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram ShippingQuery."""
|
|
||||||
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._payment.shippingaddress import ShippingAddress
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._user import User
|
|
||||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
|
||||||
from telegram._utils.types import JSONDict, ODVInput
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
from telegram._payment.shippingoption import ShippingOption
|
|
||||||
|
|
||||||
|
|
||||||
class ShippingQuery(TelegramObject):
|
|
||||||
"""This object contains information about an incoming shipping query.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`id` is equal.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
id (:obj:`str`): Unique query identifier.
|
|
||||||
from_user (:class:`telegram.User`): User who sent the query.
|
|
||||||
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
|
||||||
shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
id (:obj:`str`): Unique query identifier.
|
|
||||||
from_user (:class:`telegram.User`): User who sent the query.
|
|
||||||
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
|
||||||
shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address.
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("from_user", "id", "invoice_payload", "shipping_address")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
id: str, # pylint: disable=redefined-builtin
|
|
||||||
from_user: User,
|
|
||||||
invoice_payload: str,
|
|
||||||
shipping_address: ShippingAddress,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.id: str = id
|
|
||||||
self.from_user: User = from_user
|
|
||||||
self.invoice_payload: str = invoice_payload
|
|
||||||
self.shipping_address: ShippingAddress = shipping_address
|
|
||||||
|
|
||||||
self._id_attrs = (self.id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["ShippingQuery"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
|
||||||
data["shipping_address"] = ShippingAddress.de_json(data.get("shipping_address"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
async def answer(
|
|
||||||
self,
|
|
||||||
ok: bool,
|
|
||||||
shipping_options: Optional[Sequence["ShippingOption"]] = None,
|
|
||||||
error_message: Optional[str] = None,
|
|
||||||
*,
|
|
||||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> bool:
|
|
||||||
"""Shortcut for::
|
|
||||||
|
|
||||||
await bot.answer_shipping_query(update.shipping_query.id, *args, **kwargs)
|
|
||||||
|
|
||||||
For the documentation of the arguments, please see
|
|
||||||
:meth:`telegram.Bot.answer_shipping_query`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return await self.get_bot().answer_shipping_query(
|
|
||||||
shipping_query_id=self.id,
|
|
||||||
ok=ok,
|
|
||||||
shipping_options=shipping_options,
|
|
||||||
error_message=error_message,
|
|
||||||
read_timeout=read_timeout,
|
|
||||||
write_timeout=write_timeout,
|
|
||||||
connect_timeout=connect_timeout,
|
|
||||||
pool_timeout=pool_timeout,
|
|
||||||
api_kwargs=api_kwargs,
|
|
||||||
)
|
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,120 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains the classes for Telegram Stars affiliates."""
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._chat import Chat
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._user import User
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class AffiliateInfo(TelegramObject):
|
|
||||||
"""Contains information about the affiliate that received a commission via this transaction.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`affiliate_user`, :attr:`affiliate_chat`,
|
|
||||||
:attr:`commission_per_mille`, :attr:`amount`, and :attr:`nanostar_amount` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.9
|
|
||||||
|
|
||||||
Args:
|
|
||||||
affiliate_user (:class:`telegram.User`, optional): The bot or the user that received an
|
|
||||||
affiliate commission if it was received by a bot or a user
|
|
||||||
affiliate_chat (:class:`telegram.Chat`, optional): The chat that received an affiliate
|
|
||||||
commission if it was received by a chat
|
|
||||||
commission_per_mille (:obj:`int`): The number of Telegram Stars received by the affiliate
|
|
||||||
for each 1000 Telegram Stars received by the bot from referred users
|
|
||||||
amount (:obj:`int`): Integer amount of Telegram Stars received by the affiliate from the
|
|
||||||
transaction, rounded to 0; can be negative for refunds
|
|
||||||
nanostar_amount (:obj:`int`, optional): The number of
|
|
||||||
:tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram
|
|
||||||
Stars received by the affiliate; from
|
|
||||||
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MIN_AMOUNT` to
|
|
||||||
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`;
|
|
||||||
can be negative for refunds
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
affiliate_user (:class:`telegram.User`): Optional. The bot or the user that received an
|
|
||||||
affiliate commission if it was received by a bot or a user
|
|
||||||
affiliate_chat (:class:`telegram.Chat`): Optional. The chat that received an affiliate
|
|
||||||
commission if it was received by a chat
|
|
||||||
commission_per_mille (:obj:`int`): The number of Telegram Stars received by the affiliate
|
|
||||||
for each 1000 Telegram Stars received by the bot from referred users
|
|
||||||
amount (:obj:`int`): Integer amount of Telegram Stars received by the affiliate from the
|
|
||||||
transaction, rounded to 0; can be negative for refunds
|
|
||||||
nanostar_amount (:obj:`int`): Optional. The number of
|
|
||||||
:tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram
|
|
||||||
Stars received by the affiliate; from
|
|
||||||
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MIN_AMOUNT` to
|
|
||||||
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`;
|
|
||||||
can be negative for refunds
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"affiliate_chat",
|
|
||||||
"affiliate_user",
|
|
||||||
"amount",
|
|
||||||
"commission_per_mille",
|
|
||||||
"nanostar_amount",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
commission_per_mille: int,
|
|
||||||
amount: int,
|
|
||||||
affiliate_user: Optional["User"] = None,
|
|
||||||
affiliate_chat: Optional["Chat"] = None,
|
|
||||||
nanostar_amount: Optional[int] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.affiliate_user: Optional[User] = affiliate_user
|
|
||||||
self.affiliate_chat: Optional[Chat] = affiliate_chat
|
|
||||||
self.commission_per_mille: int = commission_per_mille
|
|
||||||
self.amount: int = amount
|
|
||||||
self.nanostar_amount: Optional[int] = nanostar_amount
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.affiliate_user,
|
|
||||||
self.affiliate_chat,
|
|
||||||
self.commission_per_mille,
|
|
||||||
self.amount,
|
|
||||||
self.nanostar_amount,
|
|
||||||
)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["AffiliateInfo"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["affiliate_user"] = User.de_json(data.get("affiliate_user"), bot)
|
|
||||||
data["affiliate_chat"] = Chat.de_json(data.get("affiliate_chat"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
# pylint: disable=redefined-builtin
|
|
||||||
"""This module contains the classes for Telegram Stars Revenue Withdrawals."""
|
|
||||||
import datetime as dtm
|
|
||||||
from typing import TYPE_CHECKING, Final, Optional
|
|
||||||
|
|
||||||
from telegram import constants
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils import enum
|
|
||||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class RevenueWithdrawalState(TelegramObject):
|
|
||||||
"""This object describes the state of a revenue withdrawal operation. Currently, it can be one
|
|
||||||
of:
|
|
||||||
|
|
||||||
* :class:`telegram.RevenueWithdrawalStatePending`
|
|
||||||
* :class:`telegram.RevenueWithdrawalStateSucceeded`
|
|
||||||
* :class:`telegram.RevenueWithdrawalStateFailed`
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`type` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): The type of the state.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the state.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("type",)
|
|
||||||
|
|
||||||
PENDING: Final[str] = constants.RevenueWithdrawalStateType.PENDING
|
|
||||||
""":const:`telegram.constants.RevenueWithdrawalStateType.PENDING`"""
|
|
||||||
SUCCEEDED: Final[str] = constants.RevenueWithdrawalStateType.SUCCEEDED
|
|
||||||
""":const:`telegram.constants.RevenueWithdrawalStateType.SUCCEEDED`"""
|
|
||||||
FAILED: Final[str] = constants.RevenueWithdrawalStateType.FAILED
|
|
||||||
""":const:`telegram.constants.RevenueWithdrawalStateType.FAILED`"""
|
|
||||||
|
|
||||||
def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.type: str = enum.get_member(constants.RevenueWithdrawalStateType, type, type)
|
|
||||||
|
|
||||||
self._id_attrs = (self.type,)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["RevenueWithdrawalState"]:
|
|
||||||
"""Converts JSON data to the appropriate :class:`RevenueWithdrawalState` object, i.e. takes
|
|
||||||
care of selecting the correct subclass.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (dict[:obj:`str`, ...]): The JSON data.
|
|
||||||
bot (:class:`telegram.Bot`): The bot associated with this object.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The Telegram object.
|
|
||||||
|
|
||||||
"""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if (cls is RevenueWithdrawalState and not data) or data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
_class_mapping: dict[str, type[RevenueWithdrawalState]] = {
|
|
||||||
cls.PENDING: RevenueWithdrawalStatePending,
|
|
||||||
cls.SUCCEEDED: RevenueWithdrawalStateSucceeded,
|
|
||||||
cls.FAILED: RevenueWithdrawalStateFailed,
|
|
||||||
}
|
|
||||||
|
|
||||||
if cls is RevenueWithdrawalState and data.get("type") in _class_mapping:
|
|
||||||
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class RevenueWithdrawalStatePending(RevenueWithdrawalState):
|
|
||||||
"""The withdrawal is in progress.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the state, always
|
|
||||||
:tg-const:`telegram.RevenueWithdrawalState.PENDING`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
super().__init__(type=RevenueWithdrawalState.PENDING, api_kwargs=api_kwargs)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class RevenueWithdrawalStateSucceeded(RevenueWithdrawalState):
|
|
||||||
"""The withdrawal succeeded.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`date` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Args:
|
|
||||||
date (:obj:`datetime.datetime`): Date the withdrawal was completed as a datetime object.
|
|
||||||
url (:obj:`str`): An HTTPS URL that can be used to see transaction details.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the state, always
|
|
||||||
:tg-const:`telegram.RevenueWithdrawalState.SUCCEEDED`.
|
|
||||||
date (:obj:`datetime.datetime`): Date the withdrawal was completed as a datetime object.
|
|
||||||
url (:obj:`str`): An HTTPS URL that can be used to see transaction details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("date", "url")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
date: dtm.datetime,
|
|
||||||
url: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(type=RevenueWithdrawalState.SUCCEEDED, api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
with self._unfrozen():
|
|
||||||
self.date: dtm.datetime = date
|
|
||||||
self.url: str = url
|
|
||||||
self._id_attrs = (
|
|
||||||
self.type,
|
|
||||||
self.date,
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["RevenueWithdrawalStateSucceeded"]:
|
|
||||||
"""See :meth:`telegram.RevenueWithdrawalState.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Get the local timezone from the bot if it has defaults
|
|
||||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
|
||||||
data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
|
||||||
|
|
||||||
|
|
||||||
class RevenueWithdrawalStateFailed(RevenueWithdrawalState):
|
|
||||||
"""The withdrawal failed and the transaction was refunded.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the state, always
|
|
||||||
:tg-const:`telegram.RevenueWithdrawalState.FAILED`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
super().__init__(type=RevenueWithdrawalState.FAILED, api_kwargs=api_kwargs)
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
# pylint: disable=redefined-builtin
|
|
||||||
"""This module contains the classes for Telegram Stars transactions."""
|
|
||||||
|
|
||||||
import datetime as dtm
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
from .transactionpartner import TransactionPartner
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class StarTransaction(TelegramObject):
|
|
||||||
"""Describes a Telegram Star transaction.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`id`, :attr:`source`, and :attr:`receiver` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Args:
|
|
||||||
id (:obj:`str`): Unique identifier of the transaction. Coincides with the identifer
|
|
||||||
of the original transaction for refund transactions.
|
|
||||||
Coincides with :attr:`SuccessfulPayment.telegram_payment_charge_id` for
|
|
||||||
successful incoming payments from users.
|
|
||||||
amount (:obj:`int`): Integer amount of Telegram Stars transferred by the transaction.
|
|
||||||
nanostar_amount (:obj:`int`, optional): The number of
|
|
||||||
:tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram
|
|
||||||
Stars transferred by the transaction; from 0 to
|
|
||||||
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`
|
|
||||||
|
|
||||||
.. versionadded:: 21.9
|
|
||||||
date (:obj:`datetime.datetime`): Date the transaction was created as a datetime object.
|
|
||||||
source (:class:`telegram.TransactionPartner`, optional): Source of an incoming transaction
|
|
||||||
(e.g., a user purchasing goods or services, Fragment refunding a failed withdrawal).
|
|
||||||
Only for incoming transactions.
|
|
||||||
receiver (:class:`telegram.TransactionPartner`, optional): Receiver of an outgoing
|
|
||||||
transaction (e.g., a user for a purchase refund, Fragment for a withdrawal). Only for
|
|
||||||
outgoing transactions.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
id (:obj:`str`): Unique identifier of the transaction. Coincides with the identifer
|
|
||||||
of the original transaction for refund transactions.
|
|
||||||
Coincides with :attr:`SuccessfulPayment.telegram_payment_charge_id` for
|
|
||||||
successful incoming payments from users.
|
|
||||||
amount (:obj:`int`): Integer amount of Telegram Stars transferred by the transaction.
|
|
||||||
nanostar_amount (:obj:`int`): Optional. The number of
|
|
||||||
:tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram
|
|
||||||
Stars transferred by the transaction; from 0 to
|
|
||||||
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`
|
|
||||||
|
|
||||||
.. versionadded:: 21.9
|
|
||||||
date (:obj:`datetime.datetime`): Date the transaction was created as a datetime object.
|
|
||||||
source (:class:`telegram.TransactionPartner`): Optional. Source of an incoming transaction
|
|
||||||
(e.g., a user purchasing goods or services, Fragment refunding a failed withdrawal).
|
|
||||||
Only for incoming transactions.
|
|
||||||
receiver (:class:`telegram.TransactionPartner`): Optional. Receiver of an outgoing
|
|
||||||
transaction (e.g., a user for a purchase refund, Fragment for a withdrawal). Only for
|
|
||||||
outgoing transactions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("amount", "date", "id", "nanostar_amount", "receiver", "source")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
id: str,
|
|
||||||
amount: int,
|
|
||||||
date: dtm.datetime,
|
|
||||||
source: Optional[TransactionPartner] = None,
|
|
||||||
receiver: Optional[TransactionPartner] = None,
|
|
||||||
nanostar_amount: Optional[int] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.id: str = id
|
|
||||||
self.amount: int = amount
|
|
||||||
self.date: dtm.datetime = date
|
|
||||||
self.source: Optional[TransactionPartner] = source
|
|
||||||
self.receiver: Optional[TransactionPartner] = receiver
|
|
||||||
self.nanostar_amount: Optional[int] = nanostar_amount
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.id,
|
|
||||||
self.source,
|
|
||||||
self.receiver,
|
|
||||||
)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["StarTransaction"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Get the local timezone from the bot if it has defaults
|
|
||||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
|
||||||
data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo)
|
|
||||||
|
|
||||||
data["source"] = TransactionPartner.de_json(data.get("source"), bot)
|
|
||||||
data["receiver"] = TransactionPartner.de_json(data.get("receiver"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class StarTransactions(TelegramObject):
|
|
||||||
"""
|
|
||||||
Contains a list of Telegram Star transactions.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`transactions` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Args:
|
|
||||||
transactions (Sequence[:class:`telegram.StarTransaction`]): The list of transactions.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
transactions (tuple[:class:`telegram.StarTransaction`]): The list of transactions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("transactions",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, transactions: Sequence[StarTransaction], *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.transactions: tuple[StarTransaction, ...] = parse_sequence_arg(transactions)
|
|
||||||
|
|
||||||
self._id_attrs = (self.transactions,)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["StarTransactions"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["transactions"] = StarTransaction.de_list(data.get("transactions"), bot)
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,405 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
# pylint: disable=redefined-builtin
|
|
||||||
"""This module contains the classes for Telegram Stars transaction partners."""
|
|
||||||
import datetime as dtm
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Final, Optional
|
|
||||||
|
|
||||||
from telegram import constants
|
|
||||||
from telegram._gifts import Gift
|
|
||||||
from telegram._paidmedia import PaidMedia
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._user import User
|
|
||||||
from telegram._utils import enum
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
from .affiliateinfo import AffiliateInfo
|
|
||||||
from .revenuewithdrawalstate import RevenueWithdrawalState
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionPartner(TelegramObject):
|
|
||||||
"""This object describes the source of a transaction, or its recipient for outgoing
|
|
||||||
transactions. Currently, it can be one of:
|
|
||||||
|
|
||||||
* :class:`TransactionPartnerUser`
|
|
||||||
* :class:`TransactionPartnerAffiliateProgram`
|
|
||||||
* :class:`TransactionPartnerFragment`
|
|
||||||
* :class:`TransactionPartnerTelegramAds`
|
|
||||||
* :class:`TransactionPartnerTelegramApi`
|
|
||||||
* :class:`TransactionPartnerOther`
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`type` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): The type of the transaction partner.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the transaction partner.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("type",)
|
|
||||||
|
|
||||||
AFFILIATE_PROGRAM: Final[str] = constants.TransactionPartnerType.AFFILIATE_PROGRAM
|
|
||||||
""":const:`telegram.constants.TransactionPartnerType.AFFILIATE_PROGRAM`
|
|
||||||
|
|
||||||
.. versionadded:: 21.9
|
|
||||||
"""
|
|
||||||
FRAGMENT: Final[str] = constants.TransactionPartnerType.FRAGMENT
|
|
||||||
""":const:`telegram.constants.TransactionPartnerType.FRAGMENT`"""
|
|
||||||
OTHER: Final[str] = constants.TransactionPartnerType.OTHER
|
|
||||||
""":const:`telegram.constants.TransactionPartnerType.OTHER`"""
|
|
||||||
TELEGRAM_ADS: Final[str] = constants.TransactionPartnerType.TELEGRAM_ADS
|
|
||||||
""":const:`telegram.constants.TransactionPartnerType.TELEGRAM_ADS`"""
|
|
||||||
TELEGRAM_API: Final[str] = constants.TransactionPartnerType.TELEGRAM_API
|
|
||||||
""":const:`telegram.constants.TransactionPartnerType.TELEGRAM_API`"""
|
|
||||||
USER: Final[str] = constants.TransactionPartnerType.USER
|
|
||||||
""":const:`telegram.constants.TransactionPartnerType.USER`"""
|
|
||||||
|
|
||||||
def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.type: str = enum.get_member(constants.TransactionPartnerType, type, type)
|
|
||||||
|
|
||||||
self._id_attrs = (self.type,)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["TransactionPartner"]:
|
|
||||||
"""Converts JSON data to the appropriate :class:`TransactionPartner` object, i.e. takes
|
|
||||||
care of selecting the correct subclass.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (dict[:obj:`str`, ...]): The JSON data.
|
|
||||||
bot (:class:`telegram.Bot`): The bot associated with this object.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The Telegram object.
|
|
||||||
|
|
||||||
"""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if (cls is TransactionPartner and not data) or data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
_class_mapping: dict[str, type[TransactionPartner]] = {
|
|
||||||
cls.AFFILIATE_PROGRAM: TransactionPartnerAffiliateProgram,
|
|
||||||
cls.FRAGMENT: TransactionPartnerFragment,
|
|
||||||
cls.USER: TransactionPartnerUser,
|
|
||||||
cls.TELEGRAM_ADS: TransactionPartnerTelegramAds,
|
|
||||||
cls.TELEGRAM_API: TransactionPartnerTelegramApi,
|
|
||||||
cls.OTHER: TransactionPartnerOther,
|
|
||||||
}
|
|
||||||
|
|
||||||
if cls is TransactionPartner and data.get("type") in _class_mapping:
|
|
||||||
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionPartnerAffiliateProgram(TransactionPartner):
|
|
||||||
"""Describes the affiliate program that issued the affiliate commission received via this
|
|
||||||
transaction.
|
|
||||||
|
|
||||||
This object is comparable in terms of equality. Two objects of this class are considered equal,
|
|
||||||
if their :attr:`commission_per_mille` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.9
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sponsor_user (:class:`telegram.User`, optional): Information about the bot that sponsored
|
|
||||||
the affiliate program
|
|
||||||
commission_per_mille (:obj:`int`): The number of Telegram Stars received by the bot for
|
|
||||||
each 1000 Telegram Stars received by the affiliate program sponsor from referred users.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the transaction partner,
|
|
||||||
always :tg-const:`telegram.TransactionPartner.AFFILIATE_PROGRAM`.
|
|
||||||
sponsor_user (:class:`telegram.User`): Optional. Information about the bot that sponsored
|
|
||||||
the affiliate program
|
|
||||||
commission_per_mille (:obj:`int`): The number of Telegram Stars received by the bot for
|
|
||||||
each 1000 Telegram Stars received by the affiliate program sponsor from referred users.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("commission_per_mille", "sponsor_user")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
commission_per_mille: int,
|
|
||||||
sponsor_user: Optional["User"] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(type=TransactionPartner.AFFILIATE_PROGRAM, api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
with self._unfrozen():
|
|
||||||
self.sponsor_user: Optional[User] = sponsor_user
|
|
||||||
self.commission_per_mille: int = commission_per_mille
|
|
||||||
self._id_attrs = (
|
|
||||||
self.type,
|
|
||||||
self.commission_per_mille,
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["TransactionPartnerAffiliateProgram"]:
|
|
||||||
"""See :meth:`telegram.TransactionPartner.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["sponsor_user"] = User.de_json(data.get("sponsor_user"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionPartnerFragment(TransactionPartner):
|
|
||||||
"""Describes a withdrawal transaction with Fragment.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Args:
|
|
||||||
withdrawal_state (:class:`telegram.RevenueWithdrawalState`, optional): State of the
|
|
||||||
transaction if the transaction is outgoing.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the transaction partner,
|
|
||||||
always :tg-const:`telegram.TransactionPartner.FRAGMENT`.
|
|
||||||
withdrawal_state (:class:`telegram.RevenueWithdrawalState`): Optional. State of the
|
|
||||||
transaction if the transaction is outgoing.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("withdrawal_state",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
withdrawal_state: Optional["RevenueWithdrawalState"] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(type=TransactionPartner.FRAGMENT, api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
with self._unfrozen():
|
|
||||||
self.withdrawal_state: Optional[RevenueWithdrawalState] = withdrawal_state
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["TransactionPartnerFragment"]:
|
|
||||||
"""See :meth:`telegram.TransactionPartner.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["withdrawal_state"] = RevenueWithdrawalState.de_json(
|
|
||||||
data.get("withdrawal_state"), bot
|
|
||||||
)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionPartnerUser(TransactionPartner):
|
|
||||||
"""Describes a transaction with a user.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`user` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Args:
|
|
||||||
user (:class:`telegram.User`): Information about the user.
|
|
||||||
affiliate (:class:`telegram.AffiliateInfo`, optional): Information about the affiliate that
|
|
||||||
received a commission via this transaction
|
|
||||||
|
|
||||||
.. versionadded:: 21.9
|
|
||||||
invoice_payload (:obj:`str`, optional): Bot-specified invoice payload.
|
|
||||||
subscription_period (:class:`datetime.timedelta`, optional): The duration of the paid
|
|
||||||
subscription
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
paid_media (Sequence[:class:`telegram.PaidMedia`], optional): Information about the paid
|
|
||||||
media bought by the user.
|
|
||||||
|
|
||||||
.. versionadded:: 21.5
|
|
||||||
paid_media_payload (:obj:`str`, optional): Bot-specified paid media payload.
|
|
||||||
|
|
||||||
.. versionadded:: 21.6
|
|
||||||
gift (:class:`telegram.Gift`, optional): The gift sent to the user by the bot
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the transaction partner,
|
|
||||||
always :tg-const:`telegram.TransactionPartner.USER`.
|
|
||||||
user (:class:`telegram.User`): Information about the user.
|
|
||||||
affiliate (:class:`telegram.AffiliateInfo`): Optional. Information about the affiliate that
|
|
||||||
received a commission via this transaction
|
|
||||||
|
|
||||||
.. versionadded:: 21.9
|
|
||||||
invoice_payload (:obj:`str`): Optional. Bot-specified invoice payload.
|
|
||||||
subscription_period (:class:`datetime.timedelta`): Optional. The duration of the paid
|
|
||||||
subscription
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
paid_media (tuple[:class:`telegram.PaidMedia`]): Optional. Information about the paid
|
|
||||||
media bought by the user.
|
|
||||||
|
|
||||||
.. versionadded:: 21.5
|
|
||||||
paid_media_payload (:obj:`str`): Optional. Bot-specified paid media payload.
|
|
||||||
|
|
||||||
.. versionadded:: 21.6
|
|
||||||
gift (:class:`telegram.Gift`): Optional. The gift sent to the user by the bot
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"affiliate",
|
|
||||||
"gift",
|
|
||||||
"invoice_payload",
|
|
||||||
"paid_media",
|
|
||||||
"paid_media_payload",
|
|
||||||
"subscription_period",
|
|
||||||
"user",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
user: "User",
|
|
||||||
invoice_payload: Optional[str] = None,
|
|
||||||
paid_media: Optional[Sequence[PaidMedia]] = None,
|
|
||||||
paid_media_payload: Optional[str] = None,
|
|
||||||
subscription_period: Optional[dtm.timedelta] = None,
|
|
||||||
gift: Optional[Gift] = None,
|
|
||||||
affiliate: Optional[AffiliateInfo] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(type=TransactionPartner.USER, api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
with self._unfrozen():
|
|
||||||
self.user: User = user
|
|
||||||
self.affiliate: Optional[AffiliateInfo] = affiliate
|
|
||||||
self.invoice_payload: Optional[str] = invoice_payload
|
|
||||||
self.paid_media: Optional[tuple[PaidMedia, ...]] = parse_sequence_arg(paid_media)
|
|
||||||
self.paid_media_payload: Optional[str] = paid_media_payload
|
|
||||||
self.subscription_period: Optional[dtm.timedelta] = subscription_period
|
|
||||||
self.gift: Optional[Gift] = gift
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.type,
|
|
||||||
self.user,
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["TransactionPartnerUser"]:
|
|
||||||
"""See :meth:`telegram.TransactionPartner.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["user"] = User.de_json(data.get("user"), bot)
|
|
||||||
data["affiliate"] = AffiliateInfo.de_json(data.get("affiliate"), bot)
|
|
||||||
data["paid_media"] = PaidMedia.de_list(data.get("paid_media"), bot=bot)
|
|
||||||
data["subscription_period"] = (
|
|
||||||
dtm.timedelta(seconds=sp)
|
|
||||||
if (sp := data.get("subscription_period")) is not None
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
data["gift"] = Gift.de_json(data.get("gift"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionPartnerOther(TransactionPartner):
|
|
||||||
"""Describes a transaction with an unknown partner.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the transaction partner,
|
|
||||||
always :tg-const:`telegram.TransactionPartner.OTHER`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
super().__init__(type=TransactionPartner.OTHER, api_kwargs=api_kwargs)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionPartnerTelegramAds(TransactionPartner):
|
|
||||||
"""Describes a withdrawal transaction to the Telegram Ads platform.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the transaction partner,
|
|
||||||
always :tg-const:`telegram.TransactionPartner.TELEGRAM_ADS`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
super().__init__(type=TransactionPartner.TELEGRAM_ADS, api_kwargs=api_kwargs)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionPartnerTelegramApi(TransactionPartner):
|
|
||||||
"""Describes a transaction with payment for
|
|
||||||
`paid broadcasting <https://core.telegram.org/bots/api#paid-broadcasts>`_.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`request_count` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.7
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request_count (:obj:`int`): The number of successful requests that exceeded regular limits
|
|
||||||
and were therefore billed.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): The type of the transaction partner,
|
|
||||||
always :tg-const:`telegram.TransactionPartner.TELEGRAM_API`.
|
|
||||||
request_count (:obj:`int`): The number of successful requests that exceeded regular limits
|
|
||||||
and were therefore billed.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("request_count",)
|
|
||||||
|
|
||||||
def __init__(self, request_count: int, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
super().__init__(type=TransactionPartner.TELEGRAM_API, api_kwargs=api_kwargs)
|
|
||||||
with self._unfrozen():
|
|
||||||
self.request_count: int = request_count
|
|
||||||
self._id_attrs = (self.request_count,)
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram SuccessfulPayment."""
|
|
||||||
|
|
||||||
import datetime as dtm
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._payment.orderinfo import OrderInfo
|
|
||||||
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 SuccessfulPayment(TelegramObject):
|
|
||||||
"""This object contains basic information about a successful payment.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`telegram_payment_charge_id` and
|
|
||||||
:attr:`provider_payment_charge_id` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
|
||||||
|tg_stars|.
|
|
||||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer,
|
|
||||||
**not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``.
|
|
||||||
See the ``exp`` parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
|
||||||
subscription_expiration_date (:class:`datetime.datetime`, optional): Expiration date of the
|
|
||||||
subscription; for recurring payments only.
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
is_recurring (:obj:`bool`, optional): True, if the payment is for a subscription.
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
is_first_recurring (:obj:`bool`, optional): True, if the payment is the first payment of a
|
|
||||||
subscription.
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the
|
|
||||||
user.
|
|
||||||
order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user.
|
|
||||||
telegram_payment_charge_id (:obj:`str`): Telegram payment identifier.
|
|
||||||
provider_payment_charge_id (:obj:`str`): Provider payment identifier.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
|
||||||
|tg_stars|.
|
|
||||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer,
|
|
||||||
**not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``.
|
|
||||||
See the ``exp`` parameter in
|
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
|
||||||
it shows the number of digits past the decimal point for each currency
|
|
||||||
(2 for the majority of currencies).
|
|
||||||
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
|
||||||
subscription_expiration_date (:class:`datetime.datetime`): Optional. Expiration
|
|
||||||
date of the subscription; for recurring payments only.
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
is_recurring (:obj:`bool`): Optional. True, if the payment is for a subscription.
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
is_first_recurring (:obj:`bool`): Optional. True, if the payment is the first payment of a
|
|
||||||
subscription.
|
|
||||||
|
|
||||||
.. versionadded:: 21.8
|
|
||||||
shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the
|
|
||||||
user.
|
|
||||||
order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user.
|
|
||||||
telegram_payment_charge_id (:obj:`str`): Telegram payment identifier.
|
|
||||||
provider_payment_charge_id (:obj:`str`): Provider payment identifier.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"currency",
|
|
||||||
"invoice_payload",
|
|
||||||
"is_first_recurring",
|
|
||||||
"is_recurring",
|
|
||||||
"order_info",
|
|
||||||
"provider_payment_charge_id",
|
|
||||||
"shipping_option_id",
|
|
||||||
"subscription_expiration_date",
|
|
||||||
"telegram_payment_charge_id",
|
|
||||||
"total_amount",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
currency: str,
|
|
||||||
total_amount: int,
|
|
||||||
invoice_payload: str,
|
|
||||||
telegram_payment_charge_id: str,
|
|
||||||
provider_payment_charge_id: str,
|
|
||||||
shipping_option_id: Optional[str] = None,
|
|
||||||
order_info: Optional[OrderInfo] = None,
|
|
||||||
subscription_expiration_date: Optional[dtm.datetime] = None,
|
|
||||||
is_recurring: Optional[bool] = None,
|
|
||||||
is_first_recurring: Optional[bool] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.currency: str = currency
|
|
||||||
self.total_amount: int = total_amount
|
|
||||||
self.invoice_payload: str = invoice_payload
|
|
||||||
self.shipping_option_id: Optional[str] = shipping_option_id
|
|
||||||
self.order_info: Optional[OrderInfo] = order_info
|
|
||||||
self.telegram_payment_charge_id: str = telegram_payment_charge_id
|
|
||||||
self.provider_payment_charge_id: str = provider_payment_charge_id
|
|
||||||
self.subscription_expiration_date: Optional[dtm.datetime] = subscription_expiration_date
|
|
||||||
self.is_recurring: Optional[bool] = is_recurring
|
|
||||||
self.is_first_recurring: Optional[bool] = is_first_recurring
|
|
||||||
|
|
||||||
self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["SuccessfulPayment"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["order_info"] = OrderInfo.de_json(data.get("order_info"), bot)
|
|
||||||
|
|
||||||
# Get the local timezone from the bot if it has defaults
|
|
||||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
|
||||||
|
|
||||||
data["subscription_expiration_date"] = from_timestamp(
|
|
||||||
data.get("subscription_expiration_date"), tzinfo=loc_tzinfo
|
|
||||||
)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,650 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram Poll."""
|
|
||||||
import datetime as dtm
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Final, Optional
|
|
||||||
|
|
||||||
from telegram import constants
|
|
||||||
from telegram._chat import Chat
|
|
||||||
from telegram._messageentity import MessageEntity
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._user import User
|
|
||||||
from telegram._utils import enum
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
|
||||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
|
||||||
from telegram._utils.entities import parse_message_entities, parse_message_entity
|
|
||||||
from telegram._utils.types import JSONDict, ODVInput
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class InputPollOption(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about one answer option in a poll to be sent.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`text` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text (:obj:`str`): Option text,
|
|
||||||
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
|
|
||||||
characters.
|
|
||||||
text_parse_mode (:obj:`str`, optional): |parse_mode|
|
|
||||||
Currently, only custom emoji entities are allowed.
|
|
||||||
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities
|
|
||||||
that appear in the option :paramref:`text`. It can be specified instead of
|
|
||||||
:paramref:`text_parse_mode`.
|
|
||||||
Currently, only custom emoji entities are allowed.
|
|
||||||
This list is empty if the text does not contain entities.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
text (:obj:`str`): Option text,
|
|
||||||
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
|
|
||||||
characters.
|
|
||||||
text_parse_mode (:obj:`str`): Optional. |parse_mode|
|
|
||||||
Currently, only custom emoji entities are allowed.
|
|
||||||
text_entities (Sequence[:class:`telegram.MessageEntity`]): Special entities
|
|
||||||
that appear in the option :paramref:`text`. It can be specified instead of
|
|
||||||
:paramref:`text_parse_mode`.
|
|
||||||
Currently, only custom emoji entities are allowed.
|
|
||||||
This list is empty if the text does not contain entities.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("text", "text_entities", "text_parse_mode")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
text: str,
|
|
||||||
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
|
||||||
text_entities: Optional[Sequence[MessageEntity]] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.text: str = text
|
|
||||||
self.text_parse_mode: ODVInput[str] = text_parse_mode
|
|
||||||
self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
|
|
||||||
|
|
||||||
self._id_attrs = (self.text,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["InputPollOption"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class PollOption(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about one answer option in a poll.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`text` and :attr:`voter_count` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text (:obj:`str`): Option text,
|
|
||||||
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
|
|
||||||
characters.
|
|
||||||
voter_count (:obj:`int`): Number of users that voted for this option.
|
|
||||||
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities
|
|
||||||
that appear in the option text. Currently, only custom emoji entities are allowed in
|
|
||||||
poll option texts.
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
text (:obj:`str`): Option text,
|
|
||||||
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
|
|
||||||
characters.
|
|
||||||
voter_count (:obj:`int`): Number of users that voted for this option.
|
|
||||||
text_entities (tuple[:class:`telegram.MessageEntity`]): Special entities
|
|
||||||
that appear in the option text. Currently, only custom emoji entities are allowed in
|
|
||||||
poll option texts.
|
|
||||||
This list is empty if the question does not contain entities.
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("text", "text_entities", "voter_count")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
text: str,
|
|
||||||
voter_count: int,
|
|
||||||
text_entities: Optional[Sequence[MessageEntity]] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.text: str = text
|
|
||||||
self.voter_count: int = voter_count
|
|
||||||
self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
|
|
||||||
|
|
||||||
self._id_attrs = (self.text, self.voter_count)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["PollOption"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), 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`.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This method is present because Telegram calculates the offset and length in
|
|
||||||
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
|
|
||||||
(That is, you can't just slice ``Message.text`` with the offset and length.)
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
Args:
|
|
||||||
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
|
|
||||||
be an entity that belongs to :attr:`text_entities`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`: The text of the given entity.
|
|
||||||
"""
|
|
||||||
return parse_message_entity(self.text, entity)
|
|
||||||
|
|
||||||
def parse_entities(self, types: Optional[list[str]] = None) -> dict[MessageEntity, str]:
|
|
||||||
"""
|
|
||||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
|
||||||
It contains entities from this polls question filtered by their ``type`` attribute as
|
|
||||||
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This method should always be used instead of the :attr:`text_entities`
|
|
||||||
attribute, since it calculates the correct substring from the message text based on
|
|
||||||
UTF-16 codepoints. See :attr:`parse_entity` for more info.
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
Args:
|
|
||||||
types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
|
|
||||||
``type`` attribute of an entity is contained in this list, it will be returned.
|
|
||||||
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
|
||||||
the text that belongs to them, calculated based on UTF-16 codepoints.
|
|
||||||
"""
|
|
||||||
return parse_message_entities(self.text, self.text_entities, types)
|
|
||||||
|
|
||||||
MIN_LENGTH: Final[int] = constants.PollLimit.MIN_OPTION_LENGTH
|
|
||||||
""":const:`telegram.constants.PollLimit.MIN_OPTION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_LENGTH: Final[int] = constants.PollLimit.MAX_OPTION_LENGTH
|
|
||||||
""":const:`telegram.constants.PollLimit.MAX_OPTION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class PollAnswer(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents an answer of a user in a non-anonymous poll.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`poll_id`, :attr:`user` and :attr:`option_ids` are equal.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.5
|
|
||||||
The order of :paramref:`option_ids` and :paramref:`user` is changed in
|
|
||||||
20.5 as the latter one became optional.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.6
|
|
||||||
Backward compatiblity for changed order of :paramref:`option_ids` and :paramref:`user`
|
|
||||||
was removed.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
poll_id (:obj:`str`): Unique poll identifier.
|
|
||||||
option_ids (Sequence[:obj:`int`]): Identifiers of answer options, chosen by the user. May
|
|
||||||
be empty if the user retracted their vote.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
user (:class:`telegram.User`, optional): The user that changed the answer to the poll,
|
|
||||||
if the voter isn't anonymous. If the voter is anonymous, this field will contain the
|
|
||||||
user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.5
|
|
||||||
:paramref:`user` became optional.
|
|
||||||
voter_chat (:class:`telegram.Chat`, optional): The chat that changed the answer to the
|
|
||||||
poll, if the voter is anonymous.
|
|
||||||
|
|
||||||
.. versionadded:: 20.5
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
poll_id (:obj:`str`): Unique poll identifier.
|
|
||||||
option_ids (tuple[:obj:`int`]): Identifiers of answer options, chosen by the user. May
|
|
||||||
be empty if the user retracted their vote.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|tupleclassattrs|
|
|
||||||
user (:class:`telegram.User`): Optional. The user, who changed the answer to the
|
|
||||||
poll, if the voter isn't anonymous. If the voter is anonymous, this field will contain
|
|
||||||
the user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility
|
|
||||||
|
|
||||||
.. versionchanged:: 20.5
|
|
||||||
:paramref:`user` became optional.
|
|
||||||
voter_chat (:class:`telegram.Chat`): Optional. The chat that changed the answer to the
|
|
||||||
poll, if the voter is anonymous.
|
|
||||||
|
|
||||||
.. versionadded:: 20.5
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("option_ids", "poll_id", "user", "voter_chat")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
poll_id: str,
|
|
||||||
option_ids: Sequence[int],
|
|
||||||
user: Optional[User] = None,
|
|
||||||
voter_chat: Optional[Chat] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.poll_id: str = poll_id
|
|
||||||
self.voter_chat: Optional[Chat] = voter_chat
|
|
||||||
self.option_ids: tuple[int, ...] = parse_sequence_arg(option_ids)
|
|
||||||
self.user: Optional[User] = user
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.poll_id,
|
|
||||||
self.option_ids,
|
|
||||||
self.user,
|
|
||||||
self.voter_chat,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["PollAnswer"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["user"] = User.de_json(data.get("user"), bot)
|
|
||||||
data["voter_chat"] = Chat.de_json(data.get("voter_chat"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class Poll(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about a poll.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`id` is equal.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
:any:`Poll Bot <examples.pollbot>`
|
|
||||||
|
|
||||||
Args:
|
|
||||||
id (:obj:`str`): Unique poll identifier.
|
|
||||||
question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`-
|
|
||||||
:tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters.
|
|
||||||
options (Sequence[:class:`~telegram.PollOption`]): List of poll options.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
is_closed (:obj:`bool`): :obj:`True`, if the poll is closed.
|
|
||||||
is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous.
|
|
||||||
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
|
|
||||||
allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers.
|
|
||||||
correct_option_id (:obj:`int`, optional): A zero based identifier of the correct answer
|
|
||||||
option. Available only for closed polls in the quiz mode, which were sent
|
|
||||||
(not forwarded), by the bot or to a private chat with the bot.
|
|
||||||
explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect
|
|
||||||
answer or taps on the lamp icon in a quiz-style poll,
|
|
||||||
0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters.
|
|
||||||
explanation_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special
|
|
||||||
entities like usernames, URLs, bot commands, etc. that appear in the
|
|
||||||
:attr:`explanation`. This list is empty if the message does not contain explanation
|
|
||||||
entities.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* This attribute is now always a (possibly empty) list and never :obj:`None`.
|
|
||||||
* |sequenceclassargs|
|
|
||||||
open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active
|
|
||||||
after creation.
|
|
||||||
close_date (:obj:`datetime.datetime`, optional): Point in time (Unix timestamp) when the
|
|
||||||
poll will be automatically closed. Converted to :obj:`datetime.datetime`.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.3
|
|
||||||
|datetime_localization|
|
|
||||||
question_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities
|
|
||||||
that appear in the :attr:`question`. Currently, only custom emoji entities are allowed
|
|
||||||
in poll questions.
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
id (:obj:`str`): Unique poll identifier.
|
|
||||||
question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`-
|
|
||||||
:tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters.
|
|
||||||
options (tuple[:class:`~telegram.PollOption`]): List of poll options.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|tupleclassattrs|
|
|
||||||
total_voter_count (:obj:`int`): Total number of users that voted in the poll.
|
|
||||||
is_closed (:obj:`bool`): :obj:`True`, if the poll is closed.
|
|
||||||
is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous.
|
|
||||||
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
|
|
||||||
allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers.
|
|
||||||
correct_option_id (:obj:`int`): Optional. A zero based identifier of the correct answer
|
|
||||||
option. Available only for closed polls in the quiz mode, which were sent
|
|
||||||
(not forwarded), by the bot or to a private chat with the bot.
|
|
||||||
explanation (:obj:`str`): Optional. Text that is shown when a user chooses an incorrect
|
|
||||||
answer or taps on the lamp icon in a quiz-style poll,
|
|
||||||
0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters.
|
|
||||||
explanation_entities (tuple[:class:`telegram.MessageEntity`]): Special entities
|
|
||||||
like usernames, URLs, bot commands, etc. that appear in the :attr:`explanation`.
|
|
||||||
This list is empty if the message does not contain explanation entities.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|tupleclassattrs|
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
This attribute is now always a (possibly empty) list and never :obj:`None`.
|
|
||||||
open_period (:obj:`int`): Optional. Amount of time in seconds the poll will be active
|
|
||||||
after creation.
|
|
||||||
close_date (:obj:`datetime.datetime`): Optional. Point in time when the poll will be
|
|
||||||
automatically closed.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.3
|
|
||||||
|datetime_localization|
|
|
||||||
question_entities (tuple[:class:`telegram.MessageEntity`]): Special entities
|
|
||||||
that appear in the :attr:`question`. Currently, only custom emoji entities are allowed
|
|
||||||
in poll questions.
|
|
||||||
This list is empty if the question does not contain entities.
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"allows_multiple_answers",
|
|
||||||
"close_date",
|
|
||||||
"correct_option_id",
|
|
||||||
"explanation",
|
|
||||||
"explanation_entities",
|
|
||||||
"id",
|
|
||||||
"is_anonymous",
|
|
||||||
"is_closed",
|
|
||||||
"open_period",
|
|
||||||
"options",
|
|
||||||
"question",
|
|
||||||
"question_entities",
|
|
||||||
"total_voter_count",
|
|
||||||
"type",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
id: str, # pylint: disable=redefined-builtin
|
|
||||||
question: str,
|
|
||||||
options: Sequence[PollOption],
|
|
||||||
total_voter_count: int,
|
|
||||||
is_closed: bool,
|
|
||||||
is_anonymous: bool,
|
|
||||||
type: str, # pylint: disable=redefined-builtin
|
|
||||||
allows_multiple_answers: bool,
|
|
||||||
correct_option_id: Optional[int] = None,
|
|
||||||
explanation: Optional[str] = None,
|
|
||||||
explanation_entities: Optional[Sequence[MessageEntity]] = None,
|
|
||||||
open_period: Optional[int] = None,
|
|
||||||
close_date: Optional[dtm.datetime] = None,
|
|
||||||
question_entities: Optional[Sequence[MessageEntity]] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.id: str = id
|
|
||||||
self.question: str = question
|
|
||||||
self.options: tuple[PollOption, ...] = parse_sequence_arg(options)
|
|
||||||
self.total_voter_count: int = total_voter_count
|
|
||||||
self.is_closed: bool = is_closed
|
|
||||||
self.is_anonymous: bool = is_anonymous
|
|
||||||
self.type: str = enum.get_member(constants.PollType, type, type)
|
|
||||||
self.allows_multiple_answers: bool = allows_multiple_answers
|
|
||||||
self.correct_option_id: Optional[int] = correct_option_id
|
|
||||||
self.explanation: Optional[str] = explanation
|
|
||||||
self.explanation_entities: tuple[MessageEntity, ...] = parse_sequence_arg(
|
|
||||||
explanation_entities
|
|
||||||
)
|
|
||||||
self.open_period: Optional[int] = open_period
|
|
||||||
self.close_date: Optional[dtm.datetime] = close_date
|
|
||||||
self.question_entities: tuple[MessageEntity, ...] = parse_sequence_arg(question_entities)
|
|
||||||
|
|
||||||
self._id_attrs = (self.id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Poll"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Get the local timezone from the bot if it has defaults
|
|
||||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
|
||||||
|
|
||||||
data["options"] = [PollOption.de_json(option, bot) for option in data["options"]]
|
|
||||||
data["explanation_entities"] = MessageEntity.de_list(data.get("explanation_entities"), bot)
|
|
||||||
data["close_date"] = from_timestamp(data.get("close_date"), tzinfo=loc_tzinfo)
|
|
||||||
data["question_entities"] = MessageEntity.de_list(data.get("question_entities"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
def parse_explanation_entity(self, entity: MessageEntity) -> str:
|
|
||||||
"""Returns the text in :attr:`explanation` from a given :class:`telegram.MessageEntity` of
|
|
||||||
:attr:`explanation_entities`.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This method is present because Telegram calculates the offset and length in
|
|
||||||
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
|
|
||||||
(That is, you can't just slice ``Message.text`` with the offset and length.)
|
|
||||||
|
|
||||||
Args:
|
|
||||||
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
|
|
||||||
be an entity that belongs to :attr:`explanation_entities`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`: The text of the given entity.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: If the poll has no explanation.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not self.explanation:
|
|
||||||
raise RuntimeError("This Poll has no 'explanation'.")
|
|
||||||
|
|
||||||
return parse_message_entity(self.explanation, entity)
|
|
||||||
|
|
||||||
def parse_explanation_entities(
|
|
||||||
self, types: Optional[list[str]] = None
|
|
||||||
) -> dict[MessageEntity, str]:
|
|
||||||
"""
|
|
||||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
|
||||||
It contains entities from this polls explanation filtered by their ``type`` attribute as
|
|
||||||
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This method should always be used instead of the :attr:`explanation_entities`
|
|
||||||
attribute, since it calculates the correct substring from the message text based on
|
|
||||||
UTF-16 codepoints. See :attr:`parse_explanation_entity` for more info.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
|
|
||||||
``type`` attribute of an entity is contained in this list, it will be returned.
|
|
||||||
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
|
||||||
the text that belongs to them, calculated based on UTF-16 codepoints.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: If the poll has no explanation.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not self.explanation:
|
|
||||||
raise RuntimeError("This Poll has no 'explanation'.")
|
|
||||||
|
|
||||||
return parse_message_entities(self.explanation, self.explanation_entities, types)
|
|
||||||
|
|
||||||
def parse_question_entity(self, entity: MessageEntity) -> str:
|
|
||||||
"""Returns the text in :attr:`question` from a given :class:`telegram.MessageEntity` of
|
|
||||||
:attr:`question_entities`.
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This method is present because Telegram calculates the offset and length in
|
|
||||||
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
|
|
||||||
(That is, you can't just slice ``Message.text`` with the offset and length.)
|
|
||||||
|
|
||||||
Args:
|
|
||||||
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
|
|
||||||
be an entity that belongs to :attr:`question_entities`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`: The text of the given entity.
|
|
||||||
"""
|
|
||||||
return parse_message_entity(self.question, entity)
|
|
||||||
|
|
||||||
def parse_question_entities(
|
|
||||||
self, types: Optional[list[str]] = None
|
|
||||||
) -> dict[MessageEntity, str]:
|
|
||||||
"""
|
|
||||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
|
||||||
It contains entities from this polls question filtered by their ``type`` attribute as
|
|
||||||
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
|
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This method should always be used instead of the :attr:`question_entities`
|
|
||||||
attribute, since it calculates the correct substring from the message text based on
|
|
||||||
UTF-16 codepoints. See :attr:`parse_question_entity` for more info.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
|
|
||||||
``type`` attribute of an entity is contained in this list, it will be returned.
|
|
||||||
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
|
||||||
the text that belongs to them, calculated based on UTF-16 codepoints.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return parse_message_entities(self.question, self.question_entities, types)
|
|
||||||
|
|
||||||
REGULAR: Final[str] = constants.PollType.REGULAR
|
|
||||||
""":const:`telegram.constants.PollType.REGULAR`"""
|
|
||||||
QUIZ: Final[str] = constants.PollType.QUIZ
|
|
||||||
""":const:`telegram.constants.PollType.QUIZ`"""
|
|
||||||
MAX_EXPLANATION_LENGTH: Final[int] = constants.PollLimit.MAX_EXPLANATION_LENGTH
|
|
||||||
""":const:`telegram.constants.PollLimit.MAX_EXPLANATION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_EXPLANATION_LINE_FEEDS: Final[int] = constants.PollLimit.MAX_EXPLANATION_LINE_FEEDS
|
|
||||||
""":const:`telegram.constants.PollLimit.MAX_EXPLANATION_LINE_FEEDS`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MIN_OPEN_PERIOD: Final[int] = constants.PollLimit.MIN_OPEN_PERIOD
|
|
||||||
""":const:`telegram.constants.PollLimit.MIN_OPEN_PERIOD`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_OPEN_PERIOD: Final[int] = constants.PollLimit.MAX_OPEN_PERIOD
|
|
||||||
""":const:`telegram.constants.PollLimit.MAX_OPEN_PERIOD`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MIN_QUESTION_LENGTH: Final[int] = constants.PollLimit.MIN_QUESTION_LENGTH
|
|
||||||
""":const:`telegram.constants.PollLimit.MIN_QUESTION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_QUESTION_LENGTH: Final[int] = constants.PollLimit.MAX_QUESTION_LENGTH
|
|
||||||
""":const:`telegram.constants.PollLimit.MAX_QUESTION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MIN_OPTION_LENGTH: Final[int] = constants.PollLimit.MIN_OPTION_LENGTH
|
|
||||||
""":const:`telegram.constants.PollLimit.MIN_OPTION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_OPTION_LENGTH: Final[int] = constants.PollLimit.MAX_OPTION_LENGTH
|
|
||||||
""":const:`telegram.constants.PollLimit.MAX_OPTION_LENGTH`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MIN_OPTION_NUMBER: Final[int] = constants.PollLimit.MIN_OPTION_NUMBER
|
|
||||||
""":const:`telegram.constants.PollLimit.MIN_OPTION_NUMBER`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_OPTION_NUMBER: Final[int] = constants.PollLimit.MAX_OPTION_NUMBER
|
|
||||||
""":const:`telegram.constants.PollLimit.MAX_OPTION_NUMBER`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram Proximity Alert."""
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._user import User
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class ProximityAlertTriggered(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents the content of a service message, sent whenever a user in the chat
|
|
||||||
triggers a proximity alert set by another user.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`traveler`, :attr:`watcher` and :attr:`distance` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
traveler (:class:`telegram.User`): User that triggered the alert
|
|
||||||
watcher (:class:`telegram.User`): User that set the alert
|
|
||||||
distance (:obj:`int`): The distance between the users
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
traveler (:class:`telegram.User`): User that triggered the alert
|
|
||||||
watcher (:class:`telegram.User`): User that set the alert
|
|
||||||
distance (:obj:`int`): The distance between the users
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("distance", "traveler", "watcher")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
traveler: User,
|
|
||||||
watcher: User,
|
|
||||||
distance: int,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.traveler: User = traveler
|
|
||||||
self.watcher: User = watcher
|
|
||||||
self.distance: int = distance
|
|
||||||
|
|
||||||
self._id_attrs = (self.traveler, self.watcher, self.distance)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["ProximityAlertTriggered"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["traveler"] = User.de_json(data.get("traveler"), bot)
|
|
||||||
data["watcher"] = User.de_json(data.get("watcher"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains objects that represents a Telegram ReactionType."""
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Final, Literal, Optional, Union
|
|
||||||
|
|
||||||
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 ReactionType(TelegramObject):
|
|
||||||
"""Base class for Telegram ReactionType Objects.
|
|
||||||
There exist :class:`telegram.ReactionTypeEmoji`, :class:`telegram.ReactionTypeCustomEmoji`
|
|
||||||
and :class:`telegram.ReactionTypePaid`.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
.. versionchanged:: 21.5
|
|
||||||
|
|
||||||
Added paid reaction.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:obj:`str`): Type of the reaction. Can be
|
|
||||||
:attr:`~telegram.ReactionType.EMOJI`, :attr:`~telegram.ReactionType.CUSTOM_EMOJI` or
|
|
||||||
:attr:`~telegram.ReactionType.PAID`.
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): Type of the reaction. Can be
|
|
||||||
:attr:`~telegram.ReactionType.EMOJI`, :attr:`~telegram.ReactionType.CUSTOM_EMOJI` or
|
|
||||||
:attr:`~telegram.ReactionType.PAID`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("type",)
|
|
||||||
|
|
||||||
EMOJI: Final[constants.ReactionType] = constants.ReactionType.EMOJI
|
|
||||||
""":const:`telegram.constants.ReactionType.EMOJI`"""
|
|
||||||
CUSTOM_EMOJI: Final[constants.ReactionType] = constants.ReactionType.CUSTOM_EMOJI
|
|
||||||
""":const:`telegram.constants.ReactionType.CUSTOM_EMOJI`"""
|
|
||||||
PAID: Final[constants.ReactionType] = constants.ReactionType.PAID
|
|
||||||
""":const:`telegram.constants.ReactionType.PAID`
|
|
||||||
|
|
||||||
.. versionadded:: 21.5
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
type: Union[ # pylint: disable=redefined-builtin
|
|
||||||
Literal["emoji", "custom_emoji", "paid"], constants.ReactionType
|
|
||||||
],
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required by all subclasses
|
|
||||||
self.type: str = enum.get_member(constants.ReactionType, type, type)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["ReactionType"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not data and cls is ReactionType:
|
|
||||||
return None
|
|
||||||
|
|
||||||
_class_mapping: dict[str, type[ReactionType]] = {
|
|
||||||
cls.EMOJI: ReactionTypeEmoji,
|
|
||||||
cls.CUSTOM_EMOJI: ReactionTypeCustomEmoji,
|
|
||||||
cls.PAID: ReactionTypePaid,
|
|
||||||
}
|
|
||||||
|
|
||||||
if cls is ReactionType and data.get("type") in _class_mapping:
|
|
||||||
return _class_mapping[data.pop("type")].de_json(data, bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class ReactionTypeEmoji(ReactionType):
|
|
||||||
"""
|
|
||||||
Represents a reaction with a normal emoji.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if the :attr:`emoji` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
Args:
|
|
||||||
emoji (:obj:`str`): Reaction emoji. It can be one of
|
|
||||||
:const:`telegram.constants.ReactionEmoji`.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): Type of the reaction,
|
|
||||||
always :tg-const:`telegram.ReactionType.EMOJI`.
|
|
||||||
emoji (:obj:`str`): Reaction emoji. It can be one of
|
|
||||||
:const:`telegram.constants.ReactionEmoji`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("emoji",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
emoji: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(type=ReactionType.EMOJI, api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
with self._unfrozen():
|
|
||||||
self.emoji: str = emoji
|
|
||||||
self._id_attrs = (self.emoji,)
|
|
||||||
|
|
||||||
|
|
||||||
class ReactionTypeCustomEmoji(ReactionType):
|
|
||||||
"""
|
|
||||||
Represents a reaction with a custom emoji.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if the :attr:`custom_emoji_id` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
Args:
|
|
||||||
custom_emoji_id (:obj:`str`): Custom emoji identifier.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): Type of the reaction,
|
|
||||||
always :tg-const:`telegram.ReactionType.CUSTOM_EMOJI`.
|
|
||||||
custom_emoji_id (:obj:`str`): Custom emoji identifier.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("custom_emoji_id",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
custom_emoji_id: str,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(type=ReactionType.CUSTOM_EMOJI, api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
with self._unfrozen():
|
|
||||||
self.custom_emoji_id: str = custom_emoji_id
|
|
||||||
self._id_attrs = (self.custom_emoji_id,)
|
|
||||||
|
|
||||||
|
|
||||||
class ReactionTypePaid(ReactionType):
|
|
||||||
"""
|
|
||||||
The reaction is paid.
|
|
||||||
|
|
||||||
.. versionadded:: 21.5
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:obj:`str`): Type of the reaction,
|
|
||||||
always :tg-const:`telegram.ReactionType.PAID`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
|
|
||||||
super().__init__(type=ReactionType.PAID, api_kwargs=api_kwargs)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class ReactionCount(TelegramObject):
|
|
||||||
"""This class represents a reaction added to a message along with the number of times it was
|
|
||||||
added.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if the :attr:`type` and :attr:`total_count` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
Args:
|
|
||||||
type (:class:`telegram.ReactionType`): Type of the reaction.
|
|
||||||
total_count (:obj:`int`): Number of times the reaction was added.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
type (:class:`telegram.ReactionType`): Type of the reaction.
|
|
||||||
total_count (:obj:`int`): Number of times the reaction was added.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"total_count",
|
|
||||||
"type",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
type: ReactionType, # pylint: disable=redefined-builtin
|
|
||||||
total_count: int,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.type: ReactionType = type
|
|
||||||
self.total_count: int = total_count
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.type,
|
|
||||||
self.total_count,
|
|
||||||
)
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["ReactionCount"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["type"] = ReactionType.de_json(data.get("type"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,472 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This modules contains objects that represents Telegram Replies"""
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional, Union
|
|
||||||
|
|
||||||
from telegram._chat import Chat
|
|
||||||
from telegram._dice import Dice
|
|
||||||
from telegram._files.animation import Animation
|
|
||||||
from telegram._files.audio import Audio
|
|
||||||
from telegram._files.contact import Contact
|
|
||||||
from telegram._files.document import Document
|
|
||||||
from telegram._files.location import Location
|
|
||||||
from telegram._files.photosize import PhotoSize
|
|
||||||
from telegram._files.sticker import Sticker
|
|
||||||
from telegram._files.venue import Venue
|
|
||||||
from telegram._files.video import Video
|
|
||||||
from telegram._files.videonote import VideoNote
|
|
||||||
from telegram._files.voice import Voice
|
|
||||||
from telegram._games.game import Game
|
|
||||||
from telegram._giveaway import Giveaway, GiveawayWinners
|
|
||||||
from telegram._linkpreviewoptions import LinkPreviewOptions
|
|
||||||
from telegram._messageentity import MessageEntity
|
|
||||||
from telegram._messageorigin import MessageOrigin
|
|
||||||
from telegram._paidmedia import PaidMediaInfo
|
|
||||||
from telegram._payment.invoice import Invoice
|
|
||||||
from telegram._poll import Poll
|
|
||||||
from telegram._story import Story
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
|
||||||
from telegram._utils.types import JSONDict, ODVInput
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class ExternalReplyInfo(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about a message that is being replied to, which may
|
|
||||||
come from another chat or forum topic.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`origin` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
Args:
|
|
||||||
origin (:class:`telegram.MessageOrigin`): Origin of the message replied to by the given
|
|
||||||
message.
|
|
||||||
chat (:class:`telegram.Chat`, optional): Chat the original message belongs to. Available
|
|
||||||
only if the chat is a supergroup or a channel.
|
|
||||||
message_id (:obj:`int`, optional): Unique message identifier inside the original chat.
|
|
||||||
Available only if the original chat is a supergroup or a channel.
|
|
||||||
link_preview_options (:class:`telegram.LinkPreviewOptions`, optional): Options used for
|
|
||||||
link preview generation for the original message, if it is a text message
|
|
||||||
animation (:class:`telegram.Animation`, optional): Message is an animation, information
|
|
||||||
about the animation.
|
|
||||||
audio (:class:`telegram.Audio`, optional): Message is an audio file, information about the
|
|
||||||
file.
|
|
||||||
document (:class:`telegram.Document`, optional): Message is a general file, information
|
|
||||||
about the file.
|
|
||||||
photo (Sequence[:class:`telegram.PhotoSize`], optional): Message is a photo, available
|
|
||||||
sizes of the photo.
|
|
||||||
sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information about the
|
|
||||||
sticker.
|
|
||||||
story (:class:`telegram.Story`, optional): Message is a forwarded story.
|
|
||||||
video (:class:`telegram.Video`, optional): Message is a video, information about the video.
|
|
||||||
video_note (:class:`telegram.VideoNote`, optional): Message is a `video note
|
|
||||||
<https://telegram.org/blog/video-messages-and-telescope>`_, information about the video
|
|
||||||
message.
|
|
||||||
voice (:class:`telegram.Voice`, optional): Message is a voice message, information about
|
|
||||||
the file.
|
|
||||||
has_media_spoiler (:obj:`bool`, optional): :obj:`True`, if the message media is covered by
|
|
||||||
a spoiler animation.
|
|
||||||
contact (:class:`telegram.Contact`, optional): Message is a shared contact, information
|
|
||||||
about the contact.
|
|
||||||
dice (:class:`telegram.Dice`, optional): Message is a dice with random value.
|
|
||||||
game (:Class:`telegram.Game`. optional): Message is a game, information about the game.
|
|
||||||
:ref:`More about games >> <games-tree>`.
|
|
||||||
giveaway (:class:`telegram.Giveaway`, optional): Message is a scheduled giveaway,
|
|
||||||
information about the giveaway.
|
|
||||||
giveaway_winners (:class:`telegram.GiveawayWinners`, optional): A giveaway with public
|
|
||||||
winners was completed.
|
|
||||||
invoice (:class:`telegram.Invoice`, optional): Message is an invoice for a payment,
|
|
||||||
information about the invoice. :ref:`More about payments >> <payments-tree>`.
|
|
||||||
location (:class:`telegram.Location`, optional): Message is a shared location, information
|
|
||||||
about the location.
|
|
||||||
poll (:class:`telegram.Poll`, optional): Message is a native poll, information about the
|
|
||||||
poll.
|
|
||||||
venue (:class:`telegram.Venue`, optional): Message is a venue, information about the venue.
|
|
||||||
paid_media (:class:`telegram.PaidMedia`, optional): Message contains paid media;
|
|
||||||
information about the paid media.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
origin (:class:`telegram.MessageOrigin`): Origin of the message replied to by the given
|
|
||||||
message.
|
|
||||||
chat (:class:`telegram.Chat`): Optional. Chat the original message belongs to. Available
|
|
||||||
only if the chat is a supergroup or a channel.
|
|
||||||
message_id (:obj:`int`): Optional. Unique message identifier inside the original chat.
|
|
||||||
Available only if the original chat is a supergroup or a channel.
|
|
||||||
link_preview_options (:class:`telegram.LinkPreviewOptions`): Optional. Options used for
|
|
||||||
link preview generation for the original message, if it is a text message.
|
|
||||||
animation (:class:`telegram.Animation`): Optional. Message is an animation, information
|
|
||||||
about the animation.
|
|
||||||
audio (:class:`telegram.Audio`): Optional. Message is an audio file, information about the
|
|
||||||
file.
|
|
||||||
document (:class:`telegram.Document`): Optional. Message is a general file, information
|
|
||||||
about the file.
|
|
||||||
photo (tuple[:class:`telegram.PhotoSize`]): Optional. Message is a photo, available sizes
|
|
||||||
of the photo.
|
|
||||||
sticker (:class:`telegram.Sticker`): Optional. Message is a sticker, information about the
|
|
||||||
sticker.
|
|
||||||
story (:class:`telegram.Story`): Optional. Message is a forwarded story.
|
|
||||||
video (:class:`telegram.Video`): Optional. Message is a video, information about the video.
|
|
||||||
video_note (:class:`telegram.VideoNote`): Optional. Message is a `video note
|
|
||||||
<https://telegram.org/blog/video-messages-and-telescope>`_, information about the video
|
|
||||||
message.
|
|
||||||
voice (:class:`telegram.Voice`): Optional. Message is a voice message, information about
|
|
||||||
the file.
|
|
||||||
has_media_spoiler (:obj:`bool`): Optional. :obj:`True`, if the message media is covered by
|
|
||||||
a spoiler animation.
|
|
||||||
contact (:class:`telegram.Contact`): Optional. Message is a shared contact, information
|
|
||||||
about the contact.
|
|
||||||
dice (:class:`telegram.Dice`): Optional. Message is a dice with random value.
|
|
||||||
game (:Class:`telegram.Game`): Optional. Message is a game, information about the game.
|
|
||||||
:ref:`More about games >> <games-tree>`.
|
|
||||||
giveaway (:class:`telegram.Giveaway`): Optional. Message is a scheduled giveaway,
|
|
||||||
information about the giveaway.
|
|
||||||
giveaway_winners (:class:`telegram.GiveawayWinners`): Optional. A giveaway with public
|
|
||||||
winners was completed.
|
|
||||||
invoice (:class:`telegram.Invoice`): Optional. Message is an invoice for a payment,
|
|
||||||
information about the invoice. :ref:`More about payments >> <payments-tree>`.
|
|
||||||
location (:class:`telegram.Location`): Optional. Message is a shared location, information
|
|
||||||
about the location.
|
|
||||||
poll (:class:`telegram.Poll`): Optional. Message is a native poll, information about the
|
|
||||||
poll.
|
|
||||||
venue (:class:`telegram.Venue`): Optional. Message is a venue, information about the venue.
|
|
||||||
paid_media (:class:`telegram.PaidMedia`): Optional. Message contains paid media;
|
|
||||||
information about the paid media.
|
|
||||||
|
|
||||||
.. versionadded:: 21.4
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"animation",
|
|
||||||
"audio",
|
|
||||||
"chat",
|
|
||||||
"contact",
|
|
||||||
"dice",
|
|
||||||
"document",
|
|
||||||
"game",
|
|
||||||
"giveaway",
|
|
||||||
"giveaway_winners",
|
|
||||||
"has_media_spoiler",
|
|
||||||
"invoice",
|
|
||||||
"link_preview_options",
|
|
||||||
"location",
|
|
||||||
"message_id",
|
|
||||||
"origin",
|
|
||||||
"paid_media",
|
|
||||||
"photo",
|
|
||||||
"poll",
|
|
||||||
"sticker",
|
|
||||||
"story",
|
|
||||||
"venue",
|
|
||||||
"video",
|
|
||||||
"video_note",
|
|
||||||
"voice",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
origin: MessageOrigin,
|
|
||||||
chat: Optional[Chat] = None,
|
|
||||||
message_id: Optional[int] = None,
|
|
||||||
link_preview_options: Optional[LinkPreviewOptions] = None,
|
|
||||||
animation: Optional[Animation] = None,
|
|
||||||
audio: Optional[Audio] = None,
|
|
||||||
document: Optional[Document] = None,
|
|
||||||
photo: Optional[Sequence[PhotoSize]] = None,
|
|
||||||
sticker: Optional[Sticker] = None,
|
|
||||||
story: Optional[Story] = None,
|
|
||||||
video: Optional[Video] = None,
|
|
||||||
video_note: Optional[VideoNote] = None,
|
|
||||||
voice: Optional[Voice] = None,
|
|
||||||
has_media_spoiler: Optional[bool] = None,
|
|
||||||
contact: Optional[Contact] = None,
|
|
||||||
dice: Optional[Dice] = None,
|
|
||||||
game: Optional[Game] = None,
|
|
||||||
giveaway: Optional[Giveaway] = None,
|
|
||||||
giveaway_winners: Optional[GiveawayWinners] = None,
|
|
||||||
invoice: Optional[Invoice] = None,
|
|
||||||
location: Optional[Location] = None,
|
|
||||||
poll: Optional[Poll] = None,
|
|
||||||
venue: Optional[Venue] = None,
|
|
||||||
paid_media: Optional[PaidMediaInfo] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
self.origin: MessageOrigin = origin
|
|
||||||
self.chat: Optional[Chat] = chat
|
|
||||||
self.message_id: Optional[int] = message_id
|
|
||||||
self.link_preview_options: Optional[LinkPreviewOptions] = link_preview_options
|
|
||||||
self.animation: Optional[Animation] = animation
|
|
||||||
self.audio: Optional[Audio] = audio
|
|
||||||
self.document: Optional[Document] = document
|
|
||||||
self.photo: Optional[tuple[PhotoSize, ...]] = parse_sequence_arg(photo)
|
|
||||||
self.sticker: Optional[Sticker] = sticker
|
|
||||||
self.story: Optional[Story] = story
|
|
||||||
self.video: Optional[Video] = video
|
|
||||||
self.video_note: Optional[VideoNote] = video_note
|
|
||||||
self.voice: Optional[Voice] = voice
|
|
||||||
self.has_media_spoiler: Optional[bool] = has_media_spoiler
|
|
||||||
self.contact: Optional[Contact] = contact
|
|
||||||
self.dice: Optional[Dice] = dice
|
|
||||||
self.game: Optional[Game] = game
|
|
||||||
self.giveaway: Optional[Giveaway] = giveaway
|
|
||||||
self.giveaway_winners: Optional[GiveawayWinners] = giveaway_winners
|
|
||||||
self.invoice: Optional[Invoice] = invoice
|
|
||||||
self.location: Optional[Location] = location
|
|
||||||
self.poll: Optional[Poll] = poll
|
|
||||||
self.venue: Optional[Venue] = venue
|
|
||||||
self.paid_media: Optional[PaidMediaInfo] = paid_media
|
|
||||||
|
|
||||||
self._id_attrs = (self.origin,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["ExternalReplyInfo"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["origin"] = MessageOrigin.de_json(data.get("origin"), bot)
|
|
||||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
|
||||||
data["link_preview_options"] = LinkPreviewOptions.de_json(
|
|
||||||
data.get("link_preview_options"), bot
|
|
||||||
)
|
|
||||||
data["animation"] = Animation.de_json(data.get("animation"), bot)
|
|
||||||
data["audio"] = Audio.de_json(data.get("audio"), bot)
|
|
||||||
data["document"] = Document.de_json(data.get("document"), bot)
|
|
||||||
data["photo"] = tuple(PhotoSize.de_list(data.get("photo"), bot))
|
|
||||||
data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
|
|
||||||
data["story"] = Story.de_json(data.get("story"), bot)
|
|
||||||
data["video"] = Video.de_json(data.get("video"), bot)
|
|
||||||
data["video_note"] = VideoNote.de_json(data.get("video_note"), bot)
|
|
||||||
data["voice"] = Voice.de_json(data.get("voice"), bot)
|
|
||||||
data["contact"] = Contact.de_json(data.get("contact"), bot)
|
|
||||||
data["dice"] = Dice.de_json(data.get("dice"), bot)
|
|
||||||
data["game"] = Game.de_json(data.get("game"), bot)
|
|
||||||
data["giveaway"] = Giveaway.de_json(data.get("giveaway"), bot)
|
|
||||||
data["giveaway_winners"] = GiveawayWinners.de_json(data.get("giveaway_winners"), bot)
|
|
||||||
data["invoice"] = Invoice.de_json(data.get("invoice"), bot)
|
|
||||||
data["location"] = Location.de_json(data.get("location"), bot)
|
|
||||||
data["poll"] = Poll.de_json(data.get("poll"), bot)
|
|
||||||
data["venue"] = Venue.de_json(data.get("venue"), bot)
|
|
||||||
data["paid_media"] = PaidMediaInfo.de_json(data.get("paid_media"), bot)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class TextQuote(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about the quoted part of a message that is replied to
|
|
||||||
by the given message.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`text` and :attr:`position` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text (:obj:`str`): Text of the quoted part of a message that is replied to by the given
|
|
||||||
message.
|
|
||||||
position (:obj:`int`): Approximate quote position in the original message in UTF-16 code
|
|
||||||
units as specified by the sender.
|
|
||||||
entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that
|
|
||||||
appear
|
|
||||||
in the quote. Currently, only bold, italic, underline, strikethrough, spoiler, and
|
|
||||||
custom_emoji entities are kept in quotes.
|
|
||||||
is_manual (:obj:`bool`, optional): :obj:`True`, if the quote was chosen manually by the
|
|
||||||
message sender. Otherwise, the quote was added automatically by the server.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
text (:obj:`str`): Text of the quoted part of a message that is replied to by the given
|
|
||||||
message.
|
|
||||||
position (:obj:`int`): Approximate quote position in the original message in UTF-16 code
|
|
||||||
units as specified by the sender.
|
|
||||||
entities (tuple[:class:`telegram.MessageEntity`]): Optional. Special entities that appear
|
|
||||||
in the quote. Currently, only bold, italic, underline, strikethrough, spoiler, and
|
|
||||||
custom_emoji entities are kept in quotes.
|
|
||||||
is_manual (:obj:`bool`): Optional. :obj:`True`, if the quote was chosen manually by the
|
|
||||||
message sender. Otherwise, the quote was added automatically by the server.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"entities",
|
|
||||||
"is_manual",
|
|
||||||
"position",
|
|
||||||
"text",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
text: str,
|
|
||||||
position: int,
|
|
||||||
entities: Optional[Sequence[MessageEntity]] = None,
|
|
||||||
is_manual: Optional[bool] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
self.text: str = text
|
|
||||||
self.position: int = position
|
|
||||||
self.entities: Optional[tuple[MessageEntity, ...]] = parse_sequence_arg(entities)
|
|
||||||
self.is_manual: Optional[bool] = is_manual
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.text,
|
|
||||||
self.position,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["TextQuote"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["entities"] = tuple(MessageEntity.de_list(data.get("entities"), bot))
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class ReplyParameters(TelegramObject):
|
|
||||||
"""
|
|
||||||
Describes reply parameters for the message that is being sent.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`message_id` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
Args:
|
|
||||||
message_id (:obj:`int`): Identifier of the message that will be replied to in the current
|
|
||||||
chat, or in the chat :paramref:`chat_id` if it is specified.
|
|
||||||
chat_id (:obj:`int` | :obj:`str`, optional): If the message to be replied to is from a
|
|
||||||
different chat, |chat_id_channel|
|
|
||||||
Not supported for messages sent on behalf of a business account.
|
|
||||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| Can be
|
|
||||||
used only for replies in the same chat and forum topic.
|
|
||||||
quote (:obj:`str`, optional): Quoted part of the message to be replied to; 0-1024
|
|
||||||
characters after entities parsing. The quote must be an exact substring of the message
|
|
||||||
to be replied to, including bold, italic, underline, strikethrough, spoiler, and
|
|
||||||
custom_emoji entities. The message will fail to send if the quote isn't found in the
|
|
||||||
original message.
|
|
||||||
quote_parse_mode (:obj:`str`, optional): Mode for parsing entities in the quote. See
|
|
||||||
:wiki:`formatting options <Code-snippets#message-formatting-bold-italic-code->` for
|
|
||||||
more details.
|
|
||||||
quote_entities (Sequence[:class:`telegram.MessageEntity`], optional): A JSON-serialized
|
|
||||||
list
|
|
||||||
of special entities that appear in the quote. It can be specified instead of
|
|
||||||
:paramref:`quote_parse_mode`.
|
|
||||||
quote_position (:obj:`int`, optional): Position of the quote in the original message in
|
|
||||||
UTF-16 code units.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
message_id (:obj:`int`): Identifier of the message that will be replied to in the current
|
|
||||||
chat, or in the chat :paramref:`chat_id` if it is specified.
|
|
||||||
chat_id (:obj:`int` | :obj:`str`): Optional. If the message to be replied to is from a
|
|
||||||
different chat, |chat_id_channel|
|
|
||||||
Not supported for messages sent on behalf of a business account.
|
|
||||||
allow_sending_without_reply (:obj:`bool`): Optional. |allow_sending_without_reply| Can be
|
|
||||||
used only for replies in the same chat and forum topic.
|
|
||||||
quote (:obj:`str`): Optional. Quoted part of the message to be replied to; 0-1024
|
|
||||||
characters after entities parsing. The quote must be an exact substring of the message
|
|
||||||
to be replied to, including bold, italic, underline, strikethrough, spoiler, and
|
|
||||||
custom_emoji entities. The message will fail to send if the quote isn't found in the
|
|
||||||
original message.
|
|
||||||
quote_parse_mode (:obj:`str`): Optional. Mode for parsing entities in the quote. See
|
|
||||||
:wiki:`formatting options <Code-snippets#message-formatting-bold-italic-code->` for
|
|
||||||
more details.
|
|
||||||
quote_entities (tuple[:class:`telegram.MessageEntity`]): Optional. A JSON-serialized list
|
|
||||||
of special entities that appear in the quote. It can be specified instead of
|
|
||||||
:paramref:`quote_parse_mode`.
|
|
||||||
quote_position (:obj:`int`): Optional. Position of the quote in the original message in
|
|
||||||
UTF-16 code units.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"allow_sending_without_reply",
|
|
||||||
"chat_id",
|
|
||||||
"message_id",
|
|
||||||
"quote",
|
|
||||||
"quote_entities",
|
|
||||||
"quote_parse_mode",
|
|
||||||
"quote_position",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
message_id: int,
|
|
||||||
chat_id: Optional[Union[int, str]] = None,
|
|
||||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
|
||||||
quote: Optional[str] = None,
|
|
||||||
quote_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
|
||||||
quote_entities: Optional[Sequence[MessageEntity]] = None,
|
|
||||||
quote_position: Optional[int] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
self.message_id: int = message_id
|
|
||||||
self.chat_id: Optional[Union[int, str]] = chat_id
|
|
||||||
self.allow_sending_without_reply: ODVInput[bool] = allow_sending_without_reply
|
|
||||||
self.quote: Optional[str] = quote
|
|
||||||
self.quote_parse_mode: ODVInput[str] = quote_parse_mode
|
|
||||||
self.quote_entities: Optional[tuple[MessageEntity, ...]] = parse_sequence_arg(
|
|
||||||
quote_entities
|
|
||||||
)
|
|
||||||
self.quote_position: Optional[int] = quote_position
|
|
||||||
|
|
||||||
self._id_attrs = (self.message_id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["ReplyParameters"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["quote_entities"] = tuple(MessageEntity.de_list(data.get("quote_entities"), bot))
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,360 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram ReplyKeyboardMarkup."""
|
|
||||||
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import Final, Optional, Union
|
|
||||||
|
|
||||||
from telegram import constants
|
|
||||||
from telegram._keyboardbutton import KeyboardButton
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.markup import check_keyboard_type
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class ReplyKeyboardMarkup(TelegramObject):
|
|
||||||
"""This object represents a custom keyboard with reply options. Not supported in channels and
|
|
||||||
for messages sent on behalf of a Telegram Business account.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their size of :attr:`keyboard` and all the buttons are equal.
|
|
||||||
|
|
||||||
.. figure:: https://core.telegram.org/file/464001950/1191a/2RwpmgU-swU.123554/b5\
|
|
||||||
0478c124d5914c23
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
A reply keyboard with reply options.
|
|
||||||
|
|
||||||
.. seealso::
|
|
||||||
Another kind of keyboard would be the :class:`telegram.InlineKeyboardMarkup`.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
* Example usage: A user requests to change the bot's language, bot replies to the request
|
|
||||||
with a keyboard to select the new language. Other users in the group don't see
|
|
||||||
the keyboard.
|
|
||||||
* :any:`Conversation Bot <examples.conversationbot>`
|
|
||||||
* :any:`Conversation Bot 2 <examples.conversationbot2>`
|
|
||||||
|
|
||||||
Args:
|
|
||||||
keyboard (Sequence[Sequence[:obj:`str` | :class:`telegram.KeyboardButton`]]): Array of
|
|
||||||
button rows, each represented by an Array of :class:`telegram.KeyboardButton` objects.
|
|
||||||
resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically
|
|
||||||
for optimal fit (e.g., make the keyboard smaller if there are just two rows of
|
|
||||||
buttons). Defaults to :obj:`False`, in which case the custom keyboard is always of the
|
|
||||||
same height as the app's standard keyboard.
|
|
||||||
one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as
|
|
||||||
it's been used. The keyboard will still be available, but clients will automatically
|
|
||||||
display the usual letter-keyboard in the chat - the user can press a special button in
|
|
||||||
the input field to see the custom keyboard again. Defaults to :obj:`False`.
|
|
||||||
selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to
|
|
||||||
specific users only. Targets:
|
|
||||||
|
|
||||||
1) Users that are @mentioned in the :attr:`~telegram.Message.text` of the
|
|
||||||
:class:`telegram.Message` object.
|
|
||||||
2) If the bot's message is a reply to a message in the same chat and forum topic,
|
|
||||||
sender of the original message.
|
|
||||||
|
|
||||||
Defaults to :obj:`False`.
|
|
||||||
|
|
||||||
input_field_placeholder (:obj:`str`, optional): The placeholder to be shown in the input
|
|
||||||
field when the keyboard is active;
|
|
||||||
:tg-const:`telegram.ReplyKeyboardMarkup.MIN_INPUT_FIELD_PLACEHOLDER`-
|
|
||||||
:tg-const:`telegram.ReplyKeyboardMarkup.MAX_INPUT_FIELD_PLACEHOLDER`
|
|
||||||
characters.
|
|
||||||
|
|
||||||
.. versionadded:: 13.7
|
|
||||||
is_persistent (:obj:`bool`, optional): Requests clients to always show the keyboard when
|
|
||||||
the regular keyboard is hidden. Defaults to :obj:`False`, in which case the custom
|
|
||||||
keyboard can be hidden and opened with a keyboard icon.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
keyboard (tuple[tuple[:class:`telegram.KeyboardButton`]]): Array of button rows,
|
|
||||||
each represented by an Array of :class:`telegram.KeyboardButton` objects.
|
|
||||||
resize_keyboard (:obj:`bool`): Optional. Requests clients to resize the keyboard vertically
|
|
||||||
for optimal fit (e.g., make the keyboard smaller if there are just two rows of
|
|
||||||
buttons). Defaults to :obj:`False`, in which case the custom keyboard is always of the
|
|
||||||
same height as the app's standard keyboard.
|
|
||||||
one_time_keyboard (:obj:`bool`): Optional. Requests clients to hide the keyboard as soon as
|
|
||||||
it's been used. The keyboard will still be available, but clients will automatically
|
|
||||||
display the usual letter-keyboard in the chat - the user can press a special button in
|
|
||||||
the input field to see the custom keyboard again. Defaults to :obj:`False`.
|
|
||||||
selective (:obj:`bool`): Optional. Show the keyboard to specific users only.
|
|
||||||
Targets:
|
|
||||||
|
|
||||||
1) Users that are @mentioned in the :attr:`~telegram.Message.text` of the
|
|
||||||
:class:`telegram.Message` object.
|
|
||||||
2) If the bot's message is a reply to a message in the same chat and forum topic,
|
|
||||||
sender of the original message.
|
|
||||||
|
|
||||||
Defaults to :obj:`False`.
|
|
||||||
|
|
||||||
input_field_placeholder (:obj:`str`): Optional. The placeholder to be shown in the input
|
|
||||||
field when the keyboard is active;
|
|
||||||
:tg-const:`telegram.ReplyKeyboardMarkup.MIN_INPUT_FIELD_PLACEHOLDER`-
|
|
||||||
:tg-const:`telegram.ReplyKeyboardMarkup.MAX_INPUT_FIELD_PLACEHOLDER`
|
|
||||||
characters.
|
|
||||||
|
|
||||||
.. versionadded:: 13.7
|
|
||||||
is_persistent (:obj:`bool`): Optional. Requests clients to always show the keyboard when
|
|
||||||
the regular keyboard is hidden. If :obj:`False`, the custom keyboard can be hidden and
|
|
||||||
opened with a keyboard icon.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"input_field_placeholder",
|
|
||||||
"is_persistent",
|
|
||||||
"keyboard",
|
|
||||||
"one_time_keyboard",
|
|
||||||
"resize_keyboard",
|
|
||||||
"selective",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
keyboard: Sequence[Sequence[Union[str, KeyboardButton]]],
|
|
||||||
resize_keyboard: Optional[bool] = None,
|
|
||||||
one_time_keyboard: Optional[bool] = None,
|
|
||||||
selective: Optional[bool] = None,
|
|
||||||
input_field_placeholder: Optional[str] = None,
|
|
||||||
is_persistent: Optional[bool] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
if not check_keyboard_type(keyboard):
|
|
||||||
raise ValueError(
|
|
||||||
"The parameter `keyboard` should be a sequence of sequences of "
|
|
||||||
"strings or KeyboardButtons"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Required
|
|
||||||
self.keyboard: tuple[tuple[KeyboardButton, ...], ...] = tuple(
|
|
||||||
tuple(KeyboardButton(button) if isinstance(button, str) else button for button in row)
|
|
||||||
for row in keyboard
|
|
||||||
)
|
|
||||||
|
|
||||||
# Optionals
|
|
||||||
self.resize_keyboard: Optional[bool] = resize_keyboard
|
|
||||||
self.one_time_keyboard: Optional[bool] = one_time_keyboard
|
|
||||||
self.selective: Optional[bool] = selective
|
|
||||||
self.input_field_placeholder: Optional[str] = input_field_placeholder
|
|
||||||
self.is_persistent: Optional[bool] = is_persistent
|
|
||||||
|
|
||||||
self._id_attrs = (self.keyboard,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_button(
|
|
||||||
cls,
|
|
||||||
button: Union[KeyboardButton, str],
|
|
||||||
resize_keyboard: bool = False,
|
|
||||||
one_time_keyboard: bool = False,
|
|
||||||
selective: bool = False,
|
|
||||||
input_field_placeholder: Optional[str] = None,
|
|
||||||
is_persistent: Optional[bool] = None,
|
|
||||||
**kwargs: object,
|
|
||||||
) -> "ReplyKeyboardMarkup":
|
|
||||||
"""Shortcut for::
|
|
||||||
|
|
||||||
ReplyKeyboardMarkup([[button]], **kwargs)
|
|
||||||
|
|
||||||
Return a ReplyKeyboardMarkup from a single KeyboardButton.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
button (:class:`telegram.KeyboardButton` | :obj:`str`): The button to use in
|
|
||||||
the markup.
|
|
||||||
resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard
|
|
||||||
vertically for optimal fit (e.g., make the keyboard smaller if there are just two
|
|
||||||
rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is
|
|
||||||
always of the same height as the app's standard keyboard.
|
|
||||||
one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as
|
|
||||||
soon as it's been used. The keyboard will still be available, but clients will
|
|
||||||
automatically display the usual letter-keyboard in the chat - the user can press
|
|
||||||
a special button in the input field to see the custom keyboard again.
|
|
||||||
Defaults to :obj:`False`.
|
|
||||||
selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard
|
|
||||||
to specific users only. Targets:
|
|
||||||
|
|
||||||
1) Users that are @mentioned in the text of the Message object.
|
|
||||||
2) If the bot's message is a reply to a message in the same chat and forum topic,
|
|
||||||
sender of the original message.
|
|
||||||
|
|
||||||
Defaults to :obj:`False`.
|
|
||||||
|
|
||||||
input_field_placeholder (:obj:`str`): Optional. The placeholder shown in the input
|
|
||||||
field when the reply is active.
|
|
||||||
|
|
||||||
.. versionadded:: 13.7
|
|
||||||
is_persistent (:obj:`bool`): Optional. Requests clients to always show the keyboard
|
|
||||||
when the regular keyboard is hidden. Defaults to :obj:`False`, in which case the
|
|
||||||
custom keyboard can be hidden and opened with a keyboard icon.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
return cls(
|
|
||||||
[[button]],
|
|
||||||
resize_keyboard=resize_keyboard,
|
|
||||||
one_time_keyboard=one_time_keyboard,
|
|
||||||
selective=selective,
|
|
||||||
input_field_placeholder=input_field_placeholder,
|
|
||||||
is_persistent=is_persistent,
|
|
||||||
**kwargs, # type: ignore[arg-type]
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_row(
|
|
||||||
cls,
|
|
||||||
button_row: Sequence[Union[str, KeyboardButton]],
|
|
||||||
resize_keyboard: bool = False,
|
|
||||||
one_time_keyboard: bool = False,
|
|
||||||
selective: bool = False,
|
|
||||||
input_field_placeholder: Optional[str] = None,
|
|
||||||
is_persistent: Optional[bool] = None,
|
|
||||||
**kwargs: object,
|
|
||||||
) -> "ReplyKeyboardMarkup":
|
|
||||||
"""Shortcut for::
|
|
||||||
|
|
||||||
ReplyKeyboardMarkup([button_row], **kwargs)
|
|
||||||
|
|
||||||
Return a ReplyKeyboardMarkup from a single row of KeyboardButtons.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
button_row (Sequence[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to
|
|
||||||
use in the markup.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceargs|
|
|
||||||
resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard
|
|
||||||
vertically for optimal fit (e.g., make the keyboard smaller if there are just two
|
|
||||||
rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is
|
|
||||||
always of the same height as the app's standard keyboard.
|
|
||||||
one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as
|
|
||||||
soon as it's been used. The keyboard will still be available, but clients will
|
|
||||||
automatically display the usual letter-keyboard in the chat - the user can press
|
|
||||||
a special button in the input field to see the custom keyboard again.
|
|
||||||
Defaults to :obj:`False`.
|
|
||||||
selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard
|
|
||||||
to specific users only. Targets:
|
|
||||||
|
|
||||||
1) Users that are @mentioned in the text of the Message object.
|
|
||||||
2) If the bot's message is a reply to a message in the same chat and forum topic,
|
|
||||||
sender of the original message.
|
|
||||||
|
|
||||||
Defaults to :obj:`False`.
|
|
||||||
|
|
||||||
input_field_placeholder (:obj:`str`): Optional. The placeholder shown in the input
|
|
||||||
field when the reply is active.
|
|
||||||
|
|
||||||
.. versionadded:: 13.7
|
|
||||||
is_persistent (:obj:`bool`): Optional. Requests clients to always show the keyboard
|
|
||||||
when the regular keyboard is hidden. Defaults to :obj:`False`, in which case the
|
|
||||||
custom keyboard can be hidden and opened with a keyboard icon.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
"""
|
|
||||||
return cls(
|
|
||||||
[button_row],
|
|
||||||
resize_keyboard=resize_keyboard,
|
|
||||||
one_time_keyboard=one_time_keyboard,
|
|
||||||
selective=selective,
|
|
||||||
input_field_placeholder=input_field_placeholder,
|
|
||||||
is_persistent=is_persistent,
|
|
||||||
**kwargs, # type: ignore[arg-type]
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_column(
|
|
||||||
cls,
|
|
||||||
button_column: Sequence[Union[str, KeyboardButton]],
|
|
||||||
resize_keyboard: bool = False,
|
|
||||||
one_time_keyboard: bool = False,
|
|
||||||
selective: bool = False,
|
|
||||||
input_field_placeholder: Optional[str] = None,
|
|
||||||
is_persistent: Optional[bool] = None,
|
|
||||||
**kwargs: object,
|
|
||||||
) -> "ReplyKeyboardMarkup":
|
|
||||||
"""Shortcut for::
|
|
||||||
|
|
||||||
ReplyKeyboardMarkup([[button] for button in button_column], **kwargs)
|
|
||||||
|
|
||||||
Return a ReplyKeyboardMarkup from a single column of KeyboardButtons.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
button_column (Sequence[:class:`telegram.KeyboardButton` | :obj:`str`]): The button
|
|
||||||
to use in the markup.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceargs|
|
|
||||||
resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard
|
|
||||||
vertically for optimal fit (e.g., make the keyboard smaller if there are just two
|
|
||||||
rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is
|
|
||||||
always of the same height as the app's standard keyboard.
|
|
||||||
one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as
|
|
||||||
soon as it's been used. The keyboard will still be available, but clients will
|
|
||||||
automatically display the usual letter-keyboard in the chat - the user can press
|
|
||||||
a special button in the input field to see the custom keyboard again.
|
|
||||||
Defaults to :obj:`False`.
|
|
||||||
selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard
|
|
||||||
to specific users only. Targets:
|
|
||||||
|
|
||||||
1) Users that are @mentioned in the text of the Message object.
|
|
||||||
2) If the bot's message is a reply to a message in the same chat and forum topic,
|
|
||||||
sender of the original message.
|
|
||||||
|
|
||||||
Defaults to :obj:`False`.
|
|
||||||
|
|
||||||
input_field_placeholder (:obj:`str`): Optional. The placeholder shown in the input
|
|
||||||
field when the reply is active.
|
|
||||||
|
|
||||||
.. versionadded:: 13.7
|
|
||||||
is_persistent (:obj:`bool`): Optional. Requests clients to always show the keyboard
|
|
||||||
when the regular keyboard is hidden. Defaults to :obj:`False`, in which case the
|
|
||||||
custom keyboard can be hidden and opened with a keyboard icon.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
"""
|
|
||||||
button_grid = [[button] for button in button_column]
|
|
||||||
return cls(
|
|
||||||
button_grid,
|
|
||||||
resize_keyboard=resize_keyboard,
|
|
||||||
one_time_keyboard=one_time_keyboard,
|
|
||||||
selective=selective,
|
|
||||||
input_field_placeholder=input_field_placeholder,
|
|
||||||
is_persistent=is_persistent,
|
|
||||||
**kwargs, # type: ignore[arg-type]
|
|
||||||
)
|
|
||||||
|
|
||||||
MIN_INPUT_FIELD_PLACEHOLDER: Final[int] = constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER
|
|
||||||
""":const:`telegram.constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
MAX_INPUT_FIELD_PLACEHOLDER: Final[int] = constants.ReplyLimit.MAX_INPUT_FIELD_PLACEHOLDER
|
|
||||||
""":const:`telegram.constants.ReplyLimit.MAX_INPUT_FIELD_PLACEHOLDER`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram ReplyKeyboardRemove."""
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class ReplyKeyboardRemove(TelegramObject):
|
|
||||||
"""
|
|
||||||
Upon receiving a message with this object, Telegram clients will remove the current custom
|
|
||||||
keyboard and display the default letter-keyboard. By default, custom keyboards are displayed
|
|
||||||
until a new keyboard is sent by a bot. An exception is made for one-time keyboards that are
|
|
||||||
hidden immediately after the user presses a button (see :class:`telegram.ReplyKeyboardMarkup`).
|
|
||||||
Not supported in channels and for messages sent on behalf of a Telegram Business account.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
User will not be able to summon this keyboard; if you want to hide the keyboard from
|
|
||||||
sight but keep it accessible, use :attr:`telegram.ReplyKeyboardMarkup.one_time_keyboard`.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
* Example usage: A user votes in a poll, bot returns confirmation message in reply to
|
|
||||||
the vote and removes the keyboard for that user, while still showing the keyboard with
|
|
||||||
poll options to users who haven't voted yet.
|
|
||||||
* :any:`Conversation Bot <examples.conversationbot>`
|
|
||||||
* :any:`Conversation Bot 2 <examples.conversationbot2>`
|
|
||||||
|
|
||||||
Args:
|
|
||||||
selective (:obj:`bool`, optional): Use this parameter if you want to remove the keyboard
|
|
||||||
for specific users only. Targets:
|
|
||||||
|
|
||||||
1) Users that are @mentioned in the text of the :class:`telegram.Message` object.
|
|
||||||
2) If the bot's message is a reply to a message in the same chat and forum topic,
|
|
||||||
sender of the original message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
remove_keyboard (:obj:`True`): Requests clients to remove the custom keyboard.
|
|
||||||
selective (:obj:`bool`): Optional. Remove the keyboard for specific users only.
|
|
||||||
Targets:
|
|
||||||
|
|
||||||
1) Users that are @mentioned in the text of the :class:`telegram.Message` object.
|
|
||||||
2) If the bot's message is a reply to a message in the same chat and forum topic,
|
|
||||||
sender of the original message.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("remove_keyboard", "selective")
|
|
||||||
|
|
||||||
def __init__(self, selective: Optional[bool] = None, *, api_kwargs: Optional[JSONDict] = None):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.remove_keyboard: bool = True
|
|
||||||
# Optionals
|
|
||||||
self.selective: Optional[bool] = selective
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram Sent Web App Message."""
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class SentWebAppMessage(TelegramObject):
|
|
||||||
"""Contains information about an inline message sent by a Web App on behalf of a user.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`inline_message_id` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
Args:
|
|
||||||
inline_message_id (:obj:`str`, optional): Identifier of the sent inline message. Available
|
|
||||||
only if there is an :attr:`inline keyboard <telegram.InlineKeyboardMarkup>` attached to
|
|
||||||
the message.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message. Available
|
|
||||||
only if there is an :attr:`inline keyboard <telegram.InlineKeyboardMarkup>` attached to
|
|
||||||
the message.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("inline_message_id",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, inline_message_id: Optional[str] = None, *, api_kwargs: Optional[JSONDict] = None
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Optionals
|
|
||||||
self.inline_message_id: Optional[str] = inline_message_id
|
|
||||||
|
|
||||||
self._id_attrs = (self.inline_message_id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains two objects used for request chats/users service messages."""
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._files.photosize import PhotoSize
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram._bot import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class UsersShared(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about the user whose identifier was shared with the bot
|
|
||||||
using a :class:`telegram.KeyboardButtonRequestUsers` button.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`request_id` and :attr:`users` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
Bot API 7.0 replaces ``UserShared`` with this class. The only difference is that now
|
|
||||||
the ``user_ids`` is a sequence instead of a single integer.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.1
|
|
||||||
The argument :attr:`users` is now considered for the equality comparison instead of
|
|
||||||
``user_ids``.
|
|
||||||
|
|
||||||
.. versionremoved:: 21.2
|
|
||||||
Removed the deprecated argument and attribute ``user_ids``.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request_id (:obj:`int`): Identifier of the request.
|
|
||||||
users (Sequence[:class:`telegram.SharedUser`]): Information about users shared with the
|
|
||||||
bot.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
.. versionchanged:: 21.2
|
|
||||||
This argument is now required.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
request_id (:obj:`int`): Identifier of the request.
|
|
||||||
users (tuple[:class:`telegram.SharedUser`]): Information about users shared with the
|
|
||||||
bot.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("request_id", "users")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
request_id: int,
|
|
||||||
users: Sequence["SharedUser"],
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.request_id: int = request_id
|
|
||||||
self.users: tuple[SharedUser, ...] = parse_sequence_arg(users)
|
|
||||||
|
|
||||||
self._id_attrs = (self.request_id, self.users)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["UsersShared"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["users"] = SharedUser.de_list(data.get("users"), bot)
|
|
||||||
|
|
||||||
api_kwargs = {}
|
|
||||||
# This is a deprecated field that TG still returns for backwards compatibility
|
|
||||||
# Let's filter it out to speed up the de-json process
|
|
||||||
if user_ids := data.get("user_ids"):
|
|
||||||
api_kwargs = {"user_ids": user_ids}
|
|
||||||
|
|
||||||
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ChatShared(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about the chat whose identifier was shared with the bot
|
|
||||||
using a :class:`telegram.KeyboardButtonRequestChat` button.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`request_id` and :attr:`chat_id` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.1
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request_id (:obj:`int`): Identifier of the request.
|
|
||||||
chat_id (:obj:`int`): Identifier of the shared user. This number may be greater than 32
|
|
||||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
|
||||||
it. But it is smaller than 52 bits, so a signed 64-bit integer or double-precision
|
|
||||||
float type are safe for storing this identifier.
|
|
||||||
title (:obj:`str`, optional): Title of the chat, if the title was requested by the bot.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
username (:obj:`str`, optional): Username of the chat, if the username was requested by
|
|
||||||
the bot and available.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
photo (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the chat photo,
|
|
||||||
if the photo was requested by the bot
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
request_id (:obj:`int`): Identifier of the request.
|
|
||||||
chat_id (:obj:`int`): Identifier of the shared user. This number may be greater than 32
|
|
||||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
|
||||||
it. But it is smaller than 52 bits, so a signed 64-bit integer or double-precision
|
|
||||||
float type are safe for storing this identifier.
|
|
||||||
title (:obj:`str`): Optional. Title of the chat, if the title was requested by the bot.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
username (:obj:`str`): Optional. Username of the chat, if the username was requested by
|
|
||||||
the bot and available.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
photo (tuple[:class:`telegram.PhotoSize`]): Optional. Available sizes of the chat photo,
|
|
||||||
if the photo was requested by the bot
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("chat_id", "photo", "request_id", "title", "username")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
request_id: int,
|
|
||||||
chat_id: int,
|
|
||||||
title: Optional[str] = None,
|
|
||||||
username: Optional[str] = None,
|
|
||||||
photo: Optional[Sequence[PhotoSize]] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.request_id: int = request_id
|
|
||||||
self.chat_id: int = chat_id
|
|
||||||
self.title: Optional[str] = title
|
|
||||||
self.username: Optional[str] = username
|
|
||||||
self.photo: Optional[tuple[PhotoSize, ...]] = parse_sequence_arg(photo)
|
|
||||||
|
|
||||||
self._id_attrs = (self.request_id, self.chat_id)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["ChatShared"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class SharedUser(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about a user that was shared with the bot using a
|
|
||||||
:class:`telegram.KeyboardButtonRequestUsers` button.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`user_id` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
Args:
|
|
||||||
user_id (:obj:`int`): Identifier of the shared user. This number may have 32 significant
|
|
||||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
|
||||||
it. But it has atmost 52 significant bits, so 64-bit integers or double-precision
|
|
||||||
float types are safe for storing these identifiers. The bot may not have access to the
|
|
||||||
user and could be unable to use this identifier, unless the user is already known to
|
|
||||||
the bot by some other means.
|
|
||||||
first_name (:obj:`str`, optional): First name of the user, if the name was requested by the
|
|
||||||
bot.
|
|
||||||
last_name (:obj:`str`, optional): Last name of the user, if the name was requested by the
|
|
||||||
bot.
|
|
||||||
username (:obj:`str`, optional): Username of the user, if the username was requested by the
|
|
||||||
bot.
|
|
||||||
photo (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the chat photo,
|
|
||||||
if the photo was requested by the bot.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
user_id (:obj:`int`): Identifier of the shared user. This number may have 32 significant
|
|
||||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
|
||||||
it. But it has atmost 52 significant bits, so 64-bit integers or double-precision
|
|
||||||
float types are safe for storing these identifiers. The bot may not have access to the
|
|
||||||
user and could be unable to use this identifier, unless the user is already known to
|
|
||||||
the bot by some other means.
|
|
||||||
first_name (:obj:`str`): Optional. First name of the user, if the name was requested by the
|
|
||||||
bot.
|
|
||||||
last_name (:obj:`str`): Optional. Last name of the user, if the name was requested by the
|
|
||||||
bot.
|
|
||||||
username (:obj:`str`): Optional. Username of the user, if the username was requested by the
|
|
||||||
bot.
|
|
||||||
photo (tuple[:class:`telegram.PhotoSize`]): Available sizes of the chat photo, if
|
|
||||||
the photo was requested by the bot. This list is empty if the photo was not requsted.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("first_name", "last_name", "photo", "user_id", "username")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
user_id: int,
|
|
||||||
first_name: Optional[str] = None,
|
|
||||||
last_name: Optional[str] = None,
|
|
||||||
username: Optional[str] = None,
|
|
||||||
photo: Optional[Sequence[PhotoSize]] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.user_id: int = user_id
|
|
||||||
self.first_name: Optional[str] = first_name
|
|
||||||
self.last_name: Optional[str] = last_name
|
|
||||||
self.username: Optional[str] = username
|
|
||||||
self.photo: Optional[tuple[PhotoSize, ...]] = parse_sequence_arg(photo)
|
|
||||||
|
|
||||||
self._id_attrs = (self.user_id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["SharedUser"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object related to a Telegram Story."""
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._chat import Chat
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class Story(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents a story.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`chat` and :attr:`id` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.5
|
|
||||||
|
|
||||||
.. versionchanged:: 21.0
|
|
||||||
Added attributes :attr:`chat` and :attr:`id` and equality based on them.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
chat (:class:`telegram.Chat`): Chat that posted the story.
|
|
||||||
id (:obj:`int`): Unique identifier for the story in the chat.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
chat (:class:`telegram.Chat`): Chat that posted the story.
|
|
||||||
id (:obj:`int`): Unique identifier for the story in the chat.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"chat",
|
|
||||||
"id",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
chat: Chat,
|
|
||||||
id: int, # pylint: disable=redefined-builtin
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.chat: Chat = chat
|
|
||||||
self.id: int = id
|
|
||||||
|
|
||||||
self._id_attrs = (self.chat, self.id)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Story"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["chat"] = Chat.de_json(data.get("chat", {}), bot)
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
"""This module contains a class that represents a Telegram SwitchInlineQueryChosenChat."""
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class SwitchInlineQueryChosenChat(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents an inline button that switches the current user to inline mode in a
|
|
||||||
chosen chat, with an optional default inline query.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`query`, :attr:`allow_user_chats`, :attr:`allow_bot_chats`,
|
|
||||||
:attr:`allow_group_chats`, and :attr:`allow_channel_chats` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.3
|
|
||||||
|
|
||||||
Caution:
|
|
||||||
The PTB team has discovered that you must pass at least one of
|
|
||||||
:paramref:`allow_user_chats`, :paramref:`allow_bot_chats`, :paramref:`allow_group_chats`,
|
|
||||||
or :paramref:`allow_channel_chats` to Telegram. Otherwise, an error will be raised.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
query (:obj:`str`, optional): The default inline query to be inserted in the input field.
|
|
||||||
If left empty, only the bot's username will be inserted.
|
|
||||||
allow_user_chats (:obj:`bool`, optional): Pass :obj:`True`, if private chats with users
|
|
||||||
can be chosen.
|
|
||||||
allow_bot_chats (:obj:`bool`, optional): Pass :obj:`True`, if private chats with bots can
|
|
||||||
be chosen.
|
|
||||||
allow_group_chats (:obj:`bool`, optional): Pass :obj:`True`, if group and supergroup chats
|
|
||||||
can be chosen.
|
|
||||||
allow_channel_chats (:obj:`bool`, optional): Pass :obj:`True`, if channel chats can be
|
|
||||||
chosen.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
query (:obj:`str`): Optional. The default inline query to be inserted in the input field.
|
|
||||||
If left empty, only the bot's username will be inserted.
|
|
||||||
allow_user_chats (:obj:`bool`): Optional. :obj:`True`, if private chats with users can be
|
|
||||||
chosen.
|
|
||||||
allow_bot_chats (:obj:`bool`): Optional. :obj:`True`, if private chats with bots can be
|
|
||||||
chosen.
|
|
||||||
allow_group_chats (:obj:`bool`): Optional. :obj:`True`, if group and supergroup chats can
|
|
||||||
be chosen.
|
|
||||||
allow_channel_chats (:obj:`bool`): Optional. :obj:`True`, if channel chats can be chosen.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"allow_bot_chats",
|
|
||||||
"allow_channel_chats",
|
|
||||||
"allow_group_chats",
|
|
||||||
"allow_user_chats",
|
|
||||||
"query",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
query: Optional[str] = None,
|
|
||||||
allow_user_chats: Optional[bool] = None,
|
|
||||||
allow_bot_chats: Optional[bool] = None,
|
|
||||||
allow_group_chats: Optional[bool] = None,
|
|
||||||
allow_channel_chats: Optional[bool] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Optional
|
|
||||||
self.query: Optional[str] = query
|
|
||||||
self.allow_user_chats: Optional[bool] = allow_user_chats
|
|
||||||
self.allow_bot_chats: Optional[bool] = allow_bot_chats
|
|
||||||
self.allow_group_chats: Optional[bool] = allow_group_chats
|
|
||||||
self.allow_channel_chats: Optional[bool] = allow_channel_chats
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.query,
|
|
||||||
self.allow_user_chats,
|
|
||||||
self.allow_bot_chats,
|
|
||||||
self.allow_group_chats,
|
|
||||||
self.allow_channel_chats,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,675 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""Base class for Telegram Objects."""
|
|
||||||
import contextlib
|
|
||||||
import datetime as dtm
|
|
||||||
import inspect
|
|
||||||
import json
|
|
||||||
from collections.abc import Iterator, Mapping, Sized
|
|
||||||
from contextlib import contextmanager
|
|
||||||
from copy import deepcopy
|
|
||||||
from itertools import chain
|
|
||||||
from types import MappingProxyType
|
|
||||||
from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypeVar, Union, cast
|
|
||||||
|
|
||||||
from telegram._utils.datetime import to_timestamp
|
|
||||||
from telegram._utils.defaultvalue import DefaultValue
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
from telegram._utils.warnings import warn
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
Tele_co = TypeVar("Tele_co", bound="TelegramObject", covariant=True)
|
|
||||||
|
|
||||||
|
|
||||||
class TelegramObject:
|
|
||||||
"""Base class for most Telegram objects.
|
|
||||||
|
|
||||||
Objects of this type are subscriptable with strings. See :meth:`__getitem__` for more details.
|
|
||||||
The :mod:`pickle` and :func:`~copy.deepcopy` behavior of objects of this type are defined by
|
|
||||||
:meth:`__getstate__`, :meth:`__setstate__` and :meth:`__deepcopy__`.
|
|
||||||
|
|
||||||
Tip:
|
|
||||||
Objects of this type can be serialized via Python's :mod:`pickle` module and pickled
|
|
||||||
objects from one version of PTB are usually loadable in future versions. However, we can
|
|
||||||
not guarantee that this compatibility will always be provided. At least a manual one-time
|
|
||||||
conversion of the data may be needed on major updates of the library.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* Removed argument and attribute ``bot`` for several subclasses. Use
|
|
||||||
:meth:`set_bot` and :meth:`get_bot` instead.
|
|
||||||
* Removed the possibility to pass arbitrary keyword arguments for several subclasses.
|
|
||||||
* String representations objects of this type was overhauled. See :meth:`__repr__` for
|
|
||||||
details. As this class doesn't implement :meth:`object.__str__`, the default
|
|
||||||
implementation will be used, which is equivalent to :meth:`__repr__`.
|
|
||||||
* Objects of this class (or subclasses) are now immutable. This means that you can't set
|
|
||||||
or delete attributes anymore. Moreover, attributes that were formerly of type
|
|
||||||
:obj:`list` are now of type :obj:`tuple`.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
api_kwargs (dict[:obj:`str`, any], optional): |toapikwargsarg|
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
api_kwargs (:obj:`types.MappingProxyType` [:obj:`str`, any]): |toapikwargsattr|
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("_bot", "_frozen", "_id_attrs", "api_kwargs")
|
|
||||||
|
|
||||||
# Used to cache the names of the parameters of the __init__ method of the class
|
|
||||||
# Must be a private attribute to avoid name clashes between subclasses
|
|
||||||
__INIT_PARAMS: ClassVar[set[str]] = set()
|
|
||||||
# Used to check if __INIT_PARAMS has been set for the current class. Unfortunately, we can't
|
|
||||||
# just check if `__INIT_PARAMS is None`, since subclasses use the parent class' __INIT_PARAMS
|
|
||||||
# unless it's overridden
|
|
||||||
__INIT_PARAMS_CHECK: Optional[type["TelegramObject"]] = None
|
|
||||||
|
|
||||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
# Setting _frozen to `False` here means that classes without arguments still need to
|
|
||||||
# implement __init__. However, with `True` would mean increased usage of
|
|
||||||
# `with self._unfrozen()` in the `__init__` of subclasses and we have fewer empty
|
|
||||||
# classes than classes with arguments.
|
|
||||||
self._frozen: bool = False
|
|
||||||
self._id_attrs: tuple[object, ...] = ()
|
|
||||||
self._bot: Optional[Bot] = None
|
|
||||||
# We don't do anything with api_kwargs here - see docstring of _apply_api_kwargs
|
|
||||||
self.api_kwargs: Mapping[str, Any] = MappingProxyType(api_kwargs or {})
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
"""Compares this object with :paramref:`other` in terms of equality.
|
|
||||||
If this object and :paramref:`other` are `not` objects of the same class,
|
|
||||||
this comparison will fall back to Python's default implementation of :meth:`object.__eq__`.
|
|
||||||
Otherwise, both objects may be compared in terms of equality, if the corresponding
|
|
||||||
subclass of :class:`TelegramObject` has defined a set of attributes to compare and
|
|
||||||
the objects are considered to be equal, if all of these attributes are equal.
|
|
||||||
If the subclass has not defined a set of attributes to compare, a warning will be issued.
|
|
||||||
|
|
||||||
Tip:
|
|
||||||
If instances of a class in the :mod:`telegram` module are comparable in terms of
|
|
||||||
equality, the documentation of the class will state the attributes that will be used
|
|
||||||
for this comparison.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other (:obj:`object`): The object to compare with.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`bool`
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isinstance(other, self.__class__):
|
|
||||||
if not self._id_attrs:
|
|
||||||
warn(
|
|
||||||
f"Objects of type {self.__class__.__name__} can not be meaningfully tested for"
|
|
||||||
" equivalence.",
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
if not other._id_attrs:
|
|
||||||
warn(
|
|
||||||
f"Objects of type {other.__class__.__name__} can not be meaningfully tested"
|
|
||||||
" for equivalence.",
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self._id_attrs == other._id_attrs
|
|
||||||
return super().__eq__(other)
|
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
|
||||||
"""Builds a hash value for this object such that the hash of two objects is equal if and
|
|
||||||
only if the objects are equal in terms of :meth:`__eq__`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`int`
|
|
||||||
"""
|
|
||||||
if self._id_attrs:
|
|
||||||
return hash((self.__class__, self._id_attrs))
|
|
||||||
return super().__hash__()
|
|
||||||
|
|
||||||
def __setattr__(self, key: str, value: object) -> None:
|
|
||||||
"""Overrides :meth:`object.__setattr__` to prevent the overriding of attributes.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:exc:`AttributeError`
|
|
||||||
"""
|
|
||||||
# protected attributes can always be set for convenient internal use
|
|
||||||
if key[0] == "_" or not getattr(self, "_frozen", True):
|
|
||||||
super().__setattr__(key, value)
|
|
||||||
return
|
|
||||||
|
|
||||||
raise AttributeError(
|
|
||||||
f"Attribute `{key}` of class `{self.__class__.__name__}` can't be set!"
|
|
||||||
)
|
|
||||||
|
|
||||||
def __delattr__(self, key: str) -> None:
|
|
||||||
"""Overrides :meth:`object.__delattr__` to prevent the deletion of attributes.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:exc:`AttributeError`
|
|
||||||
"""
|
|
||||||
# protected attributes can always be set for convenient internal use
|
|
||||||
if key[0] == "_" or not getattr(self, "_frozen", True):
|
|
||||||
super().__delattr__(key)
|
|
||||||
return
|
|
||||||
|
|
||||||
raise AttributeError(
|
|
||||||
f"Attribute `{key}` of class `{self.__class__.__name__}` can't be deleted!"
|
|
||||||
)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
"""Gives a string representation of this object in the form
|
|
||||||
``ClassName(attr_1=value_1, attr_2=value_2, ...)``, where attributes are omitted if they
|
|
||||||
have the value :obj:`None` or are empty instances of :class:`collections.abc.Sized` (e.g.
|
|
||||||
:class:`list`, :class:`dict`, :class:`set`, :class:`str`, etc.).
|
|
||||||
|
|
||||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
|
||||||
will be used, which is equivalent to :meth:`__repr__`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`
|
|
||||||
"""
|
|
||||||
# * `__repr__` goal is to be unambiguous
|
|
||||||
# * `__str__` goal is to be readable
|
|
||||||
# * `str()` calls `__repr__`, if `__str__` is not defined
|
|
||||||
# In our case "unambiguous" and "readable" largely coincide, so we can use the same logic.
|
|
||||||
as_dict = self._get_attrs(recursive=False, include_private=False)
|
|
||||||
|
|
||||||
if not self.api_kwargs:
|
|
||||||
# Drop api_kwargs from the representation, if empty
|
|
||||||
as_dict.pop("api_kwargs", None)
|
|
||||||
else:
|
|
||||||
# Otherwise, we want to skip the "mappingproxy" part of the repr
|
|
||||||
as_dict["api_kwargs"] = dict(self.api_kwargs)
|
|
||||||
|
|
||||||
contents = ", ".join(
|
|
||||||
f"{k}={as_dict[k]!r}"
|
|
||||||
for k in sorted(as_dict.keys())
|
|
||||||
if (
|
|
||||||
as_dict[k] is not None
|
|
||||||
and not (
|
|
||||||
isinstance(as_dict[k], Sized)
|
|
||||||
and len(as_dict[k]) == 0 # type: ignore[arg-type]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return f"{self.__class__.__name__}({contents})"
|
|
||||||
|
|
||||||
def __getitem__(self, item: str) -> object:
|
|
||||||
"""
|
|
||||||
Objects of this type are subscriptable with strings, where
|
|
||||||
``telegram_object["attribute_name"]`` is equivalent to ``telegram_object.attribute_name``.
|
|
||||||
|
|
||||||
Tip:
|
|
||||||
This is useful for dynamic attribute lookup, i.e. ``telegram_object[arg]`` where the
|
|
||||||
value of ``arg`` is determined at runtime.
|
|
||||||
In all other cases, it's recommended to use the dot notation instead, i.e.
|
|
||||||
``telegram_object.attribute_name``.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
``telegram_object['from']`` will look up the key ``from_user``. This is to account for
|
|
||||||
special cases like :attr:`Message.from_user` that deviate from the official Bot API.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
item (:obj:`str`): The name of the attribute to look up.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`object`
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:exc:`KeyError`: If the object does not have an attribute with the appropriate name.
|
|
||||||
"""
|
|
||||||
if item == "from":
|
|
||||||
item = "from_user"
|
|
||||||
try:
|
|
||||||
return getattr(self, item)
|
|
||||||
except AttributeError as exc:
|
|
||||||
raise KeyError(
|
|
||||||
f"Objects of type {self.__class__.__name__} don't have an attribute called "
|
|
||||||
f"`{item}`."
|
|
||||||
) from exc
|
|
||||||
|
|
||||||
def __getstate__(self) -> dict[str, Union[str, object]]:
|
|
||||||
"""
|
|
||||||
Overrides :meth:`object.__getstate__` to customize the pickling process of objects of this
|
|
||||||
type.
|
|
||||||
The returned state does `not` contain the :class:`telegram.Bot` instance set with
|
|
||||||
:meth:`set_bot` (if any), as it can't be pickled.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
state (dict[:obj:`str`, :obj:`object`]): The state of the object.
|
|
||||||
"""
|
|
||||||
out = self._get_attrs(
|
|
||||||
include_private=True, recursive=False, remove_bot=True, convert_default_vault=False
|
|
||||||
)
|
|
||||||
# MappingProxyType is not pickable, so we convert it to a dict and revert in
|
|
||||||
# __setstate__
|
|
||||||
out["api_kwargs"] = dict(self.api_kwargs)
|
|
||||||
return out
|
|
||||||
|
|
||||||
def __setstate__(self, state: dict[str, object]) -> None:
|
|
||||||
"""
|
|
||||||
Overrides :meth:`object.__setstate__` to customize the unpickling process of objects of
|
|
||||||
this type. Modifies the object in-place.
|
|
||||||
|
|
||||||
If any data was stored in the :attr:`api_kwargs` of the pickled object, this method checks
|
|
||||||
if the class now has dedicated attributes for those keys and moves the values from
|
|
||||||
:attr:`api_kwargs` to the dedicated attributes.
|
|
||||||
This can happen, if serialized data is loaded with a new version of this library, where
|
|
||||||
the new version was updated to account for updates of the Telegram Bot API.
|
|
||||||
|
|
||||||
If on the contrary an attribute was removed from the class, the value is not discarded but
|
|
||||||
made available via :attr:`api_kwargs`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
state (:obj:`dict`): The data to set as attributes of this object.
|
|
||||||
"""
|
|
||||||
self._unfreeze()
|
|
||||||
|
|
||||||
# Make sure that we have a `_bot` attribute. This is necessary, since __getstate__ omits
|
|
||||||
# this as Bots are not pickable.
|
|
||||||
self._bot = None
|
|
||||||
|
|
||||||
# get api_kwargs first because we may need to add entries to it (see try-except below)
|
|
||||||
api_kwargs = cast(dict[str, object], state.pop("api_kwargs", {}))
|
|
||||||
# get _frozen before the loop to avoid setting it to True in the loop
|
|
||||||
frozen = state.pop("_frozen", False)
|
|
||||||
|
|
||||||
for key, val in state.items():
|
|
||||||
try:
|
|
||||||
setattr(self, key, val)
|
|
||||||
except AttributeError:
|
|
||||||
# So an attribute was deprecated and removed from the class. Let's handle this:
|
|
||||||
# 1) Is the attribute now a property with no setter? Let's check that:
|
|
||||||
if isinstance(getattr(self.__class__, key, None), property):
|
|
||||||
# It is, so let's try to set the "private attribute" instead
|
|
||||||
try:
|
|
||||||
setattr(self, f"_{key}", val)
|
|
||||||
# If this fails as well, guess we've completely removed it. Let's add it to
|
|
||||||
# api_kwargs as fallback
|
|
||||||
except AttributeError:
|
|
||||||
api_kwargs[key] = val
|
|
||||||
|
|
||||||
# 2) The attribute is a private attribute, i.e. it went through case 1) in the past
|
|
||||||
elif key.startswith("_"):
|
|
||||||
continue # skip adding this to api_kwargs, the attribute is lost forever.
|
|
||||||
api_kwargs[key] = val # add it to api_kwargs as fallback
|
|
||||||
|
|
||||||
# For api_kwargs we first apply any kwargs that are already attributes of the object
|
|
||||||
# and then set the rest as MappingProxyType attribute. Converting to MappingProxyType
|
|
||||||
# is necessary, since __getstate__ converts it to a dict as MPT is not pickable.
|
|
||||||
self._apply_api_kwargs(api_kwargs)
|
|
||||||
self.api_kwargs = MappingProxyType(api_kwargs)
|
|
||||||
|
|
||||||
# Apply freezing if necessary
|
|
||||||
# we .get(…) the setting for backwards compatibility with objects that were pickled
|
|
||||||
# before the freeze feature was introduced
|
|
||||||
if frozen:
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
def __deepcopy__(self: Tele_co, memodict: dict[int, object]) -> Tele_co:
|
|
||||||
"""
|
|
||||||
Customizes how :func:`copy.deepcopy` processes objects of this type.
|
|
||||||
The only difference to the default implementation is that the :class:`telegram.Bot`
|
|
||||||
instance set via :meth:`set_bot` (if any) is not copied, but shared between the original
|
|
||||||
and the copy, i.e.::
|
|
||||||
|
|
||||||
assert telegram_object.get_bot() is copy.deepcopy(telegram_object).get_bot()
|
|
||||||
|
|
||||||
Args:
|
|
||||||
memodict (:obj:`dict`): A dictionary that maps objects to their copies.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:class:`telegram.TelegramObject`: The copied object.
|
|
||||||
"""
|
|
||||||
bot = self._bot # Save bot so we can set it after copying
|
|
||||||
self.set_bot(None) # set to None so it is not deepcopied
|
|
||||||
cls = self.__class__
|
|
||||||
result = cls.__new__(cls) # create a new instance
|
|
||||||
memodict[id(self)] = result # save the id of the object in the dict
|
|
||||||
|
|
||||||
result._frozen = False # unfreeze the new object for setting the attributes
|
|
||||||
|
|
||||||
# now we set the attributes in the deepcopied object
|
|
||||||
for k in self._get_attrs_names(include_private=True):
|
|
||||||
if k == "_frozen":
|
|
||||||
# Setting the frozen status to True would prevent the attributes from being set
|
|
||||||
continue
|
|
||||||
if k == "api_kwargs":
|
|
||||||
# Need to copy api_kwargs manually, since it's a MappingProxyType is not
|
|
||||||
# pickable and deepcopy uses the pickle interface
|
|
||||||
setattr(result, k, MappingProxyType(deepcopy(dict(self.api_kwargs), memodict)))
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
setattr(result, k, deepcopy(getattr(self, k), memodict))
|
|
||||||
except AttributeError:
|
|
||||||
# Skip missing attributes. This can happen if the object was loaded from a pickle
|
|
||||||
# file that was created with an older version of the library, where the class
|
|
||||||
# did not have the attribute yet.
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Apply freezing if necessary
|
|
||||||
if self._frozen:
|
|
||||||
result._freeze()
|
|
||||||
|
|
||||||
result.set_bot(bot) # Assign the bots back
|
|
||||||
self.set_bot(bot)
|
|
||||||
return result
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
|
|
||||||
"""Should be called by subclasses that override de_json to ensure that the input
|
|
||||||
is not altered. Whoever calls de_json might still want to use the original input
|
|
||||||
for something else.
|
|
||||||
"""
|
|
||||||
return None if data is None else data.copy()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _de_json(
|
|
||||||
cls: type[Tele_co],
|
|
||||||
data: Optional[JSONDict],
|
|
||||||
bot: Optional["Bot"],
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> Optional[Tele_co]:
|
|
||||||
if data is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# try-except is significantly faster in case we already have a correct argument set
|
|
||||||
try:
|
|
||||||
obj = cls(**data, api_kwargs=api_kwargs)
|
|
||||||
except TypeError as exc:
|
|
||||||
if "__init__() got an unexpected keyword argument" not in str(exc):
|
|
||||||
raise
|
|
||||||
|
|
||||||
if cls.__INIT_PARAMS_CHECK is not cls:
|
|
||||||
signature = inspect.signature(cls)
|
|
||||||
cls.__INIT_PARAMS = set(signature.parameters.keys())
|
|
||||||
cls.__INIT_PARAMS_CHECK = cls
|
|
||||||
|
|
||||||
api_kwargs = api_kwargs or {}
|
|
||||||
existing_kwargs: JSONDict = {}
|
|
||||||
for key, value in data.items():
|
|
||||||
(existing_kwargs if key in cls.__INIT_PARAMS else api_kwargs)[key] = value
|
|
||||||
|
|
||||||
obj = cls(api_kwargs=api_kwargs, **existing_kwargs)
|
|
||||||
|
|
||||||
obj.set_bot(bot=bot)
|
|
||||||
return obj
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls: type[Tele_co], data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional[Tele_co]:
|
|
||||||
"""Converts JSON data to a Telegram object.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return cls._de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_list(
|
|
||||||
cls: type[Tele_co], data: Optional[list[JSONDict]], bot: Optional["Bot"] = None
|
|
||||||
) -> tuple[Tele_co, ...]:
|
|
||||||
"""Converts a list of JSON objects to a tuple of Telegram objects.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* Returns a tuple instead of a list.
|
|
||||||
* Filters out any :obj:`None` values.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (list[dict[:obj:`str`, ...]]): The JSON data.
|
|
||||||
bot (:class:`telegram.Bot`, optional): The bot associated with these 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:
|
|
||||||
A tuple of Telegram objects.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not data:
|
|
||||||
return ()
|
|
||||||
|
|
||||||
return tuple(obj for obj in (cls.de_json(d, bot) for d in data) if obj is not None)
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def _unfrozen(self: Tele_co) -> Iterator[Tele_co]:
|
|
||||||
"""Context manager to temporarily unfreeze the object. For internal use only.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
with to._unfrozen() as other_to:
|
|
||||||
assert to is other_to
|
|
||||||
"""
|
|
||||||
self._unfreeze()
|
|
||||||
yield self
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
def _freeze(self) -> None:
|
|
||||||
self._frozen = True
|
|
||||||
|
|
||||||
def _unfreeze(self) -> None:
|
|
||||||
self._frozen = False
|
|
||||||
|
|
||||||
def _apply_api_kwargs(self, api_kwargs: JSONDict) -> None:
|
|
||||||
"""Loops through the api kwargs and for every key that exists as attribute of the
|
|
||||||
object (and is None), it moves the value from `api_kwargs` to the attribute.
|
|
||||||
*Edits `api_kwargs` in place!*
|
|
||||||
|
|
||||||
This method is currently only called in the unpickling process, i.e. not on "normal" init.
|
|
||||||
This is because
|
|
||||||
* automating this is tricky to get right: It should be called at the *end* of the __init__,
|
|
||||||
preferably only once at the end of the __init__ of the last child class. This could be
|
|
||||||
done via __init_subclass__, but it's hard to not destroy the signature of __init__ in the
|
|
||||||
process.
|
|
||||||
* calling it manually in every __init__ is tedious
|
|
||||||
* There probably is no use case for it anyway. If you manually initialize a TO subclass,
|
|
||||||
then you can pass everything as proper argument.
|
|
||||||
"""
|
|
||||||
# we convert to list to ensure that the list doesn't change length while we loop
|
|
||||||
for key in list(api_kwargs.keys()):
|
|
||||||
# property attributes are not settable, so we need to set the private attribute
|
|
||||||
if isinstance(getattr(self.__class__, key, None), property):
|
|
||||||
# if setattr fails, we'll just leave the value in api_kwargs:
|
|
||||||
with contextlib.suppress(AttributeError):
|
|
||||||
setattr(self, f"_{key}", api_kwargs.pop(key))
|
|
||||||
elif getattr(self, key, True) is None:
|
|
||||||
setattr(self, key, api_kwargs.pop(key))
|
|
||||||
|
|
||||||
def _get_attrs_names(self, include_private: bool) -> Iterator[str]:
|
|
||||||
"""
|
|
||||||
Returns the names of the attributes of this object. This is used to determine which
|
|
||||||
attributes should be serialized when pickling the object.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
include_private (:obj:`bool`): Whether to include private attributes.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Iterator[:obj:`str`]: An iterator over the names of the attributes of this object.
|
|
||||||
"""
|
|
||||||
# We want to get all attributes for the class, using self.__slots__ only includes the
|
|
||||||
# attributes used by that class itself, and not its superclass(es). Hence, we get its MRO
|
|
||||||
# and then get their attributes. The `[:-1]` slice excludes the `object` class
|
|
||||||
all_slots = (s for c in self.__class__.__mro__[:-1] for s in c.__slots__) # type: ignore
|
|
||||||
# chain the class's slots with the user defined subclass __dict__ (class has no slots)
|
|
||||||
all_attrs = (
|
|
||||||
chain(all_slots, self.__dict__.keys()) if hasattr(self, "__dict__") else all_slots
|
|
||||||
)
|
|
||||||
|
|
||||||
if include_private:
|
|
||||||
return all_attrs
|
|
||||||
return (attr for attr in all_attrs if not attr.startswith("_"))
|
|
||||||
|
|
||||||
def _get_attrs(
|
|
||||||
self,
|
|
||||||
include_private: bool = False,
|
|
||||||
recursive: bool = False,
|
|
||||||
remove_bot: bool = False,
|
|
||||||
convert_default_vault: bool = True,
|
|
||||||
) -> dict[str, Union[str, object]]:
|
|
||||||
"""This method is used for obtaining the attributes of the object.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
include_private (:obj:`bool`): Whether the result should include private variables.
|
|
||||||
recursive (:obj:`bool`): If :obj:`True`, will convert any ``TelegramObjects`` (if
|
|
||||||
found) in the attributes to a dictionary. Else, preserves it as an object itself.
|
|
||||||
remove_bot (:obj:`bool`): Whether the bot should be included in the result.
|
|
||||||
convert_default_vault (:obj:`bool`): Whether :class:`telegram.DefaultValue` should be
|
|
||||||
converted to its true value. This is necessary when converting to a dictionary for
|
|
||||||
end users since DefaultValue is used in some classes that work with
|
|
||||||
`tg.ext.defaults` (like `LinkPreviewOptions`)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`dict`: A dict where the keys are attribute names and values are their values.
|
|
||||||
"""
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
for key in self._get_attrs_names(include_private=include_private):
|
|
||||||
value = (
|
|
||||||
DefaultValue.get_value(getattr(self, key, None))
|
|
||||||
if convert_default_vault
|
|
||||||
else getattr(self, key, None)
|
|
||||||
)
|
|
||||||
|
|
||||||
if value is not None:
|
|
||||||
if recursive and hasattr(value, "to_dict"):
|
|
||||||
data[key] = value.to_dict(recursive=True)
|
|
||||||
else:
|
|
||||||
data[key] = value
|
|
||||||
elif not recursive:
|
|
||||||
data[key] = value
|
|
||||||
|
|
||||||
if recursive and data.get("from_user"):
|
|
||||||
data["from"] = data.pop("from_user", None)
|
|
||||||
if remove_bot:
|
|
||||||
data.pop("_bot", None)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def to_json(self) -> str:
|
|
||||||
"""Gives a JSON representation of object.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
Now includes all entries of :attr:`api_kwargs`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`
|
|
||||||
"""
|
|
||||||
return json.dumps(self.to_dict())
|
|
||||||
|
|
||||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
|
||||||
"""Gives representation of object as :obj:`dict`.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* Now includes all entries of :attr:`api_kwargs`.
|
|
||||||
* Attributes whose values are empty sequences are no longer included.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
recursive (:obj:`bool`, optional): If :obj:`True`, will convert any TelegramObjects
|
|
||||||
(if found) in the attributes to a dictionary. Else, preserves it as an object
|
|
||||||
itself. Defaults to :obj:`True`.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`dict`
|
|
||||||
"""
|
|
||||||
out = self._get_attrs(recursive=recursive)
|
|
||||||
|
|
||||||
# Now we should convert TGObjects to dicts inside objects such as sequences, and convert
|
|
||||||
# datetimes to timestamps. This mostly eliminates the need for subclasses to override
|
|
||||||
# `to_dict`
|
|
||||||
pop_keys: set[str] = set()
|
|
||||||
for key, value in out.items():
|
|
||||||
if isinstance(value, (tuple, list)):
|
|
||||||
if not value:
|
|
||||||
# not popping directly to avoid changing the dict size during iteration
|
|
||||||
pop_keys.add(key)
|
|
||||||
continue
|
|
||||||
|
|
||||||
val = [] # empty list to append our converted values to
|
|
||||||
for item in value:
|
|
||||||
if hasattr(item, "to_dict"):
|
|
||||||
val.append(item.to_dict(recursive=recursive))
|
|
||||||
# This branch is useful for e.g. tuple[tuple[PhotoSize|KeyboardButton]]
|
|
||||||
elif isinstance(item, (tuple, list)):
|
|
||||||
val.append(
|
|
||||||
[
|
|
||||||
i.to_dict(recursive=recursive) if hasattr(i, "to_dict") else i
|
|
||||||
for i in item
|
|
||||||
]
|
|
||||||
)
|
|
||||||
else: # if it's not a TGObject, just append it. E.g. [TGObject, 2]
|
|
||||||
val.append(item)
|
|
||||||
out[key] = val
|
|
||||||
|
|
||||||
elif isinstance(value, dtm.datetime):
|
|
||||||
out[key] = to_timestamp(value)
|
|
||||||
elif isinstance(value, dtm.timedelta):
|
|
||||||
out[key] = value.total_seconds()
|
|
||||||
|
|
||||||
for key in pop_keys:
|
|
||||||
out.pop(key)
|
|
||||||
|
|
||||||
# Effectively "unpack" api_kwargs into `out`:
|
|
||||||
out.update(out.pop("api_kwargs", {})) # type: ignore[call-overload]
|
|
||||||
return out
|
|
||||||
|
|
||||||
def get_bot(self) -> "Bot":
|
|
||||||
"""Returns the :class:`telegram.Bot` instance associated with this object.
|
|
||||||
|
|
||||||
.. seealso:: :meth:`set_bot`
|
|
||||||
|
|
||||||
.. versionadded: 20.0
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: If no :class:`telegram.Bot` instance was set for this object.
|
|
||||||
"""
|
|
||||||
if self._bot is None:
|
|
||||||
raise RuntimeError(
|
|
||||||
"This object has no bot associated with it. Shortcuts cannot be used."
|
|
||||||
)
|
|
||||||
return self._bot
|
|
||||||
|
|
||||||
def set_bot(self, bot: Optional["Bot"]) -> None:
|
|
||||||
"""Sets the :class:`telegram.Bot` instance associated with this object.
|
|
||||||
|
|
||||||
.. seealso:: :meth:`get_bot`
|
|
||||||
|
|
||||||
.. versionadded: 20.0
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
bot (:class:`telegram.Bot` | :obj:`None`): The bot instance.
|
|
||||||
"""
|
|
||||||
self._bot = bot
|
|
||||||
@@ -1,803 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram Update."""
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Final, Optional, Union
|
|
||||||
|
|
||||||
from telegram import constants
|
|
||||||
from telegram._business import BusinessConnection, BusinessMessagesDeleted
|
|
||||||
from telegram._callbackquery import CallbackQuery
|
|
||||||
from telegram._chatboost import ChatBoostRemoved, ChatBoostUpdated
|
|
||||||
from telegram._chatjoinrequest import ChatJoinRequest
|
|
||||||
from telegram._chatmemberupdated import ChatMemberUpdated
|
|
||||||
from telegram._choseninlineresult import ChosenInlineResult
|
|
||||||
from telegram._inline.inlinequery import InlineQuery
|
|
||||||
from telegram._message import Message
|
|
||||||
from telegram._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
|
|
||||||
from telegram._paidmedia import PaidMediaPurchased
|
|
||||||
from telegram._payment.precheckoutquery import PreCheckoutQuery
|
|
||||||
from telegram._payment.shippingquery import ShippingQuery
|
|
||||||
from telegram._poll import Poll, PollAnswer
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
from telegram._utils.warnings import warn
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot, Chat, User
|
|
||||||
|
|
||||||
|
|
||||||
class Update(TelegramObject):
|
|
||||||
"""This object represents an incoming update.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`update_id` is equal.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
At most one of the optional parameters can be present in any given update.
|
|
||||||
|
|
||||||
.. seealso:: :wiki:`Your First Bot <Extensions---Your-first-Bot>`
|
|
||||||
|
|
||||||
Args:
|
|
||||||
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
|
|
||||||
certain positive number and increase sequentially. This ID becomes especially handy if
|
|
||||||
you're using Webhooks, since it allows you to ignore repeated updates or to restore the
|
|
||||||
correct update sequence, should they get out of order. If there are no new updates for
|
|
||||||
at least a week, then identifier of the next update will be chosen randomly instead of
|
|
||||||
sequentially.
|
|
||||||
message (:class:`telegram.Message`, optional): New incoming message of any kind - text,
|
|
||||||
photo, sticker, etc.
|
|
||||||
edited_message (:class:`telegram.Message`, optional): New version of a message that is
|
|
||||||
known to the bot and was edited. This update may at times be triggered by changes to
|
|
||||||
message fields that are either unavailable or not actively used by your bot.
|
|
||||||
channel_post (:class:`telegram.Message`, optional): New incoming channel post of any kind
|
|
||||||
- text, photo, sticker, etc.
|
|
||||||
edited_channel_post (:class:`telegram.Message`, optional): New version of a channel post
|
|
||||||
that is known to the bot and was edited. This update may at times be triggered by
|
|
||||||
changes to message fields that are either unavailable or not actively used by your bot.
|
|
||||||
inline_query (:class:`telegram.InlineQuery`, optional): New incoming inline query.
|
|
||||||
chosen_inline_result (:class:`telegram.ChosenInlineResult`, optional): The result of an
|
|
||||||
inline query that was chosen by a user and sent to their chat partner.
|
|
||||||
callback_query (:class:`telegram.CallbackQuery`, optional): New incoming callback query.
|
|
||||||
shipping_query (:class:`telegram.ShippingQuery`, optional): New incoming shipping query.
|
|
||||||
Only for invoices with flexible price.
|
|
||||||
pre_checkout_query (:class:`telegram.PreCheckoutQuery`, optional): New incoming
|
|
||||||
pre-checkout query. Contains full information about checkout.
|
|
||||||
poll (:class:`telegram.Poll`, optional): New poll state. Bots receive only updates about
|
|
||||||
manually stopped polls and polls, which are sent by the bot.
|
|
||||||
poll_answer (:class:`telegram.PollAnswer`, optional): A user changed their answer
|
|
||||||
in a non-anonymous poll. Bots receive new votes only in polls that were sent
|
|
||||||
by the bot itself.
|
|
||||||
my_chat_member (:class:`telegram.ChatMemberUpdated`, optional): The bot's chat member
|
|
||||||
status was updated in a chat. For private chats, this update is received only when the
|
|
||||||
bot is blocked or unblocked by the user.
|
|
||||||
|
|
||||||
.. versionadded:: 13.4
|
|
||||||
chat_member (:class:`telegram.ChatMemberUpdated`, optional): A chat member's status was
|
|
||||||
updated in a chat. The bot must be an administrator in the chat and must explicitly
|
|
||||||
specify :attr:`CHAT_MEMBER` in the list of
|
|
||||||
:paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these
|
|
||||||
updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
|
|
||||||
:meth:`telegram.ext.Application.run_polling` and
|
|
||||||
:meth:`telegram.ext.Application.run_webhook`).
|
|
||||||
|
|
||||||
.. versionadded:: 13.4
|
|
||||||
chat_join_request (:class:`telegram.ChatJoinRequest`, optional): A request to join the
|
|
||||||
chat has been sent. The bot must have the
|
|
||||||
:attr:`telegram.ChatPermissions.can_invite_users` administrator right in the chat to
|
|
||||||
receive these updates.
|
|
||||||
|
|
||||||
.. versionadded:: 13.8
|
|
||||||
|
|
||||||
chat_boost (:class:`telegram.ChatBoostUpdated`, optional): A chat boost was added or
|
|
||||||
changed. The bot must be an administrator in the chat to receive these updates.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
removed_chat_boost (:class:`telegram.ChatBoostRemoved`, optional): A boost was removed from
|
|
||||||
a chat. The bot must be an administrator in the chat to receive these updates.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
message_reaction (:class:`telegram.MessageReactionUpdated`, optional): A reaction to a
|
|
||||||
message was changed by a user. The bot must be an administrator in the chat and must
|
|
||||||
explicitly specify :attr:`MESSAGE_REACTION` in the list of
|
|
||||||
:paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these
|
|
||||||
updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
|
|
||||||
:meth:`telegram.ext.Application.run_polling` and
|
|
||||||
:meth:`telegram.ext.Application.run_webhook`). The update isn't received for reactions
|
|
||||||
set by bots.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
message_reaction_count (:class:`telegram.MessageReactionCountUpdated`, optional): Reactions
|
|
||||||
to a message with anonymous reactions were changed. The bot must be an administrator in
|
|
||||||
the chat and must explicitly specify :attr:`MESSAGE_REACTION_COUNT` in the list of
|
|
||||||
:paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these
|
|
||||||
updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
|
|
||||||
:meth:`telegram.ext.Application.run_polling` and
|
|
||||||
:meth:`telegram.ext.Application.run_webhook`). The updates are grouped and can be sent
|
|
||||||
with delay up to a few minutes.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
business_connection (:class:`telegram.BusinessConnection`, optional): The bot was connected
|
|
||||||
to or disconnected from a business account, or a user edited an existing connection
|
|
||||||
with the bot.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
business_message (:class:`telegram.Message`, optional): New message from a connected
|
|
||||||
business account.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
edited_business_message (:class:`telegram.Message`, optional): New version of a message
|
|
||||||
from a connected business account.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
deleted_business_messages (:class:`telegram.BusinessMessagesDeleted`, optional): Messages
|
|
||||||
were deleted from a connected business account.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
purchased_paid_media (:class:`telegram.PaidMediaPurchased`, optional): A user purchased
|
|
||||||
paid media with a non-empty payload sent by the bot in a non-channel chat.
|
|
||||||
|
|
||||||
.. versionadded:: 21.6
|
|
||||||
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
|
|
||||||
certain positive number and increase sequentially. This ID becomes especially handy if
|
|
||||||
you're using Webhooks, since it allows you to ignore repeated updates or to restore the
|
|
||||||
correct update sequence, should they get out of order. If there are no new updates for
|
|
||||||
at least a week, then identifier of the next update will be chosen randomly instead of
|
|
||||||
sequentially.
|
|
||||||
message (:class:`telegram.Message`): Optional. New incoming message of any kind - text,
|
|
||||||
photo, sticker, etc.
|
|
||||||
edited_message (:class:`telegram.Message`): Optional. New version of a message that is
|
|
||||||
known to the bot and was edited. This update may at times be triggered by changes to
|
|
||||||
message fields that are either unavailable or not actively used by your bot.
|
|
||||||
channel_post (:class:`telegram.Message`): Optional. New incoming channel post of any kind
|
|
||||||
- text, photo, sticker, etc.
|
|
||||||
edited_channel_post (:class:`telegram.Message`): Optional. New version of a channel post
|
|
||||||
that is known to the bot and was edited. This update may at times be triggered by
|
|
||||||
changes to message fields that are either unavailable or not actively used by your bot.
|
|
||||||
inline_query (:class:`telegram.InlineQuery`): Optional. New incoming inline query.
|
|
||||||
chosen_inline_result (:class:`telegram.ChosenInlineResult`): Optional. The result of an
|
|
||||||
inline query that was chosen by a user and sent to their chat partner.
|
|
||||||
callback_query (:class:`telegram.CallbackQuery`): Optional. New incoming callback query.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
:any:`Arbitrary Callback Data Bot <examples.arbitrarycallbackdatabot>`
|
|
||||||
shipping_query (:class:`telegram.ShippingQuery`): Optional. New incoming shipping query.
|
|
||||||
Only for invoices with flexible price.
|
|
||||||
pre_checkout_query (:class:`telegram.PreCheckoutQuery`): Optional. New incoming
|
|
||||||
pre-checkout query. Contains full information about checkout.
|
|
||||||
poll (:class:`telegram.Poll`): Optional. New poll state. Bots receive only updates about
|
|
||||||
manually stopped polls and polls, which are sent by the bot.
|
|
||||||
poll_answer (:class:`telegram.PollAnswer`): Optional. A user changed their answer
|
|
||||||
in a non-anonymous poll. Bots receive new votes only in polls that were sent
|
|
||||||
by the bot itself.
|
|
||||||
my_chat_member (:class:`telegram.ChatMemberUpdated`): Optional. The bot's chat member
|
|
||||||
status was updated in a chat. For private chats, this update is received only when the
|
|
||||||
bot is blocked or unblocked by the user.
|
|
||||||
|
|
||||||
.. versionadded:: 13.4
|
|
||||||
chat_member (:class:`telegram.ChatMemberUpdated`): Optional. A chat member's status was
|
|
||||||
updated in a chat. The bot must be an administrator in the chat and must explicitly
|
|
||||||
specify :attr:`CHAT_MEMBER` in the list of
|
|
||||||
:paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these
|
|
||||||
updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
|
|
||||||
:meth:`telegram.ext.Application.run_polling` and
|
|
||||||
:meth:`telegram.ext.Application.run_webhook`).
|
|
||||||
|
|
||||||
.. versionadded:: 13.4
|
|
||||||
chat_join_request (:class:`telegram.ChatJoinRequest`): Optional. A request to join the
|
|
||||||
chat has been sent. The bot must have the
|
|
||||||
:attr:`telegram.ChatPermissions.can_invite_users` administrator right in the chat to
|
|
||||||
receive these updates.
|
|
||||||
|
|
||||||
.. versionadded:: 13.8
|
|
||||||
|
|
||||||
chat_boost (:class:`telegram.ChatBoostUpdated`): Optional. A chat boost was added or
|
|
||||||
changed. The bot must be an administrator in the chat to receive these updates.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
removed_chat_boost (:class:`telegram.ChatBoostRemoved`): Optional. A boost was removed from
|
|
||||||
a chat. The bot must be an administrator in the chat to receive these updates.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
message_reaction (:class:`telegram.MessageReactionUpdated`): Optional. A reaction to a
|
|
||||||
message was changed by a user. The bot must be an administrator in the chat and must
|
|
||||||
explicitly specify :attr:`MESSAGE_REACTION` in the list of
|
|
||||||
:paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these
|
|
||||||
updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
|
|
||||||
:meth:`telegram.ext.Application.run_polling` and
|
|
||||||
:meth:`telegram.ext.Application.run_webhook`). The update isn't received for reactions
|
|
||||||
set by bots.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
message_reaction_count (:class:`telegram.MessageReactionCountUpdated`): Optional. Reactions
|
|
||||||
to a message with anonymous reactions were changed. The bot must be an administrator in
|
|
||||||
the chat and must explicitly specify :attr:`MESSAGE_REACTION_COUNT` in the list of
|
|
||||||
:paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these
|
|
||||||
updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
|
|
||||||
:meth:`telegram.ext.Application.run_polling` and
|
|
||||||
:meth:`telegram.ext.Application.run_webhook`). The updates are grouped and can be sent
|
|
||||||
with delay up to a few minutes.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
|
|
||||||
business_connection (:class:`telegram.BusinessConnection`): Optional. The bot was connected
|
|
||||||
to or disconnected from a business account, or a user edited an existing connection
|
|
||||||
with the bot.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
business_message (:class:`telegram.Message`): Optional. New message from a connected
|
|
||||||
business account.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
edited_business_message (:class:`telegram.Message`): Optional. New version of a message
|
|
||||||
from a connected business account.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
deleted_business_messages (:class:`telegram.BusinessMessagesDeleted`): Optional. Messages
|
|
||||||
were deleted from a connected business account.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
|
|
||||||
purchased_paid_media (:class:`telegram.PaidMediaPurchased`): Optional. A user purchased
|
|
||||||
paid media with a non-empty payload sent by the bot in a non-channel chat.
|
|
||||||
|
|
||||||
.. versionadded:: 21.6
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"_effective_chat",
|
|
||||||
"_effective_message",
|
|
||||||
"_effective_sender",
|
|
||||||
"_effective_user",
|
|
||||||
"business_connection",
|
|
||||||
"business_message",
|
|
||||||
"callback_query",
|
|
||||||
"channel_post",
|
|
||||||
"chat_boost",
|
|
||||||
"chat_join_request",
|
|
||||||
"chat_member",
|
|
||||||
"chosen_inline_result",
|
|
||||||
"deleted_business_messages",
|
|
||||||
"edited_business_message",
|
|
||||||
"edited_channel_post",
|
|
||||||
"edited_message",
|
|
||||||
"inline_query",
|
|
||||||
"message",
|
|
||||||
"message_reaction",
|
|
||||||
"message_reaction_count",
|
|
||||||
"my_chat_member",
|
|
||||||
"poll",
|
|
||||||
"poll_answer",
|
|
||||||
"pre_checkout_query",
|
|
||||||
"purchased_paid_media",
|
|
||||||
"removed_chat_boost",
|
|
||||||
"shipping_query",
|
|
||||||
"update_id",
|
|
||||||
)
|
|
||||||
|
|
||||||
MESSAGE: Final[str] = constants.UpdateType.MESSAGE
|
|
||||||
""":const:`telegram.constants.UpdateType.MESSAGE`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
EDITED_MESSAGE: Final[str] = constants.UpdateType.EDITED_MESSAGE
|
|
||||||
""":const:`telegram.constants.UpdateType.EDITED_MESSAGE`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
CHANNEL_POST: Final[str] = constants.UpdateType.CHANNEL_POST
|
|
||||||
""":const:`telegram.constants.UpdateType.CHANNEL_POST`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
EDITED_CHANNEL_POST: Final[str] = constants.UpdateType.EDITED_CHANNEL_POST
|
|
||||||
""":const:`telegram.constants.UpdateType.EDITED_CHANNEL_POST`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
INLINE_QUERY: Final[str] = constants.UpdateType.INLINE_QUERY
|
|
||||||
""":const:`telegram.constants.UpdateType.INLINE_QUERY`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
CHOSEN_INLINE_RESULT: Final[str] = constants.UpdateType.CHOSEN_INLINE_RESULT
|
|
||||||
""":const:`telegram.constants.UpdateType.CHOSEN_INLINE_RESULT`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
CALLBACK_QUERY: Final[str] = constants.UpdateType.CALLBACK_QUERY
|
|
||||||
""":const:`telegram.constants.UpdateType.CALLBACK_QUERY`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
SHIPPING_QUERY: Final[str] = constants.UpdateType.SHIPPING_QUERY
|
|
||||||
""":const:`telegram.constants.UpdateType.SHIPPING_QUERY`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
PRE_CHECKOUT_QUERY: Final[str] = constants.UpdateType.PRE_CHECKOUT_QUERY
|
|
||||||
""":const:`telegram.constants.UpdateType.PRE_CHECKOUT_QUERY`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
POLL: Final[str] = constants.UpdateType.POLL
|
|
||||||
""":const:`telegram.constants.UpdateType.POLL`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
POLL_ANSWER: Final[str] = constants.UpdateType.POLL_ANSWER
|
|
||||||
""":const:`telegram.constants.UpdateType.POLL_ANSWER`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
MY_CHAT_MEMBER: Final[str] = constants.UpdateType.MY_CHAT_MEMBER
|
|
||||||
""":const:`telegram.constants.UpdateType.MY_CHAT_MEMBER`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
CHAT_MEMBER: Final[str] = constants.UpdateType.CHAT_MEMBER
|
|
||||||
""":const:`telegram.constants.UpdateType.CHAT_MEMBER`
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
CHAT_JOIN_REQUEST: Final[str] = constants.UpdateType.CHAT_JOIN_REQUEST
|
|
||||||
""":const:`telegram.constants.UpdateType.CHAT_JOIN_REQUEST`
|
|
||||||
|
|
||||||
.. versionadded:: 13.8"""
|
|
||||||
CHAT_BOOST: Final[str] = constants.UpdateType.CHAT_BOOST
|
|
||||||
""":const:`telegram.constants.UpdateType.CHAT_BOOST`
|
|
||||||
|
|
||||||
.. versionadded:: 20.8"""
|
|
||||||
REMOVED_CHAT_BOOST: Final[str] = constants.UpdateType.REMOVED_CHAT_BOOST
|
|
||||||
""":const:`telegram.constants.UpdateType.REMOVED_CHAT_BOOST`
|
|
||||||
|
|
||||||
.. versionadded:: 20.8"""
|
|
||||||
MESSAGE_REACTION: Final[str] = constants.UpdateType.MESSAGE_REACTION
|
|
||||||
""":const:`telegram.constants.UpdateType.MESSAGE_REACTION`
|
|
||||||
|
|
||||||
.. versionadded:: 20.8"""
|
|
||||||
MESSAGE_REACTION_COUNT: Final[str] = constants.UpdateType.MESSAGE_REACTION_COUNT
|
|
||||||
""":const:`telegram.constants.UpdateType.MESSAGE_REACTION_COUNT`
|
|
||||||
|
|
||||||
.. versionadded:: 20.8"""
|
|
||||||
BUSINESS_CONNECTION: Final[str] = constants.UpdateType.BUSINESS_CONNECTION
|
|
||||||
""":const:`telegram.constants.UpdateType.BUSINESS_CONNECTION`
|
|
||||||
|
|
||||||
.. versionadded:: 21.1"""
|
|
||||||
BUSINESS_MESSAGE: Final[str] = constants.UpdateType.BUSINESS_MESSAGE
|
|
||||||
""":const:`telegram.constants.UpdateType.BUSINESS_MESSAGE`
|
|
||||||
|
|
||||||
.. versionadded:: 21.1"""
|
|
||||||
EDITED_BUSINESS_MESSAGE: Final[str] = constants.UpdateType.EDITED_BUSINESS_MESSAGE
|
|
||||||
""":const:`telegram.constants.UpdateType.EDITED_BUSINESS_MESSAGE`
|
|
||||||
|
|
||||||
.. versionadded:: 21.1"""
|
|
||||||
DELETED_BUSINESS_MESSAGES: Final[str] = constants.UpdateType.DELETED_BUSINESS_MESSAGES
|
|
||||||
""":const:`telegram.constants.UpdateType.DELETED_BUSINESS_MESSAGES`
|
|
||||||
|
|
||||||
.. versionadded:: 21.1"""
|
|
||||||
|
|
||||||
PURCHASED_PAID_MEDIA: Final[str] = constants.UpdateType.PURCHASED_PAID_MEDIA
|
|
||||||
""":const:`telegram.constants.UpdateType.PURCHASED_PAID_MEDIA`
|
|
||||||
|
|
||||||
.. versionadded:: 21.6
|
|
||||||
"""
|
|
||||||
|
|
||||||
ALL_TYPES: Final[list[str]] = list(constants.UpdateType)
|
|
||||||
"""list[:obj:`str`]: A list of all available update types.
|
|
||||||
|
|
||||||
.. versionadded:: 13.5"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
update_id: int,
|
|
||||||
message: Optional[Message] = None,
|
|
||||||
edited_message: Optional[Message] = None,
|
|
||||||
channel_post: Optional[Message] = None,
|
|
||||||
edited_channel_post: Optional[Message] = None,
|
|
||||||
inline_query: Optional[InlineQuery] = None,
|
|
||||||
chosen_inline_result: Optional[ChosenInlineResult] = None,
|
|
||||||
callback_query: Optional[CallbackQuery] = None,
|
|
||||||
shipping_query: Optional[ShippingQuery] = None,
|
|
||||||
pre_checkout_query: Optional[PreCheckoutQuery] = None,
|
|
||||||
poll: Optional[Poll] = None,
|
|
||||||
poll_answer: Optional[PollAnswer] = None,
|
|
||||||
my_chat_member: Optional[ChatMemberUpdated] = None,
|
|
||||||
chat_member: Optional[ChatMemberUpdated] = None,
|
|
||||||
chat_join_request: Optional[ChatJoinRequest] = None,
|
|
||||||
chat_boost: Optional[ChatBoostUpdated] = None,
|
|
||||||
removed_chat_boost: Optional[ChatBoostRemoved] = None,
|
|
||||||
message_reaction: Optional[MessageReactionUpdated] = None,
|
|
||||||
message_reaction_count: Optional[MessageReactionCountUpdated] = None,
|
|
||||||
business_connection: Optional[BusinessConnection] = None,
|
|
||||||
business_message: Optional[Message] = None,
|
|
||||||
edited_business_message: Optional[Message] = None,
|
|
||||||
deleted_business_messages: Optional[BusinessMessagesDeleted] = None,
|
|
||||||
purchased_paid_media: Optional[PaidMediaPurchased] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.update_id: int = update_id
|
|
||||||
# Optionals
|
|
||||||
self.message: Optional[Message] = message
|
|
||||||
self.edited_message: Optional[Message] = edited_message
|
|
||||||
self.inline_query: Optional[InlineQuery] = inline_query
|
|
||||||
self.chosen_inline_result: Optional[ChosenInlineResult] = chosen_inline_result
|
|
||||||
self.callback_query: Optional[CallbackQuery] = callback_query
|
|
||||||
self.shipping_query: Optional[ShippingQuery] = shipping_query
|
|
||||||
self.pre_checkout_query: Optional[PreCheckoutQuery] = pre_checkout_query
|
|
||||||
self.channel_post: Optional[Message] = channel_post
|
|
||||||
self.edited_channel_post: Optional[Message] = edited_channel_post
|
|
||||||
self.poll: Optional[Poll] = poll
|
|
||||||
self.poll_answer: Optional[PollAnswer] = poll_answer
|
|
||||||
self.my_chat_member: Optional[ChatMemberUpdated] = my_chat_member
|
|
||||||
self.chat_member: Optional[ChatMemberUpdated] = chat_member
|
|
||||||
self.chat_join_request: Optional[ChatJoinRequest] = chat_join_request
|
|
||||||
self.chat_boost: Optional[ChatBoostUpdated] = chat_boost
|
|
||||||
self.removed_chat_boost: Optional[ChatBoostRemoved] = removed_chat_boost
|
|
||||||
self.message_reaction: Optional[MessageReactionUpdated] = message_reaction
|
|
||||||
self.message_reaction_count: Optional[MessageReactionCountUpdated] = message_reaction_count
|
|
||||||
self.business_connection: Optional[BusinessConnection] = business_connection
|
|
||||||
self.business_message: Optional[Message] = business_message
|
|
||||||
self.edited_business_message: Optional[Message] = edited_business_message
|
|
||||||
self.deleted_business_messages: Optional[BusinessMessagesDeleted] = (
|
|
||||||
deleted_business_messages
|
|
||||||
)
|
|
||||||
self.purchased_paid_media: Optional[PaidMediaPurchased] = purchased_paid_media
|
|
||||||
|
|
||||||
self._effective_user: Optional[User] = None
|
|
||||||
self._effective_sender: Optional[Union[User, Chat]] = None
|
|
||||||
self._effective_chat: Optional[Chat] = None
|
|
||||||
self._effective_message: Optional[Message] = None
|
|
||||||
|
|
||||||
self._id_attrs = (self.update_id,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def effective_user(self) -> Optional["User"]:
|
|
||||||
"""
|
|
||||||
:class:`telegram.User`: The user that sent this update, no matter what kind of update this
|
|
||||||
is. If no user is associated with this update, this gives :obj:`None`. This is the case
|
|
||||||
if any of
|
|
||||||
|
|
||||||
* :attr:`channel_post`
|
|
||||||
* :attr:`edited_channel_post`
|
|
||||||
* :attr:`poll`
|
|
||||||
* :attr:`chat_boost`
|
|
||||||
* :attr:`removed_chat_boost`
|
|
||||||
* :attr:`message_reaction_count`
|
|
||||||
* :attr:`deleted_business_messages`
|
|
||||||
|
|
||||||
is present.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.1
|
|
||||||
This property now also considers :attr:`business_connection`, :attr:`business_message`
|
|
||||||
and :attr:`edited_business_message`.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.6
|
|
||||||
This property now also considers :attr:`purchased_paid_media`.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
* If :attr:`message` is present, this will give
|
|
||||||
:attr:`telegram.Message.from_user`.
|
|
||||||
* If :attr:`poll_answer` is present, this will give :attr:`telegram.PollAnswer.user`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self._effective_user:
|
|
||||||
return self._effective_user
|
|
||||||
|
|
||||||
user = None
|
|
||||||
|
|
||||||
if self.message:
|
|
||||||
user = self.message.from_user
|
|
||||||
|
|
||||||
elif self.edited_message:
|
|
||||||
user = self.edited_message.from_user
|
|
||||||
|
|
||||||
elif self.inline_query:
|
|
||||||
user = self.inline_query.from_user
|
|
||||||
|
|
||||||
elif self.chosen_inline_result:
|
|
||||||
user = self.chosen_inline_result.from_user
|
|
||||||
|
|
||||||
elif self.callback_query:
|
|
||||||
user = self.callback_query.from_user
|
|
||||||
|
|
||||||
elif self.shipping_query:
|
|
||||||
user = self.shipping_query.from_user
|
|
||||||
|
|
||||||
elif self.pre_checkout_query:
|
|
||||||
user = self.pre_checkout_query.from_user
|
|
||||||
|
|
||||||
elif self.poll_answer:
|
|
||||||
user = self.poll_answer.user
|
|
||||||
|
|
||||||
elif self.my_chat_member:
|
|
||||||
user = self.my_chat_member.from_user
|
|
||||||
|
|
||||||
elif self.chat_member:
|
|
||||||
user = self.chat_member.from_user
|
|
||||||
|
|
||||||
elif self.chat_join_request:
|
|
||||||
user = self.chat_join_request.from_user
|
|
||||||
|
|
||||||
elif self.message_reaction:
|
|
||||||
user = self.message_reaction.user
|
|
||||||
|
|
||||||
elif self.business_message:
|
|
||||||
user = self.business_message.from_user
|
|
||||||
|
|
||||||
elif self.edited_business_message:
|
|
||||||
user = self.edited_business_message.from_user
|
|
||||||
|
|
||||||
elif self.business_connection:
|
|
||||||
user = self.business_connection.user
|
|
||||||
|
|
||||||
elif self.purchased_paid_media:
|
|
||||||
user = self.purchased_paid_media.from_user
|
|
||||||
|
|
||||||
self._effective_user = user
|
|
||||||
return user
|
|
||||||
|
|
||||||
@property
|
|
||||||
def effective_sender(self) -> Optional[Union["User", "Chat"]]:
|
|
||||||
"""
|
|
||||||
:class:`telegram.User` or :class:`telegram.Chat`: The user or chat that sent this update,
|
|
||||||
no matter what kind of update this is.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
* Depending on the type of update and the user's 'Remain anonymous' setting, this
|
|
||||||
could either be :class:`telegram.User`, :class:`telegram.Chat` or :obj:`None`.
|
|
||||||
|
|
||||||
If no user whatsoever is associated with this update, this gives :obj:`None`. This
|
|
||||||
is the case if any of
|
|
||||||
|
|
||||||
* :attr:`poll`
|
|
||||||
* :attr:`chat_boost`
|
|
||||||
* :attr:`removed_chat_boost`
|
|
||||||
* :attr:`message_reaction_count`
|
|
||||||
* :attr:`deleted_business_messages`
|
|
||||||
|
|
||||||
is present.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
* If :attr:`message` is present, this will give either
|
|
||||||
:attr:`telegram.Message.from_user` or :attr:`telegram.Message.sender_chat`.
|
|
||||||
* If :attr:`poll_answer` is present, this will give either
|
|
||||||
:attr:`telegram.PollAnswer.user` or :attr:`telegram.PollAnswer.voter_chat`.
|
|
||||||
* If :attr:`channel_post` is present, this will give
|
|
||||||
:attr:`telegram.Message.sender_chat`.
|
|
||||||
|
|
||||||
.. versionadded:: 21.1
|
|
||||||
"""
|
|
||||||
if self._effective_sender:
|
|
||||||
return self._effective_sender
|
|
||||||
|
|
||||||
sender: Optional[Union[User, Chat]] = None
|
|
||||||
|
|
||||||
if message := (
|
|
||||||
self.message
|
|
||||||
or self.edited_message
|
|
||||||
or self.channel_post
|
|
||||||
or self.edited_channel_post
|
|
||||||
or self.business_message
|
|
||||||
or self.edited_business_message
|
|
||||||
):
|
|
||||||
sender = message.sender_chat
|
|
||||||
|
|
||||||
elif self.poll_answer:
|
|
||||||
sender = self.poll_answer.voter_chat
|
|
||||||
|
|
||||||
elif self.message_reaction:
|
|
||||||
sender = self.message_reaction.actor_chat
|
|
||||||
|
|
||||||
if sender is None:
|
|
||||||
sender = self.effective_user
|
|
||||||
|
|
||||||
self._effective_sender = sender
|
|
||||||
return sender
|
|
||||||
|
|
||||||
@property
|
|
||||||
def effective_chat(self) -> Optional["Chat"]:
|
|
||||||
"""
|
|
||||||
:class:`telegram.Chat`: The chat that this update was sent in, no matter what kind of
|
|
||||||
update this is.
|
|
||||||
If no chat is associated with this update, this gives :obj:`None`.
|
|
||||||
This is the case, if :attr:`inline_query`,
|
|
||||||
:attr:`chosen_inline_result`, :attr:`callback_query` from inline messages,
|
|
||||||
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll`,
|
|
||||||
:attr:`poll_answer`, :attr:`business_connection`, or :attr:`purchased_paid_media`
|
|
||||||
is present.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.1
|
|
||||||
This property now also considers :attr:`business_message`,
|
|
||||||
:attr:`edited_business_message`, and :attr:`deleted_business_messages`.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
If :attr:`message` is present, this will give :attr:`telegram.Message.chat`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self._effective_chat:
|
|
||||||
return self._effective_chat
|
|
||||||
|
|
||||||
chat = None
|
|
||||||
|
|
||||||
if self.message:
|
|
||||||
chat = self.message.chat
|
|
||||||
|
|
||||||
elif self.edited_message:
|
|
||||||
chat = self.edited_message.chat
|
|
||||||
|
|
||||||
elif self.callback_query and self.callback_query.message:
|
|
||||||
chat = self.callback_query.message.chat
|
|
||||||
|
|
||||||
elif self.channel_post:
|
|
||||||
chat = self.channel_post.chat
|
|
||||||
|
|
||||||
elif self.edited_channel_post:
|
|
||||||
chat = self.edited_channel_post.chat
|
|
||||||
|
|
||||||
elif self.my_chat_member:
|
|
||||||
chat = self.my_chat_member.chat
|
|
||||||
|
|
||||||
elif self.chat_member:
|
|
||||||
chat = self.chat_member.chat
|
|
||||||
|
|
||||||
elif self.chat_join_request:
|
|
||||||
chat = self.chat_join_request.chat
|
|
||||||
|
|
||||||
elif self.chat_boost:
|
|
||||||
chat = self.chat_boost.chat
|
|
||||||
|
|
||||||
elif self.removed_chat_boost:
|
|
||||||
chat = self.removed_chat_boost.chat
|
|
||||||
|
|
||||||
elif self.message_reaction:
|
|
||||||
chat = self.message_reaction.chat
|
|
||||||
|
|
||||||
elif self.message_reaction_count:
|
|
||||||
chat = self.message_reaction_count.chat
|
|
||||||
|
|
||||||
elif self.business_message:
|
|
||||||
chat = self.business_message.chat
|
|
||||||
|
|
||||||
elif self.edited_business_message:
|
|
||||||
chat = self.edited_business_message.chat
|
|
||||||
|
|
||||||
elif self.deleted_business_messages:
|
|
||||||
chat = self.deleted_business_messages.chat
|
|
||||||
|
|
||||||
self._effective_chat = chat
|
|
||||||
return chat
|
|
||||||
|
|
||||||
@property
|
|
||||||
def effective_message(self) -> Optional[Message]:
|
|
||||||
"""
|
|
||||||
:class:`telegram.Message`: The message included in this update, no matter what kind of
|
|
||||||
update this is. More precisely, this will be the message contained in :attr:`message`,
|
|
||||||
:attr:`edited_message`, :attr:`channel_post`, :attr:`edited_channel_post` or
|
|
||||||
:attr:`callback_query` (i.e. :attr:`telegram.CallbackQuery.message`) or :obj:`None`, if
|
|
||||||
none of those are present.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.1
|
|
||||||
This property now also considers :attr:`business_message`, and
|
|
||||||
:attr:`edited_business_message`.
|
|
||||||
|
|
||||||
Tip:
|
|
||||||
This property will only ever return objects of type :class:`telegram.Message` or
|
|
||||||
:obj:`None`, never :class:`telegram.MaybeInaccessibleMessage` or
|
|
||||||
:class:`telegram.InaccessibleMessage`.
|
|
||||||
Currently, this is only relevant for :attr:`callback_query`, as
|
|
||||||
:attr:`telegram.CallbackQuery.message` is the only attribute considered by this
|
|
||||||
property that can be an object of these types.
|
|
||||||
"""
|
|
||||||
if self._effective_message:
|
|
||||||
return self._effective_message
|
|
||||||
|
|
||||||
message: Optional[Message] = None
|
|
||||||
|
|
||||||
if self.message:
|
|
||||||
message = self.message
|
|
||||||
|
|
||||||
elif self.edited_message:
|
|
||||||
message = self.edited_message
|
|
||||||
|
|
||||||
elif self.callback_query:
|
|
||||||
if (
|
|
||||||
isinstance(cbq_message := self.callback_query.message, Message)
|
|
||||||
or cbq_message is None
|
|
||||||
):
|
|
||||||
message = cbq_message
|
|
||||||
else:
|
|
||||||
warn(
|
|
||||||
(
|
|
||||||
"`update.callback_query` is not `None`, but of type "
|
|
||||||
f"`{cbq_message.__class__.__name__}`. This is not considered by "
|
|
||||||
"`Update.effective_message`. Please manually access this attribute "
|
|
||||||
"if necessary."
|
|
||||||
),
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
elif self.channel_post:
|
|
||||||
message = self.channel_post
|
|
||||||
|
|
||||||
elif self.edited_channel_post:
|
|
||||||
message = self.edited_channel_post
|
|
||||||
|
|
||||||
elif self.business_message:
|
|
||||||
message = self.business_message
|
|
||||||
|
|
||||||
elif self.edited_business_message:
|
|
||||||
message = self.edited_business_message
|
|
||||||
|
|
||||||
self._effective_message = message
|
|
||||||
return message
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Update"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["message"] = Message.de_json(data.get("message"), bot)
|
|
||||||
data["edited_message"] = Message.de_json(data.get("edited_message"), bot)
|
|
||||||
data["inline_query"] = InlineQuery.de_json(data.get("inline_query"), bot)
|
|
||||||
data["chosen_inline_result"] = ChosenInlineResult.de_json(
|
|
||||||
data.get("chosen_inline_result"), bot
|
|
||||||
)
|
|
||||||
data["callback_query"] = CallbackQuery.de_json(data.get("callback_query"), bot)
|
|
||||||
data["shipping_query"] = ShippingQuery.de_json(data.get("shipping_query"), bot)
|
|
||||||
data["pre_checkout_query"] = PreCheckoutQuery.de_json(data.get("pre_checkout_query"), bot)
|
|
||||||
data["channel_post"] = Message.de_json(data.get("channel_post"), bot)
|
|
||||||
data["edited_channel_post"] = Message.de_json(data.get("edited_channel_post"), bot)
|
|
||||||
data["poll"] = Poll.de_json(data.get("poll"), bot)
|
|
||||||
data["poll_answer"] = PollAnswer.de_json(data.get("poll_answer"), bot)
|
|
||||||
data["my_chat_member"] = ChatMemberUpdated.de_json(data.get("my_chat_member"), bot)
|
|
||||||
data["chat_member"] = ChatMemberUpdated.de_json(data.get("chat_member"), bot)
|
|
||||||
data["chat_join_request"] = ChatJoinRequest.de_json(data.get("chat_join_request"), bot)
|
|
||||||
data["chat_boost"] = ChatBoostUpdated.de_json(data.get("chat_boost"), bot)
|
|
||||||
data["removed_chat_boost"] = ChatBoostRemoved.de_json(data.get("removed_chat_boost"), bot)
|
|
||||||
data["message_reaction"] = MessageReactionUpdated.de_json(
|
|
||||||
data.get("message_reaction"), bot
|
|
||||||
)
|
|
||||||
data["message_reaction_count"] = MessageReactionCountUpdated.de_json(
|
|
||||||
data.get("message_reaction_count"), bot
|
|
||||||
)
|
|
||||||
data["business_connection"] = BusinessConnection.de_json(
|
|
||||||
data.get("business_connection"), bot
|
|
||||||
)
|
|
||||||
data["business_message"] = Message.de_json(data.get("business_message"), bot)
|
|
||||||
data["edited_business_message"] = Message.de_json(data.get("edited_business_message"), bot)
|
|
||||||
data["deleted_business_messages"] = BusinessMessagesDeleted.de_json(
|
|
||||||
data.get("deleted_business_messages"), bot
|
|
||||||
)
|
|
||||||
data["purchased_paid_media"] = PaidMediaPurchased.de_json(
|
|
||||||
data.get("purchased_paid_media"), bot
|
|
||||||
)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,85 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram UserProfilePhotos."""
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._files.photosize import PhotoSize
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class UserProfilePhotos(TelegramObject):
|
|
||||||
"""This object represents a user's profile pictures.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`total_count` and :attr:`photos` are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
total_count (:obj:`int`): Total number of profile pictures the target user has.
|
|
||||||
photos (Sequence[Sequence[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up
|
|
||||||
to 4 sizes each).
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
total_count (:obj:`int`): Total number of profile pictures.
|
|
||||||
photos (tuple[tuple[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up to 4
|
|
||||||
sizes each).
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|tupleclassattrs|
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("photos", "total_count")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
total_count: int,
|
|
||||||
photos: Sequence[Sequence[PhotoSize]],
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.total_count: int = total_count
|
|
||||||
self.photos: tuple[tuple[PhotoSize, ...], ...] = tuple(tuple(sizes) for sizes in photos)
|
|
||||||
|
|
||||||
self._id_attrs = (self.total_count, self.photos)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["UserProfilePhotos"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["photos"] = [PhotoSize.de_list(photo, bot) for photo in data["photos"]]
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,62 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains helper functions related to parsing arguments for classes and methods.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import Optional, TypeVar
|
|
||||||
|
|
||||||
from telegram._linkpreviewoptions import LinkPreviewOptions
|
|
||||||
from telegram._utils.types import ODVInput
|
|
||||||
|
|
||||||
T = TypeVar("T")
|
|
||||||
|
|
||||||
|
|
||||||
def parse_sequence_arg(arg: Optional[Sequence[T]]) -> tuple[T, ...]:
|
|
||||||
"""Parses an optional sequence into a tuple
|
|
||||||
|
|
||||||
Args:
|
|
||||||
arg (:obj:`Sequence`): The sequence to parse.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`Tuple`: The sequence converted to a tuple or an empty tuple.
|
|
||||||
"""
|
|
||||||
return tuple(arg) if arg else ()
|
|
||||||
|
|
||||||
|
|
||||||
def parse_lpo_and_dwpp(
|
|
||||||
disable_web_page_preview: Optional[bool], link_preview_options: ODVInput[LinkPreviewOptions]
|
|
||||||
) -> ODVInput[LinkPreviewOptions]:
|
|
||||||
"""Wrapper around warn_about_deprecated_arg_return_new_arg. Takes care of converting
|
|
||||||
disable_web_page_preview to LinkPreviewOptions.
|
|
||||||
"""
|
|
||||||
if disable_web_page_preview and link_preview_options:
|
|
||||||
raise ValueError(
|
|
||||||
"Parameters `disable_web_page_preview` and `link_preview_options` are mutually "
|
|
||||||
"exclusive."
|
|
||||||
)
|
|
||||||
|
|
||||||
if disable_web_page_preview is not None:
|
|
||||||
link_preview_options = LinkPreviewOptions(is_disabled=disable_web_page_preview)
|
|
||||||
|
|
||||||
return link_preview_options
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains helper functions related to datetime and timestamp conversations.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
Previously, the contents of this module were available through the (no longer existing)
|
|
||||||
module ``telegram._utils.helpers``.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
import contextlib
|
|
||||||
import datetime as dtm
|
|
||||||
import time
|
|
||||||
from typing import TYPE_CHECKING, Optional, Union
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
UTC = dtm.timezone.utc
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None # type: ignore[assignment]
|
|
||||||
|
|
||||||
|
|
||||||
def localize(datetime: dtm.datetime, tzinfo: dtm.tzinfo) -> dtm.datetime:
|
|
||||||
"""Localize the datetime, both for pytz and zoneinfo timezones."""
|
|
||||||
if tzinfo is UTC:
|
|
||||||
return datetime.replace(tzinfo=UTC)
|
|
||||||
|
|
||||||
with contextlib.suppress(AttributeError):
|
|
||||||
# Since pytz might not be available, we need the suppress context manager
|
|
||||||
if isinstance(tzinfo, pytz.BaseTzInfo):
|
|
||||||
return tzinfo.localize(datetime)
|
|
||||||
|
|
||||||
if datetime.tzinfo is None:
|
|
||||||
return datetime.replace(tzinfo=tzinfo)
|
|
||||||
return datetime.astimezone(tzinfo)
|
|
||||||
|
|
||||||
|
|
||||||
def to_float_timestamp(
|
|
||||||
time_object: Union[float, dtm.timedelta, dtm.datetime, dtm.time],
|
|
||||||
reference_timestamp: Optional[float] = None,
|
|
||||||
tzinfo: Optional[dtm.tzinfo] = None,
|
|
||||||
) -> float:
|
|
||||||
"""
|
|
||||||
Converts a given time object to a float POSIX timestamp.
|
|
||||||
Used to convert different time specifications to a common format. The time object
|
|
||||||
can be relative (i.e. indicate a time increment, or a time of day) or absolute.
|
|
||||||
Objects from the :class:`datetime` module that are timezone-naive will be assumed
|
|
||||||
to be in UTC, if ``bot`` is not passed or ``bot.defaults`` is :obj:`None`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
time_object (:obj:`float` | :obj:`datetime.timedelta` | \
|
|
||||||
:obj:`datetime.datetime` | :obj:`datetime.time`):
|
|
||||||
Time value to convert. The semantics of this parameter will depend on its type:
|
|
||||||
|
|
||||||
* :obj:`float` will be interpreted as "seconds from :paramref:`reference_t`"
|
|
||||||
* :obj:`datetime.timedelta` will be interpreted as
|
|
||||||
"time increment from :paramref:`reference_timestamp`"
|
|
||||||
* :obj:`datetime.datetime` will be interpreted as an absolute date/time value
|
|
||||||
* :obj:`datetime.time` will be interpreted as a specific time of day
|
|
||||||
|
|
||||||
reference_timestamp (:obj:`float`, optional): POSIX timestamp that indicates the absolute
|
|
||||||
time from which relative calculations are to be performed (e.g. when
|
|
||||||
:paramref:`time_object` is given as an :obj:`int`, indicating "seconds from
|
|
||||||
:paramref:`reference_time`"). Defaults to now (the time at which this function is
|
|
||||||
called).
|
|
||||||
|
|
||||||
If :paramref:`time_object` is given as an absolute representation of date & time (i.e.
|
|
||||||
a :obj:`datetime.datetime` object), :paramref:`reference_timestamp` is not relevant
|
|
||||||
and so its value should be :obj:`None`. If this is not the case, a :exc:`ValueError`
|
|
||||||
will be raised.
|
|
||||||
tzinfo (:class:`datetime.tzinfo`, optional): If :paramref:`time_object` is a naive object
|
|
||||||
from the :mod:`datetime` module, it will be interpreted as this timezone. Defaults to
|
|
||||||
:attr:`datetime.timezone.utc` otherwise.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
Only to be used by ``telegram.ext``.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`float` | :obj:`None`:
|
|
||||||
The return value depends on the type of argument :paramref:`time_object`.
|
|
||||||
If :paramref:`time_object` is given as a time increment (i.e. as a :obj:`int`,
|
|
||||||
:obj:`float` or :obj:`datetime.timedelta`), then the return value will be
|
|
||||||
:paramref:`reference_timestamp` + :paramref:`time_object`.
|
|
||||||
|
|
||||||
Else if it is given as an absolute date/time value (i.e. a :obj:`datetime.datetime`
|
|
||||||
object), the equivalent value as a POSIX timestamp will be returned.
|
|
||||||
|
|
||||||
Finally, if it is a time of the day without date (i.e. a :obj:`datetime.time`
|
|
||||||
object), the return value is the nearest future occurrence of that time of day.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
TypeError: If :paramref:`time_object` s type is not one of those described above.
|
|
||||||
ValueError: If :paramref:`time_object` is a :obj:`datetime.datetime` and
|
|
||||||
:paramref:`reference_timestamp` is not :obj:`None`.
|
|
||||||
"""
|
|
||||||
if reference_timestamp is None:
|
|
||||||
reference_timestamp = time.time()
|
|
||||||
elif isinstance(time_object, dtm.datetime):
|
|
||||||
raise ValueError("t is an (absolute) datetime while reference_timestamp is not None")
|
|
||||||
|
|
||||||
if isinstance(time_object, dtm.timedelta):
|
|
||||||
return reference_timestamp + time_object.total_seconds()
|
|
||||||
if isinstance(time_object, (int, float)):
|
|
||||||
return reference_timestamp + time_object
|
|
||||||
|
|
||||||
if tzinfo is None:
|
|
||||||
# We do this here rather than in the signature to ensure that we can make calls like
|
|
||||||
# to_float_timestamp(
|
|
||||||
# time, tzinfo=bot.defaults.tzinfo if bot.defaults else None
|
|
||||||
# )
|
|
||||||
# This ensures clean separation of concerns, i.e. the default timezone should not be
|
|
||||||
# the responsibility of the caller
|
|
||||||
tzinfo = UTC
|
|
||||||
|
|
||||||
if isinstance(time_object, dtm.time):
|
|
||||||
reference_dt = dtm.datetime.fromtimestamp(
|
|
||||||
reference_timestamp, tz=time_object.tzinfo or tzinfo
|
|
||||||
)
|
|
||||||
reference_date = reference_dt.date()
|
|
||||||
reference_time = reference_dt.timetz()
|
|
||||||
|
|
||||||
aware_datetime = dtm.datetime.combine(reference_date, time_object)
|
|
||||||
if aware_datetime.tzinfo is None:
|
|
||||||
# datetime.combine uses the tzinfo of `time_object`, which might be None
|
|
||||||
# so we still need to localize
|
|
||||||
aware_datetime = localize(aware_datetime, tzinfo)
|
|
||||||
|
|
||||||
# if the time of day has passed today, use tomorrow
|
|
||||||
if reference_time > aware_datetime.timetz():
|
|
||||||
aware_datetime += dtm.timedelta(days=1)
|
|
||||||
return _datetime_to_float_timestamp(aware_datetime)
|
|
||||||
if isinstance(time_object, dtm.datetime):
|
|
||||||
if time_object.tzinfo is None:
|
|
||||||
time_object = localize(time_object, tzinfo)
|
|
||||||
return _datetime_to_float_timestamp(time_object)
|
|
||||||
|
|
||||||
raise TypeError(f"Unable to convert {type(time_object).__name__} object to timestamp")
|
|
||||||
|
|
||||||
|
|
||||||
def to_timestamp(
|
|
||||||
dt_obj: Union[float, dtm.timedelta, dtm.datetime, dtm.time, None],
|
|
||||||
reference_timestamp: Optional[float] = None,
|
|
||||||
tzinfo: Optional[dtm.tzinfo] = None,
|
|
||||||
) -> Optional[int]:
|
|
||||||
"""
|
|
||||||
Wrapper over :func:`to_float_timestamp` which returns an integer (the float value truncated
|
|
||||||
down to the nearest integer).
|
|
||||||
|
|
||||||
See the documentation for :func:`to_float_timestamp` for more details.
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
int(to_float_timestamp(dt_obj, reference_timestamp, tzinfo))
|
|
||||||
if dt_obj is not None
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def from_timestamp(
|
|
||||||
unixtime: Optional[int],
|
|
||||||
tzinfo: Optional[dtm.tzinfo] = None,
|
|
||||||
) -> Optional[dtm.datetime]:
|
|
||||||
"""
|
|
||||||
Converts an (integer) unix timestamp to a timezone aware datetime object.
|
|
||||||
:obj:`None` s are left alone (i.e. ``from_timestamp(None)`` is :obj:`None`).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
unixtime (:obj:`int`): Integer POSIX timestamp.
|
|
||||||
tzinfo (:obj:`datetime.tzinfo`, optional): The timezone to which the timestamp is to be
|
|
||||||
converted to. Defaults to :obj:`None`, in which case the returned datetime object will
|
|
||||||
be timezone aware and in UTC.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Timezone aware equivalent :obj:`datetime.datetime` value if :paramref:`unixtime` is not
|
|
||||||
:obj:`None`; else :obj:`None`.
|
|
||||||
"""
|
|
||||||
if unixtime is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return dtm.datetime.fromtimestamp(unixtime, tz=UTC if tzinfo is None else tzinfo)
|
|
||||||
|
|
||||||
|
|
||||||
def extract_tzinfo_from_defaults(bot: Optional["Bot"]) -> Union[dtm.tzinfo, None]:
|
|
||||||
"""
|
|
||||||
Extracts the timezone info from the default values of the bot.
|
|
||||||
If the bot has no default values, :obj:`None` is returned.
|
|
||||||
"""
|
|
||||||
# We don't use `ininstance(bot, ExtBot)` here so that this works
|
|
||||||
# without the job-queue extra dependencies as well
|
|
||||||
if bot is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if hasattr(bot, "defaults") and bot.defaults:
|
|
||||||
return bot.defaults.tzinfo
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _datetime_to_float_timestamp(dt_obj: dtm.datetime) -> float:
|
|
||||||
"""
|
|
||||||
Converts a datetime object to a float timestamp (with sub-second precision).
|
|
||||||
If the datetime object is timezone-naive, it is assumed to be in UTC.
|
|
||||||
"""
|
|
||||||
if dt_obj.tzinfo is None:
|
|
||||||
dt_obj = dt_obj.replace(tzinfo=dtm.timezone.utc)
|
|
||||||
return dt_obj.timestamp()
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains the DefaultValue class.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
Previously, the contents of this module were available through the (no longer existing)
|
|
||||||
module ``telegram._utils.helpers``.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
from typing import Generic, TypeVar, Union, overload
|
|
||||||
|
|
||||||
DVType = TypeVar("DVType", bound=object) # pylint: disable=invalid-name
|
|
||||||
OT = TypeVar("OT", bound=object)
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultValue(Generic[DVType]):
|
|
||||||
"""Wrapper for immutable default arguments that allows to check, if the default value was set
|
|
||||||
explicitly. Usage::
|
|
||||||
|
|
||||||
default_one = DefaultValue(1)
|
|
||||||
def f(arg=default_one):
|
|
||||||
if arg is default_one:
|
|
||||||
print('`arg` is the default')
|
|
||||||
arg = arg.value
|
|
||||||
else:
|
|
||||||
print('`arg` was set explicitly')
|
|
||||||
print(f'`arg` = {str(arg)}')
|
|
||||||
|
|
||||||
This yields::
|
|
||||||
|
|
||||||
>>> f()
|
|
||||||
`arg` is the default
|
|
||||||
`arg` = 1
|
|
||||||
>>> f(1)
|
|
||||||
`arg` was set explicitly
|
|
||||||
`arg` = 1
|
|
||||||
>>> f(2)
|
|
||||||
`arg` was set explicitly
|
|
||||||
`arg` = 2
|
|
||||||
|
|
||||||
Also allows to evaluate truthiness::
|
|
||||||
|
|
||||||
default = DefaultValue(value)
|
|
||||||
if default:
|
|
||||||
...
|
|
||||||
|
|
||||||
is equivalent to::
|
|
||||||
|
|
||||||
default = DefaultValue(value)
|
|
||||||
if value:
|
|
||||||
...
|
|
||||||
|
|
||||||
``repr(DefaultValue(value))`` returns ``repr(value)`` and ``str(DefaultValue(value))`` returns
|
|
||||||
``f'DefaultValue({value})'``.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
value (:class:`object`): The value of the default argument
|
|
||||||
Attributes:
|
|
||||||
value (:class:`object`): The value of the default argument
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("value",)
|
|
||||||
|
|
||||||
def __init__(self, value: DVType):
|
|
||||||
self.value: DVType = value
|
|
||||||
|
|
||||||
def __bool__(self) -> bool:
|
|
||||||
return bool(self.value)
|
|
||||||
|
|
||||||
# This is mostly here for readability during debugging
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return f"DefaultValue({self.value})"
|
|
||||||
|
|
||||||
# This is here to have the default instances nicely rendered in the docs
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return repr(self.value)
|
|
||||||
|
|
||||||
@overload
|
|
||||||
@staticmethod
|
|
||||||
def get_value(obj: "DefaultValue[OT]") -> OT: ...
|
|
||||||
|
|
||||||
@overload
|
|
||||||
@staticmethod
|
|
||||||
def get_value(obj: OT) -> OT: ...
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_value(obj: Union[OT, "DefaultValue[OT]"]) -> OT:
|
|
||||||
"""Shortcut for::
|
|
||||||
|
|
||||||
return obj.value if isinstance(obj, DefaultValue) else obj
|
|
||||||
|
|
||||||
Args:
|
|
||||||
obj (:obj:`object`): The object to process
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Same type as input, or the value of the input: The value
|
|
||||||
"""
|
|
||||||
return obj.value if isinstance(obj, DefaultValue) else obj
|
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_NONE: DefaultValue[None] = DefaultValue(None)
|
|
||||||
""":class:`DefaultValue`: Default :obj:`None`"""
|
|
||||||
|
|
||||||
DEFAULT_FALSE: DefaultValue[bool] = DefaultValue(False)
|
|
||||||
""":class:`DefaultValue`: Default :obj:`False`"""
|
|
||||||
|
|
||||||
DEFAULT_TRUE: DefaultValue[bool] = DefaultValue(True)
|
|
||||||
""":class:`DefaultValue`: Default :obj:`True`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_20: DefaultValue[int] = DefaultValue(20)
|
|
||||||
""":class:`DefaultValue`: Default :obj:`20`"""
|
|
||||||
|
|
||||||
DEFAULT_IP: DefaultValue[str] = DefaultValue("127.0.0.1")
|
|
||||||
""":class:`DefaultValue`: Default :obj:`127.0.0.1`
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
"""
|
|
||||||
|
|
||||||
DEFAULT_80: DefaultValue[int] = DefaultValue(80)
|
|
||||||
""":class:`DefaultValue`: Default :obj:`80`
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
"""
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains auxiliary functionality for parsing MessageEntity objects.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._messageentity import MessageEntity
|
|
||||||
from telegram._utils.strings import TextEncoding
|
|
||||||
|
|
||||||
|
|
||||||
def parse_message_entity(text: str, entity: MessageEntity) -> str:
|
|
||||||
"""Returns the text from a given :class:`telegram.MessageEntity`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text (:obj:`str`): The text to extract the entity from.
|
|
||||||
entity (:class:`telegram.MessageEntity`): The entity to extract the text from.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`: The text of the given entity.
|
|
||||||
"""
|
|
||||||
entity_text = text.encode(TextEncoding.UTF_16_LE)
|
|
||||||
entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
|
|
||||||
|
|
||||||
return entity_text.decode(TextEncoding.UTF_16_LE)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_message_entities(
|
|
||||||
text: str, entities: Sequence[MessageEntity], types: Optional[Sequence[str]] = None
|
|
||||||
) -> dict[MessageEntity, str]:
|
|
||||||
"""
|
|
||||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
|
||||||
It contains entities filtered by their ``type`` attribute as
|
|
||||||
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text (:obj:`str`): The text to extract the entity from.
|
|
||||||
entities (list[:class:`telegram.MessageEntity`]): The entities to extract the text from.
|
|
||||||
types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
|
|
||||||
``type`` attribute of an entity is contained in this list, it will be returned.
|
|
||||||
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
|
||||||
the text that belongs to them, calculated based on UTF-16 codepoints.
|
|
||||||
"""
|
|
||||||
if types is None:
|
|
||||||
types = MessageEntity.ALL_TYPES
|
|
||||||
|
|
||||||
return {
|
|
||||||
entity: parse_message_entity(text, entity) for entity in entities if entity.type in types
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains helper functions related to enums.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
import enum as _enum
|
|
||||||
import sys
|
|
||||||
from typing import TypeVar, Union
|
|
||||||
|
|
||||||
_A = TypeVar("_A")
|
|
||||||
_B = TypeVar("_B")
|
|
||||||
_Enum = TypeVar("_Enum", bound=_enum.Enum)
|
|
||||||
|
|
||||||
|
|
||||||
def get_member(enum_cls: type[_Enum], value: _A, default: _B) -> Union[_Enum, _A, _B]:
|
|
||||||
"""Tries to call ``enum_cls(value)`` to convert the value into an enumeration member.
|
|
||||||
If that fails, the ``default`` is returned.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return enum_cls(value)
|
|
||||||
except ValueError:
|
|
||||||
return default
|
|
||||||
|
|
||||||
|
|
||||||
# Python 3.11 and above has a different output for mixin classes for IntEnum, StrEnum and IntFlag
|
|
||||||
# see https://docs.python.org/3.11/library/enum.html#notes. We want e.g. str(StrEnumTest.FOO) to
|
|
||||||
# return "foo" instead of "StrEnumTest.FOO", which is not the case < py3.11
|
|
||||||
class StringEnum(str, _enum.Enum):
|
|
||||||
"""Helper class for string enums where ``str(member)`` prints the value, but ``repr(member)``
|
|
||||||
gives ``EnumName.MEMBER_NAME``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<{self.__class__.__name__}.{self.name}>"
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return str.__str__(self)
|
|
||||||
|
|
||||||
|
|
||||||
# Apply the __repr__ modification and __str__ fix to IntEnum
|
|
||||||
class IntEnum(_enum.IntEnum): # pylint: disable=invalid-slots
|
|
||||||
"""Helper class for int enums where ``str(member)`` prints the value, but ``repr(member)``
|
|
||||||
gives ``EnumName.MEMBER_NAME``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<{self.__class__.__name__}.{self.name}>"
|
|
||||||
|
|
||||||
if sys.version_info < (3, 11):
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return str(self.value)
|
|
||||||
|
|
||||||
|
|
||||||
class FloatEnum(float, _enum.Enum):
|
|
||||||
"""Helper class for float enums where ``str(member)`` prints the value, but ``repr(member)``
|
|
||||||
gives ``EnumName.MEMBER_NAME``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<{self.__class__.__name__}.{self.name}>"
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return str(self.value)
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains helper functions related to handling of files.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
Previously, the contents of this module were available through the (no longer existing)
|
|
||||||
module ``telegram._utils.helpers``.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import IO, TYPE_CHECKING, Any, Optional, TypeVar, Union, cast, overload
|
|
||||||
|
|
||||||
from telegram._utils.types import FileInput, FilePathInput
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import InputFile, TelegramObject
|
|
||||||
|
|
||||||
_T = TypeVar("_T", bound=Union[bytes, "InputFile", str, Path, None])
|
|
||||||
|
|
||||||
|
|
||||||
@overload
|
|
||||||
def load_file(obj: IO[bytes]) -> tuple[Optional[str], bytes]: ...
|
|
||||||
|
|
||||||
|
|
||||||
@overload
|
|
||||||
def load_file(obj: _T) -> tuple[None, _T]: ...
|
|
||||||
|
|
||||||
|
|
||||||
def load_file(
|
|
||||||
obj: Optional[FileInput],
|
|
||||||
) -> tuple[Optional[str], Union[bytes, "InputFile", str, Path, None]]:
|
|
||||||
"""If the input is a file handle, read the data and name and return it. Otherwise, return
|
|
||||||
the input unchanged.
|
|
||||||
"""
|
|
||||||
if obj is None:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
try:
|
|
||||||
contents = obj.read() # type: ignore[union-attr]
|
|
||||||
except AttributeError:
|
|
||||||
return None, cast(Union[bytes, "InputFile", str, Path], obj)
|
|
||||||
|
|
||||||
filename = guess_file_name(obj)
|
|
||||||
|
|
||||||
return filename, contents
|
|
||||||
|
|
||||||
|
|
||||||
def guess_file_name(obj: FileInput) -> Optional[str]:
|
|
||||||
"""If the input is a file handle, read name and return it. Otherwise, return
|
|
||||||
the input unchanged.
|
|
||||||
"""
|
|
||||||
if hasattr(obj, "name") and not isinstance(obj.name, int):
|
|
||||||
return Path(obj.name).name
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def is_local_file(obj: Optional[FilePathInput]) -> bool:
|
|
||||||
"""
|
|
||||||
Checks if a given string is a file on local system.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
obj (:obj:`str`): The string to check.
|
|
||||||
"""
|
|
||||||
if obj is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
path = Path(obj)
|
|
||||||
try:
|
|
||||||
return path.is_file()
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def parse_file_input( # pylint: disable=too-many-return-statements
|
|
||||||
file_input: Union[FileInput, "TelegramObject"],
|
|
||||||
tg_type: Optional[type["TelegramObject"]] = None,
|
|
||||||
filename: Optional[str] = None,
|
|
||||||
attach: bool = False,
|
|
||||||
local_mode: bool = False,
|
|
||||||
) -> Union[str, "InputFile", Any]:
|
|
||||||
"""
|
|
||||||
Parses input for sending files:
|
|
||||||
|
|
||||||
* For string input, if the input is an absolute path of a local file:
|
|
||||||
|
|
||||||
* if ``local_mode`` is ``True``, adds the ``file://`` prefix. If the input is a relative
|
|
||||||
path of a local file, computes the absolute path and adds the ``file://`` prefix.
|
|
||||||
* if ``local_mode`` is ``False``, loads the file as binary data and builds an
|
|
||||||
:class:`InputFile` from that
|
|
||||||
|
|
||||||
Returns the input unchanged, otherwise.
|
|
||||||
* :class:`pathlib.Path` objects are treated the same way as strings.
|
|
||||||
* For IO and bytes input, returns an :class:`telegram.InputFile`.
|
|
||||||
* If :attr:`tg_type` is specified and the input is of that type, returns the ``file_id``
|
|
||||||
attribute.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_input (:obj:`str` | :obj:`bytes` | :term:`file object` | :class:`~telegram.InputFile`\
|
|
||||||
| Telegram media object): The input to parse.
|
|
||||||
tg_type (:obj:`type`, optional): The Telegram media type the input can be. E.g.
|
|
||||||
:class:`telegram.Animation`.
|
|
||||||
filename (:obj:`str`, optional): The filename. Only relevant in case an
|
|
||||||
:class:`telegram.InputFile` is returned.
|
|
||||||
attach (:obj:`bool`, optional): Pass :obj:`True` if the parameter this file belongs to in
|
|
||||||
the request to Telegram should point to the multipart data via an ``attach://`` URI.
|
|
||||||
Defaults to `False`. Only relevant if an :class:`telegram.InputFile` is returned.
|
|
||||||
local_mode (:obj:`bool`, optional): Pass :obj:`True` if the bot is running an api server
|
|
||||||
in ``--local`` mode.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str` | :class:`telegram.InputFile` | :obj:`object`: The parsed input or the untouched
|
|
||||||
:attr:`file_input`, in case it's no valid file input.
|
|
||||||
"""
|
|
||||||
# Importing on file-level yields cyclic Import Errors
|
|
||||||
from telegram import InputFile # pylint: disable=import-outside-toplevel
|
|
||||||
|
|
||||||
if isinstance(file_input, str) and file_input.startswith("file://"):
|
|
||||||
if not local_mode:
|
|
||||||
raise ValueError("Specified file input is a file URI, but local mode is not enabled.")
|
|
||||||
return file_input
|
|
||||||
if isinstance(file_input, (str, Path)):
|
|
||||||
if is_local_file(file_input):
|
|
||||||
path = Path(file_input)
|
|
||||||
if local_mode:
|
|
||||||
return path.absolute().as_uri()
|
|
||||||
return InputFile(path.open(mode="rb"), filename=filename, attach=attach)
|
|
||||||
|
|
||||||
return file_input
|
|
||||||
if isinstance(file_input, bytes):
|
|
||||||
return InputFile(file_input, filename=filename, attach=attach)
|
|
||||||
if hasattr(file_input, "read"):
|
|
||||||
return InputFile(cast(IO, file_input), filename=filename, attach=attach)
|
|
||||||
if tg_type and isinstance(file_input, tg_type):
|
|
||||||
return file_input.file_id # type: ignore[attr-defined]
|
|
||||||
return file_input
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains helper functions related to logging.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
def get_logger(file_name: str, class_name: Optional[str] = None) -> logging.Logger:
|
|
||||||
"""Returns a logger with an appropriate name.
|
|
||||||
Use as follows::
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
|
||||||
|
|
||||||
If for example `__name__` is `telegram.ext._updater`, the logger will be named
|
|
||||||
`telegram.ext.Updater`. If `class_name` is passed, this will result in
|
|
||||||
`telegram.ext.<class_name>`. Useful e.g. for CamelCase class names.
|
|
||||||
|
|
||||||
If the file name points to a utils module, the logger name will simply be `telegram(.ext)`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:class:`logging.Logger`: The logger.
|
|
||||||
"""
|
|
||||||
parts = file_name.split("_")
|
|
||||||
if parts[1].startswith("utils") and class_name is None:
|
|
||||||
name = parts[0].rstrip(".")
|
|
||||||
else:
|
|
||||||
name = f"{parts[0]}{class_name or parts[1].capitalize()}"
|
|
||||||
return logging.getLogger(name)
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains a helper function for Telegram's ReplyMarkups
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
Previously, the contents of this module were available through the (no longer existing)
|
|
||||||
class ``telegram.ReplyMarkup``.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
from collections.abc import Sequence
|
|
||||||
|
|
||||||
|
|
||||||
def check_keyboard_type(keyboard: object) -> bool:
|
|
||||||
"""Checks if the keyboard provided is of the correct type - A sequence of sequences.
|
|
||||||
Implicitly tested in the init-tests of `{Inline, Reply}KeyboardMarkup`
|
|
||||||
"""
|
|
||||||
# string and bytes may actually be used for ReplyKeyboardMarkup in which case each button
|
|
||||||
# would contain a single character. But that use case should be discouraged and we don't
|
|
||||||
# allow it here.
|
|
||||||
if not isinstance(keyboard, Sequence) or isinstance(keyboard, (str, bytes)):
|
|
||||||
return False
|
|
||||||
|
|
||||||
for row in keyboard:
|
|
||||||
if not isinstance(row, Sequence) or isinstance(row, (str, bytes)):
|
|
||||||
return False
|
|
||||||
for inner in row:
|
|
||||||
if isinstance(inner, Sequence) and not isinstance(inner, str):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains auxiliary functionality for building strings for __repr__ method.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
|
|
||||||
def build_repr_with_selected_attrs(obj: object, **kwargs: Any) -> str:
|
|
||||||
"""Create ``__repr__`` string in the style ``Classname[arg1=1, arg2=2]``.
|
|
||||||
|
|
||||||
The square brackets emphasize the fact that an object cannot be instantiated
|
|
||||||
from this string.
|
|
||||||
|
|
||||||
Attributes that are to be used in the representation, are passed as kwargs.
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
f"{obj.__class__.__name__}"
|
|
||||||
# square brackets emphasize that an object cannot be instantiated with these params
|
|
||||||
f"[{', '.join(_stringify(name, value) for name, value in kwargs.items())}]"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _stringify(key: str, val: Any) -> str:
|
|
||||||
return f"{key}={val.__qualname__ if callable(val) else val}"
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains a helper functions related to string manipulation.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from telegram._utils.enum import StringEnum
|
|
||||||
|
|
||||||
# TODO: Remove this when https://github.com/PyCQA/pylint/issues/6887 is resolved.
|
|
||||||
# pylint: disable=invalid-enum-extension
|
|
||||||
|
|
||||||
|
|
||||||
class TextEncoding(StringEnum):
|
|
||||||
"""This enum contains encoding schemes for text.
|
|
||||||
|
|
||||||
.. versionadded:: 21.5
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
UTF_8 = "utf-8"
|
|
||||||
UTF_16_LE = "utf-16-le"
|
|
||||||
|
|
||||||
|
|
||||||
def to_camel_case(snake_str: str) -> str:
|
|
||||||
"""Converts a snake_case string to camelCase.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
snake_str (:obj:`str`): The string to convert.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`: The converted string.
|
|
||||||
"""
|
|
||||||
components = snake_str.split("_")
|
|
||||||
return components[0] + "".join(x.title() for x in components[1:])
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains custom typing aliases for internal use within the library.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
from collections.abc import Collection
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import IO, TYPE_CHECKING, Any, Literal, Optional, TypeVar, Union
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import (
|
|
||||||
ForceReply,
|
|
||||||
InlineKeyboardMarkup,
|
|
||||||
InputFile,
|
|
||||||
ReplyKeyboardMarkup,
|
|
||||||
ReplyKeyboardRemove,
|
|
||||||
)
|
|
||||||
from telegram._utils.defaultvalue import DefaultValue
|
|
||||||
|
|
||||||
FileLike = Union[IO[bytes], "InputFile"]
|
|
||||||
"""Either a bytes-stream (e.g. open file handler) or a :class:`telegram.InputFile`."""
|
|
||||||
|
|
||||||
FilePathInput = Union[str, Path]
|
|
||||||
"""A filepath either as string or as :obj:`pathlib.Path` object."""
|
|
||||||
|
|
||||||
FileInput = Union[FilePathInput, FileLike, bytes, str]
|
|
||||||
"""Valid input for passing files to Telegram. Either a file id as string, a file like object,
|
|
||||||
a local file path as string, :class:`pathlib.Path` or the file contents as :obj:`bytes`."""
|
|
||||||
|
|
||||||
JSONDict = dict[str, Any]
|
|
||||||
"""Dictionary containing response from Telegram or data to send to the API."""
|
|
||||||
|
|
||||||
DVValueType = TypeVar("DVValueType") # pylint: disable=invalid-name
|
|
||||||
DVType = Union[DVValueType, "DefaultValue[DVValueType]"]
|
|
||||||
"""Generic type for a variable which can be either `type` or `DefaultVaule[type]`."""
|
|
||||||
ODVInput = Optional[Union["DefaultValue[DVValueType]", DVValueType, "DefaultValue[None]"]]
|
|
||||||
"""Generic type for bot method parameters which can have defaults. ``ODVInput[type]`` is the same
|
|
||||||
as ``Optional[Union[DefaultValue[type], type, DefaultValue[None]]``."""
|
|
||||||
DVInput = Union["DefaultValue[DVValueType]", DVValueType, "DefaultValue[None]"]
|
|
||||||
"""Generic type for bot method parameters which can have defaults. ``DVInput[type]`` is the same
|
|
||||||
as ``Union[DefaultValue[type], type, DefaultValue[None]]``."""
|
|
||||||
|
|
||||||
RT = TypeVar("RT")
|
|
||||||
SCT = Union[RT, Collection[RT]] # pylint: disable=invalid-name
|
|
||||||
"""Single instance or collection of instances."""
|
|
||||||
|
|
||||||
ReplyMarkup = Union[
|
|
||||||
"InlineKeyboardMarkup", "ReplyKeyboardMarkup", "ReplyKeyboardRemove", "ForceReply"
|
|
||||||
]
|
|
||||||
"""Type alias for reply markup objects.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
|
|
||||||
FieldTuple = tuple[str, Union[bytes, IO[bytes]], str]
|
|
||||||
"""Alias for return type of `InputFile.field_tuple`."""
|
|
||||||
UploadFileDict = dict[str, FieldTuple]
|
|
||||||
"""Dictionary containing file data to be uploaded to the API."""
|
|
||||||
|
|
||||||
HTTPVersion = Literal["1.1", "2.0", "2"]
|
|
||||||
"""Allowed HTTP versions.
|
|
||||||
|
|
||||||
.. versionadded:: 20.4"""
|
|
||||||
|
|
||||||
CorrectOptionID = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
||||||
|
|
||||||
MarkdownVersion = Literal[1, 2]
|
|
||||||
|
|
||||||
SocketOpt = Union[
|
|
||||||
tuple[int, int, int],
|
|
||||||
tuple[int, int, Union[bytes, bytearray]],
|
|
||||||
tuple[int, int, None, int],
|
|
||||||
]
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains helper functions related to warnings issued by the library.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Contents of this module are intended to be used internally by the library and *not* by the
|
|
||||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
|
||||||
the changelog.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from telegram.warnings import PTBUserWarning
|
|
||||||
|
|
||||||
|
|
||||||
def warn(
|
|
||||||
message: Union[str, PTBUserWarning],
|
|
||||||
category: type[Warning] = PTBUserWarning,
|
|
||||||
stacklevel: int = 0,
|
|
||||||
) -> None:
|
|
||||||
"""
|
|
||||||
Helper function used as a shortcut for warning with default values.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
Args:
|
|
||||||
message (:obj:`str` | :obj:`PTBUserWarning`): Specify the warnings message to pass to
|
|
||||||
``warnings.warn()``.
|
|
||||||
|
|
||||||
.. versionchanged:: 21.2
|
|
||||||
Now also accepts a :obj:`PTBUserWarning` instance.
|
|
||||||
|
|
||||||
category (:obj:`type[Warning]`, optional): Specify the Warning class to pass to
|
|
||||||
``warnings.warn()``. Defaults to :class:`telegram.warnings.PTBUserWarning`.
|
|
||||||
stacklevel (:obj:`int`, optional): Specify the stacklevel to pass to ``warnings.warn()``.
|
|
||||||
Pass the same value as you'd pass directly to ``warnings.warn()``. Defaults to ``0``.
|
|
||||||
"""
|
|
||||||
warnings.warn(message, category=category, stacklevel=stacklevel + 1)
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains functionality used for transition warnings issued by this library.
|
|
||||||
|
|
||||||
It was created to prevent circular imports that would be caused by creating the warnings
|
|
||||||
inside warnings.py.
|
|
||||||
|
|
||||||
.. versionadded:: 20.2
|
|
||||||
"""
|
|
||||||
from typing import Any, Callable, Union
|
|
||||||
|
|
||||||
from telegram._utils.warnings import warn
|
|
||||||
from telegram.warnings import PTBDeprecationWarning, PTBUserWarning
|
|
||||||
|
|
||||||
|
|
||||||
def build_deprecation_warning_message(
|
|
||||||
deprecated_name: str,
|
|
||||||
new_name: str,
|
|
||||||
object_type: str,
|
|
||||||
bot_api_version: str,
|
|
||||||
) -> str:
|
|
||||||
"""Builds a warning message for the transition in API when an object is renamed.
|
|
||||||
|
|
||||||
Returns a warning message that can be used in `warn` function.
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
f"The {object_type} '{deprecated_name}' was renamed to '{new_name}' in Bot API "
|
|
||||||
f"{bot_api_version}. We recommend using '{new_name}' instead of "
|
|
||||||
f"'{deprecated_name}'."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Narrower type hints will cause linting errors and/or circular imports.
|
|
||||||
# We'll use `Any` here and put type hints in the calling code.
|
|
||||||
def warn_about_deprecated_arg_return_new_arg(
|
|
||||||
deprecated_arg: Any,
|
|
||||||
new_arg: Any,
|
|
||||||
deprecated_arg_name: str,
|
|
||||||
new_arg_name: str,
|
|
||||||
bot_api_version: str,
|
|
||||||
ptb_version: str,
|
|
||||||
stacklevel: int = 2,
|
|
||||||
warn_callback: Callable[[Union[str, PTBUserWarning], type[Warning], int], None] = warn,
|
|
||||||
) -> Any:
|
|
||||||
"""A helper function for the transition in API when argument is renamed.
|
|
||||||
|
|
||||||
Checks the `deprecated_arg` and `new_arg` objects; warns if non-None `deprecated_arg` object
|
|
||||||
was passed. Returns `new_arg` object (either the one originally passed by the user or the one
|
|
||||||
that user passed as `deprecated_arg`).
|
|
||||||
|
|
||||||
Raises `ValueError` if both `deprecated_arg` and `new_arg` objects were passed, and they are
|
|
||||||
different.
|
|
||||||
"""
|
|
||||||
if deprecated_arg and new_arg and deprecated_arg != new_arg:
|
|
||||||
base_message = build_deprecation_warning_message(
|
|
||||||
deprecated_name=deprecated_arg_name,
|
|
||||||
new_name=new_arg_name,
|
|
||||||
object_type="parameter",
|
|
||||||
bot_api_version=bot_api_version,
|
|
||||||
)
|
|
||||||
raise ValueError(
|
|
||||||
f"You passed different entities as '{deprecated_arg_name}' and '{new_arg_name}'. "
|
|
||||||
f"{base_message}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if deprecated_arg:
|
|
||||||
warn_callback(
|
|
||||||
PTBDeprecationWarning(
|
|
||||||
ptb_version,
|
|
||||||
f"Bot API {bot_api_version} renamed the argument '{deprecated_arg_name}' to "
|
|
||||||
f"'{new_arg_name}'.",
|
|
||||||
),
|
|
||||||
stacklevel=stacklevel + 1, # type: ignore[call-arg]
|
|
||||||
)
|
|
||||||
return deprecated_arg
|
|
||||||
|
|
||||||
return new_arg
|
|
||||||
|
|
||||||
|
|
||||||
def warn_about_deprecated_attr_in_property(
|
|
||||||
deprecated_attr_name: str,
|
|
||||||
new_attr_name: str,
|
|
||||||
bot_api_version: str,
|
|
||||||
ptb_version: str,
|
|
||||||
stacklevel: int = 2,
|
|
||||||
) -> None:
|
|
||||||
"""A helper function for the transition in API when attribute is renamed. Call from properties.
|
|
||||||
|
|
||||||
The properties replace deprecated attributes in classes and issue these deprecation warnings.
|
|
||||||
"""
|
|
||||||
warn(
|
|
||||||
PTBDeprecationWarning(
|
|
||||||
ptb_version,
|
|
||||||
f"Bot API {bot_api_version} renamed the attribute '{deprecated_attr_name}' to "
|
|
||||||
f"'{new_attr_name}'.",
|
|
||||||
),
|
|
||||||
stacklevel=stacklevel + 1,
|
|
||||||
)
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
# pylint: disable=missing-module-docstring
|
|
||||||
from typing import Final, NamedTuple
|
|
||||||
|
|
||||||
__all__ = ("__version__", "__version_info__")
|
|
||||||
|
|
||||||
|
|
||||||
class Version(NamedTuple):
|
|
||||||
"""Copies the behavior of sys.version_info.
|
|
||||||
serial is always 0 for stable releases.
|
|
||||||
"""
|
|
||||||
|
|
||||||
major: int
|
|
||||||
minor: int
|
|
||||||
micro: int
|
|
||||||
releaselevel: str # Literal['alpha', 'beta', 'candidate', 'final']
|
|
||||||
serial: int
|
|
||||||
|
|
||||||
def _rl_shorthand(self) -> str:
|
|
||||||
return {
|
|
||||||
"alpha": "a",
|
|
||||||
"beta": "b",
|
|
||||||
"candidate": "rc",
|
|
||||||
}[self.releaselevel]
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
version = f"{self.major}.{self.minor}"
|
|
||||||
if self.micro != 0:
|
|
||||||
version = f"{version}.{self.micro}"
|
|
||||||
if self.releaselevel != "final":
|
|
||||||
version = f"{version}{self._rl_shorthand()}{self.serial}"
|
|
||||||
|
|
||||||
return version
|
|
||||||
|
|
||||||
|
|
||||||
__version_info__: Final[Version] = Version(
|
|
||||||
major=21, minor=10, micro=0, releaselevel="final", serial=0
|
|
||||||
)
|
|
||||||
__version__: Final[str] = str(__version_info__)
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains objects related to Telegram video chats."""
|
|
||||||
import datetime as dtm
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._user import User
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class VideoChatStarted(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents a service message about a video
|
|
||||||
chat started in the chat. Currently holds no information.
|
|
||||||
|
|
||||||
.. versionadded:: 13.4
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
This class was renamed from ``VoiceChatStarted`` in accordance to Bot API 6.0.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class VideoChatEnded(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents a service message about a
|
|
||||||
video chat ended in the chat.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality.
|
|
||||||
Two objects of this class are considered equal, if their
|
|
||||||
:attr:`duration` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 13.4
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
This class was renamed from ``VoiceChatEnded`` in accordance to Bot API 6.0.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
duration (:obj:`int`): Voice chat duration in seconds.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
duration (:obj:`int`): Voice chat duration in seconds.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("duration",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
duration: int,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.duration: int = duration
|
|
||||||
self._id_attrs = (self.duration,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
|
|
||||||
class VideoChatParticipantsInvited(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents a service message about new members invited to a video chat.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality.
|
|
||||||
Two objects of this class are considered equal, if their :attr:`users` are equal.
|
|
||||||
|
|
||||||
.. versionadded:: 13.4
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
This class was renamed from ``VoiceChatParticipantsInvited`` in accordance to Bot API 6.0.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
users (Sequence[:class:`telegram.User`]): New members that were invited to the video chat.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
users (tuple[:class:`telegram.User`]): New members that were invited to the video chat.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|tupleclassattrs|
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("users",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
users: Sequence[User],
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.users: tuple[User, ...] = parse_sequence_arg(users)
|
|
||||||
self._id_attrs = (self.users,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["VideoChatParticipantsInvited"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
data["users"] = User.de_list(data.get("users", []), bot)
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class VideoChatScheduled(TelegramObject):
|
|
||||||
"""This object represents a service message about a video chat scheduled in the chat.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`start_date` are equal.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
This class was renamed from ``VoiceChatScheduled`` in accordance to Bot API 6.0.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the video
|
|
||||||
chat is supposed to be started by a chat administrator
|
|
||||||
|
|
||||||
.. versionchanged:: 20.3
|
|
||||||
|datetime_localization|
|
|
||||||
Attributes:
|
|
||||||
start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the video
|
|
||||||
chat is supposed to be started by a chat administrator
|
|
||||||
|
|
||||||
.. versionchanged:: 20.3
|
|
||||||
|datetime_localization|
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("start_date",)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
start_date: dtm.datetime,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.start_date: dtm.datetime = start_date
|
|
||||||
|
|
||||||
self._id_attrs = (self.start_date,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["VideoChatScheduled"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Get the local timezone from the bot if it has defaults
|
|
||||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
|
||||||
|
|
||||||
data["start_date"] = from_timestamp(data["start_date"], tzinfo=loc_tzinfo)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram WebAppData."""
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class WebAppData(TelegramObject):
|
|
||||||
"""Contains data sent from a `Web App <https://core.telegram.org/bots/webapps>`_ to the bot.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`data` and :attr:`button_text` are equal.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
:any:`Webapp Bot <examples.webappbot>`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (:obj:`str`): The data. Be aware that a bad client can send arbitrary data in this
|
|
||||||
field.
|
|
||||||
button_text (:obj:`str`): Text of the :paramref:`~telegram.KeyboardButton.web_app` keyboard
|
|
||||||
button, from which the Web App was opened.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
data (:obj:`str`): The data. Be aware that a bad client can send arbitrary data in this
|
|
||||||
field.
|
|
||||||
button_text (:obj:`str`): Text of the :paramref:`~telegram.KeyboardButton.web_app` keyboard
|
|
||||||
button, from which the Web App was opened.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
Be aware that a bad client can send arbitrary data in this field.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("button_text", "data")
|
|
||||||
|
|
||||||
def __init__(self, data: str, button_text: str, *, api_kwargs: Optional[JSONDict] = None):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.data: str = data
|
|
||||||
self.button_text: str = button_text
|
|
||||||
|
|
||||||
self._id_attrs = (self.data, self.button_text)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram Web App Info."""
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class WebAppInfo(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object contains information about a `Web App <https://core.telegram.org/bots/webapps>`_.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`url` are equal.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
:any:`Webapp Bot <examples.webappbot>`
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
Args:
|
|
||||||
url (:obj:`str`): An HTTPS URL of a Web App to be opened with additional data as specified
|
|
||||||
in `Initializing Web Apps \
|
|
||||||
<https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
url (:obj:`str`): An HTTPS URL of a Web App to be opened with additional data as specified
|
|
||||||
in `Initializing Web Apps \
|
|
||||||
<https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("url",)
|
|
||||||
|
|
||||||
def __init__(self, url: str, *, api_kwargs: Optional[JSONDict] = None):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.url: str = url
|
|
||||||
|
|
||||||
self._id_attrs = (self.url,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains an object that represents a Telegram WebhookInfo."""
|
|
||||||
|
|
||||||
import datetime as dtm
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
|
||||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from telegram import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class WebhookInfo(TelegramObject):
|
|
||||||
"""This object represents a Telegram WebhookInfo.
|
|
||||||
|
|
||||||
Contains information about the current status of a webhook.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`url`, :attr:`has_custom_certificate`,
|
|
||||||
:attr:`pending_update_count`, :attr:`ip_address`, :attr:`last_error_date`,
|
|
||||||
:attr:`last_error_message`, :attr:`max_connections`, :attr:`allowed_updates` and
|
|
||||||
:attr:`last_synchronization_error_date` are equal.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
:attr:`last_synchronization_error_date` is considered as well when comparing objects of
|
|
||||||
this type in terms of equality.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
url (:obj:`str`): Webhook URL, may be empty if webhook is not set up.
|
|
||||||
has_custom_certificate (:obj:`bool`): :obj:`True`, if a custom certificate was provided for
|
|
||||||
webhook certificate checks.
|
|
||||||
pending_update_count (:obj:`int`): Number of updates awaiting delivery.
|
|
||||||
ip_address (:obj:`str`, optional): Currently used webhook IP address.
|
|
||||||
last_error_date (:class:`datetime.datetime`): Optional. Datetime for the most recent
|
|
||||||
error that happened when trying to deliver an update via webhook.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.3
|
|
||||||
|datetime_localization|
|
|
||||||
last_error_message (:obj:`str`, optional): Error message in human-readable format for the
|
|
||||||
most recent error that happened when trying to deliver an update via webhook.
|
|
||||||
max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS
|
|
||||||
connections to the webhook for update delivery.
|
|
||||||
allowed_updates (Sequence[:obj:`str`], optional): A sequence of update types the bot is
|
|
||||||
subscribed to. Defaults to all update types, except
|
|
||||||
:attr:`telegram.Update.chat_member`.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|sequenceclassargs|
|
|
||||||
|
|
||||||
last_synchronization_error_date (:class:`datetime.datetime`, optional): Datetime of the
|
|
||||||
most recent error that happened when trying to synchronize available updates with
|
|
||||||
Telegram datacenters.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
.. versionchanged:: 20.3
|
|
||||||
|datetime_localization|
|
|
||||||
Attributes:
|
|
||||||
url (:obj:`str`): Webhook URL, may be empty if webhook is not set up.
|
|
||||||
has_custom_certificate (:obj:`bool`): :obj:`True`, if a custom certificate was provided for
|
|
||||||
webhook certificate checks.
|
|
||||||
pending_update_count (:obj:`int`): Number of updates awaiting delivery.
|
|
||||||
ip_address (:obj:`str`): Optional. Currently used webhook IP address.
|
|
||||||
last_error_date (:class:`datetime.datetime`): Optional. Datetime for the most recent
|
|
||||||
error that happened when trying to deliver an update via webhook.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.3
|
|
||||||
|datetime_localization|
|
|
||||||
last_error_message (:obj:`str`): Optional. Error message in human-readable format for the
|
|
||||||
most recent error that happened when trying to deliver an update via webhook.
|
|
||||||
max_connections (:obj:`int`): Optional. Maximum allowed number of simultaneous HTTPS
|
|
||||||
connections to the webhook for update delivery.
|
|
||||||
allowed_updates (tuple[:obj:`str`]): Optional. A tuple of update types the bot is
|
|
||||||
subscribed to. Defaults to all update types, except
|
|
||||||
:attr:`telegram.Update.chat_member`.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
|
|
||||||
* |tupleclassattrs|
|
|
||||||
* |alwaystuple|
|
|
||||||
last_synchronization_error_date (:class:`datetime.datetime`, optional): Datetime of the
|
|
||||||
most recent error that happened when trying to synchronize available updates with
|
|
||||||
Telegram datacenters.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
|
|
||||||
.. versionchanged:: 20.3
|
|
||||||
|datetime_localization|
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"allowed_updates",
|
|
||||||
"has_custom_certificate",
|
|
||||||
"ip_address",
|
|
||||||
"last_error_date",
|
|
||||||
"last_error_message",
|
|
||||||
"last_synchronization_error_date",
|
|
||||||
"max_connections",
|
|
||||||
"pending_update_count",
|
|
||||||
"url",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
url: str,
|
|
||||||
has_custom_certificate: bool,
|
|
||||||
pending_update_count: int,
|
|
||||||
last_error_date: Optional[dtm.datetime] = None,
|
|
||||||
last_error_message: Optional[str] = None,
|
|
||||||
max_connections: Optional[int] = None,
|
|
||||||
allowed_updates: Optional[Sequence[str]] = None,
|
|
||||||
ip_address: Optional[str] = None,
|
|
||||||
last_synchronization_error_date: Optional[dtm.datetime] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
# Required
|
|
||||||
self.url: str = url
|
|
||||||
self.has_custom_certificate: bool = has_custom_certificate
|
|
||||||
self.pending_update_count: int = pending_update_count
|
|
||||||
|
|
||||||
# Optional
|
|
||||||
self.ip_address: Optional[str] = ip_address
|
|
||||||
self.last_error_date: Optional[dtm.datetime] = last_error_date
|
|
||||||
self.last_error_message: Optional[str] = last_error_message
|
|
||||||
self.max_connections: Optional[int] = max_connections
|
|
||||||
self.allowed_updates: tuple[str, ...] = parse_sequence_arg(allowed_updates)
|
|
||||||
self.last_synchronization_error_date: Optional[dtm.datetime] = (
|
|
||||||
last_synchronization_error_date
|
|
||||||
)
|
|
||||||
|
|
||||||
self._id_attrs = (
|
|
||||||
self.url,
|
|
||||||
self.has_custom_certificate,
|
|
||||||
self.pending_update_count,
|
|
||||||
self.ip_address,
|
|
||||||
self.last_error_date,
|
|
||||||
self.last_error_message,
|
|
||||||
self.max_connections,
|
|
||||||
self.allowed_updates,
|
|
||||||
self.last_synchronization_error_date,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def de_json(
|
|
||||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
|
||||||
) -> Optional["WebhookInfo"]:
|
|
||||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
|
||||||
data = cls._parse_data(data)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Get the local timezone from the bot if it has defaults
|
|
||||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
|
||||||
|
|
||||||
data["last_error_date"] = from_timestamp(data.get("last_error_date"), tzinfo=loc_tzinfo)
|
|
||||||
data["last_synchronization_error_date"] = from_timestamp(
|
|
||||||
data.get("last_synchronization_error_date"), tzinfo=loc_tzinfo
|
|
||||||
)
|
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains objects related to the write access allowed service message."""
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from telegram._telegramobject import TelegramObject
|
|
||||||
from telegram._utils.types import JSONDict
|
|
||||||
|
|
||||||
|
|
||||||
class WriteAccessAllowed(TelegramObject):
|
|
||||||
"""
|
|
||||||
This object represents a service message about a user allowing a bot to write messages after
|
|
||||||
adding it to the attachment menu, launching a Web App from a link, or accepting an explicit
|
|
||||||
request from a Web App sent by the method
|
|
||||||
`requestWriteAccess <https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
|
||||||
considered equal, if their :attr:`web_app_name` is equal.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
.. versionchanged:: 20.6
|
|
||||||
Added custom equality comparison for objects of this class.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
web_app_name (:obj:`str`, optional): Name of the Web App, if the access was granted when
|
|
||||||
the Web App was launched from a link.
|
|
||||||
|
|
||||||
.. versionadded:: 20.3
|
|
||||||
from_request (:obj:`bool`, optional): :obj:`True`, if the access was granted after the user
|
|
||||||
accepted an explicit request from a Web App sent by the method
|
|
||||||
`requestWriteAccess <https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
|
||||||
|
|
||||||
.. versionadded:: 20.6
|
|
||||||
from_attachment_menu (:obj:`bool`, optional): :obj:`True`, if the access was granted when
|
|
||||||
the bot was added to the attachment or side menu.
|
|
||||||
|
|
||||||
.. versionadded:: 20.6
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
web_app_name (:obj:`str`): Optional. Name of the Web App, if the access was granted when
|
|
||||||
the Web App was launched from a link.
|
|
||||||
|
|
||||||
.. versionadded:: 20.3
|
|
||||||
from_request (:obj:`bool`): Optional. :obj:`True`, if the access was granted after the user
|
|
||||||
accepted an explicit request from a Web App.
|
|
||||||
|
|
||||||
.. versionadded:: 20.6
|
|
||||||
from_attachment_menu (:obj:`bool`): Optional. :obj:`True`, if the access was granted when
|
|
||||||
the bot was added to the attachment or side menu.
|
|
||||||
|
|
||||||
.. versionadded:: 20.6
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("from_attachment_menu", "from_request", "web_app_name")
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
web_app_name: Optional[str] = None,
|
|
||||||
from_request: Optional[bool] = None,
|
|
||||||
from_attachment_menu: Optional[bool] = None,
|
|
||||||
*,
|
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
|
||||||
):
|
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
|
||||||
self.web_app_name: Optional[str] = web_app_name
|
|
||||||
self.from_request: Optional[bool] = from_request
|
|
||||||
self.from_attachment_menu: Optional[bool] = from_attachment_menu
|
|
||||||
|
|
||||||
self._id_attrs = (self.web_app_name,)
|
|
||||||
|
|
||||||
self._freeze()
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,252 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""This module contains classes that represent Telegram errors.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
Replaced ``Unauthorized`` by :class:`Forbidden`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__all__ = (
|
|
||||||
"BadRequest",
|
|
||||||
"ChatMigrated",
|
|
||||||
"Conflict",
|
|
||||||
"EndPointNotFound",
|
|
||||||
"Forbidden",
|
|
||||||
"InvalidToken",
|
|
||||||
"NetworkError",
|
|
||||||
"PassportDecryptionError",
|
|
||||||
"RetryAfter",
|
|
||||||
"TelegramError",
|
|
||||||
"TimedOut",
|
|
||||||
)
|
|
||||||
|
|
||||||
from typing import Optional, Union
|
|
||||||
|
|
||||||
|
|
||||||
class TelegramError(Exception):
|
|
||||||
"""
|
|
||||||
Base class for Telegram errors.
|
|
||||||
|
|
||||||
Tip:
|
|
||||||
Objects of this type can be serialized via Python's :mod:`pickle` module and pickled
|
|
||||||
objects from one version of PTB are usually loadable in future versions. However, we can
|
|
||||||
not guarantee that this compatibility will always be provided. At least a manual one-time
|
|
||||||
conversion of the data may be needed on major updates of the library.
|
|
||||||
|
|
||||||
.. seealso:: :wiki:`Exceptions, Warnings and Logging <Exceptions%2C-Warnings-and-Logging>`
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("message",)
|
|
||||||
|
|
||||||
def __init__(self, message: str):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
msg = message.removeprefix("Error: ")
|
|
||||||
msg = msg.removeprefix("[Error]: ")
|
|
||||||
msg = msg.removeprefix("Bad Request: ")
|
|
||||||
if msg != message:
|
|
||||||
# api_error - capitalize the msg...
|
|
||||||
msg = msg.capitalize()
|
|
||||||
self.message: str = msg
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
"""Gives the string representation of exceptions message.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`
|
|
||||||
"""
|
|
||||||
return self.message
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
"""Gives an unambiguous string representation of the exception.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`str`
|
|
||||||
"""
|
|
||||||
return f"{self.__class__.__name__}('{self.message}')"
|
|
||||||
|
|
||||||
def __reduce__(self) -> tuple[type, tuple[str]]:
|
|
||||||
"""Defines how to serialize the exception for pickle.
|
|
||||||
|
|
||||||
.. seealso::
|
|
||||||
:py:meth:`object.__reduce__`, :mod:`pickle`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`tuple`
|
|
||||||
"""
|
|
||||||
return self.__class__, (self.message,)
|
|
||||||
|
|
||||||
|
|
||||||
class Forbidden(TelegramError):
|
|
||||||
"""Raised when the bot has not enough rights to perform the requested action.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
:any:`Raw API Bot <examples.rawapibot>`
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
This class was previously named ``Unauthorized``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidToken(TelegramError):
|
|
||||||
"""Raised when the token is invalid.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
message (:obj:`str`, optional): Any additional information about the exception.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, message: Optional[str] = None) -> None:
|
|
||||||
super().__init__("Invalid token" if message is None else message)
|
|
||||||
|
|
||||||
|
|
||||||
class EndPointNotFound(TelegramError):
|
|
||||||
"""Raised when the requested endpoint is not found. Only relevant for
|
|
||||||
:meth:`telegram.Bot.do_api_request`.
|
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkError(TelegramError):
|
|
||||||
"""Base class for exceptions due to networking errors.
|
|
||||||
|
|
||||||
Tip:
|
|
||||||
This exception (and its subclasses) usually originates from the networking backend
|
|
||||||
used by :class:`~telegram.request.HTTPXRequest`, or a custom implementation of
|
|
||||||
:class:`~telegram.request.BaseRequest`. In this case, the original exception can be
|
|
||||||
accessed via the ``__cause__``
|
|
||||||
`attribute <https://docs.python.org/3/library/exceptions.html#exception-context>`_.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
:any:`Raw API Bot <examples.rawapibot>`
|
|
||||||
|
|
||||||
.. seealso::
|
|
||||||
:wiki:`Handling network errors <Handling-network-errors>`
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
|
|
||||||
class BadRequest(NetworkError):
|
|
||||||
"""Raised when Telegram could not process the request correctly."""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
|
|
||||||
class TimedOut(NetworkError):
|
|
||||||
"""Raised when a request took too long to finish.
|
|
||||||
|
|
||||||
.. seealso::
|
|
||||||
:wiki:`Handling network errors <Handling-network-errors>`
|
|
||||||
|
|
||||||
Args:
|
|
||||||
message (:obj:`str`, optional): Any additional information about the exception.
|
|
||||||
|
|
||||||
.. versionadded:: 20.0
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __init__(self, message: Optional[str] = None) -> None:
|
|
||||||
super().__init__(message or "Timed out")
|
|
||||||
|
|
||||||
|
|
||||||
class ChatMigrated(TelegramError):
|
|
||||||
"""
|
|
||||||
Raised when the requested group chat migrated to supergroup and has a new chat id.
|
|
||||||
|
|
||||||
.. seealso::
|
|
||||||
:wiki:`Storing Bot, User and Chat Related Data <Storing-bot%2C-user-and-chat-related-data>`
|
|
||||||
|
|
||||||
Args:
|
|
||||||
new_chat_id (:obj:`int`): The new chat id of the group.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
new_chat_id (:obj:`int`): The new chat id of the group.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("new_chat_id",)
|
|
||||||
|
|
||||||
def __init__(self, new_chat_id: int):
|
|
||||||
super().__init__(f"Group migrated to supergroup. New chat id: {new_chat_id}")
|
|
||||||
self.new_chat_id: int = new_chat_id
|
|
||||||
|
|
||||||
def __reduce__(self) -> tuple[type, tuple[int]]: # type: ignore[override]
|
|
||||||
return self.__class__, (self.new_chat_id,)
|
|
||||||
|
|
||||||
|
|
||||||
class RetryAfter(TelegramError):
|
|
||||||
"""
|
|
||||||
Raised when flood limits where exceeded.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
:attr:`retry_after` is now an integer to comply with the Bot API.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
retry_after (:obj:`int`): Time in seconds, after which the bot can retry the request.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
retry_after (:obj:`int`): Time in seconds, after which the bot can retry the request.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("retry_after",)
|
|
||||||
|
|
||||||
def __init__(self, retry_after: int):
|
|
||||||
super().__init__(f"Flood control exceeded. Retry in {retry_after} seconds")
|
|
||||||
self.retry_after: int = retry_after
|
|
||||||
|
|
||||||
def __reduce__(self) -> tuple[type, tuple[float]]: # type: ignore[override]
|
|
||||||
return self.__class__, (self.retry_after,)
|
|
||||||
|
|
||||||
|
|
||||||
class Conflict(TelegramError):
|
|
||||||
"""Raised when a long poll or webhook conflicts with another one."""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
def __reduce__(self) -> tuple[type, tuple[str]]:
|
|
||||||
return self.__class__, (self.message,)
|
|
||||||
|
|
||||||
|
|
||||||
class PassportDecryptionError(TelegramError):
|
|
||||||
"""Something went wrong with decryption.
|
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
|
||||||
This class was previously named ``TelegramDecryptionError`` and was available via
|
|
||||||
``telegram.TelegramDecryptionError``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ("_msg",)
|
|
||||||
|
|
||||||
def __init__(self, message: Union[str, Exception]):
|
|
||||||
super().__init__(f"PassportDecryptionError: {message}")
|
|
||||||
self._msg = str(message)
|
|
||||||
|
|
||||||
def __reduce__(self) -> tuple[type, tuple[str]]:
|
|
||||||
return self.__class__, (self._msg,)
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2025
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""Extensions over the Telegram Bot API to facilitate bot making"""
|
|
||||||
|
|
||||||
__all__ = (
|
|
||||||
"AIORateLimiter",
|
|
||||||
"Application",
|
|
||||||
"ApplicationBuilder",
|
|
||||||
"ApplicationHandlerStop",
|
|
||||||
"BaseHandler",
|
|
||||||
"BasePersistence",
|
|
||||||
"BaseRateLimiter",
|
|
||||||
"BaseUpdateProcessor",
|
|
||||||
"BusinessConnectionHandler",
|
|
||||||
"BusinessMessagesDeletedHandler",
|
|
||||||
"CallbackContext",
|
|
||||||
"CallbackDataCache",
|
|
||||||
"CallbackQueryHandler",
|
|
||||||
"ChatBoostHandler",
|
|
||||||
"ChatJoinRequestHandler",
|
|
||||||
"ChatMemberHandler",
|
|
||||||
"ChosenInlineResultHandler",
|
|
||||||
"CommandHandler",
|
|
||||||
"ContextTypes",
|
|
||||||
"ConversationHandler",
|
|
||||||
"Defaults",
|
|
||||||
"DictPersistence",
|
|
||||||
"ExtBot",
|
|
||||||
"InlineQueryHandler",
|
|
||||||
"InvalidCallbackData",
|
|
||||||
"Job",
|
|
||||||
"JobQueue",
|
|
||||||
"MessageHandler",
|
|
||||||
"MessageReactionHandler",
|
|
||||||
"PaidMediaPurchasedHandler",
|
|
||||||
"PersistenceInput",
|
|
||||||
"PicklePersistence",
|
|
||||||
"PollAnswerHandler",
|
|
||||||
"PollHandler",
|
|
||||||
"PreCheckoutQueryHandler",
|
|
||||||
"PrefixHandler",
|
|
||||||
"ShippingQueryHandler",
|
|
||||||
"SimpleUpdateProcessor",
|
|
||||||
"StringCommandHandler",
|
|
||||||
"StringRegexHandler",
|
|
||||||
"TypeHandler",
|
|
||||||
"Updater",
|
|
||||||
"filters",
|
|
||||||
)
|
|
||||||
|
|
||||||
from . import filters
|
|
||||||
from ._aioratelimiter import AIORateLimiter
|
|
||||||
from ._application import Application, ApplicationHandlerStop
|
|
||||||
from ._applicationbuilder import ApplicationBuilder
|
|
||||||
from ._basepersistence import BasePersistence, PersistenceInput
|
|
||||||
from ._baseratelimiter import BaseRateLimiter
|
|
||||||
from ._baseupdateprocessor import BaseUpdateProcessor, SimpleUpdateProcessor
|
|
||||||
from ._callbackcontext import CallbackContext
|
|
||||||
from ._callbackdatacache import CallbackDataCache, InvalidCallbackData
|
|
||||||
from ._contexttypes import ContextTypes
|
|
||||||
from ._defaults import Defaults
|
|
||||||
from ._dictpersistence import DictPersistence
|
|
||||||
from ._extbot import ExtBot
|
|
||||||
from ._handlers.basehandler import BaseHandler
|
|
||||||
from ._handlers.businessconnectionhandler import BusinessConnectionHandler
|
|
||||||
from ._handlers.businessmessagesdeletedhandler import BusinessMessagesDeletedHandler
|
|
||||||
from ._handlers.callbackqueryhandler import CallbackQueryHandler
|
|
||||||
from ._handlers.chatboosthandler import ChatBoostHandler
|
|
||||||
from ._handlers.chatjoinrequesthandler import ChatJoinRequestHandler
|
|
||||||
from ._handlers.chatmemberhandler import ChatMemberHandler
|
|
||||||
from ._handlers.choseninlineresulthandler import ChosenInlineResultHandler
|
|
||||||
from ._handlers.commandhandler import CommandHandler
|
|
||||||
from ._handlers.conversationhandler import ConversationHandler
|
|
||||||
from ._handlers.inlinequeryhandler import InlineQueryHandler
|
|
||||||
from ._handlers.messagehandler import MessageHandler
|
|
||||||
from ._handlers.messagereactionhandler import MessageReactionHandler
|
|
||||||
from ._handlers.paidmediapurchasedhandler import PaidMediaPurchasedHandler
|
|
||||||
from ._handlers.pollanswerhandler import PollAnswerHandler
|
|
||||||
from ._handlers.pollhandler import PollHandler
|
|
||||||
from ._handlers.precheckoutqueryhandler import PreCheckoutQueryHandler
|
|
||||||
from ._handlers.prefixhandler import PrefixHandler
|
|
||||||
from ._handlers.shippingqueryhandler import ShippingQueryHandler
|
|
||||||
from ._handlers.stringcommandhandler import StringCommandHandler
|
|
||||||
from ._handlers.stringregexhandler import StringRegexHandler
|
|
||||||
from ._handlers.typehandler import TypeHandler
|
|
||||||
from ._jobqueue import Job, JobQueue
|
|
||||||
from ._picklepersistence import PicklePersistence
|
|
||||||
from ._updater import Updater
|
|
||||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user