diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/encryptedpassportelement.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/encryptedpassportelement.cpython-311.pyc deleted file mode 100755 index f6f2a80..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/encryptedpassportelement.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportdata.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportdata.cpython-311.pyc deleted file mode 100755 index daa9f72..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportdata.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportelementerrors.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportelementerrors.cpython-311.pyc deleted file mode 100755 index 15465fe..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportelementerrors.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportfile.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportfile.cpython-311.pyc deleted file mode 100755 index de361ef..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportfile.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/credentials.py b/venv/lib/python3.11/site-packages/telegram/_passport/credentials.py deleted file mode 100755 index 8384fde..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/credentials.py +++ /dev/null @@ -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 -# -# 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/data.py b/venv/lib/python3.11/site-packages/telegram/_passport/data.py deleted file mode 100755 index 5cbd5c7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/data.py +++ /dev/null @@ -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 -# -# 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/encryptedpassportelement.py b/venv/lib/python3.11/site-packages/telegram/_passport/encryptedpassportelement.py deleted file mode 100755 index aa646df..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/encryptedpassportelement.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/passportdata.py b/venv/lib/python3.11/site-packages/telegram/_passport/passportdata.py deleted file mode 100755 index 200a458..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/passportdata.py +++ /dev/null @@ -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 -# -# 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/passportelementerrors.py b/venv/lib/python3.11/site-packages/telegram/_passport/passportelementerrors.py deleted file mode 100755 index d5a7446..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/passportelementerrors.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/passportfile.py b/venv/lib/python3.11/site-packages/telegram/_passport/passportfile.py deleted file mode 100755 index c9516e7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/passportfile.py +++ /dev/null @@ -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 -# -# 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__init__.py b/venv/lib/python3.11/site-packages/telegram/_payment/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index d365b75..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/invoice.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/invoice.cpython-311.pyc deleted file mode 100755 index a09eddf..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/invoice.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/labeledprice.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/labeledprice.cpython-311.pyc deleted file mode 100755 index dd41c5c..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/labeledprice.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/orderinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/orderinfo.cpython-311.pyc deleted file mode 100755 index 9cfe533..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/orderinfo.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/precheckoutquery.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/precheckoutquery.cpython-311.pyc deleted file mode 100755 index 55fe169..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/precheckoutquery.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/refundedpayment.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/refundedpayment.cpython-311.pyc deleted file mode 100755 index 986aa57..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/refundedpayment.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingaddress.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingaddress.cpython-311.pyc deleted file mode 100755 index e3d9ea0..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingaddress.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingoption.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingoption.cpython-311.pyc deleted file mode 100755 index 0555c4f..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingoption.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingquery.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingquery.cpython-311.pyc deleted file mode 100755 index 4331aff..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingquery.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/successfulpayment.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/successfulpayment.cpython-311.pyc deleted file mode 100755 index 8ad1be2..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/successfulpayment.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/invoice.py b/venv/lib/python3.11/site-packages/telegram/_payment/invoice.py deleted file mode 100755 index b6ec5d9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/invoice.py +++ /dev/null @@ -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 -# -# 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 `_, - 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 `_, - 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 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/labeledprice.py b/venv/lib/python3.11/site-packages/telegram/_payment/labeledprice.py deleted file mode 100755 index 3aa7091..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/labeledprice.py +++ /dev/null @@ -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 -# -# 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 ` - - 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 `_, - 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 `_, - 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/orderinfo.py b/venv/lib/python3.11/site-packages/telegram/_payment/orderinfo.py deleted file mode 100755 index ddd7aef..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/orderinfo.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/precheckoutquery.py b/venv/lib/python3.11/site-packages/telegram/_payment/precheckoutquery.py deleted file mode 100755 index 766f2a4..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/precheckoutquery.py +++ /dev/null @@ -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 -# -# 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 `_, - 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 `_, - 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, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/refundedpayment.py b/venv/lib/python3.11/site-packages/telegram/_payment/refundedpayment.py deleted file mode 100755 index 46ef4e3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/refundedpayment.py +++ /dev/null @@ -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 -# -# 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 - `_ 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 `_, - 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 - `_ 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 `_, - 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/shippingaddress.py b/venv/lib/python3.11/site-packages/telegram/_payment/shippingaddress.py deleted file mode 100755 index ed97e02..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/shippingaddress.py +++ /dev/null @@ -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 -# -# 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/shippingoption.py b/venv/lib/python3.11/site-packages/telegram/_payment/shippingoption.py deleted file mode 100755 index 341dbbe..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/shippingoption.py +++ /dev/null @@ -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 -# -# 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 ` - - 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/shippingquery.py b/venv/lib/python3.11/site-packages/telegram/_payment/shippingquery.py deleted file mode 100755 index fadf88c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/shippingquery.py +++ /dev/null @@ -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 -# -# 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, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__init__.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index ba34f9e..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/affiliateinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/affiliateinfo.cpython-311.pyc deleted file mode 100755 index 6481cd6..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/affiliateinfo.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/revenuewithdrawalstate.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/revenuewithdrawalstate.cpython-311.pyc deleted file mode 100755 index 712e73d..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/revenuewithdrawalstate.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/startransactions.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/startransactions.cpython-311.pyc deleted file mode 100755 index c0ee5e8..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/startransactions.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/transactionpartner.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/transactionpartner.cpython-311.pyc deleted file mode 100755 index 599d219..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/transactionpartner.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/affiliateinfo.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/affiliateinfo.py deleted file mode 100755 index 9026853..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/stars/affiliateinfo.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/revenuewithdrawalstate.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/revenuewithdrawalstate.py deleted file mode 100755 index be75ae4..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/stars/revenuewithdrawalstate.py +++ /dev/null @@ -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 -# -# 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/startransactions.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/startransactions.py deleted file mode 100755 index f53a0d1..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/stars/startransactions.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/transactionpartner.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/transactionpartner.py deleted file mode 100755 index 7c82bf0..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/stars/transactionpartner.py +++ /dev/null @@ -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 -# -# 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 `_. - - 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,) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/successfulpayment.py b/venv/lib/python3.11/site-packages/telegram/_payment/successfulpayment.py deleted file mode 100755 index 0642e30..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/successfulpayment.py +++ /dev/null @@ -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 -# -# 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 `_, - 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 `_, - 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_poll.py b/venv/lib/python3.11/site-packages/telegram/_poll.py deleted file mode 100755 index f26ac84..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_poll.py +++ /dev/null @@ -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 -# -# 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 ` - - 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 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_proximityalerttriggered.py b/venv/lib/python3.11/site-packages/telegram/_proximityalerttriggered.py deleted file mode 100755 index b4ea6a2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_proximityalerttriggered.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_reaction.py b/venv/lib/python3.11/site-packages/telegram/_reaction.py deleted file mode 100755 index 7d76b82..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_reaction.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_reply.py b/venv/lib/python3.11/site-packages/telegram/_reply.py deleted file mode 100755 index ba04b89..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_reply.py +++ /dev/null @@ -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 -# -# 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 - `_, 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 >> `. - 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 >> `. - 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 - `_, 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 >> `. - 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 >> `. - 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 ` 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 ` 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_replykeyboardmarkup.py b/venv/lib/python3.11/site-packages/telegram/_replykeyboardmarkup.py deleted file mode 100755 index 3928f82..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_replykeyboardmarkup.py +++ /dev/null @@ -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 -# -# 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 ` - * :any:`Conversation Bot 2 ` - - 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 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_replykeyboardremove.py b/venv/lib/python3.11/site-packages/telegram/_replykeyboardremove.py deleted file mode 100755 index 808bee2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_replykeyboardremove.py +++ /dev/null @@ -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 -# -# 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 ` - * :any:`Conversation Bot 2 ` - - 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_sentwebappmessage.py b/venv/lib/python3.11/site-packages/telegram/_sentwebappmessage.py deleted file mode 100755 index 492f440..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_sentwebappmessage.py +++ /dev/null @@ -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 -# -# 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 ` 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 ` 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_shared.py b/venv/lib/python3.11/site-packages/telegram/_shared.py deleted file mode 100755 index 5ba54ea..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_shared.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_story.py b/venv/lib/python3.11/site-packages/telegram/_story.py deleted file mode 100755 index 06832e0..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_story.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_switchinlinequerychosenchat.py b/venv/lib/python3.11/site-packages/telegram/_switchinlinequerychosenchat.py deleted file mode 100755 index 7fca5a9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_switchinlinequerychosenchat.py +++ /dev/null @@ -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 -# -# 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_telegramobject.py b/venv/lib/python3.11/site-packages/telegram/_telegramobject.py deleted file mode 100755 index baa739e..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_telegramobject.py +++ /dev/null @@ -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 -# -# 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_update.py b/venv/lib/python3.11/site-packages/telegram/_update.py deleted file mode 100755 index 34f8fe2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_update.py +++ /dev/null @@ -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 -# -# 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 ` - - 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 ` - 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_user.py b/venv/lib/python3.11/site-packages/telegram/_user.py deleted file mode 100755 index 0e9ce1f..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_user.py +++ /dev/null @@ -1,2336 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=redefined-builtin -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# 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 User.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional, Union - -from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton -from telegram._menubutton import MenuButton -from telegram._telegramobject import TelegramObject -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup -from telegram.helpers import mention_html as helpers_mention_html -from telegram.helpers import mention_markdown as helpers_mention_markdown - -if TYPE_CHECKING: - from telegram import ( - Animation, - Audio, - Contact, - Document, - Gift, - InlineKeyboardMarkup, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - InputPollOption, - LabeledPrice, - LinkPreviewOptions, - Location, - Message, - MessageEntity, - MessageId, - PhotoSize, - ReplyParameters, - Sticker, - UserChatBoosts, - UserProfilePhotos, - Venue, - Video, - VideoNote, - Voice, - ) - - -class User(TelegramObject): - """This object represents a Telegram user or bot. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - .. versionchanged:: 20.0 - The following are now keyword-only arguments in Bot methods: - ``location``, ``filename``, ``venue``, ``contact``, - ``{read, write, connect, pool}_timeout`` ``api_kwargs``. Use a named argument for those, - and notice that some positional arguments changed position as a result. - - Args: - id (:obj:`int`): Unique identifier for this user or bot. - is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. - first_name (:obj:`str`): User's or bot's first name. - last_name (:obj:`str`, optional): User's or bot's last name. - username (:obj:`str`, optional): User's or bot's username. - language_code (:obj:`str`, optional): IETF language tag of the user's language. - can_join_groups (:obj:`str`, optional): :obj:`True`, if the bot can be invited to groups. - Returned only in :meth:`telegram.Bot.get_me`. - can_read_all_group_messages (:obj:`str`, optional): :obj:`True`, if privacy mode is - disabled for the bot. Returned only in :meth:`telegram.Bot.get_me`. - supports_inline_queries (:obj:`str`, optional): :obj:`True`, if the bot supports inline - queries. Returned only in :meth:`telegram.Bot.get_me`. - - is_premium (:obj:`bool`, optional): :obj:`True`, if this user is a Telegram Premium user. - - .. versionadded:: 20.0 - added_to_attachment_menu (:obj:`bool`, optional): :obj:`True`, if this user added - the bot to the attachment menu. - - .. versionadded:: 20.0 - can_connect_to_business (:obj:`bool`, optional): :obj:`True`, if the bot can be connected - to a Telegram Business account to receive its messages. Returned only in - :meth:`telegram.Bot.get_me`. - - .. versionadded:: 21.1 - has_main_web_app (:obj:`bool`, optional): :obj:`True`, if the bot has the main Web App. - Returned only in :meth:`telegram.Bot.get_me`. - - .. versionadded:: 21.5 - - Attributes: - id (:obj:`int`): Unique identifier for this user or bot. - is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. - first_name (:obj:`str`): User's or bot's first name. - last_name (:obj:`str`): Optional. User's or bot's last name. - username (:obj:`str`): Optional. User's or bot's username. - language_code (:obj:`str`): Optional. IETF language tag of the user's language. - can_join_groups (:obj:`str`): Optional. :obj:`True`, if the bot can be invited to groups. - Returned only in :attr:`telegram.Bot.get_me` requests. - can_read_all_group_messages (:obj:`str`): Optional. :obj:`True`, if privacy mode is - disabled for the bot. Returned only in :attr:`telegram.Bot.get_me` requests. - supports_inline_queries (:obj:`str`): Optional. :obj:`True`, if the bot supports inline - queries. Returned only in :attr:`telegram.Bot.get_me` requests. - is_premium (:obj:`bool`): Optional. :obj:`True`, if this user is a Telegram - Premium user. - - .. versionadded:: 20.0 - added_to_attachment_menu (:obj:`bool`): Optional. :obj:`True`, if this user added - the bot to the attachment menu. - - .. versionadded:: 20.0 - can_connect_to_business (:obj:`bool`): Optional. :obj:`True`, if the bot can be connected - to a Telegram Business account to receive its messages. Returned only in - :meth:`telegram.Bot.get_me`. - - .. versionadded:: 21.1 - has_main_web_app (:obj:`bool`) Optional. :obj:`True`, if the bot has the main Web App. - Returned only in :meth:`telegram.Bot.get_me`. - - .. versionadded:: 21.5 - - .. |user_chat_id_note| replace:: This shortcuts build on the assumption that :attr:`User.id` - coincides with the :attr:`Chat.id` of the private chat with the user. This has been the - case so far, but Telegram does not guarantee that this stays this way. - """ - - __slots__ = ( - "added_to_attachment_menu", - "can_connect_to_business", - "can_join_groups", - "can_read_all_group_messages", - "first_name", - "has_main_web_app", - "id", - "is_bot", - "is_premium", - "language_code", - "last_name", - "supports_inline_queries", - "username", - ) - - def __init__( - self, - id: int, - first_name: str, - is_bot: bool, - last_name: Optional[str] = None, - username: Optional[str] = None, - language_code: Optional[str] = None, - can_join_groups: Optional[bool] = None, - can_read_all_group_messages: Optional[bool] = None, - supports_inline_queries: Optional[bool] = None, - is_premium: Optional[bool] = None, - added_to_attachment_menu: Optional[bool] = None, - can_connect_to_business: Optional[bool] = None, - has_main_web_app: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.id: int = id - self.first_name: str = first_name - self.is_bot: bool = is_bot - # Optionals - self.last_name: Optional[str] = last_name - self.username: Optional[str] = username - self.language_code: Optional[str] = language_code - self.can_join_groups: Optional[bool] = can_join_groups - self.can_read_all_group_messages: Optional[bool] = can_read_all_group_messages - self.supports_inline_queries: Optional[bool] = supports_inline_queries - self.is_premium: Optional[bool] = is_premium - self.added_to_attachment_menu: Optional[bool] = added_to_attachment_menu - self.can_connect_to_business: Optional[bool] = can_connect_to_business - self.has_main_web_app: Optional[bool] = has_main_web_app - - self._id_attrs = (self.id,) - - self._freeze() - - @property - def name(self) -> str: - """:obj:`str`: Convenience property. If available, returns the user's :attr:`username` - prefixed with "@". If :attr:`username` is not available, returns :attr:`full_name`. - """ - if self.username: - return f"@{self.username}" - return self.full_name - - @property - def full_name(self) -> str: - """:obj:`str`: Convenience property. The user's :attr:`first_name`, followed by (if - available) :attr:`last_name`. - """ - if self.last_name: - return f"{self.first_name} {self.last_name}" - return self.first_name - - @property - def link(self) -> Optional[str]: - """:obj:`str`: Convenience property. If :attr:`username` is available, returns a t.me link - of the user. - """ - if self.username: - return f"https://t.me/{self.username}" - return None - - async def get_profile_photos( - self, - offset: Optional[int] = None, - limit: Optional[int] = 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, - ) -> Optional["UserProfilePhotos"]: - """Shortcut for:: - - await bot.get_user_profile_photos(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_user_profile_photos`. - - """ - return await self.get_bot().get_user_profile_photos( - user_id=self.id, - offset=offset, - limit=limit, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - def mention_markdown(self, name: Optional[str] = None) -> str: - """ - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`mention_markdown_v2` - instead. - - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as markdown (version 1). - - """ - if name: - return helpers_mention_markdown(self.id, name) - return helpers_mention_markdown(self.id, self.full_name) - - def mention_markdown_v2(self, name: Optional[str] = None) -> str: - """ - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as markdown (version 2). - - """ - if name: - return helpers_mention_markdown(self.id, name, version=2) - return helpers_mention_markdown(self.id, self.full_name, version=2) - - def mention_html(self, name: Optional[str] = None) -> str: - """ - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as HTML. - - """ - if name: - return helpers_mention_html(self.id, name) - return helpers_mention_html(self.id, self.full_name) - - def mention_button(self, name: Optional[str] = None) -> InlineKeyboardButton: - """Shortcut for:: - - InlineKeyboardButton(text=name, url=f"tg://user?id={update.effective_user.id}") - - .. versionadded:: 13.9 - - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :class:`telegram.InlineKeyboardButton`: InlineButton with url set to the user mention - """ - return InlineKeyboardButton(text=name or self.full_name, url=f"tg://user?id={self.id}") - - async def pin_message( - self, - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - business_connection_id: 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.pin_chat_message(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. - - Note: - |user_chat_id_note| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().pin_chat_message( - chat_id=self.id, - message_id=message_id, - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - business_connection_id=business_connection_id, - api_kwargs=api_kwargs, - ) - - async def unpin_message( - self, - message_id: Optional[int] = None, - business_connection_id: 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.unpin_chat_message(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. - - Note: - |user_chat_id_note| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().unpin_chat_message( - chat_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - message_id=message_id, - business_connection_id=business_connection_id, - ) - - async def unpin_all_messages( - 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, - ) -> bool: - """Shortcut for:: - - await bot.unpin_all_chat_messages(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_all_chat_messages`. - - Note: - |user_chat_id_note| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().unpin_all_chat_messages( - chat_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def send_message( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - disable_web_page_preview: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "Message": - """Shortcut for:: - - await bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_message( - chat_id=self.id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - link_preview_options=link_preview_options, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - entities=entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def delete_message( - self, - message_id: int, - *, - 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.delete_message(update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.delete_message`. - - .. versionadded:: 20.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().delete_message( - chat_id=self.id, - message_id=message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def delete_messages( - self, - message_ids: Sequence[int], - *, - 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.delete_messages(update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.delete_messages`. - - .. versionadded:: 20.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().delete_messages( - chat_id=self.id, - message_ids=message_ids, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def send_photo( - self, - photo: Union[FileInput, "PhotoSize"], - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_photo(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_photo( - chat_id=self.id, - photo=photo, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - has_spoiler=has_spoiler, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_media_group( - self, - media: Sequence[ - Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] - ], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - ) -> tuple["Message", ...]: - """Shortcut for:: - - await bot.send_media_group(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. - - Note: - |user_chat_id_note| - - Returns: - tuple[:class:`telegram.Message`:] On success, a tuple of :class:`~telegram.Message` - instances that were sent is returned. - - """ - return await self.get_bot().send_media_group( - chat_id=self.id, - media=media, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_audio( - self, - audio: Union[FileInput, "Audio"], - duration: Optional[int] = None, - performer: Optional[str] = None, - title: Optional[str] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_audio(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_audio( - chat_id=self.id, - audio=audio, - duration=duration, - performer=performer, - title=title, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - thumbnail=thumbnail, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_chat_action( - self, - action: str, - message_thread_id: Optional[int] = None, - business_connection_id: 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.send_chat_action(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. - - Note: - |user_chat_id_note| - - Returns: - :obj:`True`: On success. - - """ - return await self.get_bot().send_chat_action( - chat_id=self.id, - action=action, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - business_connection_id=business_connection_id, - ) - - send_action = send_chat_action - """Alias for :attr:`send_chat_action`""" - - async def send_contact( - self, - phone_number: Optional[str] = None, - first_name: Optional[str] = None, - last_name: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - vcard: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - contact: Optional["Contact"] = 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_contact(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_contact( - chat_id=self.id, - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - contact=contact, - vcard=vcard, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_dice( - self, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - emoji: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "Message": - """Shortcut for:: - - await bot.send_dice(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_dice( - chat_id=self.id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - emoji=emoji, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_document( - self, - document: Union[FileInput, "Document"], - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_content_type_detection: Optional[bool] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_document(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_document( - chat_id=self.id, - document=document, - filename=filename, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - parse_mode=parse_mode, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - disable_content_type_detection=disable_content_type_detection, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_game( - self, - game_short_name: str, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "Message": - """Shortcut for:: - - await bot.send_game(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_game( - chat_id=self.id, - game_short_name=game_short_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_invoice( - self, - title: str, - description: str, - payload: str, - provider_token: Optional[str], - currency: str, - prices: Sequence["LabeledPrice"], - start_parameter: Optional[str] = None, - photo_url: Optional[str] = None, - photo_size: Optional[int] = None, - photo_width: Optional[int] = None, - photo_height: Optional[int] = None, - need_name: Optional[bool] = None, - need_phone_number: Optional[bool] = None, - need_email: Optional[bool] = None, - need_shipping_address: Optional[bool] = None, - is_flexible: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - provider_data: Optional[Union[str, object]] = None, - send_phone_number_to_provider: Optional[bool] = None, - send_email_to_provider: Optional[bool] = None, - max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[Sequence[int]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "Message": - """Shortcut for:: - - await bot.send_invoice(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. - - Warning: - As of API 5.2 :paramref:`start_parameter ` - is an optional argument and therefore the - order of the arguments had to be changed. Use keyword arguments to make sure that the - arguments are passed correctly. - - Note: - |user_chat_id_note| - - .. versionchanged:: 13.5 - As of Bot API 5.2, the parameter - :paramref:`start_parameter ` is optional. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_invoice( - chat_id=self.id, - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - start_parameter=start_parameter, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - is_flexible=is_flexible, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - provider_data=provider_data, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - protect_content=protect_content, - message_thread_id=message_thread_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_location( - self, - latitude: Optional[float] = None, - longitude: Optional[float] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - live_period: Optional[int] = None, - horizontal_accuracy: Optional[float] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - location: Optional["Location"] = 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_location(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_location( - chat_id=self.id, - latitude=latitude, - longitude=longitude, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - location=location, - live_period=live_period, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_animation( - self, - animation: Union[FileInput, "Animation"], - duration: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_animation(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_animation( - chat_id=self.id, - animation=animation, - duration=duration, - width=width, - height=height, - caption=caption, - parse_mode=parse_mode, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - has_spoiler=has_spoiler, - thumbnail=thumbnail, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_sticker( - self, - sticker: Union[FileInput, "Sticker"], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - emoji: Optional[str] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "Message": - """Shortcut for:: - - await bot.send_sticker(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_sticker( - chat_id=self.id, - sticker=sticker, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - emoji=emoji, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_video( - self, - video: Union[FileInput, "Video"], - duration: Optional[int] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - width: Optional[int] = None, - height: Optional[int] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - supports_streaming: Optional[bool] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_video(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_video( - chat_id=self.id, - video=video, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - width=width, - height=height, - parse_mode=parse_mode, - supports_streaming=supports_streaming, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - has_spoiler=has_spoiler, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_venue( - self, - latitude: Optional[float] = None, - longitude: Optional[float] = None, - title: Optional[str] = None, - address: Optional[str] = None, - foursquare_id: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - foursquare_type: Optional[str] = None, - google_place_id: Optional[str] = None, - google_place_type: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - venue: Optional["Venue"] = 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_venue(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_venue( - chat_id=self.id, - latitude=latitude, - longitude=longitude, - title=title, - address=address, - foursquare_id=foursquare_id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - venue=venue, - foursquare_type=foursquare_type, - api_kwargs=api_kwargs, - google_place_id=google_place_id, - google_place_type=google_place_type, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_video_note( - self, - video_note: Union[FileInput, "VideoNote"], - duration: Optional[int] = None, - length: Optional[int] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_video_note(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_video_note( - chat_id=self.id, - video_note=video_note, - duration=duration, - length=length, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - thumbnail=thumbnail, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_voice( - self, - voice: Union[FileInput, "Voice"], - duration: Optional[int] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_voice(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_voice( - chat_id=self.id, - voice=voice, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_poll( - self, - question: str, - options: Sequence[Union[str, "InputPollOption"]], - is_anonymous: Optional[bool] = None, - type: Optional[str] = None, - allows_multiple_answers: Optional[bool] = None, - correct_option_id: Optional[CorrectOptionID] = None, - is_closed: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - explanation: Optional[str] = None, - explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, - open_period: Optional[int] = None, - close_date: Optional[Union[int, dtm.datetime]] = None, - explanation_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - question_parse_mode: ODVInput[str] = DEFAULT_NONE, - question_entities: Optional[Sequence["MessageEntity"]] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "Message": - """Shortcut for:: - - await bot.send_poll(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_poll( - chat_id=self.id, - question=question, - options=options, - is_anonymous=is_anonymous, - type=type, # pylint=pylint, - allows_multiple_answers=allows_multiple_answers, - correct_option_id=correct_option_id, - is_closed=is_closed, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - explanation=explanation, - explanation_parse_mode=explanation_parse_mode, - open_period=open_period, - close_date=close_date, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - explanation_entities=explanation_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - question_parse_mode=question_parse_mode, - question_entities=question_entities, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_gift( - self, - gift_id: Union[str, "Gift"], - text: Optional[str] = None, - text_parse_mode: ODVInput[str] = DEFAULT_NONE, - text_entities: Optional[Sequence["MessageEntity"]] = None, - pay_for_upgrade: Optional[bool] = 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.send_gift( user_id=update.effective_user.id, *args, **kwargs ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_gift`. - - .. versionadded:: 21.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().send_gift( - user_id=self.id, - gift_id=gift_id, - text=text, - text_parse_mode=text_parse_mode, - text_entities=text_entities, - pay_for_upgrade=pay_for_upgrade, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def send_copy( - self, - from_chat_id: Union[str, int], - message_id: int, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - show_caption_above_media: Optional[bool] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "MessageId": - """Shortcut for:: - - await bot.copy_message(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().copy_message( - chat_id=self.id, - from_chat_id=from_chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - protect_content=protect_content, - message_thread_id=message_thread_id, - show_caption_above_media=show_caption_above_media, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def copy_message( - self, - chat_id: Union[int, str], - message_id: int, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - show_caption_above_media: Optional[bool] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "MessageId": - """Shortcut for:: - - await bot.copy_message(from_chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. - - """ - return await self.get_bot().copy_message( - from_chat_id=self.id, - chat_id=chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - protect_content=protect_content, - message_thread_id=message_thread_id, - show_caption_above_media=show_caption_above_media, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_copies( - self, - from_chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - remove_caption: Optional[bool] = 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, - ) -> tuple["MessageId", ...]: - """Shortcut for:: - - await bot.copy_messages(chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_messages`. - - .. seealso:: :meth:`copy_message`, :meth:`send_copy`, :meth:`copy_messages`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of the sent messages is returned. - - """ - return await self.get_bot().copy_messages( - chat_id=self.id, - from_chat_id=from_chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - remove_caption=remove_caption, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def copy_messages( - self, - chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - remove_caption: Optional[bool] = 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, - ) -> tuple["MessageId", ...]: - """Shortcut for:: - - await bot.copy_messages(from_chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_messages`. - - .. seealso:: :meth:`copy_message`, :meth:`send_copy`, :meth:`send_copies`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of the sent messages is returned. - - """ - return await self.get_bot().copy_messages( - from_chat_id=self.id, - chat_id=chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - remove_caption=remove_caption, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def forward_from( - self, - from_chat_id: Union[str, int], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = 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, - ) -> "Message": - """Shortcut for:: - - await bot.forward_message(chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`. - - .. seealso:: :meth:`forward_to`, :meth:`forward_messages_from`, :meth:`forward_messages_to` - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().forward_message( - chat_id=self.id, - from_chat_id=from_chat_id, - message_id=message_id, - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - protect_content=protect_content, - message_thread_id=message_thread_id, - ) - - async def forward_to( - self, - chat_id: Union[int, str], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = 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, - ) -> "Message": - """Shortcut for:: - - await bot.forward_message(from_chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`. - - .. seealso:: :meth:`forward_from`, :meth:`forward_messages_from`, - :meth:`forward_messages_to` - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().forward_message( - from_chat_id=self.id, - chat_id=chat_id, - message_id=message_id, - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - protect_content=protect_content, - message_thread_id=message_thread_id, - ) - - async def forward_messages_from( - self, - from_chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = 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, - ) -> tuple["MessageId", ...]: - """Shortcut for:: - - await bot.forward_messages(chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_messages`. - - .. seealso:: :meth:`forward_to`, :meth:`forward_from`, :meth:`forward_messages_to`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of sent messages is returned. - - """ - return await self.get_bot().forward_messages( - chat_id=self.id, - from_chat_id=from_chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def forward_messages_to( - self, - chat_id: Union[int, str], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = 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, - ) -> tuple["MessageId", ...]: - """Shortcut for:: - - await bot.forward_messages(from_chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_messages`. - - .. seealso:: :meth:`forward_from`, :meth:`forward_to`, :meth:`forward_messages_from`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of sent messages is returned. - - """ - return await self.get_bot().forward_messages( - from_chat_id=self.id, - chat_id=chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def approve_join_request( - self, - chat_id: Union[int, str], - *, - 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.approve_chat_join_request(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.approve_chat_join_request`. - - Note: - |user_chat_id_note| - - .. versionadded:: 13.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().approve_chat_join_request( - user_id=self.id, - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def decline_join_request( - self, - chat_id: Union[int, str], - *, - 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.decline_chat_join_request(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.decline_chat_join_request`. - - Note: - |user_chat_id_note| - - .. versionadded:: 13.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().decline_chat_join_request( - user_id=self.id, - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def set_menu_button( - self, - menu_button: Optional[MenuButton] = 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.set_chat_menu_button(chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_menu_button`. - - .. seealso:: :meth:`get_menu_button` - - Note: - |user_chat_id_note| - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().set_chat_menu_button( - chat_id=self.id, - menu_button=menu_button, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def get_menu_button( - 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, - ) -> MenuButton: - """Shortcut for:: - - await bot.get_chat_menu_button(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_chat_menu_button`. - - .. seealso:: :meth:`set_menu_button` - - Note: - |user_chat_id_note| - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.MenuButton`: On success, the current menu button is returned. - """ - return await self.get_bot().get_chat_menu_button( - chat_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def get_chat_boosts( - self, - chat_id: Union[int, str], - *, - 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, - ) -> "UserChatBoosts": - """Shortcut for:: - - await bot.get_user_chat_boosts(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_user_chat_boosts`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.UserChatBoosts`: On success, returns the boosts applied by the user. - """ - return await self.get_bot().get_user_chat_boosts( - chat_id=chat_id, - user_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def refund_star_payment( - self, - telegram_payment_charge_id: str, - *, - 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.refund_star_payment(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.refund_star_payment`. - - .. versionadded:: 21.3 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().refund_star_payment( - user_id=self.id, - telegram_payment_charge_id=telegram_payment_charge_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def verify( - self, - custom_description: 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.verify_user(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.verify_user`. - - .. versionadded:: 21.10 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().verify_user( - user_id=self.id, - custom_description=custom_description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def remove_verification( - 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, - ) -> bool: - """Shortcut for:: - - await bot.remove_user_verification(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.remove_user_verification`. - - .. versionadded:: 21.10 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().remove_user_verification( - user_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_userprofilephotos.py b/venv/lib/python3.11/site-packages/telegram/_userprofilephotos.py deleted file mode 100755 index cc812d5..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_userprofilephotos.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__init__.py b/venv/lib/python3.11/site-packages/telegram/_utils/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 039b3be..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/argumentparsing.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/argumentparsing.cpython-311.pyc deleted file mode 100755 index 2aa4227..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/argumentparsing.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/datetime.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/datetime.cpython-311.pyc deleted file mode 100755 index 37325b0..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/datetime.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/defaultvalue.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/defaultvalue.cpython-311.pyc deleted file mode 100755 index c69e7ed..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/defaultvalue.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/entities.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/entities.cpython-311.pyc deleted file mode 100755 index 0d37126..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/entities.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/enum.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/enum.cpython-311.pyc deleted file mode 100755 index c47defd..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/enum.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/files.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/files.cpython-311.pyc deleted file mode 100755 index 84c1c47..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/files.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/logging.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/logging.cpython-311.pyc deleted file mode 100755 index 4ed23de..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/logging.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/markup.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/markup.cpython-311.pyc deleted file mode 100755 index 5b7599c..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/markup.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/repr.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/repr.cpython-311.pyc deleted file mode 100755 index 9df45be..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/repr.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/strings.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/strings.cpython-311.pyc deleted file mode 100755 index 6fcdef3..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/strings.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/types.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/types.cpython-311.pyc deleted file mode 100755 index 41b3fb6..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/types.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/warnings.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/warnings.cpython-311.pyc deleted file mode 100755 index b85634f..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/warnings.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/warnings_transition.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/warnings_transition.cpython-311.pyc deleted file mode 100755 index a95bd07..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/warnings_transition.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/argumentparsing.py b/venv/lib/python3.11/site-packages/telegram/_utils/argumentparsing.py deleted file mode 100755 index e72848a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/argumentparsing.py +++ /dev/null @@ -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 -# -# 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/datetime.py b/venv/lib/python3.11/site-packages/telegram/_utils/datetime.py deleted file mode 100755 index 8e6ebdd..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/datetime.py +++ /dev/null @@ -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 -# -# 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/defaultvalue.py b/venv/lib/python3.11/site-packages/telegram/_utils/defaultvalue.py deleted file mode 100755 index f9374c5..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/defaultvalue.py +++ /dev/null @@ -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 -# -# 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 -""" diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/entities.py b/venv/lib/python3.11/site-packages/telegram/_utils/entities.py deleted file mode 100755 index 7ca3eff..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/entities.py +++ /dev/null @@ -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 -# -# 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 - } diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/enum.py b/venv/lib/python3.11/site-packages/telegram/_utils/enum.py deleted file mode 100755 index 5836287..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/enum.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/files.py b/venv/lib/python3.11/site-packages/telegram/_utils/files.py deleted file mode 100755 index 8bce30d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/files.py +++ /dev/null @@ -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 -# -# 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/logging.py b/venv/lib/python3.11/site-packages/telegram/_utils/logging.py deleted file mode 100755 index 0bd778b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/logging.py +++ /dev/null @@ -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 -# -# 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.`. 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/markup.py b/venv/lib/python3.11/site-packages/telegram/_utils/markup.py deleted file mode 100755 index eed70b3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/markup.py +++ /dev/null @@ -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 -# -# 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/repr.py b/venv/lib/python3.11/site-packages/telegram/_utils/repr.py deleted file mode 100755 index 38d9834..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/repr.py +++ /dev/null @@ -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 -# -# 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}" diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/strings.py b/venv/lib/python3.11/site-packages/telegram/_utils/strings.py deleted file mode 100755 index 76a8bcd..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/strings.py +++ /dev/null @@ -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 -# -# 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:]) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/types.py b/venv/lib/python3.11/site-packages/telegram/_utils/types.py deleted file mode 100755 index e1bf77d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/types.py +++ /dev/null @@ -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 -# -# 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], -] diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/warnings.py b/venv/lib/python3.11/site-packages/telegram/_utils/warnings.py deleted file mode 100755 index 2aa79db..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/warnings.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/warnings_transition.py b/venv/lib/python3.11/site-packages/telegram/_utils/warnings_transition.py deleted file mode 100755 index cd9fecd..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/warnings_transition.py +++ /dev/null @@ -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 -# -# 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, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_version.py b/venv/lib/python3.11/site-packages/telegram/_version.py deleted file mode 100755 index f514a9b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_version.py +++ /dev/null @@ -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 -# -# 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__) diff --git a/venv/lib/python3.11/site-packages/telegram/_videochat.py b/venv/lib/python3.11/site-packages/telegram/_videochat.py deleted file mode 100755 index 77da893..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_videochat.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_webappdata.py b/venv/lib/python3.11/site-packages/telegram/_webappdata.py deleted file mode 100755 index 2b1a8fd..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_webappdata.py +++ /dev/null @@ -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 -# -# 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 `_ 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 ` - - .. 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_webappinfo.py b/venv/lib/python3.11/site-packages/telegram/_webappinfo.py deleted file mode 100755 index 11a6bf3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_webappinfo.py +++ /dev/null @@ -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 -# -# 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 `_. - - 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 ` - - .. 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 \ - `_. - - Attributes: - url (:obj:`str`): An HTTPS URL of a Web App to be opened with additional data as specified - in `Initializing Web 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() diff --git a/venv/lib/python3.11/site-packages/telegram/_webhookinfo.py b/venv/lib/python3.11/site-packages/telegram/_webhookinfo.py deleted file mode 100755 index 5f46e64..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_webhookinfo.py +++ /dev/null @@ -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 -# -# 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) diff --git a/venv/lib/python3.11/site-packages/telegram/_writeaccessallowed.py b/venv/lib/python3.11/site-packages/telegram/_writeaccessallowed.py deleted file mode 100755 index 07fdd6b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_writeaccessallowed.py +++ /dev/null @@ -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 -# -# 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 `_. - - 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 `_. - - .. 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() diff --git a/venv/lib/python3.11/site-packages/telegram/constants.py b/venv/lib/python3.11/site-packages/telegram/constants.py deleted file mode 100755 index c61b3b9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/constants.py +++ /dev/null @@ -1,3249 +0,0 @@ -# python-telegram-bot - a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# by the python-telegram-bot contributors -# -# 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 several constants that are relevant for working with the Bot API. - -Unless noted otherwise, all constants in this module were extracted from the -`Telegram Bots FAQ `_ and -`Telegram Bots API `_. - -Most of the following constants are related to specific classes or topics and are grouped into -enums. If they are related to a specific class, then they are also available as attributes of -those classes. - -.. versionchanged:: 20.0 - - * Most of the constants in this module are grouped into enums. -""" -# TODO: Remove this when https://github.com/PyCQA/pylint/issues/6887 is resolved. -# pylint: disable=invalid-enum-extension,invalid-slots - -__all__ = [ - "BOT_API_VERSION", - "BOT_API_VERSION_INFO", - "SUPPORTED_WEBHOOK_PORTS", - "ZERO_DATE", - "AccentColor", - "BackgroundFillLimit", - "BackgroundFillType", - "BackgroundTypeLimit", - "BackgroundTypeType", - "BotCommandLimit", - "BotCommandScopeType", - "BotDescriptionLimit", - "BotNameLimit", - "BulkRequestLimit", - "CallbackQueryLimit", - "ChatAction", - "ChatBoostSources", - "ChatID", - "ChatInviteLinkLimit", - "ChatLimit", - "ChatMemberStatus", - "ChatPhotoSize", - "ChatSubscriptionLimit", - "ChatType", - "ContactLimit", - "CustomEmojiStickerLimit", - "DiceEmoji", - "DiceLimit", - "FileSizeLimit", - "FloodLimit", - "ForumIconColor", - "ForumTopicLimit", - "GiftLimit", - "GiveawayLimit", - "InlineKeyboardButtonLimit", - "InlineKeyboardMarkupLimit", - "InlineQueryLimit", - "InlineQueryResultLimit", - "InlineQueryResultType", - "InlineQueryResultsButtonLimit", - "InputMediaType", - "InputPaidMediaType", - "InvoiceLimit", - "KeyboardButtonRequestUsersLimit", - "LocationLimit", - "MaskPosition", - "MediaGroupLimit", - "MenuButtonType", - "MessageAttachmentType", - "MessageEntityType", - "MessageLimit", - "MessageOriginType", - "MessageType", - "PaidMediaType", - "ParseMode", - "PollLimit", - "PollType", - "PollingLimit", - "ProfileAccentColor", - "ReactionEmoji", - "ReactionType", - "ReplyLimit", - "RevenueWithdrawalStateType", - "StarTransactions", - "StarTransactionsLimit", - "StickerFormat", - "StickerLimit", - "StickerSetLimit", - "StickerType", - "TransactionPartnerType", - "UpdateType", - "UserProfilePhotosLimit", - "VerifyLimit", - "WebhookLimit", -] - -import datetime as dtm -import sys -from enum import Enum -from typing import Final, NamedTuple, Optional - -from telegram._utils.datetime import UTC -from telegram._utils.enum import FloatEnum, IntEnum, StringEnum - - -class _BotAPIVersion(NamedTuple): - """Similar behavior to sys.version_info. - So far TG has only published X.Y releases. We can add X.Y.Z(a(S)) if needed. - """ - - major: int - minor: int - - def __repr__(self) -> str: - """Unfortunately calling super().__repr__ doesn't work with typing.NamedTuple, so we - do this manually. - """ - return f"BotAPIVersion(major={self.major}, minor={self.minor})" - - def __str__(self) -> str: - return f"{self.major}.{self.minor}" - - -class _AccentColor(NamedTuple): - """A helper class for (profile) accent colors. Since TG doesn't define a class for this and - the behavior is quite different for the different accent colors, we don't make this a public - class. This gives us more flexibility to change the implementation if necessary for future - versions. - """ - - identifier: int - name: Optional[str] = None - light_colors: tuple[int, ...] = () - dark_colors: tuple[int, ...] = () - - -#: :class:`typing.NamedTuple`: A tuple containing the two components of the version number: -# ``major`` and ``minor``. Both values are integers. -#: The components can also be accessed by name, so ``BOT_API_VERSION_INFO[0]`` is equivalent -#: to ``BOT_API_VERSION_INFO.major`` and so on. Also available as -#: :data:`telegram.__bot_api_version_info__`. -#: -#: .. versionadded:: 20.0 -BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=8, minor=2) -#: :obj:`str`: Telegram Bot API -#: version supported by this version of `python-telegram-bot`. Also available as -#: :data:`telegram.__bot_api_version__`. -#: -#: .. versionadded:: 13.4 -BOT_API_VERSION: Final[str] = str(BOT_API_VERSION_INFO) - -# constants above this line are tested - -#: list[:obj:`int`]: Ports supported by -#: :paramref:`telegram.Bot.set_webhook.url`. -SUPPORTED_WEBHOOK_PORTS: Final[list[int]] = [443, 80, 88, 8443] - -#: :obj:`datetime.datetime`, value of unix 0. -#: This date literal is used in :class:`telegram.InaccessibleMessage` -#: -#: .. versionadded:: 20.8 -ZERO_DATE: Final[dtm.datetime] = dtm.datetime(1970, 1, 1, tzinfo=UTC) - - -class AccentColor(Enum): - """This enum contains the available accent colors for - :class:`telegram.ChatFullInfo.accent_color_id`. - The members of this enum are named tuples with the following attributes: - - - ``identifier`` (:obj:`int`): The identifier of the accent color. - - ``name`` (:obj:`str`): Optional. The name of the accent color. - - ``light_colors`` (tuple[:obj:`str`]): Optional. The light colors of the accent color as HEX - value. - - ``dark_colors`` (tuple[:obj:`str`]): Optional. The dark colors of the accent color as HEX - value. - - Since Telegram gives no exact specification for the accent colors, future accent colors might - have a different data type. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - COLOR_000 = _AccentColor(identifier=0, name="red") - """Accent color 0. This color can be customized by app themes.""" - COLOR_001 = _AccentColor(identifier=1, name="orange") - """Accent color 1. This color can be customized by app themes.""" - COLOR_002 = _AccentColor(identifier=2, name="purple/violet") - """Accent color 2. This color can be customized by app themes.""" - COLOR_003 = _AccentColor(identifier=3, name="green") - """Accent color 3. This color can be customized by app themes.""" - COLOR_004 = _AccentColor(identifier=4, name="cyan") - """Accent color 4. This color can be customized by app themes.""" - COLOR_005 = _AccentColor(identifier=5, name="blue") - """Accent color 5. This color can be customized by app themes.""" - COLOR_006 = _AccentColor(identifier=6, name="pink") - """Accent color 6. This color can be customized by app themes.""" - COLOR_007 = _AccentColor( - identifier=7, light_colors=(0xE15052, 0xF9AE63), dark_colors=(0xFF9380, 0x992F37) - ) - """Accent color 7. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_008 = _AccentColor( - identifier=8, light_colors=(0xE0802B, 0xFAC534), dark_colors=(0xECB04E, 0xC35714) - ) - """Accent color 8. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_009 = _AccentColor( - identifier=9, light_colors=(0xA05FF3, 0xF48FFF), dark_colors=(0xC697FF, 0x5E31C8) - ) - """Accent color 9. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_010 = _AccentColor( - identifier=10, light_colors=(0x27A910, 0xA7DC57), dark_colors=(0xA7EB6E, 0x167E2D) - ) - """Accent color 10. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_011 = _AccentColor( - identifier=11, light_colors=(0x27ACCE, 0x82E8D6), dark_colors=(0x40D8D0, 0x045C7F) - ) - """Accent color 11. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - - COLOR_012 = _AccentColor( - identifier=12, light_colors=(0x3391D4, 0x7DD3F0), dark_colors=(0x52BFFF, 0x0B5494) - ) - """Accent color 12. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_013 = _AccentColor( - identifier=13, light_colors=(0xDD4371, 0xFFBE9F), dark_colors=(0xFF86A6, 0x8E366E) - ) - """Accent color 13. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_014 = _AccentColor( - identifier=14, - light_colors=(0x247BED, 0xF04856, 0xFFFFFF), - dark_colors=(0x3FA2FE, 0xE5424F, 0xFFFFFF), - ) - """Accent color 14. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_015 = _AccentColor( - identifier=15, - light_colors=(0xD67722, 0x1EA011, 0xFFFFFF), - dark_colors=(0xFF905E, 0x32A527, 0xFFFFFF), - ) - """Accent color 15. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_016 = _AccentColor( - identifier=16, - light_colors=(0x179E42, 0xE84A3F, 0xFFFFFF), - dark_colors=(0x66D364, 0xD5444F, 0xFFFFFF), - ) - """Accent color 16. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_017 = _AccentColor( - identifier=17, - light_colors=(0x2894AF, 0x6FC456, 0xFFFFFF), - dark_colors=(0x22BCE2, 0x3DA240, 0xFFFFFF), - ) - """Accent color 17. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_018 = _AccentColor( - identifier=18, - light_colors=(0x0C9AB3, 0xFFAD95, 0xFFE6B5), - dark_colors=(0x22BCE2, 0xFF9778, 0xFFDA6B), - ) - """Accent color 18. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_019 = _AccentColor( - identifier=19, - light_colors=(0x7757D6, 0xF79610, 0xFFDE8E), - dark_colors=(0x9791FF, 0xF2731D, 0xFFDB59), - ) - """Accent color 19. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_020 = _AccentColor( - identifier=20, - light_colors=(0x1585CF, 0xF2AB1D, 0xFFFFFF), - dark_colors=(0x3DA6EB, 0xEEA51D, 0xFFFFFF), - ) - """Accent color 20. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - -class BackgroundTypeType(StringEnum): - """This enum contains the available types of :class:`telegram.BackgroundType`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.2 - """ - - __slots__ = () - - FILL = "fill" - """:obj:`str`: A :class:`telegram.BackgroundType` with fill background.""" - WALLPAPER = "wallpaper" - """:obj:`str`: A :class:`telegram.BackgroundType` with wallpaper background.""" - PATTERN = "pattern" - """:obj:`str`: A :class:`telegram.BackgroundType` with pattern background.""" - CHAT_THEME = "chat_theme" - """:obj:`str`: A :class:`telegram.BackgroundType` with chat_theme background.""" - - -class BackgroundFillType(StringEnum): - """This enum contains the available types of :class:`telegram.BackgroundFill`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.2 - """ - - __slots__ = () - - SOLID = "solid" - """:obj:`str`: A :class:`telegram.BackgroundFill` with solid fill.""" - GRADIENT = "gradient" - """:obj:`str`: A :class:`telegram.BackgroundFill` with gradient fill.""" - FREEFORM_GRADIENT = "freeform_gradient" - """:obj:`str`: A :class:`telegram.BackgroundFill` with freeform_gradient fill.""" - - -class BotCommandLimit(IntEnum): - """This enum contains limitations for :class:`telegram.BotCommand` and - :meth:`telegram.Bot.set_my_commands`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_COMMAND = 1 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.BotCommand.command` parameter of - :class:`telegram.BotCommand`. - """ - MAX_COMMAND = 32 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.BotCommand.command` parameter of - :class:`telegram.BotCommand`. - """ - MIN_DESCRIPTION = 1 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.BotCommand.description` - parameter of :class:`telegram.BotCommand`. - """ - MAX_DESCRIPTION = 256 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.BotCommand.description` - parameter of :class:`telegram.BotCommand`. - """ - MAX_COMMAND_NUMBER = 100 - """:obj:`int`: Maximum number of bot commands passed in a :obj:`list` to the - :paramref:`~telegram.Bot.set_my_commands.commands` - parameter of :meth:`telegram.Bot.set_my_commands`. - """ - - -class BotCommandScopeType(StringEnum): - """This enum contains the available types of :class:`telegram.BotCommandScope`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - DEFAULT = "default" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeDefault`.""" - ALL_PRIVATE_CHATS = "all_private_chats" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeAllPrivateChats`.""" - ALL_GROUP_CHATS = "all_group_chats" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeAllGroupChats`.""" - ALL_CHAT_ADMINISTRATORS = "all_chat_administrators" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeAllChatAdministrators`.""" - CHAT = "chat" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeChat`.""" - CHAT_ADMINISTRATORS = "chat_administrators" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeChatAdministrators`.""" - CHAT_MEMBER = "chat_member" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeChatMember`.""" - - -class BotDescriptionLimit(IntEnum): - """This enum contains limitations for the methods :meth:`telegram.Bot.set_my_description` and - :meth:`telegram.Bot.set_my_short_description`. The enum members of this enumeration are - instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.2 - """ - - __slots__ = () - - MAX_DESCRIPTION_LENGTH = 512 - """:obj:`int`: Maximum length for the parameter - :paramref:`~telegram.Bot.set_my_description.description` of - :meth:`telegram.Bot.set_my_description` - """ - MAX_SHORT_DESCRIPTION_LENGTH = 120 - """:obj:`int`: Maximum length for the parameter - :paramref:`~telegram.Bot.set_my_short_description.short_description` of - :meth:`telegram.Bot.set_my_short_description` - """ - - -class BotNameLimit(IntEnum): - """This enum contains limitations for the methods :meth:`telegram.Bot.set_my_name`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.3 - """ - - __slots__ = () - - MAX_NAME_LENGTH = 64 - """:obj:`int`: Maximum length for the parameter :paramref:`~telegram.Bot.set_my_name.name` of - :meth:`telegram.Bot.set_my_name` - """ - - -class BulkRequestLimit(IntEnum): - """This enum contains limitations for :meth:`telegram.Bot.delete_messages`, - :meth:`telegram.Bot.forward_messages` and :meth:`telegram.Bot.copy_messages`. The enum members - of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - MIN_LIMIT = 1 - """:obj:`int`: Minimum number of messages required for bulk actions.""" - MAX_LIMIT = 100 - """:obj:`int`: Maximum number of messages required for bulk actions.""" - - -class CallbackQueryLimit(IntEnum): - """This enum contains limitations for :class:`telegram.CallbackQuery`/ - :meth:`telegram.Bot.answer_callback_query`. The enum members of this enumeration are instances - of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - ANSWER_CALLBACK_QUERY_TEXT_LENGTH = 200 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.answer_callback_query.text` parameter of - :meth:`telegram.Bot.answer_callback_query`.""" - - -class ChatAction(StringEnum): - """This enum contains the available chat actions for :meth:`telegram.Bot.send_chat_action`. - The enum members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - CHOOSE_STICKER = "choose_sticker" - """:obj:`str`: Chat action indicating that the bot is selecting a sticker.""" - FIND_LOCATION = "find_location" - """:obj:`str`: Chat action indicating that the bot is selecting a location.""" - RECORD_VOICE = "record_voice" - """:obj:`str`: Chat action indicating that the bot is recording a voice message.""" - RECORD_VIDEO = "record_video" - """:obj:`str`: Chat action indicating that the bot is recording a video.""" - RECORD_VIDEO_NOTE = "record_video_note" - """:obj:`str`: Chat action indicating that the bot is recording a video note.""" - TYPING = "typing" - """:obj:`str`: A chat indicating the bot is typing.""" - UPLOAD_VOICE = "upload_voice" - """:obj:`str`: Chat action indicating that the bot is uploading a voice message.""" - UPLOAD_DOCUMENT = "upload_document" - """:obj:`str`: Chat action indicating that the bot is uploading a document.""" - UPLOAD_PHOTO = "upload_photo" - """:obj:`str`: Chat action indicating that the bot is uploading a photo.""" - UPLOAD_VIDEO = "upload_video" - """:obj:`str`: Chat action indicating that the bot is uploading a video.""" - UPLOAD_VIDEO_NOTE = "upload_video_note" - """:obj:`str`: Chat action indicating that the bot is uploading a video note.""" - - -class ChatBoostSources(StringEnum): - """This enum contains the available sources for a - :class:`Telegram chat boost `. - The enum members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - GIFT_CODE = "gift_code" - """:obj:`str`: The source of the chat boost was a Telegram Premium gift code.""" - GIVEAWAY = "giveaway" - """:obj:`str`: The source of the chat boost was a Telegram Premium giveaway.""" - PREMIUM = "premium" - """:obj:`str`: The source of the chat boost was a Telegram Premium subscription/gift.""" - - -class ChatID(IntEnum): - """This enum contains some special chat IDs. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - ANONYMOUS_ADMIN = 1087968824 - """:obj:`int`: User ID in groups for messages sent by anonymous admins. Telegram chat: - `@GroupAnonymousBot `_. - - Note: - :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. - It's recommended to use :attr:`telegram.Message.sender_chat` instead. - """ - SERVICE_CHAT = 777000 - """:obj:`int`: Telegram service chat, that also acts as sender of channel posts forwarded to - discussion groups. Telegram chat: `Telegram `_. - - Note: - :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. - It's recommended to use :attr:`telegram.Message.sender_chat` instead. - """ - FAKE_CHANNEL = 136817688 - """:obj:`int`: User ID in groups when message is sent on behalf of a channel, or when a channel - votes on a poll. Telegram chat: `@Channel_Bot `_. - - Note: - * :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. - It's recommended to use :attr:`telegram.Message.sender_chat` instead. - * :attr:`telegram.PollAnswer.user` will contain this ID for backwards compatibility only. - It's recommended to use :attr:`telegram.PollAnswer.voter_chat` instead. - """ - - -class ChatInviteLinkLimit(IntEnum): - """This enum contains limitations for :class:`telegram.ChatInviteLink`/ - :meth:`telegram.Bot.create_chat_invite_link`/:meth:`telegram.Bot.edit_chat_invite_link`. The - enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_MEMBER_LIMIT = 1 - """:obj:`int`: Minimum value allowed for the - :paramref:`~telegram.Bot.create_chat_invite_link.member_limit` parameter of - :meth:`telegram.Bot.create_chat_invite_link` and - :paramref:`~telegram.Bot.edit_chat_invite_link.member_limit` of - :meth:`telegram.Bot.edit_chat_invite_link`. - """ - MAX_MEMBER_LIMIT = 99999 - """:obj:`int`: Maximum value allowed for the - :paramref:`~telegram.Bot.create_chat_invite_link.member_limit` parameter of - :meth:`telegram.Bot.create_chat_invite_link` and - :paramref:`~telegram.Bot.edit_chat_invite_link.member_limit` of - :meth:`telegram.Bot.edit_chat_invite_link`. - """ - NAME_LENGTH = 32 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.create_chat_invite_link.name` parameter of - :meth:`telegram.Bot.create_chat_invite_link` and - :paramref:`~telegram.Bot.edit_chat_invite_link.name` of - :meth:`telegram.Bot.edit_chat_invite_link`. - """ - - -class ChatLimit(IntEnum): - """This enum contains limitations for - :meth:`telegram.Bot.set_chat_administrator_custom_title`, - :meth:`telegram.Bot.set_chat_description`, and :meth:`telegram.Bot.set_chat_title`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - CHAT_ADMINISTRATOR_CUSTOM_TITLE_LENGTH = 16 - """:obj:`int`: Maximum length of a :obj:`str` passed as the - :paramref:`~telegram.Bot.set_chat_administrator_custom_title.custom_title` parameter of - :meth:`telegram.Bot.set_chat_administrator_custom_title`. - """ - CHAT_DESCRIPTION_LENGTH = 255 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.set_chat_description.description` parameter of - :meth:`telegram.Bot.set_chat_description`. - """ - MIN_CHAT_TITLE_LENGTH = 1 - """:obj:`int`: Minimum length of a :obj:`str` passed as the - :paramref:`~telegram.Bot.set_chat_title.title` parameter of - :meth:`telegram.Bot.set_chat_title`. - """ - MAX_CHAT_TITLE_LENGTH = 128 - """:obj:`int`: Maximum length of a :obj:`str` passed as the - :paramref:`~telegram.Bot.set_chat_title.title` parameter of - :meth:`telegram.Bot.set_chat_title`. - """ - - -class ChatSubscriptionLimit(IntEnum): - """This enum contains limitations for - :paramref:`telegram.Bot.create_chat_subscription_invite_link.subscription_period` and - :paramref:`telegram.Bot.create_chat_subscription_invite_link.subscription_price`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.5 - """ - - __slots__ = () - - SUBSCRIPTION_PERIOD = 2592000 - """:obj:`int`: The number of seconds the subscription will be active.""" - MIN_PRICE = 1 - """:obj:`int`: Amount of stars a user pays, minimum amount the subscription can be set to.""" - MAX_PRICE = 2500 - """:obj:`int`: Amount of stars a user pays, maximum amount the subscription can be set to.""" - - -class BackgroundTypeLimit(IntEnum): - """This enum contains limitations for :class:`telegram.BackgroundTypeFill`, - :class:`telegram.BackgroundTypeWallpaper` and :class:`telegram.BackgroundTypePattern`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.2 - """ - - __slots__ = () - - MAX_DIMMING = 100 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.BackgroundTypeFill.dark_theme_dimming` parameter of - :class:`telegram.BackgroundTypeFill` - * :paramref:`~telegram.BackgroundTypeWallpaper.dark_theme_dimming` parameter of - :class:`telegram.BackgroundTypeWallpaper` - """ - MAX_INTENSITY = 100 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.BackgroundTypePattern.intensity` - parameter of :class:`telegram.BackgroundTypePattern` - """ - - -class BackgroundFillLimit(IntEnum): - """This enum contains limitations for :class:`telegram.BackgroundFillGradient`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.2 - """ - - __slots__ = () - - MAX_ROTATION_ANGLE = 359 - """:obj:`int`: Maximum value allowed for: - :paramref:`~telegram.BackgroundFillGradient.rotation_angle` parameter of - :class:`telegram.BackgroundFillGradient` - """ - - -class ChatMemberStatus(StringEnum): - """This enum contains the available states for :class:`telegram.ChatMember`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - ADMINISTRATOR = "administrator" - """:obj:`str`: A :class:`telegram.ChatMember` who is administrator of the chat.""" - OWNER = "creator" - """:obj:`str`: A :class:`telegram.ChatMember` who is the owner of the chat.""" - BANNED = "kicked" - """:obj:`str`: A :class:`telegram.ChatMember` who was banned in the chat.""" - LEFT = "left" - """:obj:`str`: A :class:`telegram.ChatMember` who has left the chat.""" - MEMBER = "member" - """:obj:`str`: A :class:`telegram.ChatMember` who is a member of the chat.""" - RESTRICTED = "restricted" - """:obj:`str`: A :class:`telegram.ChatMember` who was restricted in this chat.""" - - -class ChatPhotoSize(IntEnum): - """This enum contains limitations for :class:`telegram.ChatPhoto`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - SMALL = 160 - """:obj:`int`: Width and height of a small chat photo, ID of which is passed in - :paramref:`~telegram.ChatPhoto.small_file_id` and - :paramref:`~telegram.ChatPhoto.small_file_unique_id` parameters of - :class:`telegram.ChatPhoto`. - """ - BIG = 640 - """:obj:`int`: Width and height of a big chat photo, ID of which is passed in - :paramref:`~telegram.ChatPhoto.big_file_id` and - :paramref:`~telegram.ChatPhoto.big_file_unique_id` parameters of - :class:`telegram.ChatPhoto`. - """ - - -class ChatType(StringEnum): - """This enum contains the available types of :class:`telegram.Chat`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - SENDER = "sender" - """:obj:`str`: A :class:`telegram.Chat` that represents the chat of a :class:`telegram.User` - sending an :class:`telegram.InlineQuery`. """ - PRIVATE = "private" - """:obj:`str`: A :class:`telegram.Chat` that is private.""" - GROUP = "group" - """:obj:`str`: A :class:`telegram.Chat` that is a group.""" - SUPERGROUP = "supergroup" - """:obj:`str`: A :class:`telegram.Chat` that is a supergroup.""" - CHANNEL = "channel" - """:obj:`str`: A :class:`telegram.Chat` that is a channel.""" - - -class ContactLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineQueryResultContact`, - :class:`telegram.InputContactMessageContent`, and :meth:`telegram.Bot.send_contact`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - VCARD = 2048 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.Bot.send_contact.vcard` parameter of :meth:`~telegram.Bot.send_contact` - * :paramref:`~telegram.InlineQueryResultContact.vcard` parameter of - :class:`~telegram.InlineQueryResultContact` - * :paramref:`~telegram.InputContactMessageContent.vcard` parameter of - :class:`~telegram.InputContactMessageContent` - """ - - -class CustomEmojiStickerLimit(IntEnum): - """This enum contains limitations for :meth:`telegram.Bot.get_custom_emoji_stickers`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - CUSTOM_EMOJI_IDENTIFIER_LIMIT = 200 - """:obj:`int`: Maximum amount of custom emoji identifiers which can be specified for the - :paramref:`~telegram.Bot.get_custom_emoji_stickers.custom_emoji_ids` parameter of - :meth:`telegram.Bot.get_custom_emoji_stickers`. - """ - - -class DiceEmoji(StringEnum): - """This enum contains the available emoji for :class:`telegram.Dice`/ - :meth:`telegram.Bot.send_dice`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - DICE = "🎲" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🎲``.""" - DARTS = "🎯" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🎯``.""" - BASKETBALL = "🏀" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🏀``.""" - FOOTBALL = "⚽" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``⚽``.""" - SLOT_MACHINE = "🎰" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🎰``.""" - BOWLING = "🎳" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🎳``.""" - - -class DiceLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Dice`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_VALUE = 1 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` (any emoji). - """ - - MAX_VALUE_BASKETBALL = 5 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.BASKETBALL`. - """ - MAX_VALUE_BOWLING = 6 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.BOWLING`. - """ - MAX_VALUE_DARTS = 6 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.DARTS`. - """ - MAX_VALUE_DICE = 6 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.DICE`. - """ - MAX_VALUE_FOOTBALL = 5 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.FOOTBALL`. - """ - MAX_VALUE_SLOT_MACHINE = 64 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.SLOT_MACHINE`. - """ - - -class FileSizeLimit(IntEnum): - """This enum contains limitations regarding the upload and download of files. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - FILESIZE_DOWNLOAD = int(20e6) # (20MB) - """:obj:`int`: Bots can download files of up to 20MB in size.""" - FILESIZE_UPLOAD = int(50e6) # (50MB) - """:obj:`int`: Bots can upload non-photo files of up to 50MB in size.""" - FILESIZE_UPLOAD_LOCAL_MODE = int(2e9) # (2000MB) - """:obj:`int`: Bots can upload non-photo files of up to 2000MB in size when using a local bot - API server. - """ - FILESIZE_DOWNLOAD_LOCAL_MODE = sys.maxsize - """:obj:`int`: Bots can download files without a size limit when using a local bot API server. - """ - PHOTOSIZE_UPLOAD = int(10e6) # (10MB) - """:obj:`int`: Bots can upload photo files of up to 10MB in size.""" - VOICE_NOTE_FILE_SIZE = int(1e6) # (1MB) - """:obj:`int`: File size limit for the :meth:`~telegram.Bot.send_voice` method of - :class:`telegram.Bot`. Bots can send :mimetype:`audio/ogg` files of up to 1MB in size as - a voice note. Larger voice notes (up to 20MB) will be sent as files.""" - # It seems OK to link 20MB limit to FILESIZE_DOWNLOAD rather than creating a new constant - - -class FloodLimit(IntEnum): - """This enum contains limitations regarding flood limits. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MESSAGES_PER_SECOND_PER_CHAT = 1 - """:obj:`int`: The number of messages that can be sent per second in a particular chat. - Telegram may allow short bursts that go over this limit, but eventually you'll begin - receiving 429 errors. - """ - MESSAGES_PER_SECOND = 30 - """:obj:`int`: The number of messages that can roughly be sent in an interval of 30 seconds - across all chats. - """ - MESSAGES_PER_MINUTE_PER_GROUP = 20 - """:obj:`int`: The number of messages that can roughly be sent to a particular group within one - minute. - """ - PAID_MESSAGES_PER_SECOND = 1000 - """:obj:`int`: The number of messages that can be sent per second when paying with the bot's - Telegram Star balance. See e.g. parameter - :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` of - :meth:`~telegram.Bot.send_message`. - - .. versionadded:: 21.7 - """ - - -class ForumIconColor(IntEnum): - """This enum contains the available colors for use in - :paramref:`telegram.Bot.create_forum_topic.icon_color`. The enum members of this enumeration - are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - BLUE = 0x6FB9F0 - """:obj:`int`: An icon with a color which corresponds to blue (``0x6FB9F0``). - - .. raw:: html - -
- - """ - YELLOW = 0xFFD67E - """:obj:`int`: An icon with a color which corresponds to yellow (``0xFFD67E``). - - .. raw:: html - -
- - """ - PURPLE = 0xCB86DB - """:obj:`int`: An icon with a color which corresponds to purple (``0xCB86DB``). - - .. raw:: html - -
- - """ - GREEN = 0x8EEE98 - """:obj:`int`: An icon with a color which corresponds to green (``0x8EEE98``). - - .. raw:: html - -
- - """ - PINK = 0xFF93B2 - """:obj:`int`: An icon with a color which corresponds to pink (``0xFF93B2``). - - .. raw:: html - -
- - """ - RED = 0xFB6F5F - """:obj:`int`: An icon with a color which corresponds to red (``0xFB6F5F``). - - .. raw:: html - -
- - """ - - -class GiftLimit(IntEnum): - """This enum contains limitations for :meth:`~telegram.Bot.send_gift`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.8 - """ - - __slots__ = () - - MAX_TEXT_LENGTH = 255 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.send_gift.text` parameter of :meth:`~telegram.Bot.send_gift`. - """ - - -class GiveawayLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Giveaway` and related classes. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - MAX_WINNERS = 100 - """:obj:`int`: Maximum number of winners allowed for :class:`telegram.GiveawayWinners.winners`. - """ - - -class KeyboardButtonRequestUsersLimit(IntEnum): - """This enum contains limitations for :class:`telegram.KeyboardButtonRequestUsers`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - MIN_QUANTITY = 1 - """:obj:`int`: Minimum value allowed for - :paramref:`~telegram.KeyboardButtonRequestUsers.max_quantity` parameter of - :class:`telegram.KeyboardButtonRequestUsers`. - """ - MAX_QUANTITY = 10 - """:obj:`int`: Maximum value allowed for - :paramref:`~telegram.KeyboardButtonRequestUsers.max_quantity` parameter of - :class:`telegram.KeyboardButtonRequestUsers`. - """ - - -class InlineKeyboardButtonLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineKeyboardButton`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_CALLBACK_DATA = 1 - """:obj:`int`: Minimum length allowed for - :paramref:`~telegram.InlineKeyboardButton.callback_data` parameter of - :class:`telegram.InlineKeyboardButton` - """ - MAX_CALLBACK_DATA = 64 - """:obj:`int`: Maximum length allowed for - :paramref:`~telegram.InlineKeyboardButton.callback_data` parameter of - :class:`telegram.InlineKeyboardButton` - """ - MIN_COPY_TEXT = 1 - """:obj:`int`: Minimum length allowed for - :paramref:`~telegram.CopyTextButton.text` parameter of :class:`telegram.CopyTextButton` - """ - MAX_COPY_TEXT = 256 - """:obj:`int`: Maximum length allowed for - :paramref:`~telegram.CopyTextButton.text` parameter of :class:`telegram.CopyTextButton` - """ - - -class InlineKeyboardMarkupLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineKeyboardMarkup`/ - :meth:`telegram.Bot.send_message` & friends. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - TOTAL_BUTTON_NUMBER = 100 - """:obj:`int`: Maximum number of buttons that can be attached to a message. - - Note: - This value is undocumented and might be changed by Telegram. - """ - BUTTONS_PER_ROW = 8 - """:obj:`int`: Maximum number of buttons that can be attached to a message per row. - - Note: - This value is undocumented and might be changed by Telegram. - """ - - -class InputMediaType(StringEnum): - """This enum contains the available types of :class:`telegram.InputMedia`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - ANIMATION = "animation" - """:obj:`str`: Type of :class:`telegram.InputMediaAnimation`.""" - DOCUMENT = "document" - """:obj:`str`: Type of :class:`telegram.InputMediaDocument`.""" - AUDIO = "audio" - """:obj:`str`: Type of :class:`telegram.InputMediaAudio`.""" - PHOTO = "photo" - """:obj:`str`: Type of :class:`telegram.InputMediaPhoto`.""" - VIDEO = "video" - """:obj:`str`: Type of :class:`telegram.InputMediaVideo`.""" - - -class InputPaidMediaType(StringEnum): - """This enum contains the available types of :class:`telegram.InputPaidMedia`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - PHOTO = "photo" - """:obj:`str`: Type of :class:`telegram.InputMediaPhoto`.""" - VIDEO = "video" - """:obj:`str`: Type of :class:`telegram.InputMediaVideo`.""" - - -class InlineQueryLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineQuery`/ - :meth:`telegram.Bot.answer_inline_query`. The enum members of this enumeration are instances - of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - RESULTS = 50 - """:obj:`int`: Maximum number of results that can be passed to - :meth:`telegram.Bot.answer_inline_query`.""" - MAX_OFFSET_LENGTH = 64 - """:obj:`int`: Maximum number of bytes in a :obj:`str` passed as the - :paramref:`~telegram.Bot.answer_inline_query.next_offset` parameter of - :meth:`telegram.Bot.answer_inline_query`.""" - MAX_QUERY_LENGTH = 256 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.InlineQuery.query` parameter of :class:`telegram.InlineQuery`.""" - MIN_SWITCH_PM_TEXT_LENGTH = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.answer_inline_query.switch_pm_parameter` parameter of - :meth:`telegram.Bot.answer_inline_query`. - - .. deprecated:: 20.3 - Deprecated in favor of :attr:`InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH`. - """ - MAX_SWITCH_PM_TEXT_LENGTH = 64 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.answer_inline_query.switch_pm_parameter` parameter of - :meth:`telegram.Bot.answer_inline_query`. - - .. deprecated:: 20.3 - Deprecated in favor of :attr:`InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH`. - """ - - -class InlineQueryResultLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineQueryResult` and its subclasses. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_ID_LENGTH = 1 - """:obj:`int`: Minimum number of bytes in a :obj:`str` passed as the - :paramref:`~telegram.InlineQueryResult.id` parameter of - :class:`telegram.InlineQueryResult` and its subclasses - """ - MAX_ID_LENGTH = 64 - """:obj:`int`: Maximum number of bytes in a :obj:`str` passed as the - :paramref:`~telegram.InlineQueryResult.id` parameter of - :class:`telegram.InlineQueryResult` and its subclasses - """ - - -class InlineQueryResultsButtonLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineQueryResultsButton`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.3 - """ - - __slots__ = () - - MIN_START_PARAMETER_LENGTH = InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.InlineQueryResultsButton.start_parameter` parameter of - :meth:`telegram.InlineQueryResultsButton`.""" - - MAX_START_PARAMETER_LENGTH = InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.InlineQueryResultsButton.start_parameter` parameter of - :meth:`telegram.InlineQueryResultsButton`.""" - - -class InlineQueryResultType(StringEnum): - """This enum contains the available types of :class:`telegram.InlineQueryResult`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - AUDIO = "audio" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultAudio` and - :class:`telegram.InlineQueryResultCachedAudio`. - """ - DOCUMENT = "document" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultDocument` and - :class:`telegram.InlineQueryResultCachedDocument`. - """ - GIF = "gif" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultGif` and - :class:`telegram.InlineQueryResultCachedGif`. - """ - MPEG4GIF = "mpeg4_gif" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultMpeg4Gif` and - :class:`telegram.InlineQueryResultCachedMpeg4Gif`. - """ - PHOTO = "photo" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultPhoto` and - :class:`telegram.InlineQueryResultCachedPhoto`. - """ - STICKER = "sticker" - """:obj:`str`: Type of and :class:`telegram.InlineQueryResultCachedSticker`.""" - VIDEO = "video" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultVideo` and - :class:`telegram.InlineQueryResultCachedVideo`. - """ - VOICE = "voice" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultVoice` and - :class:`telegram.InlineQueryResultCachedVoice`. - """ - ARTICLE = "article" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultArticle`.""" - CONTACT = "contact" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultContact`.""" - GAME = "game" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultGame`.""" - LOCATION = "location" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultLocation`.""" - VENUE = "venue" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultVenue`.""" - - -class LocationLimit(IntEnum): - """This enum contains limitations for - :class:`telegram.Location`/:class:`telegram.ChatLocation`/ - :meth:`telegram.Bot.edit_message_live_location`/:meth:`telegram.Bot.send_location`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_CHAT_LOCATION_ADDRESS = 1 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.ChatLocation.address` parameter - of :class:`telegram.ChatLocation` - """ - MAX_CHAT_LOCATION_ADDRESS = 64 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.ChatLocation.address` parameter - of :class:`telegram.ChatLocation` - """ - - HORIZONTAL_ACCURACY = 1500 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.Location.horizontal_accuracy` parameter of :class:`telegram.Location` - * :paramref:`~telegram.InlineQueryResultLocation.horizontal_accuracy` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.horizontal_accuracy` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.horizontal_accuracy` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.horizontal_accuracy` parameter of - :meth:`telegram.Bot.send_location` - """ - - MIN_HEADING = 1 - """:obj:`int`: Minimum value allowed for: - - * :paramref:`~telegram.Location.heading` parameter of :class:`telegram.Location` - * :paramref:`~telegram.InlineQueryResultLocation.heading` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.heading` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.heading` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.heading` parameter of - :meth:`telegram.Bot.send_location` - """ - MAX_HEADING = 360 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.Location.heading` parameter of :class:`telegram.Location` - * :paramref:`~telegram.InlineQueryResultLocation.heading` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.heading` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.heading` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.heading` parameter of - :meth:`telegram.Bot.send_location` - """ - - MIN_LIVE_PERIOD = 60 - """:obj:`int`: Minimum value allowed for: - - * :paramref:`~telegram.InlineQueryResultLocation.live_period` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.live_period` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.live_period` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.live_period` parameter of - :meth:`telegram.Bot.send_location` - """ - MAX_LIVE_PERIOD = 86400 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.InlineQueryResultLocation.live_period` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.live_period` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.live_period` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.live_period` parameter of - :meth:`telegram.Bot.send_location` - """ - - LIVE_PERIOD_FOREVER = int(hex(0x7FFFFFFF), 16) - """:obj:`int`: Value for live locations that can be edited indefinitely. Passed in: - - * :paramref:`~telegram.InlineQueryResultLocation.live_period` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.live_period` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.live_period` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.live_period` parameter of - :meth:`telegram.Bot.send_location` - - .. versionadded:: 21.2 - """ - - MIN_PROXIMITY_ALERT_RADIUS = 1 - """:obj:`int`: Minimum value allowed for: - - * :paramref:`~telegram.InlineQueryResultLocation.proximity_alert_radius` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.proximity_alert_radius` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.proximity_alert_radius` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.proximity_alert_radius` parameter of - :meth:`telegram.Bot.send_location` - """ - MAX_PROXIMITY_ALERT_RADIUS = 100000 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.InlineQueryResultLocation.proximity_alert_radius` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.proximity_alert_radius` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.proximity_alert_radius` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.proximity_alert_radius` parameter of - :meth:`telegram.Bot.send_location` - """ - - -class MaskPosition(StringEnum): - """This enum contains the available positions for :class:`telegram.MaskPosition`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - FOREHEAD = "forehead" - """:obj:`str`: Mask position for a sticker on the forehead.""" - EYES = "eyes" - """:obj:`str`: Mask position for a sticker on the eyes.""" - MOUTH = "mouth" - """:obj:`str`: Mask position for a sticker on the mouth.""" - CHIN = "chin" - """:obj:`str`: Mask position for a sticker on the chin.""" - - -class MediaGroupLimit(IntEnum): - """This enum contains limitations for :meth:`telegram.Bot.send_media_group`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_MEDIA_LENGTH = 2 - """:obj:`int`: Minimum length of a :obj:`list` passed as the - :paramref:`~telegram.Bot.send_media_group.media` parameter of - :meth:`telegram.Bot.send_media_group`. - """ - MAX_MEDIA_LENGTH = 10 - """:obj:`int`: Maximum length of a :obj:`list` passed as the - :paramref:`~telegram.Bot.send_media_group.media` parameter of - :meth:`telegram.Bot.send_media_group`. - """ - - -class MenuButtonType(StringEnum): - """This enum contains the available types of :class:`telegram.MenuButton`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - COMMANDS = "commands" - """:obj:`str`: The type of :class:`telegram.MenuButtonCommands`.""" - WEB_APP = "web_app" - """:obj:`str`: The type of :class:`telegram.MenuButtonWebApp`.""" - DEFAULT = "default" - """:obj:`str`: The type of :class:`telegram.MenuButtonDefault`.""" - - -class MessageAttachmentType(StringEnum): - """This enum contains the available types of :class:`telegram.Message` that can be seen - as attachment. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - # Make sure that all constants here are also listed in the MessageType Enum! - # (Enums are not extendable) - - ANIMATION = "animation" - """:obj:`str`: Messages with :attr:`telegram.Message.animation`.""" - AUDIO = "audio" - """:obj:`str`: Messages with :attr:`telegram.Message.audio`.""" - CONTACT = "contact" - """:obj:`str`: Messages with :attr:`telegram.Message.contact`.""" - DICE = "dice" - """:obj:`str`: Messages with :attr:`telegram.Message.dice`.""" - DOCUMENT = "document" - """:obj:`str`: Messages with :attr:`telegram.Message.document`.""" - GAME = "game" - """:obj:`str`: Messages with :attr:`telegram.Message.game`.""" - INVOICE = "invoice" - """:obj:`str`: Messages with :attr:`telegram.Message.invoice`.""" - LOCATION = "location" - """:obj:`str`: Messages with :attr:`telegram.Message.location`.""" - PAID_MEDIA = "paid_media" - """:obj:`str`: Messages with :attr:`telegram.Message.paid_media`. - - .. versionadded:: 21.4 - """ - PASSPORT_DATA = "passport_data" - """:obj:`str`: Messages with :attr:`telegram.Message.passport_data`.""" - PHOTO = "photo" - """:obj:`str`: Messages with :attr:`telegram.Message.photo`.""" - POLL = "poll" - """:obj:`str`: Messages with :attr:`telegram.Message.poll`.""" - STICKER = "sticker" - """:obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" - STORY = "story" - """:obj:`str`: Messages with :attr:`telegram.Message.story`.""" - SUCCESSFUL_PAYMENT = "successful_payment" - """:obj:`str`: Messages with :attr:`telegram.Message.successful_payment`.""" - VIDEO = "video" - """:obj:`str`: Messages with :attr:`telegram.Message.video`.""" - VIDEO_NOTE = "video_note" - """:obj:`str`: Messages with :attr:`telegram.Message.video_note`.""" - VOICE = "voice" - """:obj:`str`: Messages with :attr:`telegram.Message.voice`.""" - VENUE = "venue" - """:obj:`str`: Messages with :attr:`telegram.Message.venue`.""" - - -class MessageEntityType(StringEnum): - """This enum contains the available types of :class:`telegram.MessageEntity`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - BLOCKQUOTE = "blockquote" - """:obj:`str`: Message entities representing a block quotation. - - .. versionadded:: 20.8 - """ - BOLD = "bold" - """:obj:`str`: Message entities representing bold text.""" - BOT_COMMAND = "bot_command" - """:obj:`str`: Message entities representing a bot command.""" - CASHTAG = "cashtag" - """:obj:`str`: Message entities representing a cashtag.""" - CODE = "code" - """:obj:`str`: Message entities representing monowidth string.""" - CUSTOM_EMOJI = "custom_emoji" - """:obj:`str`: Message entities representing inline custom emoji stickers. - - .. versionadded:: 20.0 - """ - EMAIL = "email" - """:obj:`str`: Message entities representing a email.""" - EXPANDABLE_BLOCKQUOTE = "expandable_blockquote" - """:obj:`str`: Message entities representing collapsed-by-default block quotation. - - .. versionadded:: 21.3 - """ - HASHTAG = "hashtag" - """:obj:`str`: Message entities representing a hashtag.""" - ITALIC = "italic" - """:obj:`str`: Message entities representing italic text.""" - MENTION = "mention" - """:obj:`str`: Message entities representing a mention.""" - PHONE_NUMBER = "phone_number" - """:obj:`str`: Message entities representing a phone number.""" - PRE = "pre" - """:obj:`str`: Message entities representing monowidth block.""" - SPOILER = "spoiler" - """:obj:`str`: Message entities representing spoiler text.""" - STRIKETHROUGH = "strikethrough" - """:obj:`str`: Message entities representing strikethrough text.""" - TEXT_LINK = "text_link" - """:obj:`str`: Message entities representing clickable text URLs.""" - TEXT_MENTION = "text_mention" - """:obj:`str`: Message entities representing text mention for users without usernames.""" - UNDERLINE = "underline" - """:obj:`str`: Message entities representing underline text.""" - URL = "url" - """:obj:`str`: Message entities representing a url.""" - - -class MessageLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Message`/ - :class:`telegram.InputTextMessageContent`/ - :meth:`telegram.Bot.send_message` & friends. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - # TODO add links to params? - MAX_TEXT_LENGTH = 4096 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.Game.text` parameter of :class:`telegram.Game` - * :paramref:`~telegram.Message.text` parameter of :class:`telegram.Message` - * :paramref:`~telegram.InputTextMessageContent.message_text` parameter of - :class:`telegram.InputTextMessageContent` - * :paramref:`~telegram.Bot.send_message.text` parameter of :meth:`telegram.Bot.send_message` - * :paramref:`~telegram.Bot.edit_message_text.text` parameter of - :meth:`telegram.Bot.edit_message_text` - """ - CAPTION_LENGTH = 1024 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.Message.caption` parameter of :class:`telegram.Message` - * :paramref:`~telegram.InputMedia.caption` parameter of :class:`telegram.InputMedia` - and its subclasses - * ``caption`` parameter of subclasses of :class:`telegram.InlineQueryResult` - * ``caption`` parameter of :meth:`telegram.Bot.send_photo`, :meth:`telegram.Bot.send_audio`, - :meth:`telegram.Bot.send_document`, :meth:`telegram.Bot.send_video`, - :meth:`telegram.Bot.send_animation`, :meth:`telegram.Bot.send_voice`, - :meth:`telegram.Bot.edit_message_caption`, :meth:`telegram.Bot.copy_message` - """ - # constants above this line are tested - MIN_TEXT_LENGTH = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.InputTextMessageContent.message_text` parameter of - :class:`telegram.InputTextMessageContent` and the - :paramref:`~telegram.Bot.edit_message_text.text` parameter of - :meth:`telegram.Bot.edit_message_text`. - """ - DEEP_LINK_LENGTH = 64 - """:obj:`int`: Maximum number of characters for a deep link.""" - # TODO this constant is not used anywhere - MESSAGE_ENTITIES = 100 - """:obj:`int`: Maximum number of entities that can be displayed in a message. Further entities - will simply be ignored by Telegram. - - Note: - This value is undocumented and might be changed by Telegram. - """ - - -class MessageOriginType(StringEnum): - """This enum contains the available types of :class:`telegram.MessageOrigin`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - USER = "user" - """:obj:`str`: A :class:`telegram.MessageOrigin` who is sent by an user.""" - HIDDEN_USER = "hidden_user" - """:obj:`str`: A :class:`telegram.MessageOrigin` who is sent by a hidden user.""" - CHAT = "chat" - """:obj:`str`: A :class:`telegram.MessageOrigin` who is sent by a chat.""" - CHANNEL = "channel" - """:obj:`str`: A :class:`telegram.MessageOrigin` who is sent by a channel.""" - - -class MessageType(StringEnum): - """This enum contains the available types of :class:`telegram.Message`. Here, a "type" means - a kind of message that is visually distinct from other kinds of messages in the Telegram app. - In particular, auxiliary attributes that can be present for multiple types of messages are - not considered in this enumeration. - - The enum members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - # Make sure that all attachment type constants are also listed in the - # MessageAttachmentType Enum! (Enums are not extendable) - - ANIMATION = "animation" - """:obj:`str`: Messages with :attr:`telegram.Message.animation`.""" - AUDIO = "audio" - """:obj:`str`: Messages with :attr:`telegram.Message.audio`.""" - BOOST_ADDED = "boost_added" - """:obj:`str`: Messages with :attr:`telegram.Message.boost_added`. - - .. versionadded:: 21.0 - """ - BUSINESS_CONNECTION_ID = "business_connection_id" - """:obj:`str`: Messages with :attr:`telegram.Message.business_connection_id`. - - .. versionadded:: 21.1 - """ - CHANNEL_CHAT_CREATED = "channel_chat_created" - """:obj:`str`: Messages with :attr:`telegram.Message.channel_chat_created`.""" - CHAT_SHARED = "chat_shared" - """:obj:`str`: Messages with :attr:`telegram.Message.chat_shared`. - - .. versionadded:: 20.8 - """ - CHAT_BACKGROUND_SET = "chat_background_set" - """:obj:`str`: Messages with :attr:`telegram.Message.chat_background_set`. - - .. versionadded:: 21.2 - """ - CONNECTED_WEBSITE = "connected_website" - """:obj:`str`: Messages with :attr:`telegram.Message.connected_website`.""" - CONTACT = "contact" - """:obj:`str`: Messages with :attr:`telegram.Message.contact`.""" - DELETE_CHAT_PHOTO = "delete_chat_photo" - """:obj:`str`: Messages with :attr:`telegram.Message.delete_chat_photo`.""" - DICE = "dice" - """:obj:`str`: Messages with :attr:`telegram.Message.dice`.""" - DOCUMENT = "document" - """:obj:`str`: Messages with :attr:`telegram.Message.document`.""" - EFFECT_ID = "effect_id" - """:obj:`str`: Messages with :attr:`telegram.Message.effect_id`. - - .. versionadded:: 21.3""" - FORUM_TOPIC_CREATED = "forum_topic_created" - """:obj:`str`: Messages with :attr:`telegram.Message.forum_topic_created`. - - .. versionadded:: 20.8 - """ - FORUM_TOPIC_CLOSED = "forum_topic_closed" - """:obj:`str`: Messages with :attr:`telegram.Message.forum_topic_closed`. - - .. versionadded:: 20.8 - """ - FORUM_TOPIC_EDITED = "forum_topic_edited" - """:obj:`str`: Messages with :attr:`telegram.Message.forum_topic_edited`. - - .. versionadded:: 20.8 - """ - FORUM_TOPIC_REOPENED = "forum_topic_reopened" - """:obj:`str`: Messages with :attr:`telegram.Message.forum_topic_reopened`. - - .. versionadded:: 20.8 - """ - GAME = "game" - """:obj:`str`: Messages with :attr:`telegram.Message.game`.""" - GENERAL_FORUM_TOPIC_HIDDEN = "general_forum_topic_hidden" - """:obj:`str`: Messages with :attr:`telegram.Message.general_forum_topic_hidden`. - - .. versionadded:: 20.8 - """ - GENERAL_FORUM_TOPIC_UNHIDDEN = "general_forum_topic_unhidden" - """:obj:`str`: Messages with :attr:`telegram.Message.general_forum_topic_unhidden`. - - .. versionadded:: 20.8 - """ - GIVEAWAY = "giveaway" - """:obj:`str`: Messages with :attr:`telegram.Message.giveaway`. - - .. versionadded:: 20.8 - """ - GIVEAWAY_CREATED = "giveaway_created" - """:obj:`str`: Messages with :attr:`telegram.Message.giveaway_created`. - - .. versionadded:: 20.8 - """ - GIVEAWAY_WINNERS = "giveaway_winners" - """:obj:`str`: Messages with :attr:`telegram.Message.giveaway_winners`. - - .. versionadded:: 20.8 - """ - GIVEAWAY_COMPLETED = "giveaway_completed" - """:obj:`str`: Messages with :attr:`telegram.Message.giveaway_completed`. - - .. versionadded:: 20.8 - """ - GROUP_CHAT_CREATED = "group_chat_created" - """:obj:`str`: Messages with :attr:`telegram.Message.group_chat_created`.""" - INVOICE = "invoice" - """:obj:`str`: Messages with :attr:`telegram.Message.invoice`.""" - LEFT_CHAT_MEMBER = "left_chat_member" - """:obj:`str`: Messages with :attr:`telegram.Message.left_chat_member`.""" - LOCATION = "location" - """:obj:`str`: Messages with :attr:`telegram.Message.location`.""" - MESSAGE_AUTO_DELETE_TIMER_CHANGED = "message_auto_delete_timer_changed" - """:obj:`str`: Messages with :attr:`telegram.Message.message_auto_delete_timer_changed`.""" - MIGRATE_TO_CHAT_ID = "migrate_to_chat_id" - """:obj:`str`: Messages with :attr:`telegram.Message.migrate_to_chat_id`.""" - NEW_CHAT_MEMBERS = "new_chat_members" - """:obj:`str`: Messages with :attr:`telegram.Message.new_chat_members`.""" - NEW_CHAT_TITLE = "new_chat_title" - """:obj:`str`: Messages with :attr:`telegram.Message.new_chat_title`.""" - NEW_CHAT_PHOTO = "new_chat_photo" - """:obj:`str`: Messages with :attr:`telegram.Message.new_chat_photo`.""" - PAID_MEDIA = "paid_media" - """:obj:`str`: Messages with :attr:`telegram.Message.paid_media`. - - .. versionadded:: 21.4 - """ - PASSPORT_DATA = "passport_data" - """:obj:`str`: Messages with :attr:`telegram.Message.passport_data`.""" - PHOTO = "photo" - """:obj:`str`: Messages with :attr:`telegram.Message.photo`.""" - PINNED_MESSAGE = "pinned_message" - """:obj:`str`: Messages with :attr:`telegram.Message.pinned_message`.""" - POLL = "poll" - """:obj:`str`: Messages with :attr:`telegram.Message.poll`.""" - PROXIMITY_ALERT_TRIGGERED = "proximity_alert_triggered" - """:obj:`str`: Messages with :attr:`telegram.Message.proximity_alert_triggered`.""" - REFUNDED_PAYMENT = "refunded_payment" - """:obj:`str`: Messages with :attr:`telegram.Message.refunded_payment`. - - .. versionadded:: 21.4 - """ - REPLY_TO_STORY = "reply_to_story" - """:obj:`str`: Messages with :attr:`telegram.Message.reply_to_story`. - - .. versionadded:: 21.0 - """ - SENDER_BOOST_COUNT = "sender_boost_count" - """:obj:`str`: Messages with :attr:`telegram.Message.sender_boost_count`. - - .. versionadded:: 21.0 - """ - SENDER_BUSINESS_BOT = "sender_business_bot" - """:obj:`str`: Messages with :attr:`telegram.Message.sender_business_bot`. - - .. versionadded:: 21.1 - """ - STICKER = "sticker" - """:obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" - STORY = "story" - """:obj:`str`: Messages with :attr:`telegram.Message.story`.""" - SUPERGROUP_CHAT_CREATED = "supergroup_chat_created" - """:obj:`str`: Messages with :attr:`telegram.Message.supergroup_chat_created`.""" - SUCCESSFUL_PAYMENT = "successful_payment" - """:obj:`str`: Messages with :attr:`telegram.Message.successful_payment`.""" - TEXT = "text" - """:obj:`str`: Messages with :attr:`telegram.Message.text`.""" - USERS_SHARED = "users_shared" - """:obj:`str`: Messages with :attr:`telegram.Message.users_shared`. - - .. versionadded:: 20.8 - """ - VENUE = "venue" - """:obj:`str`: Messages with :attr:`telegram.Message.venue`.""" - VIDEO = "video" - """:obj:`str`: Messages with :attr:`telegram.Message.video`.""" - VIDEO_CHAT_SCHEDULED = "video_chat_scheduled" - """:obj:`str`: Messages with :attr:`telegram.Message.video_chat_scheduled`.""" - VIDEO_CHAT_STARTED = "video_chat_started" - """:obj:`str`: Messages with :attr:`telegram.Message.video_chat_started`.""" - VIDEO_CHAT_ENDED = "video_chat_ended" - """:obj:`str`: Messages with :attr:`telegram.Message.video_chat_ended`.""" - VIDEO_CHAT_PARTICIPANTS_INVITED = "video_chat_participants_invited" - """:obj:`str`: Messages with :attr:`telegram.Message.video_chat_participants_invited`.""" - VIDEO_NOTE = "video_note" - """:obj:`str`: Messages with :attr:`telegram.Message.video_note`.""" - VOICE = "voice" - """:obj:`str`: Messages with :attr:`telegram.Message.voice`.""" - WEB_APP_DATA = "web_app_data" - """:obj:`str`: Messages with :attr:`telegram.Message.web_app_data`. - - .. versionadded:: 20.8 - """ - WRITE_ACCESS_ALLOWED = "write_access_allowed" - """:obj:`str`: Messages with :attr:`telegram.Message.write_access_allowed`. - - .. versionadded:: 20.8 - """ - - -class PaidMediaType(StringEnum): - """ - This enum contains the available types of :class:`telegram.PaidMedia`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - PREVIEW = "preview" - """:obj:`str`: The type of :class:`telegram.PaidMediaPreview`.""" - VIDEO = "video" - """:obj:`str`: The type of :class:`telegram.PaidMediaVideo`.""" - PHOTO = "photo" - """:obj:`str`: The type of :class:`telegram.PaidMediaPhoto`.""" - - -class PollingLimit(IntEnum): - """This enum contains limitations for :paramref:`telegram.Bot.get_updates.limit`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_LIMIT = 1 - """:obj:`int`: Minimum value allowed for the :paramref:`~telegram.Bot.get_updates.limit` - parameter of :meth:`telegram.Bot.get_updates`. - """ - MAX_LIMIT = 100 - """:obj:`int`: Maximum value allowed for the :paramref:`~telegram.Bot.get_updates.limit` - parameter of :meth:`telegram.Bot.get_updates`. - """ - - -class ProfileAccentColor(Enum): - """This enum contains the available accent colors for - :class:`telegram.ChatFullInfo.profile_accent_color_id`. - The members of this enum are named tuples with the following attributes: - - - ``identifier`` (:obj:`int`): The identifier of the accent color. - - ``name`` (:obj:`str`): Optional. The name of the accent color. - - ``light_colors`` (tuple[:obj:`str`]): Optional. The light colors of the accent color as HEX - value. - - ``dark_colors`` (tuple[:obj:`str`]): Optional. The dark colors of the accent color as HEX - value. - - Since Telegram gives no exact specification for the accent colors, future accent colors might - have a different data type. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - COLOR_000 = _AccentColor(identifier=0, light_colors=(0xBA5650,), dark_colors=(0x9C4540,)) - """Accent color 0. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_001 = _AccentColor(identifier=1, light_colors=(0xC27C3E,), dark_colors=(0x945E2C,)) - """Accent color 1. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_002 = _AccentColor(identifier=2, light_colors=(0x956AC8,), dark_colors=(0x715099,)) - """Accent color 2. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_003 = _AccentColor(identifier=3, light_colors=(0x49A355,), dark_colors=(0x33713B,)) - """Accent color 3. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_004 = _AccentColor(identifier=4, light_colors=(0x3E97AD,), dark_colors=(0x387E87,)) - """Accent color 4. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_005 = _AccentColor(identifier=5, light_colors=(0x5A8FBB,), dark_colors=(0x477194,)) - """Accent color 5. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_006 = _AccentColor(identifier=6, light_colors=(0xB85378,), dark_colors=(0x944763,)) - """Accent color 6. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_007 = _AccentColor(identifier=7, light_colors=(0x7F8B95,), dark_colors=(0x435261,)) - """Accent color 7. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_008 = _AccentColor( - identifier=8, light_colors=(0xC9565D, 0xD97C57), dark_colors=(0x994343, 0xAC583E) - ) - """Accent color 8. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_009 = _AccentColor( - identifier=9, light_colors=(0xCF7244, 0xCC9433), dark_colors=(0x8F552F, 0xA17232) - ) - """Accent color 9. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_010 = _AccentColor( - identifier=10, light_colors=(0x9662D4, 0xB966B6), dark_colors=(0x634691, 0x9250A2) - ) - """Accent color 10. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_011 = _AccentColor( - identifier=11, light_colors=(0x3D9755, 0x89A650), dark_colors=(0x296A43, 0x5F8F44) - ) - """Accent color 11. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_012 = _AccentColor( - identifier=12, light_colors=(0x3D95BA, 0x50AD98), dark_colors=(0x306C7C, 0x3E987E) - ) - """Accent color 12. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_013 = _AccentColor( - identifier=13, light_colors=(0x538BC2, 0x4DA8BD), dark_colors=(0x38618C, 0x458BA1) - ) - """Accent color 13. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_014 = _AccentColor( - identifier=14, light_colors=(0xB04F74, 0xD1666D), dark_colors=(0x884160, 0xA65259) - ) - """Accent color 14. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_015 = _AccentColor( - identifier=15, light_colors=(0x637482, 0x7B8A97), dark_colors=(0x53606E, 0x384654) - ) - """Accent color 15. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - - -class ReplyLimit(IntEnum): - """This enum contains limitations for :class:`telegram.ForceReply` - and :class:`telegram.ReplyKeyboardMarkup`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_INPUT_FIELD_PLACEHOLDER = 1 - """:obj:`int`: Minimum value allowed for - :paramref:`~telegram.ForceReply.input_field_placeholder` parameter of - :class:`telegram.ForceReply` and - :paramref:`~telegram.ReplyKeyboardMarkup.input_field_placeholder` parameter of - :class:`telegram.ReplyKeyboardMarkup` - """ - MAX_INPUT_FIELD_PLACEHOLDER = 64 - """:obj:`int`: Maximum value allowed for - :paramref:`~telegram.ForceReply.input_field_placeholder` parameter of - :class:`telegram.ForceReply` and - :paramref:`~telegram.ReplyKeyboardMarkup.input_field_placeholder` parameter of - :class:`telegram.ReplyKeyboardMarkup` - """ - - -class RevenueWithdrawalStateType(StringEnum): - """This enum contains the available types of :class:`telegram.RevenueWithdrawalState`. - The enum members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - PENDING = "pending" - """:obj:`str`: A withdrawal in progress.""" - SUCCEEDED = "succeeded" - """:obj:`str`: A withdrawal succeeded.""" - FAILED = "failed" - """:obj:`str`: A withdrawal failed and the transaction was refunded.""" - - -class StarTransactions(FloatEnum): - """This enum contains constants for :class:`telegram.StarTransaction`. - The enum members of this enumeration are instances of :class:`float` and can be treated as - such. - - .. versionadded:: 21.9 - """ - - __slots__ = () - - NANOSTAR_VALUE = 1 / 1000000000 - """:obj:`float`: The value of one nanostar as used in - :attr:`telegram.StarTransaction.nanostar_amount`. - """ - - -class StarTransactionsLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Bot.get_star_transactions` and - :class:`telegram.StarTransaction`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - MIN_LIMIT = 1 - """:obj:`int`: Minimum value allowed for the - :paramref:`~telegram.Bot.get_star_transactions.limit` parameter of - :meth:`telegram.Bot.get_star_transactions`.""" - MAX_LIMIT = 100 - """:obj:`int`: Maximum value allowed for the - :paramref:`~telegram.Bot.get_star_transactions.limit` parameter of - :meth:`telegram.Bot.get_star_transactions`.""" - NANOSTAR_MIN_AMOUNT = -999999999 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.AffiliateInfo.nanostar_amount` - parameter of :class:`telegram.AffiliateInfo`. - - .. versionadded:: 21.9 - """ - NANOSTAR_MAX_AMOUNT = 999999999 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.StarTransaction.nanostar_amount` - parameter of :class:`telegram.StarTransaction` and - :paramref:`~telegram.AffiliateInfo.nanostar_amount` parameter of - :class:`telegram.AffiliateInfo`. - - .. versionadded:: 21.9 - """ - - -class StickerFormat(StringEnum): - """This enum contains the available formats of :class:`telegram.Sticker` in the set. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.2 - """ - - __slots__ = () - - STATIC = "static" - """:obj:`str`: Static sticker.""" - ANIMATED = "animated" - """:obj:`str`: Animated sticker.""" - VIDEO = "video" - """:obj:`str`: Video sticker.""" - - -class StickerLimit(IntEnum): - """This enum contains limitations for various sticker methods, such as - :meth:`telegram.Bot.create_new_sticker_set`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_NAME_AND_TITLE = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.create_new_sticker_set.name` parameter or the - :paramref:`~telegram.Bot.create_new_sticker_set.title` parameter of - :meth:`telegram.Bot.create_new_sticker_set`. - """ - MAX_NAME_AND_TITLE = 64 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.create_new_sticker_set.name` parameter or the - :paramref:`~telegram.Bot.create_new_sticker_set.title` parameter of - :meth:`telegram.Bot.create_new_sticker_set`. - """ - MIN_STICKER_EMOJI = 1 - """:obj:`int`: Minimum number of emojis associated with a sticker, passed as the - :paramref:`~telegram.Bot.setStickerEmojiList.emoji_list` parameter of - :meth:`telegram.Bot.set_sticker_emoji_list`. - - .. versionadded:: 20.2 - """ - MAX_STICKER_EMOJI = 20 - """:obj:`int`: Maximum number of emojis associated with a sticker, passed as the - :paramref:`~telegram.Bot.setStickerEmojiList.emoji_list` parameter of - :meth:`telegram.Bot.set_sticker_emoji_list`. - - .. versionadded:: 20.2 - """ - MAX_SEARCH_KEYWORDS = 20 - """:obj:`int`: Maximum number of search keywords for a sticker, passed as the - :paramref:`~telegram.Bot.set_sticker_keywords.keywords` parameter of - :meth:`telegram.Bot.set_sticker_keywords`. - - .. versionadded:: 20.2 - """ - MAX_KEYWORD_LENGTH = 64 - """:obj:`int`: Maximum number of characters in a search keyword for a sticker, for each item in - :paramref:`~telegram.Bot.set_sticker_keywords.keywords` sequence of - :meth:`telegram.Bot.set_sticker_keywords`. - - .. versionadded:: 20.2 - """ - - -class StickerSetLimit(IntEnum): - """This enum contains limitations for various sticker set methods, such as - :meth:`telegram.Bot.create_new_sticker_set` and :meth:`telegram.Bot.add_sticker_to_set`. - - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.2 - """ - - __slots__ = () - - MIN_INITIAL_STICKERS = 1 - """:obj:`int`: Minimum number of stickers needed to create a sticker set, passed as the - :paramref:`~telegram.Bot.create_new_sticker_set.stickers` parameter of - :meth:`telegram.Bot.create_new_sticker_set`. - """ - MAX_INITIAL_STICKERS = 50 - """:obj:`int`: Maximum number of stickers allowed while creating a sticker set, passed as the - :paramref:`~telegram.Bot.create_new_sticker_set.stickers` parameter of - :meth:`telegram.Bot.create_new_sticker_set`. - """ - MAX_EMOJI_STICKERS = 200 - """:obj:`int`: Maximum number of stickers allowed in an emoji sticker set, as given in - :meth:`telegram.Bot.add_sticker_to_set`. - """ - MAX_ANIMATED_STICKERS = 50 - """:obj:`int`: Maximum number of stickers allowed in an animated or video sticker set, as given - in :meth:`telegram.Bot.add_sticker_to_set`. - - .. deprecated:: 21.1 - The animated sticker limit is now 120, the same as :attr:`MAX_STATIC_STICKERS`. - """ - MAX_STATIC_STICKERS = 120 - """:obj:`int`: Maximum number of stickers allowed in a static sticker set, as given in - :meth:`telegram.Bot.add_sticker_to_set`. - """ - MAX_STATIC_THUMBNAIL_SIZE = 128 - """:obj:`int`: Maximum size of the thumbnail if it is a **.WEBP** or **.PNG** in kilobytes, - as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`.""" - MAX_ANIMATED_THUMBNAIL_SIZE = 32 - """:obj:`int`: Maximum size of the thumbnail if it is a **.TGS** or **.WEBM** in kilobytes, - as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`.""" - STATIC_THUMB_DIMENSIONS = 100 - """:obj:`int`: Exact height and width of the thumbnail if it is a **.WEBP** or **.PNG** in - pixels, as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`.""" - - -class StickerType(StringEnum): - """This enum contains the available types of :class:`telegram.Sticker`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - REGULAR = "regular" - """:obj:`str`: Regular sticker.""" - MASK = "mask" - """:obj:`str`: Mask sticker.""" - CUSTOM_EMOJI = "custom_emoji" - """:obj:`str`: Custom emoji sticker.""" - - -class TransactionPartnerType(StringEnum): - """This enum contains the available types of :class:`telegram.TransactionPartner`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - AFFILIATE_PROGRAM = "affiliate_program" - """:obj:`str`: Transaction with Affiliate Program. - - .. versionadded:: 21.9 - """ - FRAGMENT = "fragment" - """:obj:`str`: Withdrawal transaction with Fragment.""" - OTHER = "other" - """:obj:`str`: Transaction with unknown source or recipient.""" - TELEGRAM_ADS = "telegram_ads" - """:obj:`str`: Transaction with Telegram Ads.""" - TELEGRAM_API = "telegram_api" - """:obj:`str`: Transaction with with payment for - `paid broadcasting `_. - - ..versionadded:: 21.7 - """ - USER = "user" - """:obj:`str`: Transaction with a user.""" - - -class ParseMode(StringEnum): - """This enum contains the available parse modes. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MARKDOWN = "Markdown" - """:obj:`str`: Markdown parse mode. - - Note: - :attr:`MARKDOWN` is a legacy mode, retained by Telegram for backward compatibility. - You should use :attr:`MARKDOWN_V2` instead. - """ - MARKDOWN_V2 = "MarkdownV2" - """:obj:`str`: Markdown parse mode version 2.""" - HTML = "HTML" - """:obj:`str`: HTML parse mode.""" - - -class PollLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Poll`/:class:`telegram.PollOption`/ - :meth:`telegram.Bot.send_poll`. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_QUESTION_LENGTH = 1 - """:obj:`int`: Minimum value allowed for the :paramref:`~telegram.Poll.question` - parameter of :class:`telegram.Poll` and the :paramref:`~telegram.Bot.send_poll.question` - parameter of :meth:`telegram.Bot.send_poll`. - """ - MAX_QUESTION_LENGTH = 300 - """:obj:`int`: Maximum value allowed for the :paramref:`~telegram.Poll.question` - parameter of :class:`telegram.Poll` and the :paramref:`~telegram.Bot.send_poll.question` - parameter of :meth:`telegram.Bot.send_poll`. - """ - MIN_OPTION_LENGTH = 1 - """:obj:`int`: Minimum length of each :obj:`str` passed in a :obj:`list` - to the :paramref:`~telegram.Bot.send_poll.options` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MAX_OPTION_LENGTH = 100 - """:obj:`int`: Maximum length of each :obj:`str` passed in a :obj:`list` - to the :paramref:`~telegram.Bot.send_poll.options` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MIN_OPTION_NUMBER = 2 - """:obj:`int`: Minimum number of strings passed in a :obj:`list` - to the :paramref:`~telegram.Bot.send_poll.options` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MAX_OPTION_NUMBER = 10 - """:obj:`int`: Maximum number of strings passed in a :obj:`list` - to the :paramref:`~telegram.Bot.send_poll.options` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MAX_EXPLANATION_LENGTH = 200 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Poll.explanation` parameter of :class:`telegram.Poll` and the - :paramref:`~telegram.Bot.send_poll.explanation` parameter of :meth:`telegram.Bot.send_poll`. - """ - MAX_EXPLANATION_LINE_FEEDS = 2 - """:obj:`int`: Maximum number of line feeds in a :obj:`str` passed as the - :paramref:`~telegram.Bot.send_poll.explanation` parameter of :meth:`telegram.Bot.send_poll` - after entities parsing. - """ - MIN_OPEN_PERIOD = 5 - """:obj:`int`: Minimum value allowed for the - :paramref:`~telegram.Bot.send_poll.open_period` parameter of :meth:`telegram.Bot.send_poll`. - Also used in the :paramref:`~telegram.Bot.send_poll.close_date` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MAX_OPEN_PERIOD = 600 - """:obj:`int`: Maximum value allowed for the - :paramref:`~telegram.Bot.send_poll.open_period` parameter of :meth:`telegram.Bot.send_poll`. - Also used in the :paramref:`~telegram.Bot.send_poll.close_date` parameter of - :meth:`telegram.Bot.send_poll`. - """ - - -class PollType(StringEnum): - """This enum contains the available types for :class:`telegram.Poll`/ - :meth:`telegram.Bot.send_poll`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - REGULAR = "regular" - """:obj:`str`: regular polls.""" - QUIZ = "quiz" - """:obj:`str`: quiz polls.""" - - -class UpdateType(StringEnum): - """This enum contains the available types of :class:`telegram.Update`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MESSAGE = "message" - """:obj:`str`: Updates with :attr:`telegram.Update.message`.""" - EDITED_MESSAGE = "edited_message" - """:obj:`str`: Updates with :attr:`telegram.Update.edited_message`.""" - CHANNEL_POST = "channel_post" - """:obj:`str`: Updates with :attr:`telegram.Update.channel_post`.""" - EDITED_CHANNEL_POST = "edited_channel_post" - """:obj:`str`: Updates with :attr:`telegram.Update.edited_channel_post`.""" - INLINE_QUERY = "inline_query" - """:obj:`str`: Updates with :attr:`telegram.Update.inline_query`.""" - CHOSEN_INLINE_RESULT = "chosen_inline_result" - """:obj:`str`: Updates with :attr:`telegram.Update.chosen_inline_result`.""" - CALLBACK_QUERY = "callback_query" - """:obj:`str`: Updates with :attr:`telegram.Update.callback_query`.""" - SHIPPING_QUERY = "shipping_query" - """:obj:`str`: Updates with :attr:`telegram.Update.shipping_query`.""" - PRE_CHECKOUT_QUERY = "pre_checkout_query" - """:obj:`str`: Updates with :attr:`telegram.Update.pre_checkout_query`.""" - POLL = "poll" - """:obj:`str`: Updates with :attr:`telegram.Update.poll`.""" - POLL_ANSWER = "poll_answer" - """:obj:`str`: Updates with :attr:`telegram.Update.poll_answer`.""" - MY_CHAT_MEMBER = "my_chat_member" - """:obj:`str`: Updates with :attr:`telegram.Update.my_chat_member`.""" - CHAT_MEMBER = "chat_member" - """:obj:`str`: Updates with :attr:`telegram.Update.chat_member`.""" - CHAT_JOIN_REQUEST = "chat_join_request" - """:obj:`str`: Updates with :attr:`telegram.Update.chat_join_request`.""" - CHAT_BOOST = "chat_boost" - """:obj:`str`: Updates with :attr:`telegram.Update.chat_boost`. - - .. versionadded:: 20.8 - """ - REMOVED_CHAT_BOOST = "removed_chat_boost" - """:obj:`str`: Updates with :attr:`telegram.Update.removed_chat_boost`. - - .. versionadded:: 20.8 - """ - MESSAGE_REACTION = "message_reaction" - """:obj:`str`: Updates with :attr:`telegram.Update.message_reaction`. - - .. versionadded:: 20.8 - """ - MESSAGE_REACTION_COUNT = "message_reaction_count" - """:obj:`str`: Updates with :attr:`telegram.Update.message_reaction_count`. - - .. versionadded:: 20.8 - """ - BUSINESS_CONNECTION = "business_connection" - """:obj:`str`: Updates with :attr:`telegram.Update.business_connection`. - - .. versionadded:: 21.1 - """ - BUSINESS_MESSAGE = "business_message" - """:obj:`str`: Updates with :attr:`telegram.Update.business_message`. - - .. versionadded:: 21.1 - """ - EDITED_BUSINESS_MESSAGE = "edited_business_message" - """:obj:`str`: Updates with :attr:`telegram.Update.edited_business_message`. - - .. versionadded:: 21.1 - """ - DELETED_BUSINESS_MESSAGES = "deleted_business_messages" - """:obj:`str`: Updates with :attr:`telegram.Update.deleted_business_messages`. - - .. versionadded:: 21.1 - """ - PURCHASED_PAID_MEDIA = "purchased_paid_media" - """:obj:`str`: Updates with :attr:`telegram.Update.purchased_paid_media`. - - .. versionadded:: 21.6 - """ - - -class InvoiceLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InputInvoiceMessageContent`, - :meth:`telegram.Bot.send_invoice`, and :meth:`telegram.Bot.create_invoice_link`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_TITLE_LENGTH = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.title` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.title` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.title` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MAX_TITLE_LENGTH = 32 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.title` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.title` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.title` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MIN_DESCRIPTION_LENGTH = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.description` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.description` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.description` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MAX_DESCRIPTION_LENGTH = 255 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.description` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.description` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.description` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MIN_PAYLOAD_LENGTH = 1 - """:obj:`int`: Minimum amount of bytes in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.payload` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.payload` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.payload` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MAX_PAYLOAD_LENGTH = 128 - """:obj:`int`: Maximum amount of bytes in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.payload` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.payload` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.payload` parameter of - :meth:`telegram.Bot.create_invoice_link`. - * :paramref:`~telegram.Bot.send_paid_media.payload` parameter of - :meth:`telegram.Bot.send_paid_media`. - """ - MAX_TIP_AMOUNTS = 4 - """:obj:`int`: Maximum length of a :obj:`Sequence` passed as: - - * :paramref:`~telegram.Bot.send_invoice.suggested_tip_amounts` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.suggested_tip_amounts` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MIN_STAR_COUNT = 1 - """:obj:`int`: Minimum amount of starts that must be paid to buy access to a paid media - passed as :paramref:`~telegram.Bot.send_paid_media.star_count` parameter of - :meth:`telegram.Bot.send_paid_media`. - - .. versionadded:: 21.6 - """ - MAX_STAR_COUNT = 2500 - """:obj:`int`: Maximum amount of starts that must be paid to buy access to a paid media - passed as :paramref:`~telegram.Bot.send_paid_media.star_count` parameter of - :meth:`telegram.Bot.send_paid_media`. - - .. versionadded:: 21.6 - """ - SUBSCRIPTION_PERIOD = dtm.timedelta(days=30).total_seconds() - """:obj:`int`: The period of time for which the subscription is active before - the next payment, passed as :paramref:`~telegram.Bot.create_invoice_link.subscription_period` - parameter of :meth:`telegram.Bot.create_invoice_link`. - - .. versionadded:: 21.8 - """ - SUBSCRIPTION_MAX_PRICE = 2500 - """:obj:`int`: The maximum price of a subscription created wtih - :meth:`telegram.Bot.create_invoice_link`. - - .. versionadded:: 21.9 - """ - - -class UserProfilePhotosLimit(IntEnum): - """This enum contains limitations for :paramref:`telegram.Bot.get_user_profile_photos.limit`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_LIMIT = 1 - """:obj:`int`: Minimum value allowed for - :paramref:`~telegram.Bot.get_user_profile_photos.limit` parameter of - :meth:`telegram.Bot.get_user_profile_photos`. - """ - MAX_LIMIT = 100 - """:obj:`int`: Maximum value allowed for - :paramref:`~telegram.Bot.get_user_profile_photos.limit` parameter of - :meth:`telegram.Bot.get_user_profile_photos`. - """ - - -class WebhookLimit(IntEnum): - """This enum contains limitations for :paramref:`telegram.Bot.set_webhook.max_connections` and - :paramref:`telegram.Bot.set_webhook.secret_token`. The enum members of this enumeration are - instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_CONNECTIONS_LIMIT = 1 - """:obj:`int`: Minimum value allowed for the - :paramref:`~telegram.Bot.set_webhook.max_connections` parameter of - :meth:`telegram.Bot.set_webhook`. - """ - MAX_CONNECTIONS_LIMIT = 100 - """:obj:`int`: Maximum value allowed for the - :paramref:`~telegram.Bot.set_webhook.max_connections` parameter of - :meth:`telegram.Bot.set_webhook`. - """ - MIN_SECRET_TOKEN_LENGTH = 1 - """:obj:`int`: Minimum length of the secret token for the - :paramref:`~telegram.Bot.set_webhook.secret_token` parameter of - :meth:`telegram.Bot.set_webhook`. - """ - MAX_SECRET_TOKEN_LENGTH = 256 - """:obj:`int`: Maximum length of the secret token for the - :paramref:`~telegram.Bot.set_webhook.secret_token` parameter of - :meth:`telegram.Bot.set_webhook`. - """ - - -class ForumTopicLimit(IntEnum): - """This enum contains limitations for :paramref:`telegram.Bot.create_forum_topic.name` and - :paramref:`telegram.Bot.edit_forum_topic.name`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_NAME_LENGTH = 1 - """:obj:`int`: Minimum length of a :obj:`str` passed as: - - * :paramref:`~telegram.Bot.create_forum_topic.name` parameter of - :meth:`telegram.Bot.create_forum_topic` - * :paramref:`~telegram.Bot.edit_forum_topic.name` parameter of - :meth:`telegram.Bot.edit_forum_topic` - * :paramref:`~telegram.Bot.edit_general_forum_topic.name` parameter of - :meth:`telegram.Bot.edit_general_forum_topic` - """ - MAX_NAME_LENGTH = 128 - """:obj:`int`: Maximum length of a :obj:`str` passed as: - - * :paramref:`~telegram.Bot.create_forum_topic.name` parameter of - :meth:`telegram.Bot.create_forum_topic` - * :paramref:`~telegram.Bot.edit_forum_topic.name` parameter of - :meth:`telegram.Bot.edit_forum_topic` - * :paramref:`~telegram.Bot.edit_general_forum_topic.name` parameter of - :meth:`telegram.Bot.edit_general_forum_topic` - """ - - -class ReactionType(StringEnum): - """This enum contains the available types of :class:`telegram.ReactionType`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - EMOJI = "emoji" - """:obj:`str`: A :class:`telegram.ReactionType` with a normal emoji.""" - CUSTOM_EMOJI = "custom_emoji" - """:obj:`str`: A :class:`telegram.ReactionType` with a custom emoji.""" - PAID = "paid" - """:obj:`str`: A :class:`telegram.ReactionType` with a paid reaction. - - .. versionadded:: 21.5 - """ - - -class ReactionEmoji(StringEnum): - """This enum contains the available emojis of :class:`telegram.ReactionTypeEmoji`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - THUMBS_UP = "👍" - """:obj:`str`: Thumbs Up""" - THUMBS_DOWN = "👎" - """:obj:`str`: Thumbs Down""" - RED_HEART = "❤" - """:obj:`str`: Red Heart""" - FIRE = "🔥" - """:obj:`str`: Fire""" - SMILING_FACE_WITH_HEARTS = "🥰" - """:obj:`str`: Smiling Face with Hearts""" - CLAPPING_HANDS = "👏" - """:obj:`str`: Clapping Hands""" - GRINNING_FACE_WITH_SMILING_EYES = "😁" - """:obj:`str`: Grinning face with smiling eyes""" - THINKING_FACE = "🤔" - """:obj:`str`: Thinking face""" - SHOCKED_FACE_WITH_EXPLODING_HEAD = "🤯" - """:obj:`str`: Shocked face with exploding head""" - FACE_SCREAMING_IN_FEAR = "😱" - """:obj:`str`: Face screaming in fear""" - SERIOUS_FACE_WITH_SYMBOLS_COVERING_MOUTH = "🤬" - """:obj:`str`: Serious face with symbols covering mouth""" - CRYING_FACE = "😢" - """:obj:`str`: Crying face""" - PARTY_POPPER = "🎉" - """:obj:`str`: Party popper""" - GRINNING_FACE_WITH_STAR_EYES = "🤩" - """:obj:`str`: Grinning face with star eyes""" - FACE_WITH_OPEN_MOUTH_VOMITING = "🤮" - """:obj:`str`: Face with open mouth vomiting""" - PILE_OF_POO = "💩" - """:obj:`str`: Pile of poo""" - PERSON_WITH_FOLDED_HANDS = "🙏" - """:obj:`str`: Person with folded hands""" - OK_HAND_SIGN = "👌" - """:obj:`str`: Ok hand sign""" - DOVE_OF_PEACE = "🕊" - """:obj:`str`: Dove of peace""" - CLOWN_FACE = "🤡" - """:obj:`str`: Clown face""" - YAWNING_FACE = "🥱" - """:obj:`str`: Yawning face""" - FACE_WITH_UNEVEN_EYES_AND_WAVY_MOUTH = "🥴" - """:obj:`str`: Face with uneven eyes and wavy mouth""" - SMILING_FACE_WITH_HEART_SHAPED_EYES = "😍" - """:obj:`str`: Smiling face with heart-shaped eyes""" - SPOUTING_WHALE = "🐳" - """:obj:`str`: Spouting whale""" - HEART_ON_FIRE = "❤️‍🔥" - """:obj:`str`: Heart on fire""" - NEW_MOON_WITH_FACE = "🌚" - """:obj:`str`: New moon with face""" - HOT_DOG = "🌭" - """:obj:`str`: Hot dog""" - HUNDRED_POINTS_SYMBOL = "💯" - """:obj:`str`: Hundred points symbol""" - ROLLING_ON_THE_FLOOR_LAUGHING = "🤣" - """:obj:`str`: Rolling on the floor laughing""" - HIGH_VOLTAGE_SIGN = "⚡" - """:obj:`str`: High voltage sign""" - BANANA = "🍌" - """:obj:`str`: Banana""" - TROPHY = "🏆" - """:obj:`str`: Trophy""" - BROKEN_HEART = "💔" - """:obj:`str`: Broken heart""" - FACE_WITH_ONE_EYEBROW_RAISED = "🤨" - """:obj:`str`: Face with one eyebrow raised""" - NEUTRAL_FACE = "😐" - """:obj:`str`: Neutral face""" - STRAWBERRY = "🍓" - """:obj:`str`: Strawberry""" - BOTTLE_WITH_POPPING_CORK = "🍾" - """:obj:`str`: Bottle with popping cork""" - KISS_MARK = "💋" - """:obj:`str`: Kiss mark""" - REVERSED_HAND_WITH_MIDDLE_FINGER_EXTENDED = "🖕" - """:obj:`str`: Reversed hand with middle finger extended""" - SMILING_FACE_WITH_HORNS = "😈" - """:obj:`str`: Smiling face with horns""" - SLEEPING_FACE = "😴" - """:obj:`str`: Sleeping face""" - LOUDLY_CRYING_FACE = "😭" - """:obj:`str`: Loudly crying face""" - NERD_FACE = "🤓" - """:obj:`str`: Nerd face""" - GHOST = "👻" - """:obj:`str`: Ghost""" - MAN_TECHNOLOGIST = "👨‍💻" - """:obj:`str`: Man Technologist""" - EYES = "👀" - """:obj:`str`: Eyes""" - JACK_O_LANTERN = "🎃" - """:obj:`str`: Jack-o-lantern""" - SEE_NO_EVIL_MONKEY = "🙈" - """:obj:`str`: See-no-evil monkey""" - SMILING_FACE_WITH_HALO = "😇" - """:obj:`str`: Smiling face with halo""" - FEARFUL_FACE = "😨" - """:obj:`str`: Fearful face""" - HANDSHAKE = "🤝" - """:obj:`str`: Handshake""" - WRITING_HAND = "✍" - """:obj:`str`: Writing hand""" - HUGGING_FACE = "🤗" - """:obj:`str`: Hugging face""" - SALUTING_FACE = "🫡" - """:obj:`str`: Saluting face""" - FATHER_CHRISTMAS = "🎅" - """:obj:`str`: Father christmas""" - CHRISTMAS_TREE = "🎄" - """:obj:`str`: Christmas tree""" - SNOWMAN = "☃" - """:obj:`str`: Snowman""" - NAIL_POLISH = "💅" - """:obj:`str`: Nail polish""" - GRINNING_FACE_WITH_ONE_LARGE_AND_ONE_SMALL_EYE = "🤪" - """:obj:`str`: Grinning face with one large and one small eye""" - MOYAI = "🗿" - """:obj:`str`: Moyai""" - SQUARED_COOL = "🆒" - """:obj:`str`: Squared cool""" - HEART_WITH_ARROW = "💘" - """:obj:`str`: Heart with arrow""" - HEAR_NO_EVIL_MONKEY = "🙉" - """:obj:`str`: Hear-no-evil monkey""" - UNICORN_FACE = "🦄" - """:obj:`str`: Unicorn face""" - FACE_THROWING_A_KISS = "😘" - """:obj:`str`: Face throwing a kiss""" - PILL = "💊" - """:obj:`str`: Pill""" - SPEAK_NO_EVIL_MONKEY = "🙊" - """:obj:`str`: Speak-no-evil monkey""" - SMILING_FACE_WITH_SUNGLASSES = "😎" - """:obj:`str`: Smiling face with sunglasses""" - ALIEN_MONSTER = "👾" - """:obj:`str`: Alien monster""" - MAN_SHRUGGING = "🤷‍♂️" - """:obj:`str`: Man Shrugging""" - SHRUG = "🤷" - """:obj:`str`: Shrug""" - WOMAN_SHRUGGING = "🤷‍♀️" - """:obj:`str`: Woman Shrugging""" - POUTING_FACE = "😡" - """:obj:`str`: Pouting face""" - - -class VerifyLimit(IntEnum): - """This enum contains limitations for :meth:`~telegram.Bot.verify_chat` and - :meth:`~telegram.Bot.verify_user`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.10 - """ - - __slots__ = () - - MAX_TEXT_LENGTH = 70 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.verify_chat.custom_description` or - :paramref:`~telegram.Bot.verify_user.custom_description` parameter. - """ diff --git a/venv/lib/python3.11/site-packages/telegram/error.py b/venv/lib/python3.11/site-packages/telegram/error.py deleted file mode 100755 index 2de0361..0000000 --- a/venv/lib/python3.11/site-packages/telegram/error.py +++ /dev/null @@ -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 -# -# 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 ` - """ - - __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 ` - - .. 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 `_. - - Examples: - :any:`Raw API Bot ` - - .. seealso:: - :wiki:`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 ` - - 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 ` - - 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,) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__init__.py b/venv/lib/python3.11/site-packages/telegram/ext/__init__.py deleted file mode 100755 index 7cd6578..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/__init__.py +++ /dev/null @@ -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 -# -# 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 59c3c8d..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_aioratelimiter.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_aioratelimiter.cpython-311.pyc deleted file mode 100755 index b0d0a8d..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_aioratelimiter.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_application.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_application.cpython-311.pyc deleted file mode 100755 index 4a775e1..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_application.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_applicationbuilder.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_applicationbuilder.cpython-311.pyc deleted file mode 100755 index 6d3afd4..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_applicationbuilder.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_basepersistence.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_basepersistence.cpython-311.pyc deleted file mode 100755 index bc9cc5a..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_basepersistence.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseratelimiter.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseratelimiter.cpython-311.pyc deleted file mode 100755 index ce99e3f..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseratelimiter.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseupdateprocessor.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseupdateprocessor.cpython-311.pyc deleted file mode 100755 index 8ce4a07..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseupdateprocessor.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackcontext.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackcontext.cpython-311.pyc deleted file mode 100755 index b215eed..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackcontext.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackdatacache.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackdatacache.cpython-311.pyc deleted file mode 100755 index 71bdd59..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackdatacache.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_contexttypes.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_contexttypes.cpython-311.pyc deleted file mode 100755 index 56cad64..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_contexttypes.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_defaults.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_defaults.cpython-311.pyc deleted file mode 100755 index 8d0ff1d..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_defaults.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_dictpersistence.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_dictpersistence.cpython-311.pyc deleted file mode 100755 index 03ebca9..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_dictpersistence.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_extbot.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_extbot.cpython-311.pyc deleted file mode 100755 index efb6e9c..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_extbot.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_jobqueue.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_jobqueue.cpython-311.pyc deleted file mode 100755 index 4f0013f..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_jobqueue.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_picklepersistence.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_picklepersistence.cpython-311.pyc deleted file mode 100755 index f0510ca..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_picklepersistence.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_updater.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_updater.cpython-311.pyc deleted file mode 100755 index 7927b2d..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_updater.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/filters.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/filters.cpython-311.pyc deleted file mode 100755 index 60c7451..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/filters.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_aioratelimiter.py b/venv/lib/python3.11/site-packages/telegram/ext/_aioratelimiter.py deleted file mode 100755 index c990a54..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_aioratelimiter.py +++ /dev/null @@ -1,277 +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 -# -# 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 implementation of the BaseRateLimiter class based on the aiolimiter -library. -""" -import asyncio -import contextlib -import sys -from collections.abc import AsyncIterator, Coroutine -from typing import Any, Callable, Optional, Union - -try: - from aiolimiter import AsyncLimiter - - AIO_LIMITER_AVAILABLE = True -except ImportError: - AIO_LIMITER_AVAILABLE = False - -from telegram._utils.logging import get_logger -from telegram._utils.types import JSONDict -from telegram.error import RetryAfter -from telegram.ext._baseratelimiter import BaseRateLimiter - -# Useful for something like: -# async with group_limiter if group else null_context(): -# so we don't have to differentiate between "I'm using a context manager" and "I'm not" -if sys.version_info >= (3, 10): - null_context = contextlib.nullcontext # pylint: disable=invalid-name -else: - - @contextlib.asynccontextmanager - async def null_context() -> AsyncIterator[None]: - yield None - - -_LOGGER = get_logger(__name__, class_name="AIORateLimiter") - - -class AIORateLimiter(BaseRateLimiter[int]): - """ - Implementation of :class:`~telegram.ext.BaseRateLimiter` using the library - `aiolimiter `_. - - Important: - If you want to use this class, you must install PTB with the optional requirement - ``rate-limiter``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[rate-limiter]" - - The rate limiting is applied by combining two levels of throttling and :meth:`process_request` - roughly boils down to:: - - async with group_limiter(group_id): - async with overall_limiter: - await callback(*args, **kwargs) - - Here, ``group_id`` is determined by checking if there is a ``chat_id`` parameter in the - :paramref:`~telegram.ext.BaseRateLimiter.process_request.data`. - The ``overall_limiter`` is applied only if a ``chat_id`` argument is present at all. - - Attention: - * Some bot methods accept a ``chat_id`` parameter in form of a ``@username`` for - supergroups and channels. As we can't know which ``@username`` corresponds to which - integer ``chat_id``, these will be treated as different groups, which may lead to - exceeding the rate limit. - * As channels can't be differentiated from supergroups by the ``@username`` or integer - ``chat_id``, this also applies the group related rate limits to channels. - * A :exc:`~telegram.error.RetryAfter` exception will halt *all* requests for - :attr:`~telegram.error.RetryAfter.retry_after` + 0.1 seconds. This may be stricter than - necessary in some cases, e.g. the bot may hit a rate limit in one group but might still - be allowed to send messages in another group. - - Tip: - With `Bot API 7.1 `_ - (PTB v27.1), Telegram introduced the parameter - :paramref:`~telegram.Bot.send_message.allow_paid_broadcast`. - This allows bots to send up to - :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second by - paying a fee in Telegram Stars. - - .. caution:: - This class currently doesn't take the - :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` parameter into account. - This means that the rate limiting is applied just like for any other message. - - Note: - This class is to be understood as minimal effort reference implementation. - If you would like to handle rate limiting in a more sophisticated, fine-tuned way, we - welcome you to implement your own subclass of :class:`~telegram.ext.BaseRateLimiter`. - Feel free to check out the source code of this class for inspiration. - - .. seealso:: :wiki:`Avoiding Flood Limits ` - - .. versionadded:: 20.0 - - Args: - overall_max_rate (:obj:`float`): The maximum number of requests allowed for the entire bot - per :paramref:`overall_time_period`. When set to 0, no rate limiting will be applied. - Defaults to ``30``. - overall_time_period (:obj:`float`): The time period (in seconds) during which the - :paramref:`overall_max_rate` is enforced. When set to 0, no rate limiting will be - applied. Defaults to 1. - group_max_rate (:obj:`float`): The maximum number of requests allowed for requests related - to groups and channels per :paramref:`group_time_period`. When set to 0, no rate - limiting will be applied. Defaults to 20. - group_time_period (:obj:`float`): The time period (in seconds) during which the - :paramref:`group_max_rate` is enforced. When set to 0, no rate limiting will be - applied. Defaults to 60. - max_retries (:obj:`int`): The maximum number of retries to be made in case of a - :exc:`~telegram.error.RetryAfter` exception. - If set to 0, no retries will be made. Defaults to ``0``. - - """ - - __slots__ = ( - "_base_limiter", - "_group_limiters", - "_group_max_rate", - "_group_time_period", - "_max_retries", - "_retry_after_event", - ) - - def __init__( - self, - overall_max_rate: float = 30, - overall_time_period: float = 1, - group_max_rate: float = 20, - group_time_period: float = 60, - max_retries: int = 0, - ) -> None: - if not AIO_LIMITER_AVAILABLE: - raise RuntimeError( - "To use `AIORateLimiter`, PTB must be installed via `pip install " - '"python-telegram-bot[rate-limiter]"`.' - ) - if overall_max_rate and overall_time_period: - self._base_limiter: Optional[AsyncLimiter] = AsyncLimiter( - max_rate=overall_max_rate, time_period=overall_time_period - ) - else: - self._base_limiter = None - - if group_max_rate and group_time_period: - self._group_max_rate: float = group_max_rate - self._group_time_period: float = group_time_period - else: - self._group_max_rate = 0 - self._group_time_period = 0 - - self._group_limiters: dict[Union[str, int], AsyncLimiter] = {} - self._max_retries: int = max_retries - self._retry_after_event = asyncio.Event() - self._retry_after_event.set() - - async def initialize(self) -> None: - """Does nothing.""" - - async def shutdown(self) -> None: - """Does nothing.""" - - def _get_group_limiter(self, group_id: Union[str, int, bool]) -> "AsyncLimiter": - # Remove limiters that haven't been used for so long that all their capacity is unused - # We only do that if we have a lot of limiters lying around to avoid looping on every call - # This is a minimal effort approach - a full-fledged cache could use a TTL approach - # or at least adapt the threshold dynamically depending on the number of active limiters - if len(self._group_limiters) > 512: - # We copy to avoid modifying the dict while we iterate over it - for key, limiter in self._group_limiters.copy().items(): - if key == group_id: - continue - if limiter.has_capacity(limiter.max_rate): - del self._group_limiters[key] - - if group_id not in self._group_limiters: - self._group_limiters[group_id] = AsyncLimiter( - max_rate=self._group_max_rate, - time_period=self._group_time_period, - ) - return self._group_limiters[group_id] - - async def _run_request( - self, - chat: bool, - group: Union[str, int, bool], - callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, list[JSONDict]]]], - args: Any, - kwargs: dict[str, Any], - ) -> Union[bool, JSONDict, list[JSONDict]]: - base_context = self._base_limiter if (chat and self._base_limiter) else null_context() - group_context = ( - self._get_group_limiter(group) if group and self._group_max_rate else null_context() - ) - - async with group_context, base_context: - # In case a retry_after was hit, we wait with processing the request - await self._retry_after_event.wait() - - return await callback(*args, **kwargs) - - # mypy doesn't understand that the last run of the for loop raises an exception - async def process_request( - self, - callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, list[JSONDict]]]], - args: Any, - kwargs: dict[str, Any], - endpoint: str, # noqa: ARG002 - data: dict[str, Any], - rate_limit_args: Optional[int], - ) -> Union[bool, JSONDict, list[JSONDict]]: - """ - Processes a request by applying rate limiting. - - See :meth:`telegram.ext.BaseRateLimiter.process_request` for detailed information on the - arguments. - - Args: - rate_limit_args (:obj:`None` | :obj:`int`): If set, specifies the maximum number of - retries to be made in case of a :exc:`~telegram.error.RetryAfter` exception. - Defaults to :paramref:`AIORateLimiter.max_retries`. - """ - max_retries = rate_limit_args or self._max_retries - - group: Union[int, str, bool] = False - chat: bool = False - chat_id = data.get("chat_id") - if chat_id is not None: - chat = True - - # In case user passes integer chat id as string - with contextlib.suppress(ValueError, TypeError): - chat_id = int(chat_id) - - if (isinstance(chat_id, int) and chat_id < 0) or isinstance(chat_id, str): - # string chat_id only works for channels and supergroups - # We can't really tell channels from groups though ... - group = chat_id - - for i in range(max_retries + 1): - try: - return await self._run_request( - chat=chat, group=group, callback=callback, args=args, kwargs=kwargs - ) - except RetryAfter as exc: - if i == max_retries: - _LOGGER.exception( - "Rate limit hit after maximum of %d retries", max_retries, exc_info=exc - ) - raise - - sleep = exc.retry_after + 0.1 - _LOGGER.info("Rate limit hit. Retrying after %f seconds", sleep) - # Make sure we don't allow other requests to be processed - self._retry_after_event.clear() - await asyncio.sleep(sleep) - finally: - # Allow other requests to be processed - self._retry_after_event.set() - return None # type: ignore[return-value] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_application.py b/venv/lib/python3.11/site-packages/telegram/ext/_application.py deleted file mode 100755 index 5815b34..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_application.py +++ /dev/null @@ -1,1917 +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 -# -# 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 Application class.""" - -import asyncio -import contextlib -import inspect -import itertools -import platform -import signal -import sys -from collections import defaultdict -from collections.abc import Awaitable, Coroutine, Generator, Mapping, Sequence -from copy import deepcopy -from pathlib import Path -from types import MappingProxyType, TracebackType -from typing import TYPE_CHECKING, Any, Callable, Generic, NoReturn, Optional, TypeVar, Union - -from telegram._update import Update -from telegram._utils.defaultvalue import ( - DEFAULT_80, - DEFAULT_IP, - DEFAULT_NONE, - DEFAULT_TRUE, - DefaultValue, -) -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import SCT, DVType, ODVInput -from telegram._utils.warnings import warn -from telegram.error import TelegramError -from telegram.ext._basepersistence import BasePersistence -from telegram.ext._contexttypes import ContextTypes -from telegram.ext._extbot import ExtBot -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._updater import Updater -from telegram.ext._utils.stack import was_called_by -from telegram.ext._utils.trackingdict import TrackingDict -from telegram.ext._utils.types import BD, BT, CCT, CD, JQ, RT, UD, ConversationKey, HandlerCallback -from telegram.warnings import PTBDeprecationWarning - -if TYPE_CHECKING: - from socket import socket - - from telegram import Message - from telegram.ext import ConversationHandler, JobQueue - from telegram.ext._applicationbuilder import InitApplicationBuilder - from telegram.ext._baseupdateprocessor import BaseUpdateProcessor - from telegram.ext._jobqueue import Job - -DEFAULT_GROUP: int = 0 - -_AppType = TypeVar("_AppType", bound="Application") # pylint: disable=invalid-name -_STOP_SIGNAL = object() -_DEFAULT_0 = DefaultValue(0) - -# Since python 3.12, the coroutine passed to create_task should not be an (async) generator. Remove -# this check when we drop support for python 3.11. -if sys.version_info >= (3, 12): - _CoroType = Awaitable[RT] -else: - _CoroType = Union[Generator["asyncio.Future[object]", None, RT], Awaitable[RT]] - -_ErrorCoroType = Optional[_CoroType[RT]] - -_LOGGER = get_logger(__name__) - - -class ApplicationHandlerStop(Exception): - """ - Raise this in a handler or an error handler to prevent execution of any other handler (even in - different groups). - - In order to use this exception in a :class:`telegram.ext.ConversationHandler`, pass the - optional :paramref:`state` parameter instead of returning the next state: - - .. code-block:: python - - async def conversation_callback(update, context): - ... - raise ApplicationHandlerStop(next_state) - - Note: - Has no effect, if the handler or error handler is run in a non-blocking way. - - Args: - state (:obj:`object`, optional): The next state of the conversation. - - Attributes: - state (:obj:`object`): Optional. The next state of the conversation. - """ - - __slots__ = ("state",) - - def __init__(self, state: Optional[object] = None) -> None: - super().__init__() - self.state: Optional[object] = state - - -class Application( - Generic[BT, CCT, UD, CD, BD, JQ], - contextlib.AbstractAsyncContextManager["Application"], -): - """This class dispatches all kinds of updates to its registered handlers, and is the entry - point to a PTB application. - - Tip: - This class may not be initialized directly. Use :class:`telegram.ext.ApplicationBuilder` - or :meth:`builder` (for convenience). - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with application: - # code - - is roughly equivalent to - - .. code:: python - - try: - await application.initialize() - # code - finally: - await application.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - This class is a :class:`~typing.Generic` class and accepts six type variables: - - 1. The type of :attr:`bot`. Must be :class:`telegram.Bot` or a subclass of that class. - 2. The type of the argument ``context`` of callback functions for (error) handlers and jobs. - Must be :class:`telegram.ext.CallbackContext` or a subclass of that class. This must be - consistent with the following types. - 3. The type of the values of :attr:`user_data`. - 4. The type of the values of :attr:`chat_data`. - 5. The type of :attr:`bot_data`. - 6. The type of :attr:`job_queue`. Must either be :class:`telegram.ext.JobQueue` or a subclass - of that or :obj:`None`. - - Examples: - :any:`Echo Bot ` - - .. seealso:: :wiki:`Your First Bot `, - :wiki:`Architecture Overview ` - - .. versionchanged:: 20.0 - - * Initialization is now done through the :class:`telegram.ext.ApplicationBuilder`. - * Removed the attribute ``groups``. - - Attributes: - bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers. - update_queue (:class:`asyncio.Queue`): The synchronized queue that will contain the - updates. - updater (:class:`telegram.ext.Updater`): Optional. The updater used by this application. - chat_data (:obj:`types.MappingProxyType`): A dictionary handlers can use to store data for - the chat. For each integer chat id, the corresponding value of this mapping is - available as :attr:`telegram.ext.CallbackContext.chat_data` in handler callbacks for - updates from that chat. - - .. versionchanged:: 20.0 - :attr:`chat_data` is now read-only. Note that the values of the mapping are still - mutable, i.e. editing ``context.chat_data`` within a handler callback is possible - (and encouraged), but editing the mapping ``application.chat_data`` itself is not. - - .. tip:: - - * Manually modifying :attr:`chat_data` is almost never needed and unadvisable. - * Entries are never deleted automatically from this mapping. If you want to delete - the data associated with a specific chat, e.g. if the bot got removed from that - chat, please use :meth:`drop_chat_data`. - - user_data (:obj:`types.MappingProxyType`): A dictionary handlers can use to store data for - the user. For each integer user id, the corresponding value of this mapping is - available as :attr:`telegram.ext.CallbackContext.user_data` in handler callbacks for - updates from that user. - - .. versionchanged:: 20.0 - :attr:`user_data` is now read-only. Note that the values of the mapping are still - mutable, i.e. editing ``context.user_data`` within a handler callback is possible - (and encouraged), but editing the mapping ``application.user_data`` itself is not. - - .. tip:: - - * Manually modifying :attr:`user_data` is almost never needed and unadvisable. - * Entries are never deleted automatically from this mapping. If you want to delete - the data associated with a specific user, e.g. if that user blocked the bot, - please use :meth:`drop_user_data`. - - bot_data (:obj:`dict`): A dictionary handlers can use to store data for the bot. - persistence (:class:`telegram.ext.BasePersistence`): The persistence class to - store data that should be persistent over restarts. - handlers (dict[:obj:`int`, list[:class:`telegram.ext.BaseHandler`]]): A dictionary mapping - each handler group to the list of handlers registered to that group. - - .. seealso:: - :meth:`add_handler`, :meth:`add_handlers`. - error_handlers (dict[:term:`coroutine function`, :obj:`bool`]): A dictionary where the keys - are error handlers and the values indicate whether they are to be run blocking. - - .. seealso:: - :meth:`add_error_handler` - context_types (:class:`telegram.ext.ContextTypes`): Specifies the types used by this - dispatcher for the ``context`` argument of handler and job callbacks. - post_init (:term:`coroutine function`): Optional. A callback that will be executed by - :meth:`Application.run_polling` and :meth:`Application.run_webhook` after initializing - the application via :meth:`initialize`. - post_shutdown (:term:`coroutine function`): Optional. A callback that will be executed by - :meth:`Application.run_polling` and :meth:`Application.run_webhook` after shutting down - the application via :meth:`shutdown`. - post_stop (:term:`coroutine function`): Optional. A callback that will be executed by - :meth:`Application.run_polling` and :meth:`Application.run_webhook` after stopping - the application via :meth:`stop`. - - .. versionadded:: 20.1 - - """ - - __slots__ = ( - ( # noqa: RUF005 - "__create_task_tasks", - "__update_fetcher_task", - "__update_persistence_event", - "__update_persistence_lock", - "__update_persistence_task", - "__stop_running_marker", - "_chat_data", - "_chat_ids_to_be_deleted_in_persistence", - "_chat_ids_to_be_updated_in_persistence", - "_conversation_handler_conversations", - "_initialized", - "_job_queue", - "_running", - "_update_processor", - "_user_data", - "_user_ids_to_be_deleted_in_persistence", - "_user_ids_to_be_updated_in_persistence", - "bot", - "bot_data", - "chat_data", - "context_types", - "error_handlers", - "handlers", - "persistence", - "post_init", - "post_shutdown", - "post_stop", - "update_queue", - "updater", - "user_data", - ) - # Allowing '__weakref__' creation here since we need it for the JobQueue - # Currently the __weakref__ slot is already created - # in the AsyncContextManager base class for pythons < 3.13 - + ("__weakref__",) - if sys.version_info >= (3, 13) - else () - ) - - def __init__( - self: "Application[BT, CCT, UD, CD, BD, JQ]", - *, - bot: BT, - update_queue: "asyncio.Queue[object]", - updater: Optional[Updater], - job_queue: JQ, - update_processor: "BaseUpdateProcessor", - persistence: Optional[BasePersistence[UD, CD, BD]], - context_types: ContextTypes[CCT, UD, CD, BD], - post_init: Optional[ - Callable[["Application[BT, CCT, UD, CD, BD, JQ]"], Coroutine[Any, Any, None]] - ], - post_shutdown: Optional[ - Callable[["Application[BT, CCT, UD, CD, BD, JQ]"], Coroutine[Any, Any, None]] - ], - post_stop: Optional[ - Callable[["Application[BT, CCT, UD, CD, BD, JQ]"], Coroutine[Any, Any, None]] - ], - ): - if not was_called_by( - inspect.currentframe(), Path(__file__).parent.resolve() / "_applicationbuilder.py" - ): - warn( - "`Application` instances should be built via the `ApplicationBuilder`.", - stacklevel=2, - ) - - self.bot: BT = bot - self.update_queue: asyncio.Queue[object] = update_queue - self.context_types: ContextTypes[CCT, UD, CD, BD] = context_types - self.updater: Optional[Updater] = updater - self.handlers: dict[int, list[BaseHandler[Any, CCT, Any]]] = {} - self.error_handlers: dict[ - HandlerCallback[object, CCT, None], Union[bool, DefaultValue[bool]] - ] = {} - self.post_init: Optional[ - Callable[[Application[BT, CCT, UD, CD, BD, JQ]], Coroutine[Any, Any, None]] - ] = post_init - self.post_shutdown: Optional[ - Callable[[Application[BT, CCT, UD, CD, BD, JQ]], Coroutine[Any, Any, None]] - ] = post_shutdown - self.post_stop: Optional[ - Callable[[Application[BT, CCT, UD, CD, BD, JQ]], Coroutine[Any, Any, None]] - ] = post_stop - self._update_processor = update_processor - self.bot_data: BD = self.context_types.bot_data() - self._user_data: defaultdict[int, UD] = defaultdict(self.context_types.user_data) - self._chat_data: defaultdict[int, CD] = defaultdict(self.context_types.chat_data) - # Read only mapping - self.user_data: Mapping[int, UD] = MappingProxyType(self._user_data) - self.chat_data: Mapping[int, CD] = MappingProxyType(self._chat_data) - - self.persistence: Optional[BasePersistence[UD, CD, BD]] = None - if persistence and not isinstance(persistence, BasePersistence): - raise TypeError("persistence must be based on telegram.ext.BasePersistence") - self.persistence = persistence - - # Some bookkeeping for persistence logic - self._chat_ids_to_be_updated_in_persistence: set[int] = set() - self._user_ids_to_be_updated_in_persistence: set[int] = set() - self._chat_ids_to_be_deleted_in_persistence: set[int] = set() - self._user_ids_to_be_deleted_in_persistence: set[int] = set() - - # This attribute will hold references to the conversation dicts of all conversation - # handlers so that we can extract the changed states during `update_persistence` - self._conversation_handler_conversations: dict[ - str, TrackingDict[ConversationKey, object] - ] = {} - - # A number of low-level helpers for the internal logic - self._initialized = False - self._running = False - self._job_queue: JQ = job_queue - self.__update_fetcher_task: Optional[asyncio.Task] = None - self.__update_persistence_task: Optional[asyncio.Task] = None - self.__update_persistence_event = asyncio.Event() - self.__update_persistence_lock = asyncio.Lock() - self.__create_task_tasks: set[asyncio.Task] = set() # Used for awaiting tasks upon exit - self.__stop_running_marker = asyncio.Event() - - async def __aenter__(self: _AppType) -> _AppType: # noqa: PYI019 - """|async_context_manager| :meth:`initializes ` the App. - - Returns: - The initialized App instance. - - Raises: - :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. - """ - try: - await self.initialize() - except Exception: - await self.shutdown() - raise - return self - - async def __aexit__( - self, - exc_type: Optional[type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - """|async_context_manager| :meth:`shuts down ` the App.""" - # Make sure not to return `True` so that exceptions are not suppressed - # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ - await self.shutdown() - - def __repr__(self) -> str: - """Give a string representation of the application in the form ``Application[bot=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs(self, bot=self.bot) - - @property - def running(self) -> bool: - """:obj:`bool`: Indicates if this application is running. - - .. seealso:: - :meth:`start`, :meth:`stop` - """ - return self._running - - @property - def concurrent_updates(self) -> int: - """:obj:`int`: The number of concurrent updates that will be processed in parallel. A - value of ``0`` indicates updates are *not* being processed concurrently. - - .. versionchanged:: 20.4 - This is now just a shortcut to :attr:`update_processor.max_concurrent_updates - `. - - .. seealso:: :wiki:`Concurrency` - """ - return self._update_processor.max_concurrent_updates - - @property - def job_queue(self) -> Optional["JobQueue[CCT]"]: - """ - :class:`telegram.ext.JobQueue`: The :class:`JobQueue` used by the - :class:`telegram.ext.Application`. - - .. seealso:: :wiki:`Job Queue ` - """ - if self._job_queue is None: - warn( - "No `JobQueue` set up. To use `JobQueue`, you must install PTB via " - '`pip install "python-telegram-bot[job-queue]"`.', - stacklevel=2, - ) - return self._job_queue - - @property - def update_processor(self) -> "BaseUpdateProcessor": - """:class:`telegram.ext.BaseUpdateProcessor`: The update processor used by this - application. - - .. seealso:: :wiki:`Concurrency` - - .. versionadded:: 20.4 - """ - return self._update_processor - - @staticmethod - def _raise_system_exit() -> NoReturn: - raise SystemExit - - @staticmethod - def builder() -> "InitApplicationBuilder": - """Convenience method. Returns a new :class:`telegram.ext.ApplicationBuilder`. - - .. versionadded:: 20.0 - """ - # Unfortunately this needs to be here due to cyclical imports - from telegram.ext import ApplicationBuilder # pylint: disable=import-outside-toplevel - - return ApplicationBuilder() - - def _check_initialized(self) -> None: - if not self._initialized: - raise RuntimeError( - "This Application was not initialized via `Application.initialize`!" - ) - - async def initialize(self) -> None: - """Initializes the Application by initializing: - - * The :attr:`bot`, by calling :meth:`telegram.Bot.initialize`. - * The :attr:`updater`, by calling :meth:`telegram.ext.Updater.initialize`. - * The :attr:`persistence`, by loading persistent conversations and data. - * The :attr:`update_processor` by calling - :meth:`telegram.ext.BaseUpdateProcessor.initialize`. - - Does *not* call :attr:`post_init` - that is only done by :meth:`run_polling` and - :meth:`run_webhook`. - - .. seealso:: - :meth:`shutdown` - """ - if self._initialized: - _LOGGER.debug("This Application is already initialized.") - return - - await self.bot.initialize() - await self._update_processor.initialize() - - if self.updater: - await self.updater.initialize() - - if not self.persistence: - self._initialized = True - return - - await self._initialize_persistence() - - # Unfortunately due to circular imports this has to be here - # pylint: disable=import-outside-toplevel - from telegram.ext._handlers.conversationhandler import ConversationHandler - - # Initialize the persistent conversation handlers with the stored states - for handler in itertools.chain.from_iterable(self.handlers.values()): - if isinstance(handler, ConversationHandler) and handler.persistent and handler.name: - await self._add_ch_to_persistence(handler) - - self._initialized = True - self.__stop_running_marker.clear() - - async def _add_ch_to_persistence(self, handler: "ConversationHandler") -> None: - self._conversation_handler_conversations.update( - await handler._initialize_persistence(self) # pylint: disable=protected-access - ) - - async def shutdown(self) -> None: - """Shuts down the Application by shutting down: - - * :attr:`bot` by calling :meth:`telegram.Bot.shutdown` - * :attr:`updater` by calling :meth:`telegram.ext.Updater.shutdown` - * :attr:`persistence` by calling :meth:`update_persistence` and - :meth:`BasePersistence.flush` - * :attr:`update_processor` by calling :meth:`telegram.ext.BaseUpdateProcessor.shutdown` - - Does *not* call :attr:`post_shutdown` - that is only done by :meth:`run_polling` and - :meth:`run_webhook`. - - .. seealso:: - :meth:`initialize` - - Raises: - :exc:`RuntimeError`: If the application is still :attr:`running`. - """ - if self.running: - raise RuntimeError("This Application is still running!") - - if not self._initialized: - _LOGGER.debug("This Application is already shut down. Returning.") - return - - await self.bot.shutdown() - await self._update_processor.shutdown() - - if self.updater: - await self.updater.shutdown() - - if self.persistence: - _LOGGER.debug("Updating & flushing persistence before shutdown") - await self.update_persistence() - await self.persistence.flush() - _LOGGER.debug("Updated and flushed persistence") - - self._initialized = False - - async def _initialize_persistence(self) -> None: - """This method basically just loads all the data by awaiting the BP methods""" - if not self.persistence: - return - - if self.persistence.store_data.user_data: - self._user_data.update(await self.persistence.get_user_data()) - if self.persistence.store_data.chat_data: - self._chat_data.update(await self.persistence.get_chat_data()) - if self.persistence.store_data.bot_data: - self.bot_data = await self.persistence.get_bot_data() - if not isinstance(self.bot_data, self.context_types.bot_data): - raise ValueError( - f"bot_data must be of type {self.context_types.bot_data.__name__}" - ) - - # Mypy doesn't know that persistence.set_bot (see above) already checks that - # self.bot is an instance of ExtBot if callback_data should be stored ... - if self.persistence.store_data.callback_data and ( - self.bot.callback_data_cache is not None # type: ignore[attr-defined] - ): - persistent_data = await self.persistence.get_callback_data() - if persistent_data is not None: - if not isinstance(persistent_data, tuple) or len(persistent_data) != 2: - raise ValueError("callback_data must be a tuple of length 2") - self.bot.callback_data_cache.load_persistence_data( # type: ignore[attr-defined] - persistent_data - ) - - async def start(self) -> None: - """Starts - - * a background task that fetches updates from :attr:`update_queue` and processes them via - :meth:`process_update`. - * :attr:`job_queue`, if set. - * a background task that calls :meth:`update_persistence` in regular intervals, if - :attr:`persistence` is set. - - Note: - This does *not* start fetching updates from Telegram. To fetch updates, you need to - either start :attr:`updater` manually or use one of :meth:`run_polling` or - :meth:`run_webhook`. - - Tip: - When using a custom logic for startup and shutdown of the application, eventual - cancellation of pending tasks should happen only `after` :meth:`stop` has been called - in order to ensure that the tasks mentioned above are not cancelled prematurely. - - .. seealso:: - :meth:`stop` - - Raises: - :exc:`RuntimeError`: If the application is already running or was not initialized. - """ - if self.running: - raise RuntimeError("This Application is already running!") - self._check_initialized() - - self._running = True - self.__update_persistence_event.clear() - - try: - if self.persistence: - self.__update_persistence_task = asyncio.create_task( - self._persistence_updater(), - name=f"Application:{self.bot.id}:persistence_updater", - ) - _LOGGER.debug("Loop for updating persistence started") - - if self._job_queue: - await self._job_queue.start() # type: ignore[union-attr] - _LOGGER.debug("JobQueue started") - - self.__update_fetcher_task = asyncio.create_task( - self._update_fetcher(), name=f"Application:{self.bot.id}:update_fetcher" - ) - _LOGGER.info("Application started") - - except Exception: - self._running = False - raise - - async def stop(self) -> None: - """Stops the process after processing any pending updates or tasks created by - :meth:`create_task`. Also stops :attr:`job_queue`, if set. - Finally, calls :meth:`update_persistence` and :meth:`BasePersistence.flush` on - :attr:`persistence`, if set. - - Warning: - Once this method is called, no more updates will be fetched from :attr:`update_queue`, - even if it's not empty. - - .. seealso:: - :meth:`start` - - Note: - * This does *not* stop :attr:`updater`. You need to either manually call - :meth:`telegram.ext.Updater.stop` or use one of :meth:`run_polling` or - :meth:`run_webhook`. - * Does *not* call :attr:`post_stop` - that is only done by - :meth:`run_polling` and :meth:`run_webhook`. - - Raises: - :exc:`RuntimeError`: If the application is not running. - """ - if not self.running: - raise RuntimeError("This Application is not running!") - - self._running = False - self.__stop_running_marker.clear() - _LOGGER.info("Application is stopping. This might take a moment.") - - # Stop listening for new updates and handle all pending ones - if self.__update_fetcher_task: - if self.__update_fetcher_task.done(): - try: - self.__update_fetcher_task.result() - except BaseException as exc: - _LOGGER.critical( - "Fetching updates was aborted due to %r. Suppressing " - "exception to ensure graceful shutdown.", - exc, - exc_info=True, - ) - else: - await self.update_queue.put(_STOP_SIGNAL) - _LOGGER.debug("Waiting for update_queue to join") - await self.update_queue.join() - await self.__update_fetcher_task - _LOGGER.debug("Application stopped fetching of updates.") - - if self._job_queue: - _LOGGER.debug("Waiting for running jobs to finish") - await self._job_queue.stop(wait=True) # type: ignore[union-attr] - _LOGGER.debug("JobQueue stopped") - - _LOGGER.debug("Waiting for `create_task` calls to be processed") - await asyncio.gather(*self.__create_task_tasks, return_exceptions=True) - - # Make sure that this is the *last* step of stopping the application! - if self.persistence and self.__update_persistence_task: - _LOGGER.debug("Waiting for persistence loop to finish") - self.__update_persistence_event.set() - await self.__update_persistence_task - self.__update_persistence_event.clear() - - _LOGGER.info("Application.stop() complete") - - def stop_running(self) -> None: - """This method can be used to stop the execution of :meth:`run_polling` or - :meth:`run_webhook` from within a handler, job or error callback. This allows a graceful - shutdown of the application, i.e. the methods listed in :attr:`run_polling` and - :attr:`run_webhook` will still be executed. - - This method can also be called within :meth:`post_init`. This allows for a graceful, - early shutdown of the application if some condition is met (e.g., a database connection - could not be established). - - Note: - If the application is not running and this method is not called within - :meth:`post_init`, this method does nothing. - - Warning: - This method is designed to for use in combination with :meth:`run_polling` or - :meth:`run_webhook`. Using this method in combination with a custom logic for starting - and stopping the application is not guaranteed to work as expected. Use at your own - risk. - - .. versionadded:: 20.5 - - .. versionchanged:: 21.2 - Added support for calling within :meth:`post_init`. - """ - if self.running: - # This works because `__run` is using `loop.run_forever()`. If that changes, this - # method needs to be adapted. - asyncio.get_running_loop().stop() - else: - self.__stop_running_marker.set() - if not self._initialized: - _LOGGER.debug( - "Application is not running and not initialized. `stop_running()` likely has " - "no effect." - ) - - def run_polling( - self, - poll_interval: float = 0.0, - timeout: int = 10, - bootstrap_retries: int = -1, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - allowed_updates: Optional[Sequence[str]] = None, - drop_pending_updates: Optional[bool] = None, - close_loop: bool = True, - stop_signals: ODVInput[Sequence[int]] = DEFAULT_NONE, - ) -> None: - """Convenience method that takes care of initializing and starting the app, - polling updates from Telegram using :meth:`telegram.ext.Updater.start_polling` and - a graceful shutdown of the app on exit. - - |app_run_shutdown| :paramref:`stop_signals`. - - The order of execution by :meth:`run_polling` is roughly as follows: - - - :meth:`initialize` - - :meth:`post_init` - - :meth:`telegram.ext.Updater.start_polling` - - :meth:`start` - - Run the application until the users stops it - - :meth:`telegram.ext.Updater.stop` - - :meth:`stop` - - :meth:`post_stop` - - :meth:`shutdown` - - :meth:`post_shutdown` - - A small wrapper is passed to :paramref:`telegram.ext.Updater.start_polling.error_callback` - which forwards errors occurring during polling to - :meth:`registered error handlers `. The update parameter of the callback - will be set to :obj:`None`. - - .. include:: inclusions/application_run_tip.rst - - Args: - poll_interval (:obj:`float`, optional): Time to wait between polling updates from - Telegram in seconds. Default is ``0.0``. - timeout (:obj:`int`, optional): Passed to - :paramref:`telegram.Bot.get_updates.timeout`. Default is ``10`` seconds. - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely (default) - * 0 - no retries - * > 0 - retry up to X times - - read_timeout (:obj:`float`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.read_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. versionchanged:: 20.7 - Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE` instead of - ``2``. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_read_timeout`. - write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.write_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_write_timeout`. - connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.connect_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_connect_timeout`. - pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.pool_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_pool_timeout`. - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - allowed_updates (Sequence[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.get_updates`. - - .. versionchanged:: 21.9 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - close_loop (:obj:`bool`, optional): If :obj:`True`, the current event loop will be - closed upon shutdown. Defaults to :obj:`True`. - - .. seealso:: - :meth:`asyncio.loop.close` - stop_signals (Sequence[:obj:`int`] | :obj:`None`, optional): Signals that will shut - down the app. Pass :obj:`None` to not use stop signals. - Defaults to :data:`signal.SIGINT`, :data:`signal.SIGTERM` and - :data:`signal.SIGABRT` on non Windows platforms. - - Caution: - Not every :class:`asyncio.AbstractEventLoop` implements - :meth:`asyncio.loop.add_signal_handler`. Most notably, the standard event loop - on Windows, :class:`asyncio.ProactorEventLoop`, does not implement this method. - If this method is not available, stop signals can not be set. - - Raises: - :exc:`RuntimeError`: If the Application does not have an :class:`telegram.ext.Updater`. - """ - if not self.updater: - raise RuntimeError( - "Application.run_polling is only available if the application has an Updater." - ) - - if (read_timeout, write_timeout, connect_timeout, pool_timeout) != ((DEFAULT_NONE,) * 4): - warn( - PTBDeprecationWarning( - "20.6", - "Setting timeouts via `Application.run_polling` is deprecated. " - "Please use `ApplicationBuilder.get_updates_*_timeout` instead.", - ), - stacklevel=2, - ) - - def error_callback(exc: TelegramError) -> None: - self.create_task(self.process_error(error=exc, update=None)) - - return self.__run( - updater_coroutine=self.updater.start_polling( - poll_interval=poll_interval, - timeout=timeout, - bootstrap_retries=bootstrap_retries, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - allowed_updates=allowed_updates, - drop_pending_updates=drop_pending_updates, - error_callback=error_callback, # if there is an error in fetching updates - ), - close_loop=close_loop, - stop_signals=stop_signals, - ) - - def run_webhook( - self, - listen: DVType[str] = DEFAULT_IP, - port: DVType[int] = DEFAULT_80, - url_path: str = "", - cert: Optional[Union[str, Path]] = None, - key: Optional[Union[str, Path]] = None, - bootstrap_retries: int = 0, - webhook_url: Optional[str] = None, - allowed_updates: Optional[Sequence[str]] = None, - drop_pending_updates: Optional[bool] = None, - ip_address: Optional[str] = None, - max_connections: int = 40, - close_loop: bool = True, - stop_signals: ODVInput[Sequence[int]] = DEFAULT_NONE, - secret_token: Optional[str] = None, - unix: Optional[Union[str, Path, "socket"]] = None, - ) -> None: - """Convenience method that takes care of initializing and starting the app, - listening for updates from Telegram using :meth:`telegram.ext.Updater.start_webhook` and - a graceful shutdown of the app on exit. - - |app_run_shutdown| :paramref:`stop_signals`. - - If :paramref:`cert` - and :paramref:`key` are not provided, the webhook will be started directly on - ``http://listen:port/url_path``, so SSL can be handled by another - application. Else, the webhook will be started on - ``https://listen:port/url_path``. Also calls :meth:`telegram.Bot.set_webhook` as - required. - - The order of execution by :meth:`run_webhook` is roughly as follows: - - - :meth:`initialize` - - :meth:`post_init` - - :meth:`telegram.ext.Updater.start_webhook` - - :meth:`start` - - Run the application until the users stops it - - :meth:`telegram.ext.Updater.stop` - - :meth:`stop` - - :meth:`post_stop` - - :meth:`shutdown` - - :meth:`post_shutdown` - - Important: - If you want to use this method, you must install PTB with the optional requirement - ``webhooks``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[webhooks]" - - .. include:: inclusions/application_run_tip.rst - - .. seealso:: - :wiki:`Webhooks` - - Args: - listen (:obj:`str`, optional): IP-Address to listen on. Defaults to - `127.0.0.1 `_. - port (:obj:`int`, optional): Port the bot should be listening on. Must be one of - :attr:`telegram.constants.SUPPORTED_WEBHOOK_PORTS` unless the bot is running - behind a proxy. Defaults to ``80``. - url_path (:obj:`str`, optional): Path inside url. Defaults to `` '' `` - cert (:class:`pathlib.Path` | :obj:`str`, optional): Path to the SSL certificate file. - key (:class:`pathlib.Path` | :obj:`str`, optional): Path to the SSL key file. - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely - * 0 - no retries (default) - * > 0 - retry up to X times - webhook_url (:obj:`str`, optional): Explicitly specify the webhook url. Useful behind - NAT, reverse proxy, etc. Default is derived from :paramref:`listen`, - :paramref:`port`, :paramref:`url_path`, :paramref:`cert`, and :paramref:`key`. - allowed_updates (Sequence[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.set_webhook`. - - .. versionchanged:: 21.9 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - ip_address (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`. - max_connections (:obj:`int`, optional): Passed to - :meth:`telegram.Bot.set_webhook`. Defaults to ``40``. - close_loop (:obj:`bool`, optional): If :obj:`True`, the current event loop will be - closed upon shutdown. Defaults to :obj:`True`. - - .. seealso:: - :meth:`asyncio.loop.close` - stop_signals (Sequence[:obj:`int`] | :obj:`None`, optional): Signals that will shut - down the app. Pass :obj:`None` to not use stop signals. - Defaults to :data:`signal.SIGINT`, :data:`signal.SIGTERM` and - :data:`signal.SIGABRT`. - - Caution: - Not every :class:`asyncio.AbstractEventLoop` implements - :meth:`asyncio.loop.add_signal_handler`. Most notably, the standard event loop - on Windows, :class:`asyncio.ProactorEventLoop`, does not implement this method. - If this method is not available, stop signals can not be set. - secret_token (:obj:`str`, optional): Secret token to ensure webhook requests originate - from Telegram. See :paramref:`telegram.Bot.set_webhook.secret_token` for more - details. - - When added, the web server started by this call will expect the token to be set in - the ``X-Telegram-Bot-Api-Secret-Token`` header of an incoming request and will - raise a :class:`http.HTTPStatus.FORBIDDEN ` error if either the - header isn't set or it is set to a wrong token. - - .. versionadded:: 20.0 - unix (:class:`pathlib.Path` | :obj:`str` | :class:`socket.socket`, optional): Can be - either: - - * the path to the unix socket file as :class:`pathlib.Path` or :obj:`str`. This - will be passed to `tornado.netutil.bind_unix_socket `_ to create the socket. - If the Path does not exist, the file will be created. - - * or the socket itself. This option allows you to e.g. restrict the permissions of - the socket for improved security. Note that you need to pass the correct family, - type and socket options yourself. - - Caution: - This parameter is a replacement for the default TCP bind. Therefore, it is - mutually exclusive with :paramref:`listen` and :paramref:`port`. When using - this param, you must also run a reverse proxy to the unix socket and set the - appropriate :paramref:`webhook_url`. - - .. versionadded:: 20.8 - .. versionchanged:: 21.1 - Added support to pass a socket instance itself. - """ - if not self.updater: - raise RuntimeError( - "Application.run_webhook is only available if the application has an Updater." - ) - - return self.__run( - updater_coroutine=self.updater.start_webhook( - listen=listen, - port=port, - url_path=url_path, - cert=cert, - key=key, - bootstrap_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url=webhook_url, - allowed_updates=allowed_updates, - ip_address=ip_address, - max_connections=max_connections, - secret_token=secret_token, - unix=unix, - ), - close_loop=close_loop, - stop_signals=stop_signals, - ) - - def __run( - self, - updater_coroutine: Coroutine, - stop_signals: ODVInput[Sequence[int]], - close_loop: bool = True, - ) -> None: - # Calling get_event_loop() should still be okay even in py3.10+ as long as there is a - # running event loop or we are in the main thread, which are the intended use cases. - # See the docs of get_event_loop() and get_running_loop() for more info - loop = asyncio.get_event_loop() - - if stop_signals is DEFAULT_NONE and platform.system() != "Windows": - stop_signals = (signal.SIGINT, signal.SIGTERM, signal.SIGABRT) - - try: - if not isinstance(stop_signals, DefaultValue): - for sig in stop_signals or []: - loop.add_signal_handler(sig, self._raise_system_exit) - except NotImplementedError as exc: - warn( - f"Could not add signal handlers for the stop signals {stop_signals} due to " - f"exception `{exc!r}`. If your event loop does not implement `add_signal_handler`," - " please pass `stop_signals=None`.", - stacklevel=3, - ) - - try: - loop.run_until_complete(self.initialize()) - if self.post_init: - loop.run_until_complete(self.post_init(self)) - if self.__stop_running_marker.is_set(): - _LOGGER.info("Application received stop signal via `stop_running`. Shutting down.") - return - loop.run_until_complete(updater_coroutine) # one of updater.start_webhook/polling - loop.run_until_complete(self.start()) - loop.run_forever() - except (KeyboardInterrupt, SystemExit): - _LOGGER.debug("Application received stop signal. Shutting down.") - finally: - # We arrive here either by catching the exceptions above or if the loop gets stopped - # In case the coroutine wasn't awaited, we don't need to bother the user with a warning - updater_coroutine.close() - - try: - # Mypy doesn't know that we already check if updater is None - if self.updater.running: # type: ignore[union-attr] - loop.run_until_complete(self.updater.stop()) # type: ignore[union-attr] - if self.running: - loop.run_until_complete(self.stop()) - # post_stop should be called only if stop was called! - if self.post_stop: - loop.run_until_complete(self.post_stop(self)) - loop.run_until_complete(self.shutdown()) - if self.post_shutdown: - loop.run_until_complete(self.post_shutdown(self)) - finally: - if close_loop: - loop.close() - - def create_task( - self, - coroutine: _CoroType[RT], - update: Optional[object] = None, - *, - name: Optional[str] = None, - ) -> "asyncio.Task[RT]": - """Thin wrapper around :func:`asyncio.create_task` that handles exceptions raised by - the :paramref:`coroutine` with :meth:`process_error`. - - Note: - * If :paramref:`coroutine` raises an exception, it will be set on the task created by - this method even though it's handled by :meth:`process_error`. - * If the application is currently running, tasks created by this method will be - awaited with :meth:`stop`. - - .. seealso:: :wiki:`Concurrency` - - Args: - coroutine (:term:`awaitable`): The awaitable to run as task. - - .. versionchanged:: 20.2 - Accepts :class:`asyncio.Future` and generator-based coroutine functions. - .. deprecated:: 20.4 - Since Python 3.12, generator-based coroutine functions are no longer accepted. - update (:obj:`object`, optional): If set, will be passed to :meth:`process_error` - as additional information for the error handlers. Moreover, the corresponding - :attr:`chat_data` and :attr:`user_data` entries will be updated in the next run of - :meth:`update_persistence` after the :paramref:`coroutine` is finished. - - Keyword Args: - name (:obj:`str`, optional): The name of the task. - - .. versionadded:: 20.4 - - Returns: - :class:`asyncio.Task`: The created task. - """ - return self.__create_task(coroutine=coroutine, update=update, name=name) - - def __create_task( - self, - coroutine: _CoroType[RT], - update: Optional[object] = None, - is_error_handler: bool = False, - name: Optional[str] = None, - ) -> "asyncio.Task[RT]": - # Unfortunately, we can't know if `coroutine` runs one of the error handler functions - # but by passing `is_error_handler=True` from `process_error`, we can make sure that we - # get at most one recursion of the user calls `create_task` manually with an error handler - # function - task: asyncio.Task[RT] = asyncio.create_task( - self.__create_task_callback( - coroutine=coroutine, update=update, is_error_handler=is_error_handler - ), - name=name, - ) - - if self.running: - self.__create_task_tasks.add(task) - task.add_done_callback(self.__create_task_done_callback) - else: - warn( - "Tasks created via `Application.create_task` while the application is not " - "running won't be automatically awaited!", - stacklevel=3, - ) - - return task - - def __create_task_done_callback(self, task: asyncio.Task) -> None: - self.__create_task_tasks.discard(task) # Discard from our set since we are done with it - # We just retrieve the eventual exception so that asyncio doesn't complain in case - # it's not retrieved somewhere else - with contextlib.suppress(asyncio.CancelledError, asyncio.InvalidStateError): - task.exception() - - async def __create_task_callback( - self, - coroutine: _CoroType[RT], - update: Optional[object] = None, - is_error_handler: bool = False, - ) -> RT: - try: - # Generator-based coroutines are not supported in Python 3.12+ - if sys.version_info < (3, 12) and isinstance(coroutine, Generator): - warn( - PTBDeprecationWarning( - "20.4", - "Generator-based coroutines are deprecated in create_task and will not" - " work in Python 3.12+", - ), - ) - return await asyncio.create_task(coroutine) - # If user uses generator in python 3.12+, Exception will happen and we cannot do - # anything about it. (hence the type ignore if mypy is run on python 3.12-) - return await coroutine # type: ignore[misc] - except Exception as exception: - if isinstance(exception, ApplicationHandlerStop): - warn( - "ApplicationHandlerStop is not supported with handlers running non-blocking.", - stacklevel=1, - ) - - # Avoid infinite recursion of error handlers. - elif is_error_handler: - _LOGGER.exception( - "An error was raised and an uncaught error was raised while " - "handling the error with an error_handler.", - exc_info=exception, - ) - - else: - # If we arrive here, an exception happened in the task and was neither - # ApplicationHandlerStop nor raised by an error handler. - # So we can and must handle it - await self.process_error(update=update, error=exception, coroutine=coroutine) - - # Raise exception so that it can be set on the task and retrieved by task.exception() - raise - finally: - self._mark_for_persistence_update(update=update) - - async def __update_fetcher(self) -> None: - # Continuously fetch updates from the queue. Exit only once the signal object is found. - while True: - update = await self.update_queue.get() - - if update is _STOP_SIGNAL: - # For the _STOP_SIGNAL - self.update_queue.task_done() - return - - _LOGGER.debug("Processing update %s", update) - - if self._update_processor.max_concurrent_updates > 1: - # We don't await the below because it has to be run concurrently - self.create_task( - self.__process_update_wrapper(update), - update=update, - name=f"Application:{self.bot.id}:process_concurrent_update", - ) - else: - await self.__process_update_wrapper(update) - - async def _update_fetcher(self) -> None: - try: - await self.__update_fetcher() - finally: - while not self.update_queue.empty(): - _LOGGER.debug("Dropping pending update: %s", self.update_queue.get_nowait()) - with contextlib.suppress(ValueError): - # Since we're shutting down here, it's not too bad if we call task_done - # on an empty queue - self.update_queue.task_done() - - async def __process_update_wrapper(self, update: object) -> None: - try: - await self._update_processor.process_update(update, self.process_update(update)) - finally: - self.update_queue.task_done() - - async def process_update(self, update: object) -> None: - """Processes a single update and marks the update to be updated by the persistence later. - Exceptions raised by handler callbacks will be processed by :meth:`process_error`. - - .. seealso:: :wiki:`Concurrency` - - .. versionchanged:: 20.0 - Persistence is now updated in an interval set by - :attr:`telegram.ext.BasePersistence.update_interval`. - - Args: - update (:class:`telegram.Update` | :obj:`object` | \ - :class:`telegram.error.TelegramError`): The update to process. - - Raises: - :exc:`RuntimeError`: If the application was not initialized. - """ - # Processing updates before initialize() is a problem e.g. if persistence is used - self._check_initialized() - - context = None - any_blocking = False # Flag which is set to True if any handler specifies block=True - - for handlers in self.handlers.values(): - try: - for handler in handlers: - check = handler.check_update(update) # Should the handler handle this update? - if check is None or check is False: - continue - - if not context: # build a context if not already built - try: - context = self.context_types.context.from_update(update, self) - except Exception as exc: - _LOGGER.critical( - ( - "Error while building CallbackContext for update %s. " - "Update will not be processed." - ), - update, - exc_info=exc, - ) - return - await context.refresh_data() - coroutine: Coroutine = handler.handle_update(update, self, check, context) - - if not handler.block or ( # if handler is running with block=False, - handler.block is DEFAULT_TRUE - and isinstance(self.bot, ExtBot) - and self.bot.defaults - and not self.bot.defaults.block - ): - self.create_task( - coroutine, - update=update, - name=( - f"Application:{self.bot.id}:process_update_non_blocking" - f":{handler}" - ), - ) - else: - any_blocking = True - await coroutine - break # Only a max of 1 handler per group is handled - - # Stop processing with any other handler. - except ApplicationHandlerStop: - _LOGGER.debug("Stopping further handlers due to ApplicationHandlerStop") - break - - # Dispatch any error. - except Exception as exc: - if await self.process_error(update=update, error=exc): - _LOGGER.debug("Error handler stopped further handlers.") - break - - if any_blocking: - # Only need to mark the update for persistence if there was at least one - # blocking handler - the non-blocking handlers mark the update again when finished - # (in __create_task_callback) - self._mark_for_persistence_update(update=update) - - def add_handler(self, handler: BaseHandler[Any, CCT, Any], group: int = DEFAULT_GROUP) -> None: - """Register a handler. - - TL;DR: Order and priority counts. 0 or 1 handlers per group will be used. End handling of - update with :class:`telegram.ext.ApplicationHandlerStop`. - - A handler must be an instance of a subclass of :class:`telegram.ext.BaseHandler`. All - handlers - are organized in groups with a numeric value. The default group is 0. All groups will be - evaluated for handling an update, but only 0 or 1 handler per group will be used. If - :class:`telegram.ext.ApplicationHandlerStop` is raised from one of the handlers, no further - handlers (regardless of the group) will be called. - - The priority/order of handlers is determined as follows: - - * Priority of the group (lower group number == higher priority) - * The first handler in a group which can handle an update (see - :attr:`telegram.ext.BaseHandler.check_update`) will be used. Other handlers from the - group will not be used. The order in which handlers were added to the group defines the - priority. - - Warning: - Adding persistent :class:`telegram.ext.ConversationHandler` after the application has - been initialized is discouraged. This is because the persisted conversation states need - to be loaded into memory while the application is already processing updates, which - might lead to race conditions and undesired behavior. In particular, current - conversation states may be overridden by the loaded data. - - Args: - handler (:class:`telegram.ext.BaseHandler`): A BaseHandler instance. - group (:obj:`int`, optional): The group identifier. Default is ``0``. - - """ - # Unfortunately due to circular imports this has to be here - # pylint: disable=import-outside-toplevel - from telegram.ext._handlers.conversationhandler import ConversationHandler - - if not isinstance(handler, BaseHandler): - raise TypeError(f"handler is not an instance of {BaseHandler.__name__}") - if not isinstance(group, int): - raise TypeError("group is not int") - if isinstance(handler, ConversationHandler) and handler.persistent and handler.name: - if not self.persistence: - raise ValueError( - f"ConversationHandler {handler.name} " - "can not be persistent if application has no persistence" - ) - if self._initialized: - self.create_task( - self._add_ch_to_persistence(handler), - name=f"Application:{self.bot.id}:add_handler:conversation_handler_after_init", - ) - warn( - "A persistent `ConversationHandler` was passed to `add_handler`, " - "after `Application.initialize` was called. This is discouraged." - "See the docs of `Application.add_handler` for details.", - stacklevel=2, - ) - - if group not in self.handlers: - self.handlers[group] = [] - self.handlers = dict(sorted(self.handlers.items())) # lower -> higher groups - - self.handlers[group].append(handler) - - def add_handlers( - self, - handlers: Union[ - Sequence[BaseHandler[Any, CCT, Any]], - dict[int, Sequence[BaseHandler[Any, CCT, Any]]], - ], - group: Union[int, DefaultValue[int]] = _DEFAULT_0, - ) -> None: - """Registers multiple handlers at once. The order of the handlers in the passed - sequence(s) matters. See :meth:`add_handler` for details. - - .. versionadded:: 20.0 - - Args: - handlers (Sequence[:class:`telegram.ext.BaseHandler`] | \ - dict[int, Sequence[:class:`telegram.ext.BaseHandler`]]): - Specify a sequence of handlers *or* a dictionary where the keys are groups and - values are handlers. - - .. versionchanged:: 21.7 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - or tuple. - - group (:obj:`int`, optional): Specify which group the sequence of :paramref:`handlers` - should be added to. Defaults to ``0``. - - Example:: - - app.add_handlers(handlers={ - -1: [MessageHandler(...)], - 1: [CallbackQueryHandler(...), CommandHandler(...)] - } - - Raises: - :exc:`TypeError`: If the combination of arguments is invalid. - """ - if isinstance(handlers, dict) and not isinstance(group, DefaultValue): - raise TypeError("The `group` argument can only be used with a sequence of handlers.") - - if isinstance(handlers, dict): - for handler_group, grp_handlers in handlers.items(): - if not isinstance(grp_handlers, Sequence): - raise TypeError( - f"Handlers for group {handler_group} must be a sequence of handlers." - ) - - for handler in grp_handlers: - self.add_handler(handler, handler_group) - - elif isinstance(handlers, Sequence): - for handler in handlers: - self.add_handler(handler, DefaultValue.get_value(group)) - - else: - raise TypeError( - "The `handlers` argument must be a sequence of handlers or a " - "dictionary where the keys are groups and values are sequences of handlers." - ) - - def remove_handler( - self, handler: BaseHandler[Any, CCT, Any], group: int = DEFAULT_GROUP - ) -> None: - """Remove a handler from the specified group. - - Args: - handler (:class:`telegram.ext.BaseHandler`): A :class:`telegram.ext.BaseHandler` - instance. - group (:obj:`object`, optional): The group identifier. Default is ``0``. - - """ - if handler in self.handlers[group]: - self.handlers[group].remove(handler) - if not self.handlers[group]: - del self.handlers[group] - - def drop_chat_data(self, chat_id: int) -> None: - """Drops the corresponding entry from the :attr:`chat_data`. Will also be deleted from - the persistence on the next run of :meth:`update_persistence`, if applicable. - - Warning: - When using :attr:`concurrent_updates` or the :attr:`job_queue`, - :meth:`process_update` or :meth:`telegram.ext.Job.run` may re-create this entry due to - the asynchronous nature of these features. Please make sure that your program can - avoid or handle such situations. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`): The chat id to delete. The entry will be deleted even if it is - not empty. - """ - self._chat_data.pop(chat_id, None) - self._chat_ids_to_be_deleted_in_persistence.add(chat_id) - - def drop_user_data(self, user_id: int) -> None: - """Drops the corresponding entry from the :attr:`user_data`. Will also be deleted from - the persistence on the next run of :meth:`update_persistence`, if applicable. - - Warning: - When using :attr:`concurrent_updates` or the :attr:`job_queue`, - :meth:`process_update` or :meth:`telegram.ext.Job.run` may re-create this entry due to - the asynchronous nature of these features. Please make sure that your program can - avoid or handle such situations. - - .. versionadded:: 20.0 - - Args: - user_id (:obj:`int`): The user id to delete. The entry will be deleted even if it is - not empty. - """ - self._user_data.pop(user_id, None) - self._user_ids_to_be_deleted_in_persistence.add(user_id) - - def migrate_chat_data( - self, - message: Optional["Message"] = None, - old_chat_id: Optional[int] = None, - new_chat_id: Optional[int] = None, - ) -> None: - """Moves the contents of :attr:`chat_data` at key :paramref:`old_chat_id` to the key - :paramref:`new_chat_id`. Also marks the entries to be updated accordingly in the next run - of :meth:`update_persistence`. - - Warning: - * Any data stored in :attr:`chat_data` at key :paramref:`new_chat_id` will be - overridden - * The key :paramref:`old_chat_id` of :attr:`chat_data` will be deleted - * This does not update the :attr:`~telegram.ext.Job.chat_id` attribute of any scheduled - :class:`telegram.ext.Job`. - - When using :attr:`concurrent_updates` or the :attr:`job_queue`, - :meth:`process_update` or :meth:`telegram.ext.Job.run` may re-create the old entry due - to the asynchronous nature of these features. Please make sure that your program can - avoid or handle such situations. - - .. seealso:: :wiki:`Storing Bot, User and Chat Related Data\ - ` - - Args: - message (:class:`telegram.Message`, optional): A message with either - :attr:`~telegram.Message.migrate_from_chat_id` or - :attr:`~telegram.Message.migrate_to_chat_id`. - Mutually exclusive with passing :paramref:`old_chat_id` and - :paramref:`new_chat_id`. - - .. seealso:: - :attr:`telegram.ext.filters.StatusUpdate.MIGRATE` - - old_chat_id (:obj:`int`, optional): The old chat ID. - Mutually exclusive with passing :paramref:`message` - new_chat_id (:obj:`int`, optional): The new chat ID. - Mutually exclusive with passing :paramref:`message` - - Raises: - ValueError: Raised if the input is invalid. - """ - if message and (old_chat_id or new_chat_id): - raise ValueError("Message and chat_id pair are mutually exclusive") - if not any((message, old_chat_id, new_chat_id)): - raise ValueError("chat_id pair or message must be passed") - - if message: - if message.migrate_from_chat_id is None and message.migrate_to_chat_id is None: - raise ValueError( - "Invalid message instance. The message must have either " - "`Message.migrate_from_chat_id` or `Message.migrate_to_chat_id`." - ) - - old_chat_id = message.migrate_from_chat_id or message.chat.id - new_chat_id = message.migrate_to_chat_id or message.chat.id - - elif not (isinstance(old_chat_id, int) and isinstance(new_chat_id, int)): - raise ValueError("old_chat_id and new_chat_id must be integers") - - self._chat_data[new_chat_id] = self._chat_data[old_chat_id] - self.drop_chat_data(old_chat_id) - - self._chat_ids_to_be_updated_in_persistence.add(new_chat_id) - # old_chat_id is marked for deletion by drop_chat_data above - - def _mark_for_persistence_update( - self, *, update: Optional[object] = None, job: Optional["Job"] = None - ) -> None: - if isinstance(update, Update): - if update.effective_chat: - self._chat_ids_to_be_updated_in_persistence.add(update.effective_chat.id) - if update.effective_user: - self._user_ids_to_be_updated_in_persistence.add(update.effective_user.id) - - if job: - if job.chat_id: - self._chat_ids_to_be_updated_in_persistence.add(job.chat_id) - if job.user_id: - self._user_ids_to_be_updated_in_persistence.add(job.user_id) - - def mark_data_for_update_persistence( - self, chat_ids: Optional[SCT[int]] = None, user_ids: Optional[SCT[int]] = None - ) -> None: - """Mark entries of :attr:`chat_data` and :attr:`user_data` to be updated on the next - run of :meth:`update_persistence`. - - Tip: - Use this method sparingly. If you have to use this method, it likely means that you - access and modify ``context.application.chat/user_data[some_id]`` within a callback. - Note that for data which should be available globally in all handler callbacks - independent of the chat/user, it is recommended to use :attr:`bot_data` instead. - - .. versionadded:: 20.3 - - Args: - chat_ids (:obj:`int` | Collection[:obj:`int`], optional): Chat IDs to mark. - user_ids (:obj:`int` | Collection[:obj:`int`], optional): User IDs to mark. - - """ - if chat_ids: - if isinstance(chat_ids, int): - self._chat_ids_to_be_updated_in_persistence.add(chat_ids) - else: - self._chat_ids_to_be_updated_in_persistence.update(chat_ids) - if user_ids: - if isinstance(user_ids, int): - self._user_ids_to_be_updated_in_persistence.add(user_ids) - else: - self._user_ids_to_be_updated_in_persistence.update(user_ids) - - async def _persistence_updater(self) -> None: - # Update the persistence in regular intervals. Exit only when the stop event has been set - while not self.__update_persistence_event.is_set(): - if not self.persistence: - return - - # asyncio synchronization primitives don't accept a timeout argument, it is recommended - # to use wait_for instead - try: - await asyncio.wait_for( - self.__update_persistence_event.wait(), - timeout=self.persistence.update_interval, - ) - except asyncio.TimeoutError: - pass - else: - return - - # putting this *after* the wait_for so we don't immediately update on startup as - # that would make little sense - await self.update_persistence() - - async def update_persistence(self) -> None: - """Updates :attr:`user_data`, :attr:`chat_data`, :attr:`bot_data` in :attr:`persistence` - along with :attr:`~telegram.ext.ExtBot.callback_data_cache` and the conversation states of - any persistent :class:`~telegram.ext.ConversationHandler` registered for this application. - - For :attr:`user_data` and :attr:`chat_data`, only those entries are updated which either - were used or have been manually marked via :meth:`mark_data_for_update_persistence` since - the last run of this method. - - Tip: - This method will be called in regular intervals by the application. There is usually - no need to call it manually. - - Note: - Any data is deep copied with :func:`copy.deepcopy` before handing it over to the - persistence in order to avoid race conditions, so all persisted data must be copyable. - - .. seealso:: :attr:`telegram.ext.BasePersistence.update_interval`, - :meth:`mark_data_for_update_persistence` - """ - async with self.__update_persistence_lock: - await self.__update_persistence() - - async def __update_persistence(self) -> None: - if not self.persistence: - return - - _LOGGER.debug("Starting next run of updating the persistence.") - - coroutines: set[Coroutine] = set() - - # Mypy doesn't know that persistence.set_bot (see above) already checks that - # self.bot is an instance of ExtBot if callback_data should be stored ... - if self.persistence.store_data.callback_data and ( - self.bot.callback_data_cache is not None # type: ignore[attr-defined] - ): - coroutines.add( - self.persistence.update_callback_data( - deepcopy( - self.bot.callback_data_cache.persistence_data # type: ignore[attr-defined] - ) - ) - ) - - if self.persistence.store_data.bot_data: - coroutines.add(self.persistence.update_bot_data(deepcopy(self.bot_data))) - - if self.persistence.store_data.chat_data: - update_ids = self._chat_ids_to_be_updated_in_persistence - self._chat_ids_to_be_updated_in_persistence = set() - delete_ids = self._chat_ids_to_be_deleted_in_persistence - self._chat_ids_to_be_deleted_in_persistence = set() - - # We don't want to update any data that has been deleted! - update_ids -= delete_ids - - for chat_id in update_ids: - coroutines.add( - self.persistence.update_chat_data(chat_id, deepcopy(self.chat_data[chat_id])) - ) - for chat_id in delete_ids: - coroutines.add(self.persistence.drop_chat_data(chat_id)) - - if self.persistence.store_data.user_data: - update_ids = self._user_ids_to_be_updated_in_persistence - self._user_ids_to_be_updated_in_persistence = set() - delete_ids = self._user_ids_to_be_deleted_in_persistence - self._user_ids_to_be_deleted_in_persistence = set() - - # We don't want to update any data that has been deleted! - update_ids -= delete_ids - - for user_id in update_ids: - coroutines.add( - self.persistence.update_user_data(user_id, deepcopy(self.user_data[user_id])) - ) - for user_id in delete_ids: - coroutines.add(self.persistence.drop_user_data(user_id)) - - # Unfortunately due to circular imports this has to be here - # pylint: disable=import-outside-toplevel - from telegram.ext._handlers.conversationhandler import PendingState - - for name, (key, new_state) in itertools.chain.from_iterable( - zip(itertools.repeat(name), states_dict.pop_accessed_write_items()) - for name, states_dict in self._conversation_handler_conversations.items() - ): - if isinstance(new_state, PendingState): - # If the handler was running non-blocking, we check if the new state is already - # available. Otherwise, we update with the old state, which is the next best - # guess. - # Note that when updating the persistence one last time during self.stop(), - # *all* tasks will be done. - if not new_state.done(): - if self.running: - _LOGGER.debug( - "A ConversationHandlers state was not yet resolved. Updating the " - "persistence with the current state. Will check again on next run of " - "Application.update_persistence." - ) - else: - _LOGGER.warning( - "A ConversationHandlers state was not yet resolved. Updating the " - "persistence with the current state." - ) - result = new_state.old_state - # We need to check again on the next run if the state is done - self._conversation_handler_conversations[name].mark_as_accessed(key) - else: - result = new_state.resolve() - else: - result = new_state - - effective_new_state = None if result is TrackingDict.DELETED else result - coroutines.add( - self.persistence.update_conversation( - name=name, key=key, new_state=effective_new_state - ) - ) - - results = await asyncio.gather(*coroutines, return_exceptions=True) - _LOGGER.debug("Finished updating persistence.") - - # dispatch any errors - await asyncio.gather( - *( - self.process_error(error=result, update=None) - for result in results - if isinstance(result, Exception) - ) - ) - - def add_error_handler( - self, - callback: HandlerCallback[object, CCT, None], - block: DVType[bool] = DEFAULT_TRUE, - ) -> None: - """Registers an error handler in the Application. This handler will receive every error - which happens in your bot. See the docs of :meth:`process_error` for more details on how - errors are handled. - - Note: - Attempts to add the same callback multiple times will be ignored. - - Examples: - :any:`Errorhandler Bot ` - - .. seealso:: :wiki:`Exceptions, Warnings and Logging ` - - Args: - callback (:term:`coroutine function`): The callback function for this error handler. - Will be called when an error is raised. Callback signature:: - - async def callback(update: Optional[object], context: CallbackContext) - - The error that happened will be present in - :attr:`telegram.ext.CallbackContext.error`. - block (:obj:`bool`, optional): Determines whether the return value of the callback - should be awaited before processing the next error handler in - :meth:`process_error`. Defaults to :obj:`True`. - """ - if callback in self.error_handlers: - _LOGGER.warning("The callback is already registered as an error handler. Ignoring.") - return - - self.error_handlers[callback] = block - - def remove_error_handler(self, callback: HandlerCallback[object, CCT, None]) -> None: - """Removes an error handler. - - Args: - callback (:term:`coroutine function`): The error handler to remove. - - """ - self.error_handlers.pop(callback, None) - - async def process_error( - self, - update: Optional[object], - error: Exception, - job: Optional["Job[CCT]"] = None, - coroutine: Optional[_ErrorCoroType[RT]] = None, - ) -> bool: - """Processes an error by passing it to all error handlers registered with - :meth:`add_error_handler`. If one of the error handlers raises - :class:`telegram.ext.ApplicationHandlerStop`, the error will not be handled by other error - handlers. Raising :class:`telegram.ext.ApplicationHandlerStop` also stops processing of - the update when this method is called by :meth:`process_update`, i.e. no further handlers - (even in other groups) will handle the update. All other exceptions raised by an error - handler will just be logged. - - .. versionchanged:: 20.0 - - * ``dispatch_error`` was renamed to :meth:`process_error`. - * Exceptions raised by error handlers are now properly logged. - * :class:`telegram.ext.ApplicationHandlerStop` is no longer reraised but converted into - the return value. - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update that caused the error. - error (:obj:`Exception`): The error that was raised. - job (:class:`telegram.ext.Job`, optional): The job that caused the error. - - .. versionadded:: 20.0 - coroutine (:term:`coroutine function`, optional): The coroutine that caused the error. - - Returns: - :obj:`bool`: :obj:`True`, if one of the error handlers raised - :class:`telegram.ext.ApplicationHandlerStop`. :obj:`False`, otherwise. - """ - if self.error_handlers: - for ( - callback, - block, - ) in self.error_handlers.items(): - try: - context = self.context_types.context.from_error( - update=update, - error=error, - application=self, - job=job, - coroutine=coroutine, - ) - except Exception as exc: - _LOGGER.critical( - ( - "Error while building CallbackContext for exception %s. " - "Exception will not be processed by error handlers." - ), - error, - exc_info=exc, - ) - return False - - if not block or ( # If error handler has `block=False`, create a Task to run cb - block is DEFAULT_TRUE - and isinstance(self.bot, ExtBot) - and self.bot.defaults - and not self.bot.defaults.block - ): - self.__create_task( - callback(update, context), - update=update, - is_error_handler=True, - name=f"Application:{self.bot.id}:process_error:non_blocking", - ) - else: - try: - await callback(update, context) - except ApplicationHandlerStop: - return True - except Exception as exc: - _LOGGER.exception( - "An error was raised and an uncaught error was raised while " - "handling the error with an error_handler.", - exc_info=exc, - ) - return False - - _LOGGER.exception("No error handlers are registered, logging exception.", exc_info=error) - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_applicationbuilder.py b/venv/lib/python3.11/site-packages/telegram/ext/_applicationbuilder.py deleted file mode 100755 index d0ade04..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_applicationbuilder.py +++ /dev/null @@ -1,1394 +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 -# -# 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 Builder classes for the telegram.ext module.""" -from asyncio import Queue -from collections.abc import Collection, Coroutine -from pathlib import Path -from typing import TYPE_CHECKING, Any, Callable, Generic, Optional, TypeVar, Union - -import httpx - -from telegram._bot import Bot -from telegram._utils.defaultvalue import DEFAULT_FALSE, DEFAULT_NONE, DefaultValue -from telegram._utils.types import DVInput, DVType, FilePathInput, HTTPVersion, ODVInput, SocketOpt -from telegram._utils.warnings import warn -from telegram.ext._application import Application -from telegram.ext._baseupdateprocessor import BaseUpdateProcessor, SimpleUpdateProcessor -from telegram.ext._contexttypes import ContextTypes -from telegram.ext._extbot import ExtBot -from telegram.ext._jobqueue import JobQueue -from telegram.ext._updater import Updater -from telegram.ext._utils.types import BD, BT, CCT, CD, JQ, UD -from telegram.request import BaseRequest -from telegram.request._httpxrequest import HTTPXRequest -from telegram.warnings import PTBDeprecationWarning - -if TYPE_CHECKING: - from telegram import Update - from telegram.ext import BasePersistence, BaseRateLimiter, CallbackContext, Defaults - from telegram.ext._utils.types import RLARGS - -# Type hinting is a bit complicated here because we try to get to a sane level of -# leveraging generics and therefore need a number of type variables. -# 'In' stands for input - used in parameters of methods below -# pylint: disable=invalid-name -InBT = TypeVar("InBT", bound=Bot) -InJQ = TypeVar("InJQ", bound=Union[None, JobQueue]) -InCCT = TypeVar("InCCT", bound="CallbackContext") -InUD = TypeVar("InUD") -InCD = TypeVar("InCD") -InBD = TypeVar("InBD") -BuilderType = TypeVar("BuilderType", bound="ApplicationBuilder") - - -_BOT_CHECKS = [ - ("request", "request instance"), - ("get_updates_request", "get_updates_request instance"), - ("connection_pool_size", "connection_pool_size"), - ("proxy", "proxy"), - ("socket_options", "socket_options"), - ("pool_timeout", "pool_timeout"), - ("connect_timeout", "connect_timeout"), - ("read_timeout", "read_timeout"), - ("write_timeout", "write_timeout"), - ("media_write_timeout", "media_write_timeout"), - ("http_version", "http_version"), - ("get_updates_connection_pool_size", "get_updates_connection_pool_size"), - ("get_updates_proxy", "get_updates_proxy"), - ("get_updates_socket_options", "get_updates_socket_options"), - ("get_updates_pool_timeout", "get_updates_pool_timeout"), - ("get_updates_connect_timeout", "get_updates_connect_timeout"), - ("get_updates_read_timeout", "get_updates_read_timeout"), - ("get_updates_write_timeout", "get_updates_write_timeout"), - ("get_updates_http_version", "get_updates_http_version"), - ("base_file_url", "base_file_url"), - ("base_url", "base_url"), - ("token", "token"), - ("defaults", "defaults"), - ("arbitrary_callback_data", "arbitrary_callback_data"), - ("private_key", "private_key"), - ("rate_limiter", "rate_limiter instance"), - ("local_mode", "local_mode setting"), -] - -_TWO_ARGS_REQ = "The parameter `{}` may only be set, if no {} was set." - - -class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]): - """This class serves as initializer for :class:`telegram.ext.Application` via the so called - `builder pattern`_. To build a :class:`telegram.ext.Application`, one first initializes an - instance of this class. Arguments for the :class:`telegram.ext.Application` to build are then - added by subsequently calling the methods of the builder. Finally, the - :class:`telegram.ext.Application` is built by calling :meth:`build`. In the simplest case this - can look like the following example. - - Example: - .. code:: python - - application = ApplicationBuilder().token("TOKEN").build() - - Please see the description of the individual methods for information on which arguments can be - set and what the defaults are when not called. When no default is mentioned, the argument will - not be used by default. - - Note: - * Some arguments are mutually exclusive. E.g. after calling :meth:`token`, you can't set - a custom bot with :meth:`bot` and vice versa. - * Unless a custom :class:`telegram.Bot` instance is set via :meth:`bot`, :meth:`build` will - use :class:`telegram.ext.ExtBot` for the bot. - - .. seealso:: :wiki:`Your First Bot `, - :wiki:`Builder Pattern ` - - .. _`builder pattern`: https://en.wikipedia.org/wiki/Builder_pattern - """ - - __slots__ = ( - "_application_class", - "_application_kwargs", - "_arbitrary_callback_data", - "_base_file_url", - "_base_url", - "_bot", - "_connect_timeout", - "_connection_pool_size", - "_context_types", - "_defaults", - "_get_updates_connect_timeout", - "_get_updates_connection_pool_size", - "_get_updates_http_version", - "_get_updates_pool_timeout", - "_get_updates_proxy", - "_get_updates_read_timeout", - "_get_updates_request", - "_get_updates_socket_options", - "_get_updates_write_timeout", - "_http_version", - "_job_queue", - "_local_mode", - "_media_write_timeout", - "_persistence", - "_pool_timeout", - "_post_init", - "_post_shutdown", - "_post_stop", - "_private_key", - "_private_key_password", - "_proxy", - "_rate_limiter", - "_read_timeout", - "_request", - "_socket_options", - "_token", - "_update_processor", - "_update_queue", - "_updater", - "_write_timeout", - ) - - def __init__(self: "InitApplicationBuilder"): - self._token: DVType[str] = DefaultValue("") - self._base_url: DVType[str] = DefaultValue("https://api.telegram.org/bot") - self._base_file_url: DVType[str] = DefaultValue("https://api.telegram.org/file/bot") - self._connection_pool_size: DVInput[int] = DEFAULT_NONE - self._proxy: DVInput[Union[str, httpx.Proxy, httpx.URL]] = DEFAULT_NONE - self._socket_options: DVInput[Collection[SocketOpt]] = DEFAULT_NONE - self._connect_timeout: ODVInput[float] = DEFAULT_NONE - self._read_timeout: ODVInput[float] = DEFAULT_NONE - self._write_timeout: ODVInput[float] = DEFAULT_NONE - self._media_write_timeout: ODVInput[float] = DEFAULT_NONE - self._pool_timeout: ODVInput[float] = DEFAULT_NONE - self._request: DVInput[BaseRequest] = DEFAULT_NONE - self._get_updates_connection_pool_size: DVInput[int] = DEFAULT_NONE - self._get_updates_proxy: DVInput[Union[str, httpx.Proxy, httpx.URL]] = DEFAULT_NONE - self._get_updates_socket_options: DVInput[Collection[SocketOpt]] = DEFAULT_NONE - self._get_updates_connect_timeout: ODVInput[float] = DEFAULT_NONE - self._get_updates_read_timeout: ODVInput[float] = DEFAULT_NONE - self._get_updates_write_timeout: ODVInput[float] = DEFAULT_NONE - self._get_updates_pool_timeout: ODVInput[float] = DEFAULT_NONE - self._get_updates_request: DVInput[BaseRequest] = DEFAULT_NONE - self._get_updates_http_version: DVInput[str] = DefaultValue("1.1") - self._private_key: ODVInput[bytes] = DEFAULT_NONE - self._private_key_password: ODVInput[bytes] = DEFAULT_NONE - self._defaults: ODVInput[Defaults] = DEFAULT_NONE - self._arbitrary_callback_data: Union[DefaultValue[bool], int] = DEFAULT_FALSE - self._local_mode: DVType[bool] = DEFAULT_FALSE - self._bot: DVInput[Bot] = DEFAULT_NONE - self._update_queue: DVType[Queue[Union[Update, object]]] = DefaultValue(Queue()) - - try: - self._job_queue: ODVInput[JobQueue] = DefaultValue(JobQueue()) - except RuntimeError as exc: - if "PTB must be installed via" not in str(exc): - raise - self._job_queue = DEFAULT_NONE - - self._persistence: ODVInput[BasePersistence] = DEFAULT_NONE - self._context_types: DVType[ContextTypes] = DefaultValue(ContextTypes()) - self._application_class: DVType[type[Application]] = DefaultValue(Application) - self._application_kwargs: dict[str, object] = {} - self._update_processor: BaseUpdateProcessor = SimpleUpdateProcessor( - max_concurrent_updates=1 - ) - self._updater: ODVInput[Updater] = DEFAULT_NONE - self._post_init: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None - self._post_shutdown: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None - self._post_stop: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None - self._rate_limiter: ODVInput[BaseRateLimiter] = DEFAULT_NONE - self._http_version: DVInput[str] = DefaultValue("1.1") - - def _build_request(self, get_updates: bool) -> BaseRequest: - prefix = "_get_updates_" if get_updates else "_" - if not isinstance(getattr(self, f"{prefix}request"), DefaultValue): - return getattr(self, f"{prefix}request") - - proxy = DefaultValue.get_value(getattr(self, f"{prefix}proxy")) - socket_options = DefaultValue.get_value(getattr(self, f"{prefix}socket_options")) - if get_updates: - connection_pool_size = ( - DefaultValue.get_value(getattr(self, f"{prefix}connection_pool_size")) or 1 - ) - else: - connection_pool_size = ( - DefaultValue.get_value(getattr(self, f"{prefix}connection_pool_size")) or 256 - ) - - timeouts = { - "connect_timeout": getattr(self, f"{prefix}connect_timeout"), - "read_timeout": getattr(self, f"{prefix}read_timeout"), - "write_timeout": getattr(self, f"{prefix}write_timeout"), - "pool_timeout": getattr(self, f"{prefix}pool_timeout"), - } - - if not get_updates: - timeouts["media_write_timeout"] = self._media_write_timeout - - # Get timeouts that were actually set- - effective_timeouts = { - key: value for key, value in timeouts.items() if not isinstance(value, DefaultValue) - } - - http_version = DefaultValue.get_value(getattr(self, f"{prefix}http_version")) or "1.1" - - return HTTPXRequest( - connection_pool_size=connection_pool_size, - proxy=proxy, - http_version=http_version, # type: ignore[arg-type] - socket_options=socket_options, - **effective_timeouts, - ) - - def _build_ext_bot(self) -> ExtBot: - if isinstance(self._token, DefaultValue): - raise RuntimeError("No bot token was set.") - - return ExtBot( - token=self._token, - base_url=DefaultValue.get_value(self._base_url), - base_file_url=DefaultValue.get_value(self._base_file_url), - private_key=DefaultValue.get_value(self._private_key), - private_key_password=DefaultValue.get_value(self._private_key_password), - defaults=DefaultValue.get_value(self._defaults), - arbitrary_callback_data=DefaultValue.get_value(self._arbitrary_callback_data), - request=self._build_request(get_updates=False), - get_updates_request=self._build_request(get_updates=True), - rate_limiter=DefaultValue.get_value(self._rate_limiter), - local_mode=DefaultValue.get_value(self._local_mode), - ) - - def _bot_check(self, name: str) -> None: - if self._bot is not DEFAULT_NONE: - raise RuntimeError(_TWO_ARGS_REQ.format(name, "bot instance")) - - def _updater_check(self, name: str) -> None: - if self._updater not in (DEFAULT_NONE, None): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "updater")) - - def build( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - ) -> Application[BT, CCT, UD, CD, BD, JQ]: - """Builds a :class:`telegram.ext.Application` with the provided arguments. - - Calls :meth:`telegram.ext.JobQueue.set_application` and - :meth:`telegram.ext.BasePersistence.set_bot` if appropriate. - - Returns: - :class:`telegram.ext.Application` - """ - job_queue = DefaultValue.get_value(self._job_queue) - persistence = DefaultValue.get_value(self._persistence) - # If user didn't set updater - if isinstance(self._updater, DefaultValue) or self._updater is None: - if isinstance(self._bot, DefaultValue): # and didn't set a bot - bot: Bot = self._build_ext_bot() # build a bot - else: - bot = self._bot - # now also build an updater/update_queue for them - update_queue = DefaultValue.get_value(self._update_queue) - - if self._updater is None: - updater = None - else: - updater = Updater(bot=bot, update_queue=update_queue) - else: # if they set an updater, get all necessary attributes for Application from Updater: - updater = self._updater - bot = self._updater.bot - update_queue = self._updater.update_queue - - application: Application[BT, CCT, UD, CD, BD, JQ] = DefaultValue.get_value( - self._application_class - )( - bot=bot, - update_queue=update_queue, - updater=updater, - update_processor=self._update_processor, - job_queue=job_queue, - persistence=persistence, - context_types=DefaultValue.get_value(self._context_types), - post_init=self._post_init, - post_shutdown=self._post_shutdown, - post_stop=self._post_stop, - **self._application_kwargs, # For custom Application subclasses - ) - - if job_queue is not None: - job_queue.set_application(application) # type: ignore[arg-type] - - if persistence is not None: - # This raises an exception if persistence.store_data.callback_data is True - # but self.bot is not an instance of ExtBot - so no need to check that later on - persistence.set_bot(bot) - - return application - - def application_class( - self: BuilderType, - application_class: type[Application[Any, Any, Any, Any, Any, Any]], - kwargs: Optional[dict[str, object]] = None, - ) -> BuilderType: - """Sets a custom subclass instead of :class:`telegram.ext.Application`. The - subclass's ``__init__`` should look like this - - .. code:: python - - def __init__(self, custom_arg_1, custom_arg_2, ..., **kwargs): - super().__init__(**kwargs) - self.custom_arg_1 = custom_arg_1 - self.custom_arg_2 = custom_arg_2 - - Args: - application_class (:obj:`type`): A subclass of :class:`telegram.ext.Application` - kwargs (dict[:obj:`str`, :obj:`object`], optional): Keyword arguments for the - initialization. Defaults to an empty dict. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._application_class = application_class - self._application_kwargs = kwargs or {} - return self - - def token(self: BuilderType, token: str) -> BuilderType: - """Sets the token for :attr:`telegram.ext.Application.bot`. - - Args: - token (:obj:`str`): The token. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("token") - self._updater_check("token") - self._token = token - return self - - def base_url(self: BuilderType, base_url: str) -> BuilderType: - """Sets the base URL for :attr:`telegram.ext.Application.bot`. If not called, - will default to ``'https://api.telegram.org/bot'``. - - .. seealso:: :paramref:`telegram.Bot.base_url`, - :wiki:`Local Bot API Server `, :meth:`base_file_url` - - Args: - base_url (:obj:`str`): The URL. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("base_url") - self._updater_check("base_url") - self._base_url = base_url - return self - - def base_file_url(self: BuilderType, base_file_url: str) -> BuilderType: - """Sets the base file URL for :attr:`telegram.ext.Application.bot`. If not - called, will default to ``'https://api.telegram.org/file/bot'``. - - .. seealso:: :paramref:`telegram.Bot.base_file_url`, - :wiki:`Local Bot API Server `, :meth:`base_url` - - Args: - base_file_url (:obj:`str`): The URL. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("base_file_url") - self._updater_check("base_file_url") - self._base_file_url = base_file_url - return self - - def _request_check(self, get_updates: bool) -> None: - prefix = "get_updates_" if get_updates else "" - name = prefix + "request" - - timeouts = ["connect_timeout", "read_timeout", "write_timeout", "pool_timeout"] - if not get_updates: - timeouts.append("media_write_timeout") - - # Code below tests if it's okay to set a Request object. Only okay if no other request args - # or instances containing a Request were set previously - for attr in timeouts: - if not isinstance(getattr(self, f"_{prefix}{attr}"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, attr)) - - if not isinstance(getattr(self, f"_{prefix}connection_pool_size"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "connection_pool_size")) - - if not isinstance(getattr(self, f"_{prefix}proxy"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "proxy")) - - if not isinstance(getattr(self, f"_{prefix}socket_options"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "socket_options")) - - if not isinstance(getattr(self, f"_{prefix}http_version"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "http_version")) - - self._bot_check(name) - - if self._updater not in (DEFAULT_NONE, None): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "updater instance")) - - def _request_param_check(self, name: str, get_updates: bool) -> None: - if get_updates and self._get_updates_request is not DEFAULT_NONE: - raise RuntimeError( # disallow request args for get_updates if Request for that is set - _TWO_ARGS_REQ.format(f"get_updates_{name}", "get_updates_request instance") - ) - if self._request is not DEFAULT_NONE: # disallow request args if request is set - raise RuntimeError(_TWO_ARGS_REQ.format(name, "request instance")) - - if self._bot is not DEFAULT_NONE: # disallow request args if bot is set (has Request) - raise RuntimeError( - _TWO_ARGS_REQ.format( - f"get_updates_{name}" if get_updates else name, "bot instance" - ) - ) - - if self._updater not in (DEFAULT_NONE, None): # disallow request args for updater(has bot) - raise RuntimeError( - _TWO_ARGS_REQ.format(f"get_updates_{name}" if get_updates else name, "updater") - ) - - def request(self: BuilderType, request: BaseRequest) -> BuilderType: - """Sets a :class:`telegram.request.BaseRequest` instance for the - :paramref:`telegram.Bot.request` parameter of :attr:`telegram.ext.Application.bot`. - - .. seealso:: :meth:`get_updates_request` - - Args: - request (:class:`telegram.request.BaseRequest`): The request instance. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_check(get_updates=False) - self._request = request - return self - - def connection_pool_size(self: BuilderType, connection_pool_size: int) -> BuilderType: - """Sets the size of the connection pool for the - :paramref:`~telegram.request.HTTPXRequest.connection_pool_size` parameter of - :attr:`telegram.Bot.request`. Defaults to ``256``. - - .. include:: inclusions/pool_size_tip.rst - - .. seealso:: :meth:`get_updates_connection_pool_size` - - Args: - connection_pool_size (:obj:`int`): The size of the connection pool. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="connection_pool_size", get_updates=False) - self._connection_pool_size = connection_pool_size - return self - - def proxy_url(self: BuilderType, proxy_url: str) -> BuilderType: - """Legacy name for :meth:`proxy`, kept for backward compatibility. - - .. seealso:: :meth:`get_updates_proxy` - - .. deprecated:: 20.7 - - Args: - proxy_url (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): See - :paramref:`telegram.ext.ApplicationBuilder.proxy.proxy`. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - warn( - PTBDeprecationWarning( - "20.7", - "`ApplicationBuilder.proxy_url` is deprecated. Use `ApplicationBuilder.proxy` " - "instead.", - ), - stacklevel=2, - ) - return self.proxy(proxy_url) - - def proxy(self: BuilderType, proxy: Union[str, httpx.Proxy, httpx.URL]) -> BuilderType: - """Sets the proxy for the :paramref:`~telegram.request.HTTPXRequest.proxy` - parameter of :attr:`telegram.Bot.request`. Defaults to :obj:`None`. - - .. seealso:: :meth:`get_updates_proxy` - - .. versionadded:: 20.7 - - Args: - proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): The URL to a proxy - server, a ``httpx.Proxy`` object or a ``httpx.URL`` object. See - :paramref:`telegram.request.HTTPXRequest.proxy` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="proxy", get_updates=False) - self._proxy = proxy - return self - - def socket_options(self: BuilderType, socket_options: Collection[SocketOpt]) -> BuilderType: - """Sets the options for the :paramref:`~telegram.request.HTTPXRequest.socket_options` - parameter of :attr:`telegram.Bot.request`. Defaults to :obj:`None`. - - .. seealso:: :meth:`get_updates_socket_options` - - .. versionadded:: 20.7 - - Args: - socket_options (Collection[:obj:`tuple`], optional): Socket options. See - :paramref:`telegram.request.HTTPXRequest.socket_options` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="socket_options", get_updates=False) - self._socket_options = socket_options - return self - - def connect_timeout(self: BuilderType, connect_timeout: Optional[float]) -> BuilderType: - """Sets the connection attempt timeout for the - :paramref:`~telegram.request.HTTPXRequest.connect_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``5.0``. - - .. seealso:: :meth:`get_updates_connect_timeout` - - Args: - connect_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.connect_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="connect_timeout", get_updates=False) - self._connect_timeout = connect_timeout - return self - - def read_timeout(self: BuilderType, read_timeout: Optional[float]) -> BuilderType: - """Sets the waiting timeout for the - :paramref:`~telegram.request.HTTPXRequest.read_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``5.0``. - - .. seealso:: :meth:`get_updates_read_timeout` - - Args: - read_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.read_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="read_timeout", get_updates=False) - self._read_timeout = read_timeout - return self - - def write_timeout(self: BuilderType, write_timeout: Optional[float]) -> BuilderType: - """Sets the write operation timeout for the - :paramref:`~telegram.request.HTTPXRequest.write_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``5.0``. - - .. seealso:: :meth:`get_updates_write_timeout` - - Args: - write_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.write_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="write_timeout", get_updates=False) - self._write_timeout = write_timeout - return self - - def media_write_timeout( - self: BuilderType, media_write_timeout: Optional[float] - ) -> BuilderType: - """Sets the media write operation timeout for the - :paramref:`~telegram.request.HTTPXRequest.media_write_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``20``. - - .. versionadded:: 21.0 - - Args: - media_write_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.media_write_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="media_write_timeout", get_updates=False) - self._media_write_timeout = media_write_timeout - return self - - def pool_timeout(self: BuilderType, pool_timeout: Optional[float]) -> BuilderType: - """Sets the connection pool's connection freeing timeout for the - :paramref:`~telegram.request.HTTPXRequest.pool_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``1.0``. - - .. include:: inclusions/pool_size_tip.rst - - .. seealso:: :meth:`get_updates_pool_timeout` - - Args: - pool_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.pool_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="pool_timeout", get_updates=False) - self._pool_timeout = pool_timeout - return self - - def http_version(self: BuilderType, http_version: HTTPVersion) -> BuilderType: - """Sets the HTTP protocol version which is used for the - :paramref:`~telegram.request.HTTPXRequest.http_version` parameter of - :attr:`telegram.Bot.request`. By default, HTTP/1.1 is used. - - .. seealso:: :meth:`get_updates_http_version` - - Note: - Users have observed stability issues with HTTP/2, which happen due to how the `h2 - library handles `_ cancellations of - keepalive connections. See `#3556 `_ for a discussion. - - If you want to use HTTP/2, you must install PTB with the optional requirement - ``http2``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[http2]" - - Keep in mind that the HTTP/1.1 implementation may be considered the `"more - robust option at this time" `_. - - .. versionadded:: 20.1 - .. versionchanged:: 20.2 - Reset the default version to 1.1. - - Args: - http_version (:obj:`str`): Pass ``"2"`` or ``"2.0"`` if you'd like to use HTTP/2 for - making requests to Telegram. Defaults to ``"1.1"``, in which case HTTP/1.1 is used. - - .. versionchanged:: 20.5 - Accept ``"2"`` as a valid value. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="http_version", get_updates=False) - self._http_version = http_version - return self - - def get_updates_request(self: BuilderType, get_updates_request: BaseRequest) -> BuilderType: - """Sets a :class:`telegram.request.BaseRequest` instance for the - :paramref:`~telegram.Bot.get_updates_request` parameter of - :attr:`telegram.ext.Application.bot`. - - .. seealso:: :meth:`request` - - Args: - get_updates_request (:class:`telegram.request.BaseRequest`): The request instance. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_check(get_updates=True) - self._get_updates_request = get_updates_request - return self - - def get_updates_connection_pool_size( - self: BuilderType, get_updates_connection_pool_size: int - ) -> BuilderType: - """Sets the size of the connection pool for the - :paramref:`telegram.request.HTTPXRequest.connection_pool_size` parameter which is used - for the :meth:`telegram.Bot.get_updates` request. Defaults to ``1``. - - .. seealso:: :meth:`connection_pool_size` - - Args: - get_updates_connection_pool_size (:obj:`int`): The size of the connection pool. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="connection_pool_size", get_updates=True) - self._get_updates_connection_pool_size = get_updates_connection_pool_size - return self - - def get_updates_proxy_url(self: BuilderType, get_updates_proxy_url: str) -> BuilderType: - """Legacy name for :meth:`get_updates_proxy`, kept for backward compatibility. - - .. seealso:: :meth:`proxy` - - .. deprecated:: 20.7 - - Args: - get_updates_proxy_url (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): See - :paramref:`telegram.ext.ApplicationBuilder.get_updates_proxy.get_updates_proxy`. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - warn( - PTBDeprecationWarning( - "20.7", - "`ApplicationBuilder.get_updates_proxy_url` is deprecated. Use " - "`ApplicationBuilder.get_updates_proxy` instead.", - ), - stacklevel=2, - ) - return self.get_updates_proxy(get_updates_proxy_url) - - def get_updates_proxy( - self: BuilderType, get_updates_proxy: Union[str, httpx.Proxy, httpx.URL] - ) -> BuilderType: - """Sets the proxy for the :paramref:`telegram.request.HTTPXRequest.proxy` - parameter which is used for :meth:`telegram.Bot.get_updates`. Defaults to :obj:`None`. - - .. seealso:: :meth:`proxy` - - .. versionadded:: 20.7 - - Args: - proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): The URL to a proxy server, - a ``httpx.Proxy`` object or a ``httpx.URL`` object. See - :paramref:`telegram.request.HTTPXRequest.proxy` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="proxy", get_updates=True) - self._get_updates_proxy = get_updates_proxy - return self - - def get_updates_socket_options( - self: BuilderType, get_updates_socket_options: Collection[SocketOpt] - ) -> BuilderType: - """Sets the options for the :paramref:`~telegram.request.HTTPXRequest.socket_options` - parameter of :paramref:`telegram.Bot.get_updates_request`. Defaults to :obj:`None`. - - .. seealso:: :meth:`socket_options` - - .. versionadded:: 20.7 - - Args: - get_updates_socket_options (Collection[:obj:`tuple`], optional): Socket options. See - :paramref:`telegram.request.HTTPXRequest.socket_options` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="socket_options", get_updates=True) - self._get_updates_socket_options = get_updates_socket_options - return self - - def get_updates_connect_timeout( - self: BuilderType, get_updates_connect_timeout: Optional[float] - ) -> BuilderType: - """Sets the connection attempt timeout for the - :paramref:`telegram.request.HTTPXRequest.connect_timeout` parameter which is used for - the :meth:`telegram.Bot.get_updates` request. Defaults to ``5.0``. - - .. seealso:: :meth:`connect_timeout` - - Args: - get_updates_connect_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.connect_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="connect_timeout", get_updates=True) - self._get_updates_connect_timeout = get_updates_connect_timeout - return self - - def get_updates_read_timeout( - self: BuilderType, get_updates_read_timeout: Optional[float] - ) -> BuilderType: - """Sets the waiting timeout for the - :paramref:`telegram.request.HTTPXRequest.read_timeout` parameter which is used for the - :meth:`telegram.Bot.get_updates` request. Defaults to ``5.0``. - - .. seealso:: :meth:`read_timeout` - - Args: - get_updates_read_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.read_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="read_timeout", get_updates=True) - self._get_updates_read_timeout = get_updates_read_timeout - return self - - def get_updates_write_timeout( - self: BuilderType, get_updates_write_timeout: Optional[float] - ) -> BuilderType: - """Sets the write operation timeout for the - :paramref:`telegram.request.HTTPXRequest.write_timeout` parameter which is used for - the :meth:`telegram.Bot.get_updates` request. Defaults to ``5.0``. - - .. seealso:: :meth:`write_timeout` - - Args: - get_updates_write_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.write_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="write_timeout", get_updates=True) - self._get_updates_write_timeout = get_updates_write_timeout - return self - - def get_updates_pool_timeout( - self: BuilderType, get_updates_pool_timeout: Optional[float] - ) -> BuilderType: - """Sets the connection pool's connection freeing timeout for the - :paramref:`~telegram.request.HTTPXRequest.pool_timeout` parameter which is used for the - :meth:`telegram.Bot.get_updates` request. Defaults to ``1.0``. - - .. seealso:: :meth:`pool_timeout` - - Args: - get_updates_pool_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.pool_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="pool_timeout", get_updates=True) - self._get_updates_pool_timeout = get_updates_pool_timeout - return self - - def get_updates_http_version( - self: BuilderType, get_updates_http_version: HTTPVersion - ) -> BuilderType: - """Sets the HTTP protocol version which is used for the - :paramref:`~telegram.request.HTTPXRequest.http_version` parameter which is used in the - :meth:`telegram.Bot.get_updates` request. By default, HTTP/1.1 is used. - - .. seealso:: :meth:`http_version` - - Note: - Users have observed stability issues with HTTP/2, which happen due to how the `h2 - library handles `_ cancellations of - keepalive connections. See `#3556 `_ for a discussion. - - You will also need to install the http2 dependency. Keep in mind that the HTTP/1.1 - implementation may be considered the `"more robust option at this time" - `_. - - .. code-block:: bash - - pip install httpx[http2] - - .. versionadded:: 20.1 - .. versionchanged:: 20.2 - Reset the default version to 1.1. - - Args: - get_updates_http_version (:obj:`str`): Pass ``"2"`` or ``"2.0"`` if you'd like to use - HTTP/2 for making requests to Telegram. Defaults to ``"1.1"``, in which case - HTTP/1.1 is used. - - .. versionchanged:: 20.5 - Accept ``"2"`` as a valid value. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="http_version", get_updates=True) - self._get_updates_http_version = get_updates_http_version - return self - - def private_key( - self: BuilderType, - private_key: Union[bytes, FilePathInput], - password: Optional[Union[bytes, FilePathInput]] = None, - ) -> BuilderType: - """Sets the private key and corresponding password for decryption of telegram passport data - for :attr:`telegram.ext.Application.bot`. - - Examples: - :any:`Passport Bot ` - - .. seealso:: :wiki:`Telegram Passports ` - - Args: - private_key (:obj:`bytes` | :obj:`str` | :obj:`pathlib.Path`): The private key or the - file path of a file that contains the key. In the latter case, the file's content - will be read automatically. - password (:obj:`bytes` | :obj:`str` | :obj:`pathlib.Path`, optional): The corresponding - password or the file path of a file that contains the password. In the latter case, - the file's content will be read automatically. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("private_key") - self._updater_check("private_key") - - self._private_key = ( - private_key if isinstance(private_key, bytes) else Path(private_key).read_bytes() - ) - if password is None or isinstance(password, bytes): - self._private_key_password = password - else: - self._private_key_password = Path(password).read_bytes() - - return self - - def defaults(self: BuilderType, defaults: "Defaults") -> BuilderType: - """Sets the :class:`telegram.ext.Defaults` instance for - :attr:`telegram.ext.Application.bot`. - - .. seealso:: :wiki:`Adding Defaults to Your Bot ` - - Args: - defaults (:class:`telegram.ext.Defaults`): The defaults instance. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("defaults") - self._updater_check("defaults") - self._defaults = defaults - return self - - def arbitrary_callback_data( - self: BuilderType, arbitrary_callback_data: Union[bool, int] - ) -> BuilderType: - """Specifies whether :attr:`telegram.ext.Application.bot` should allow arbitrary objects as - callback data for :class:`telegram.InlineKeyboardButton` and how many keyboards should be - cached in memory. If not called, only strings can be used as callback data and no data will - be stored in memory. - - Important: - If you want to use this feature, you must install PTB with the optional requirement - ``callback-data``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[callback-data]" - - Examples: - :any:`Arbitrary callback_data Bot ` - - .. seealso:: :wiki:`Arbitrary callback_data ` - - Args: - arbitrary_callback_data (:obj:`bool` | :obj:`int`): If :obj:`True` is passed, the - default cache size of ``1024`` will be used. Pass an integer to specify a different - cache size. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("arbitrary_callback_data") - self._updater_check("arbitrary_callback_data") - self._arbitrary_callback_data = arbitrary_callback_data - return self - - def local_mode(self: BuilderType, local_mode: bool) -> BuilderType: - """Specifies the value for :paramref:`~telegram.Bot.local_mode` for the - :attr:`telegram.ext.Application.bot`. - If not called, will default to :obj:`False`. - - .. seealso:: :wiki:`Local Bot API Server ` - - Args: - local_mode (:obj:`bool`): Whether the bot should run in local mode. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("local_mode") - self._updater_check("local_mode") - self._local_mode = local_mode - return self - - def bot( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - bot: InBT, - ) -> "ApplicationBuilder[InBT, CCT, UD, CD, BD, JQ]": - """Sets a :class:`telegram.Bot` instance for - :attr:`telegram.ext.Application.bot`. Instances of subclasses like - :class:`telegram.ext.ExtBot` are also valid. - - Args: - bot (:class:`telegram.Bot`): The bot. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._updater_check("bot") - for attr, error in _BOT_CHECKS: - if not isinstance(getattr(self, f"_{attr}"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format("bot", error)) - self._bot = bot - return self # type: ignore[return-value] - - def update_queue(self: BuilderType, update_queue: "Queue[object]") -> BuilderType: - """Sets a :class:`asyncio.Queue` instance for - :attr:`telegram.ext.Application.update_queue`, i.e. the queue that the application will - fetch updates from. Will also be used for the :attr:`telegram.ext.Application.updater`. - If not called, a queue will be instantiated. - - .. seealso:: :attr:`telegram.ext.Updater.update_queue` - - Args: - update_queue (:class:`asyncio.Queue`): The queue. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - if self._updater not in (DEFAULT_NONE, None): - raise RuntimeError(_TWO_ARGS_REQ.format("update_queue", "updater instance")) - self._update_queue = update_queue - return self - - def concurrent_updates( - self: BuilderType, concurrent_updates: Union[bool, int, "BaseUpdateProcessor"] - ) -> BuilderType: - """Specifies if and how many updates may be processed concurrently instead of one by one. - If not called, updates will be processed one by one. - - Warning: - Processing updates concurrently is not recommended when stateful handlers like - :class:`telegram.ext.ConversationHandler` are used. Only use this if you are sure - that your bot does not (explicitly or implicitly) rely on updates being processed - sequentially. - - .. include:: inclusions/pool_size_tip.rst - - .. seealso:: :attr:`telegram.ext.Application.concurrent_updates` - - Args: - concurrent_updates (:obj:`bool` | :obj:`int` | :class:`BaseUpdateProcessor`): Passing - :obj:`True` will allow for ``256`` updates to be processed concurrently using - :class:`telegram.ext.SimpleUpdateProcessor`. Pass an integer to specify a different - number of updates that may be processed concurrently. Pass an instance of - :class:`telegram.ext.BaseUpdateProcessor` to use that instance for handling updates - concurrently. - - .. versionchanged:: 20.4 - Now accepts :class:`BaseUpdateProcessor` instances. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - # Check if concurrent updates is bool and convert to integer - if concurrent_updates is True: - concurrent_updates = 256 - elif concurrent_updates is False: - concurrent_updates = 1 - - # If `concurrent_updates` is an integer, create a `SimpleUpdateProcessor` - # instance with that integer value; otherwise, raise an error if the value - # is negative - if isinstance(concurrent_updates, int): - concurrent_updates = SimpleUpdateProcessor(concurrent_updates) - - # Assign default value of concurrent_updates if it is instance of - # `BaseUpdateProcessor` - self._update_processor: BaseUpdateProcessor = concurrent_updates # type: ignore[no-redef] - return self - - def job_queue( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - job_queue: InJQ, - ) -> "ApplicationBuilder[BT, CCT, UD, CD, BD, InJQ]": - """Sets a :class:`telegram.ext.JobQueue` instance for - :attr:`telegram.ext.Application.job_queue`. If not called, a job queue will be - instantiated if the requirements of :class:`telegram.ext.JobQueue` are installed. - - Examples: - :any:`Timer Bot ` - - .. seealso:: :wiki:`Job Queue ` - - Note: - * :meth:`telegram.ext.JobQueue.set_application` will be called automatically by - :meth:`build`. - * The job queue will be automatically started and stopped by - :meth:`telegram.ext.Application.start` and :meth:`telegram.ext.Application.stop`, - respectively. - * When passing :obj:`None` or when the requirements of :class:`telegram.ext.JobQueue` - are not installed, :attr:`telegram.ext.ConversationHandler.conversation_timeout` - can not be used, as this uses :attr:`telegram.ext.Application.job_queue` internally. - - Args: - job_queue (:class:`telegram.ext.JobQueue`): The job queue. Pass :obj:`None` if you - don't want to use a job queue. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._job_queue = job_queue - return self # type: ignore[return-value] - - def persistence( - self: BuilderType, persistence: "BasePersistence[Any, Any, Any]" - ) -> BuilderType: - """Sets a :class:`telegram.ext.BasePersistence` instance for - :attr:`telegram.ext.Application.persistence`. - - Note: - When using a persistence, note that all - data stored in :attr:`context.user_data `, - :attr:`context.chat_data `, - :attr:`context.bot_data ` and - in :attr:`telegram.ext.ExtBot.callback_data_cache` must be copyable with - :func:`copy.deepcopy`. This is due to the data being deep copied before handing it over - to the persistence in order to avoid race conditions. - - Examples: - :any:`Persistent Conversation Bot ` - - .. seealso:: :wiki:`Making Your Bot Persistent ` - - Warning: - If a :class:`telegram.ext.ContextTypes` instance is set via :meth:`context_types`, - the persistence instance must use the same types! - - Args: - persistence (:class:`telegram.ext.BasePersistence`): The persistence instance. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._persistence = persistence - return self - - def context_types( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - context_types: "ContextTypes[InCCT, InUD, InCD, InBD]", - ) -> "ApplicationBuilder[BT, InCCT, InUD, InCD, InBD, JQ]": - """Sets a :class:`telegram.ext.ContextTypes` instance for - :attr:`telegram.ext.Application.context_types`. - - Examples: - :any:`Context Types Bot ` - - Args: - context_types (:class:`telegram.ext.ContextTypes`): The context types. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._context_types = context_types - return self # type: ignore[return-value] - - def updater(self: BuilderType, updater: Optional[Updater]) -> BuilderType: - """Sets a :class:`telegram.ext.Updater` instance for - :attr:`telegram.ext.Application.updater`. The :attr:`telegram.ext.Updater.bot` and - :attr:`telegram.ext.Updater.update_queue` will be used for - :attr:`telegram.ext.Application.bot` and :attr:`telegram.ext.Application.update_queue`, - respectively. - - Args: - updater (:class:`telegram.ext.Updater` | :obj:`None`): The updater instance or - :obj:`None` if no updater should be used. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - if updater is None: - self._updater = updater - return self - - for attr, error in ( - (self._bot, "bot instance"), - (self._update_queue, "update_queue"), - ): - if not isinstance(attr, DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format("updater", error)) - - for attr_name, error in _BOT_CHECKS: - if not isinstance(getattr(self, f"_{attr_name}"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format("updater", error)) - - self._updater = updater - return self - - def post_init( - self: BuilderType, post_init: Callable[[Application], Coroutine[Any, Any, None]] - ) -> BuilderType: - """ - Sets a callback to be executed by :meth:`Application.run_polling` and - :meth:`Application.run_webhook` *after* executing :meth:`Application.initialize` but - *before* executing :meth:`Updater.start_polling` or :meth:`Updater.start_webhook`, - respectively. - - Tip: - This can be used for custom startup logic that requires to await coroutines, e.g. - setting up the bots commands via :meth:`~telegram.Bot.set_my_commands`. - - Example: - .. code:: - - async def post_init(application: Application) -> None: - await application.bot.set_my_commands([('start', 'Starts the bot')]) - - application = Application.builder().token("TOKEN").post_init(post_init).build() - - Note: - |post_methods_note| - - .. seealso:: :meth:`post_stop`, :meth:`post_shutdown` - - Args: - post_init (:term:`coroutine function`): The custom callback. Must be a - :term:`coroutine function` and must accept exactly one positional argument, which - is the :class:`~telegram.ext.Application`:: - - async def post_init(application: Application) -> None: - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._post_init = post_init - return self - - def post_shutdown( - self: BuilderType, post_shutdown: Callable[[Application], Coroutine[Any, Any, None]] - ) -> BuilderType: - """ - Sets a callback to be executed by :meth:`Application.run_polling` and - :meth:`Application.run_webhook` *after* executing :meth:`Updater.shutdown` - and :meth:`Application.shutdown`. - - Tip: - This can be used for custom shutdown logic that requires to await coroutines, e.g. - closing a database connection - - Example: - .. code:: - - async def post_shutdown(application: Application) -> None: - await application.bot_data['database'].close() - - application = Application.builder() - .token("TOKEN") - .post_shutdown(post_shutdown) - .build() - - Note: - |post_methods_note| - - .. seealso:: :meth:`post_init`, :meth:`post_stop` - - Args: - post_shutdown (:term:`coroutine function`): The custom callback. Must be a - :term:`coroutine function` and must accept exactly one positional argument, which - is the :class:`~telegram.ext.Application`:: - - async def post_shutdown(application: Application) -> None: - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._post_shutdown = post_shutdown - return self - - def post_stop( - self: BuilderType, post_stop: Callable[[Application], Coroutine[Any, Any, None]] - ) -> BuilderType: - """ - Sets a callback to be executed by :meth:`Application.run_polling` and - :meth:`Application.run_webhook` *after* executing :meth:`Updater.stop` - and :meth:`Application.stop`. - - .. versionadded:: 20.1 - - Tip: - This can be used for custom stop logic that requires to await coroutines, e.g. - sending message to a chat before shutting down the bot. - - Hint: - The callback will be called only, if :meth:`Application.stop` was indeed called - successfully. For example, if the application is stopped early by calling - :meth:`Application.stop_running` within :meth:`post_init`, then the set callback will - *not* be called. - - Example: - .. code:: - - async def post_stop(application: Application) -> None: - await application.bot.send_message(123456, "Shutting down...") - - application = Application.builder() - .token("TOKEN") - .post_stop(post_stop) - .build() - - Note: - |post_methods_note| - - .. seealso:: :meth:`post_init`, :meth:`post_shutdown` - - Args: - post_stop (:term:`coroutine function`): The custom callback. Must be a - :term:`coroutine function` and must accept exactly one positional argument, which - is the :class:`~telegram.ext.Application`:: - - async def post_stop(application: Application) -> None: - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._post_stop = post_stop - return self - - def rate_limiter( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - rate_limiter: "BaseRateLimiter[RLARGS]", - ) -> "ApplicationBuilder[ExtBot[RLARGS], CCT, UD, CD, BD, JQ]": - """Sets a :class:`telegram.ext.BaseRateLimiter` instance for the - :paramref:`telegram.ext.ExtBot.rate_limiter` parameter of - :attr:`telegram.ext.Application.bot`. - - Args: - rate_limiter (:class:`telegram.ext.BaseRateLimiter`): The rate limiter. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("rate_limiter") - self._updater_check("rate_limiter") - self._rate_limiter = rate_limiter - return self # type: ignore[return-value] - - -InitApplicationBuilder = ( # This is defined all the way down here so that its type is inferred - ApplicationBuilder[ # by Pylance correctly. - ExtBot[None], - ContextTypes.DEFAULT_TYPE, - dict[Any, Any], - dict[Any, Any], - dict[Any, Any], - JobQueue[ContextTypes.DEFAULT_TYPE], - ] -) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_basepersistence.py b/venv/lib/python3.11/site-packages/telegram/ext/_basepersistence.py deleted file mode 100755 index 3571f6d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_basepersistence.py +++ /dev/null @@ -1,440 +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 -# -# 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 BasePersistence class.""" -from abc import ABC, abstractmethod -from typing import Generic, NamedTuple, NoReturn, Optional - -from telegram._bot import Bot -from telegram.ext._extbot import ExtBot -from telegram.ext._utils.types import BD, CD, UD, CDCData, ConversationDict, ConversationKey - - -class PersistenceInput(NamedTuple): - """Convenience wrapper to group boolean input for the :paramref:`~BasePersistence.store_data` - parameter for :class:`BasePersistence`. - - Args: - bot_data (:obj:`bool`, optional): Whether the setting should be applied for ``bot_data``. - Defaults to :obj:`True`. - chat_data (:obj:`bool`, optional): Whether the setting should be applied for ``chat_data``. - Defaults to :obj:`True`. - user_data (:obj:`bool`, optional): Whether the setting should be applied for ``user_data``. - Defaults to :obj:`True`. - callback_data (:obj:`bool`, optional): Whether the setting should be applied for - ``callback_data``. Defaults to :obj:`True`. - - Attributes: - bot_data (:obj:`bool`): Whether the setting should be applied for ``bot_data``. - chat_data (:obj:`bool`): Whether the setting should be applied for ``chat_data``. - user_data (:obj:`bool`): Whether the setting should be applied for ``user_data``. - callback_data (:obj:`bool`): Whether the setting should be applied for ``callback_data``. - - """ - - bot_data: bool = True - chat_data: bool = True - user_data: bool = True - callback_data: bool = True - - -class BasePersistence(Generic[UD, CD, BD], ABC): - """Interface class for adding persistence to your bot. - Subclass this object for different implementations of a persistent bot. - - Attention: - The interface provided by this class is intended to be accessed exclusively by - :class:`~telegram.ext.Application`. Calling any of the methods below manually might - interfere with the integration of persistence into :class:`~telegram.ext.Application`. - - All relevant methods must be overwritten. This includes: - - * :meth:`get_bot_data` - * :meth:`update_bot_data` - * :meth:`refresh_bot_data` - * :meth:`get_chat_data` - * :meth:`update_chat_data` - * :meth:`refresh_chat_data` - * :meth:`drop_chat_data` - * :meth:`get_user_data` - * :meth:`update_user_data` - * :meth:`refresh_user_data` - * :meth:`drop_user_data` - * :meth:`get_callback_data` - * :meth:`update_callback_data` - * :meth:`get_conversations` - * :meth:`update_conversation` - * :meth:`flush` - - If you don't actually need one of those methods, a simple :keyword:`pass` is enough. - For example, if you don't store ``bot_data``, you don't need :meth:`get_bot_data`, - :meth:`update_bot_data` or :meth:`refresh_bot_data`. - - Note: - You should avoid saving :class:`telegram.Bot` instances. This is because if you change e.g. - the bots token, this won't propagate to the serialized instances and may lead to exceptions. - - To prevent this, the implementation may use :attr:`bot` to replace bot instances with a - placeholder before serialization and insert :attr:`bot` back when loading the data. - Since :attr:`bot` will be set when the process starts, this will be the up-to-date bot - instance. - - If the persistence implementation does not take care of this, you should make sure not to - store any bot instances in the data that will be persisted. E.g. in case of - :class:`telegram.TelegramObject`, one may call :meth:`set_bot` to ensure that shortcuts like - :meth:`telegram.Message.reply_text` are available. - - This class is a :class:`~typing.Generic` class and accepts three type variables: - - 1. The type of the second argument of :meth:`update_user_data`, which must coincide with the - type of the second argument of :meth:`refresh_user_data` and the values in the dictionary - returned by :meth:`get_user_data`. - 2. The type of the second argument of :meth:`update_chat_data`, which must coincide with the - type of the second argument of :meth:`refresh_chat_data` and the values in the dictionary - returned by :meth:`get_chat_data`. - 3. The type of the argument of :meth:`update_bot_data`, which must coincide with the - type of the argument of :meth:`refresh_bot_data` and the return value of - :meth:`get_bot_data`. - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Making Your Bot Persistent ` - - .. versionchanged:: 20.0 - - * The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`. - * ``insert/replace_bot`` was dropped. Serialization of bot instances now needs to be - handled by the specific implementation - see above note. - - Args: - store_data (:class:`~telegram.ext.PersistenceInput`, optional): Specifies which kinds of - data will be saved by this persistence instance. By default, all available kinds of - data will be saved. - update_interval (:obj:`int` | :obj:`float`, optional): The - :class:`~telegram.ext.Application` will update - the persistence in regular intervals. This parameter specifies the time (in seconds) to - wait between two consecutive runs of updating the persistence. Defaults to ``60`` - seconds. - - .. versionadded:: 20.0 - Attributes: - store_data (:class:`~telegram.ext.PersistenceInput`): Specifies which kinds of data will - be saved by this persistence instance. - bot (:class:`telegram.Bot`): The bot associated with the persistence. - """ - - __slots__ = ( - "_update_interval", - "bot", - "store_data", - ) - - def __init__( - self, - store_data: Optional[PersistenceInput] = None, - update_interval: float = 60, - ): - self.store_data: PersistenceInput = store_data or PersistenceInput() - self._update_interval: float = update_interval - - self.bot: Bot = None # type: ignore[assignment] - - @property - def update_interval(self) -> float: - """:obj:`float`: Time (in seconds) that the :class:`~telegram.ext.Application` - will wait between two consecutive runs of updating the persistence. - - .. versionadded:: 20.0 - """ - return self._update_interval - - @update_interval.setter - def update_interval(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to update_interval after initialization." - ) - - def set_bot(self, bot: Bot) -> None: - """Set the Bot to be used by this persistence instance. - - Args: - bot (:class:`telegram.Bot`): The bot. - - Raises: - :exc:`TypeError`: If :attr:`PersistenceInput.callback_data` is :obj:`True` and the - :paramref:`bot` is not an instance of :class:`telegram.ext.ExtBot`. - """ - if self.store_data.callback_data and (not isinstance(bot, ExtBot)): - raise TypeError("callback_data can only be stored when using telegram.ext.ExtBot.") - - self.bot = bot - - @abstractmethod - async def get_user_data(self) -> dict[int, UD]: - """Will be called by :class:`telegram.ext.Application` upon creation with a - persistence object. It should return the ``user_data`` if stored, or an empty - :obj:`dict`. In the latter case, the dictionary should produce values - corresponding to one of the following: - - - :obj:`dict` - - The type from :attr:`telegram.ext.ContextTypes.user_data` - if :class:`telegram.ext.ContextTypes` is used. - - .. versionchanged:: 20.0 - This method may now return a :obj:`dict` instead of a :obj:`collections.defaultdict` - - Returns: - dict[:obj:`int`, :obj:`dict` | :attr:`telegram.ext.ContextTypes.user_data`]: - The restored user data. - """ - - @abstractmethod - async def get_chat_data(self) -> dict[int, CD]: - """Will be called by :class:`telegram.ext.Application` upon creation with a - persistence object. It should return the ``chat_data`` if stored, or an empty - :obj:`dict`. In the latter case, the dictionary should produce values - corresponding to one of the following: - - - :obj:`dict` - - The type from :attr:`telegram.ext.ContextTypes.chat_data` - if :class:`telegram.ext.ContextTypes` is used. - - .. versionchanged:: 20.0 - This method may now return a :obj:`dict` instead of a :obj:`collections.defaultdict` - - Returns: - dict[:obj:`int`, :obj:`dict` | :attr:`telegram.ext.ContextTypes.chat_data`]: - The restored chat data. - """ - - @abstractmethod - async def get_bot_data(self) -> BD: - """Will be called by :class:`telegram.ext.Application` upon creation with a - persistence object. It should return the ``bot_data`` if stored, or an empty - :obj:`dict`. In the latter case, the :obj:`dict` should produce values - corresponding to one of the following: - - - :obj:`dict` - - The type from :attr:`telegram.ext.ContextTypes.bot_data` - if :class:`telegram.ext.ContextTypes` are used. - - Returns: - dict[:obj:`int`, :obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`]: - The restored bot data. - """ - - @abstractmethod - async def get_callback_data(self) -> Optional[CDCData]: - """Will be called by :class:`telegram.ext.Application` upon creation with a - persistence object. If callback data was stored, it should be returned. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Returns: - tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], - dict[:obj:`str`, :obj:`str`]] | :obj:`None`: The restored metadata or :obj:`None`, - if no data was stored. - """ - - @abstractmethod - async def get_conversations(self, name: str) -> ConversationDict: - """Will be called by :class:`telegram.ext.Application` when a - :class:`telegram.ext.ConversationHandler` is added if - :attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`. - It should return the conversations for the handler with :paramref:`name` or an empty - :obj:`dict`. - - Args: - name (:obj:`str`): The handlers name. - - Returns: - :obj:`dict`: The restored conversations for the handler. - """ - - @abstractmethod - async def update_conversation( - self, name: str, key: ConversationKey, new_state: Optional[object] - ) -> None: - """Will be called when a :class:`telegram.ext.ConversationHandler` changes states. - This allows the storage of the new state in the persistence. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:class:`object`): The new state for the given key. - """ - - @abstractmethod - async def update_user_data(self, user_id: int, data: UD) -> None: - """Will be called by the :class:`telegram.ext.Application` after a handler has - handled an update. - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.user_data`): - The :attr:`telegram.ext.Application.user_data` ``[user_id]``. - """ - - @abstractmethod - async def update_chat_data(self, chat_id: int, data: CD) -> None: - """Will be called by the :class:`telegram.ext.Application` after a handler has - handled an update. - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.chat_data`): - The :attr:`telegram.ext.Application.chat_data` ``[chat_id]``. - """ - - @abstractmethod - async def update_bot_data(self, data: BD) -> None: - """Will be called by the :class:`telegram.ext.Application` after a handler has - handled an update. - - Args: - data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`): - The :attr:`telegram.ext.Application.bot_data`. - """ - - @abstractmethod - async def update_callback_data(self, data: CDCData) -> None: - """Will be called by the :class:`telegram.ext.Application` after a handler has - handled an update. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Args: - data (tuple[list[tuple[:obj:`str`, :obj:`float`, \ - dict[:obj:`str`, :obj:`Any`]]], dict[:obj:`str`, :obj:`str`]] | :obj:`None`): - The relevant data to restore :class:`telegram.ext.CallbackDataCache`. - """ - - @abstractmethod - async def drop_chat_data(self, chat_id: int) -> None: - """Will be called by the :class:`telegram.ext.Application`, when using - :meth:`~telegram.ext.Application.drop_chat_data`. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`): The chat id to delete from the persistence. - """ - - @abstractmethod - async def drop_user_data(self, user_id: int) -> None: - """Will be called by the :class:`telegram.ext.Application`, when using - :meth:`~telegram.ext.Application.drop_user_data`. - - .. versionadded:: 20.0 - - Args: - user_id (:obj:`int`): The user id to delete from the persistence. - """ - - @abstractmethod - async def refresh_user_data(self, user_id: int, user_data: UD) -> None: - """Will be called by the :class:`telegram.ext.Application` before passing the - :attr:`~telegram.ext.Application.user_data` to a callback. Can be used to update data - stored in :attr:`~telegram.ext.Application.user_data` from an external source. - - Tip: - This method is expected to edit the object :paramref:`user_data` in-place instead of - returning a new object. - - Warning: - When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method - may be called while a handler callback is still running. This might lead to race - conditions. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Args: - user_id (:obj:`int`): The user ID this :attr:`~telegram.ext.Application.user_data` is - associated with. - user_data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.user_data`): - The ``user_data`` of a single user. - """ - - @abstractmethod - async def refresh_chat_data(self, chat_id: int, chat_data: CD) -> None: - """Will be called by the :class:`telegram.ext.Application` before passing the - :attr:`~telegram.ext.Application.chat_data` to a callback. Can be used to update data - stored in :attr:`~telegram.ext.Application.chat_data` from an external source. - - Tip: - This method is expected to edit the object :paramref:`chat_data` in-place instead of - returning a new object. - - Warning: - When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method - may be called while a handler callback is still running. This might lead to race - conditions. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Args: - chat_id (:obj:`int`): The chat ID this :attr:`~telegram.ext.Application.chat_data` is - associated with. - chat_data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.chat_data`): - The ``chat_data`` of a single chat. - """ - - @abstractmethod - async def refresh_bot_data(self, bot_data: BD) -> None: - """Will be called by the :class:`telegram.ext.Application` before passing the - :attr:`~telegram.ext.Application.bot_data` to a callback. Can be used to update data stored - in :attr:`~telegram.ext.Application.bot_data` from an external source. - - Tip: - This method is expected to edit the object :paramref:`bot_data` in-place instead of - returning a new object. - - Warning: - When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method - may be called while a handler callback is still running. This might lead to race - conditions. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Args: - bot_data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`): - The ``bot_data``. - """ - - @abstractmethod - async def flush(self) -> None: - """Will be called by :meth:`telegram.ext.Application.stop`. Gives the - persistence a chance to finish up saving or close a database connection gracefully. - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - """ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_baseratelimiter.py b/venv/lib/python3.11/site-packages/telegram/ext/_baseratelimiter.py deleted file mode 100755 index ad11e44..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_baseratelimiter.py +++ /dev/null @@ -1,142 +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 -# -# 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 class that allows to rate limit requests to the Bot API.""" -from abc import ABC, abstractmethod -from collections.abc import Coroutine -from typing import Any, Callable, Generic, Optional, Union - -from telegram._utils.types import JSONDict -from telegram.ext._utils.types import RLARGS - - -class BaseRateLimiter(ABC, Generic[RLARGS]): - """ - Abstract interface class that allows to rate limit the requests that python-telegram-bot - sends to the Telegram Bot API. An implementation of this class - must implement all abstract methods and properties. - - This class is a :class:`~typing.Generic` class and accepts one type variable that specifies - the type of the argument :paramref:`~process_request.rate_limit_args` of - :meth:`process_request` and the methods of :class:`~telegram.ext.ExtBot`. - - Hint: - Requests to :meth:`~telegram.Bot.get_updates` are never rate limited. - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Avoiding Flood Limits ` - - .. versionadded:: 20.0 - """ - - __slots__ = () - - @abstractmethod - async def initialize(self) -> None: - """Initialize resources used by this class. Must be implemented by a subclass.""" - - @abstractmethod - async def shutdown(self) -> None: - """Stop & clear resources used by this class. Must be implemented by a subclass.""" - - @abstractmethod - async def process_request( - self, - callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, list[JSONDict]]]], - args: Any, - kwargs: dict[str, Any], - endpoint: str, - data: dict[str, Any], - rate_limit_args: Optional[RLARGS], - ) -> Union[bool, JSONDict, list[JSONDict]]: - """ - Process a request. Must be implemented by a subclass. - - This method must call :paramref:`callback` and return the result of the call. - `When` the callback is called is up to the implementation. - - Important: - This method must only return once the result of :paramref:`callback` is known! - - If a :exc:`~telegram.error.RetryAfter` error is raised, this method may try to make - a new request by calling the callback again. - - Warning: - This method *should not* handle any other exception raised by :paramref:`callback`! - - There are basically two different approaches how a rate limiter can be implemented: - - 1. React only if necessary. In this case, the :paramref:`callback` is called without any - precautions. If a :exc:`~telegram.error.RetryAfter` error is raised, processing requests - is halted for the :attr:`~telegram.error.RetryAfter.retry_after` and finally the - :paramref:`callback` is called again. This approach is often amendable for bots that - don't have a large user base and/or don't send more messages than they get updates. - 2. Throttle all outgoing requests. In this case the implementation makes sure that the - requests are spread out over a longer time interval in order to stay below the rate - limits. This approach is often amendable for bots that have a large user base and/or - send more messages than they get updates. - - An implementation can use the information provided by :paramref:`data`, - :paramref:`endpoint` and :paramref:`rate_limit_args` to handle each request differently. - - Examples: - * It is usually desirable to call :meth:`telegram.Bot.answer_inline_query` - as quickly as possible, while delaying :meth:`telegram.Bot.send_message` - is acceptable. - * There are `different `_ rate limits for group chats and - private chats. - * When sending broadcast messages to a large number of users, these requests can - typically be delayed for a longer time than messages that are direct replies to a - user input. - - Args: - callback (Callable[..., :term:`coroutine`]): The coroutine function that must be called - to make the request. - args (tuple[:obj:`object`]): The positional arguments for the :paramref:`callback` - function. - kwargs (dict[:obj:`str`, :obj:`object`]): The keyword arguments for the - :paramref:`callback` function. - endpoint (:obj:`str`): The endpoint that the request is made for, e.g. - ``"sendMessage"``. - data (dict[:obj:`str`, :obj:`object`]): The parameters that were passed to the method - of :class:`~telegram.ext.ExtBot`. Any ``api_kwargs`` are included in this and - any :paramref:`~telegram.ext.ExtBot.defaults` are already applied. - - Example: - - When calling:: - - await ext_bot.send_message( - chat_id=1, - text="Hello world!", - api_kwargs={"custom": "arg"} - ) - - then :paramref:`data` will be:: - - {"chat_id": 1, "text": "Hello world!", "custom": "arg"} - - rate_limit_args (:obj:`None` | :class:`object`): Custom arguments passed to the methods - of :class:`~telegram.ext.ExtBot`. Can e.g. be used to specify the priority of - the request. - - Returns: - :obj:`bool` | dict[:obj:`str`, :obj:`object`] | :obj:`None`: The result of the - callback function. - """ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_baseupdateprocessor.py b/venv/lib/python3.11/site-packages/telegram/ext/_baseupdateprocessor.py deleted file mode 100755 index 3d6ad37..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_baseupdateprocessor.py +++ /dev/null @@ -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 -# -# 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 BaseProcessor class.""" -from abc import ABC, abstractmethod -from asyncio import BoundedSemaphore -from contextlib import AbstractAsyncContextManager -from types import TracebackType -from typing import TYPE_CHECKING, Any, Optional, TypeVar, final - -if TYPE_CHECKING: - from collections.abc import Awaitable - -_BUPT = TypeVar("_BUPT", bound="BaseUpdateProcessor") - - -class BaseUpdateProcessor(AbstractAsyncContextManager["BaseUpdateProcessor"], ABC): - """An abstract base class for update processors. You can use this class to implement - your own update processor. - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with processor: - # code - - is roughly equivalent to - - .. code:: python - - try: - await processor.initialize() - # code - finally: - await processor.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - .. seealso:: :wiki:`Concurrency` - - .. versionadded:: 20.4 - - Args: - max_concurrent_updates (:obj:`int`): The maximum number of updates to be processed - concurrently. If this number is exceeded, new updates will be queued until the number - of currently processed updates decreases. - - Raises: - :exc:`ValueError`: If :paramref:`max_concurrent_updates` is a non-positive integer. - """ - - __slots__ = ("_max_concurrent_updates", "_semaphore") - - def __init__(self, max_concurrent_updates: int): - self._max_concurrent_updates = max_concurrent_updates - if self.max_concurrent_updates < 1: - raise ValueError("`max_concurrent_updates` must be a positive integer!") - self._semaphore = BoundedSemaphore(self.max_concurrent_updates) - - async def __aenter__(self: _BUPT) -> _BUPT: # noqa: PYI019 - """|async_context_manager| :meth:`initializes ` the Processor. - - Returns: - The initialized Processor instance. - - Raises: - :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. - """ - try: - await self.initialize() - except Exception: - await self.shutdown() - raise - return self - - async def __aexit__( - self, - exc_type: Optional[type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - """|async_context_manager| :meth:`shuts down ` the Processor.""" - await self.shutdown() - - @property - def max_concurrent_updates(self) -> int: - """:obj:`int`: The maximum number of updates that can be processed concurrently.""" - return self._max_concurrent_updates - - @abstractmethod - async def do_process_update( - self, - update: object, - coroutine: "Awaitable[Any]", - ) -> None: - """Custom implementation of how to process an update. Must be implemented by a subclass. - - Warning: - This method will be called by :meth:`process_update`. It should *not* be called - manually. - - Args: - update (:obj:`object`): The update to be processed. - coroutine (:term:`Awaitable`): The coroutine that will be awaited to process the - update. - """ - - @abstractmethod - async def initialize(self) -> None: - """Initializes the processor so resources can be allocated. Must be implemented by a - subclass. - - .. seealso:: - :meth:`shutdown` - """ - - @abstractmethod - async def shutdown(self) -> None: - """Shutdown the processor so resources can be freed. Must be implemented by a subclass. - - .. seealso:: - :meth:`initialize` - """ - - @final - async def process_update( - self, - update: object, - coroutine: "Awaitable[Any]", - ) -> None: - """Calls :meth:`do_process_update` with a semaphore to limit the number of concurrent - updates. - - Args: - update (:obj:`object`): The update to be processed. - coroutine (:term:`Awaitable`): The coroutine that will be awaited to process the - update. - """ - async with self._semaphore: - await self.do_process_update(update, coroutine) - - -class SimpleUpdateProcessor(BaseUpdateProcessor): - """Instance of :class:`telegram.ext.BaseUpdateProcessor` that immediately awaits the - coroutine, i.e. does not apply any additional processing. This is used by default when - :attr:`telegram.ext.ApplicationBuilder.concurrent_updates` is :obj:`int`. - - .. versionadded:: 20.4 - """ - - __slots__ = () - - async def do_process_update( - self, - update: object, # noqa: ARG002 - coroutine: "Awaitable[Any]", - ) -> None: - """Immediately awaits the coroutine, i.e. does not apply any additional processing. - - Args: - update (:obj:`object`): The update to be processed. - coroutine (:term:`Awaitable`): The coroutine that will be awaited to process the - update. - """ - await coroutine - - async def initialize(self) -> None: - """Does nothing.""" - - async def shutdown(self) -> None: - """Does nothing.""" diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_callbackcontext.py b/venv/lib/python3.11/site-packages/telegram/ext/_callbackcontext.py deleted file mode 100755 index d03250c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_callbackcontext.py +++ /dev/null @@ -1,429 +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 -# -# 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 CallbackContext class.""" - -from collections.abc import Awaitable, Generator -from re import Match -from typing import TYPE_CHECKING, Any, Generic, NoReturn, Optional, TypeVar, Union - -from telegram._callbackquery import CallbackQuery -from telegram._update import Update -from telegram._utils.warnings import warn -from telegram.ext._extbot import ExtBot -from telegram.ext._utils.types import BD, BT, CD, UD - -if TYPE_CHECKING: - from asyncio import Future, Queue - - from telegram.ext import Application, Job, JobQueue - from telegram.ext._utils.types import CCT - -_STORING_DATA_WIKI = ( - "https://github.com/python-telegram-bot/python-telegram-bot" - "/wiki/Storing-bot%2C-user-and-chat-related-data" -) - -# something like poor mans "typing.Self" for py<3.11 -ST = TypeVar("ST", bound="CallbackContext[Any, Any, Any, Any]") - - -class CallbackContext(Generic[BT, UD, CD, BD]): - """ - This is a context object passed to the callback called by :class:`telegram.ext.BaseHandler` - or by the :class:`telegram.ext.Application` in an error handler added by - :attr:`telegram.ext.Application.add_error_handler` or to the callback of a - :class:`telegram.ext.Job`. - - Note: - :class:`telegram.ext.Application` will create a single context for an entire update. This - means that if you got 2 handlers in different groups and they both get called, they will - receive the same :class:`CallbackContext` object (of course with proper attributes like - :attr:`matches` differing). This allows you to add custom attributes in a lower handler - group callback, and then subsequently access those attributes in a higher handler group - callback. Note that the attributes on :class:`CallbackContext` might change in the future, - so make sure to use a fairly unique name for the attributes. - - Warning: - Do not combine custom attributes with :paramref:`telegram.ext.BaseHandler.block` set to - :obj:`False` or :attr:`telegram.ext.Application.concurrent_updates` set to - :obj:`True`. Due to how those work, it will almost certainly execute the callbacks for an - update out of order, and the attributes that you think you added will not be present. - - This class is a :class:`~typing.Generic` class and accepts four type variables: - - 1. The type of :attr:`bot`. Must be :class:`telegram.Bot` or a subclass of that class. - 2. The type of :attr:`user_data` (if :attr:`user_data` is not :obj:`None`). - 3. The type of :attr:`chat_data` (if :attr:`chat_data` is not :obj:`None`). - 4. The type of :attr:`bot_data` (if :attr:`bot_data` is not :obj:`None`). - - Examples: - * :any:`Context Types Bot ` - * :any:`Custom Webhook Bot ` - - .. seealso:: :attr:`telegram.ext.ContextTypes.DEFAULT_TYPE`, - :wiki:`Job Queue ` - - Args: - application (:class:`telegram.ext.Application`): The application associated with this - context. - chat_id (:obj:`int`, optional): The ID of the chat associated with this object. Used - to provide :attr:`chat_data`. - - .. versionadded:: 20.0 - user_id (:obj:`int`, optional): The ID of the user associated with this object. Used - to provide :attr:`user_data`. - - .. versionadded:: 20.0 - Attributes: - coroutine (:term:`awaitable`): Optional. Only present in error handlers if the - error was caused by an awaitable run with :meth:`Application.create_task` or a handler - callback with :attr:`block=False `. - matches (list[:meth:`re.Match `]): Optional. If the associated update - originated from a :class:`filters.Regex`, this will contain a list of match objects for - every pattern where ``re.search(pattern, string)`` returned a match. Note that filters - short circuit, so combined regex filters will not always be evaluated. - args (list[:obj:`str`]): Optional. Arguments passed to a command if the associated update - is handled by :class:`telegram.ext.CommandHandler`, :class:`telegram.ext.PrefixHandler` - or :class:`telegram.ext.StringCommandHandler`. It contains a list of the words in the - text after the command, using any whitespace string as a delimiter. - error (:exc:`Exception`): Optional. The error that was raised. Only present when passed - to an error handler registered with :attr:`telegram.ext.Application.add_error_handler`. - job (:class:`telegram.ext.Job`): Optional. The job which originated this callback. - Only present when passed to the callback of :class:`telegram.ext.Job` or in error - handlers if the error is caused by a job. - - .. versionchanged:: 20.0 - :attr:`job` is now also present in error handlers if the error is caused by a job. - - """ - - __slots__ = ( - "__dict__", - "_application", - "_chat_id", - "_user_id", - "args", - "coroutine", - "error", - "job", - "matches", - ) - - def __init__( - self: ST, - application: "Application[BT, ST, UD, CD, BD, Any]", - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - ): - self._application: Application[BT, ST, UD, CD, BD, Any] = application - self._chat_id: Optional[int] = chat_id - self._user_id: Optional[int] = user_id - self.args: Optional[list[str]] = None - self.matches: Optional[list[Match[str]]] = None - self.error: Optional[Exception] = None - self.job: Optional[Job[Any]] = None - self.coroutine: Optional[ - Union[Generator[Optional[Future[object]], None, Any], Awaitable[Any]] - ] = None - - @property - def application(self) -> "Application[BT, ST, UD, CD, BD, Any]": - """:class:`telegram.ext.Application`: The application associated with this context.""" - return self._application - - @property - def bot_data(self) -> BD: - """:obj:`ContextTypes.bot_data`: Optional. An object that can be used to keep any data in. - For each update it will be the same :attr:`ContextTypes.bot_data`. Defaults to :obj:`dict`. - - .. seealso:: :wiki:`Storing Bot, User and Chat Related Data\ - ` - """ - return self.application.bot_data - - @bot_data.setter - def bot_data(self, _: object) -> NoReturn: - raise AttributeError( - f"You can not assign a new value to bot_data, see {_STORING_DATA_WIKI}" - ) - - @property - def chat_data(self) -> Optional[CD]: - """:obj:`ContextTypes.chat_data`: Optional. An object that can be used to keep any data in. - For each update from the same chat id it will be the same :obj:`ContextTypes.chat_data`. - Defaults to :obj:`dict`. - - Warning: - When a group chat migrates to a supergroup, its chat id will change and the - ``chat_data`` needs to be transferred. For details see our - :wiki:`wiki page `. - - .. seealso:: :wiki:`Storing Bot, User and Chat Related Data\ - ` - - .. versionchanged:: 20.0 - The chat data is now also present in error handlers if the error is caused by a job. - """ - if self._chat_id is not None: - return self._application.chat_data[self._chat_id] - return None - - @chat_data.setter - def chat_data(self, _: object) -> NoReturn: - raise AttributeError( - f"You can not assign a new value to chat_data, see {_STORING_DATA_WIKI}" - ) - - @property - def user_data(self) -> Optional[UD]: - """:obj:`ContextTypes.user_data`: Optional. An object that can be used to keep any data in. - For each update from the same user it will be the same :obj:`ContextTypes.user_data`. - Defaults to :obj:`dict`. - - .. seealso:: :wiki:`Storing Bot, User and Chat Related Data\ - ` - - .. versionchanged:: 20.0 - The user data is now also present in error handlers if the error is caused by a job. - """ - if self._user_id is not None: - return self._application.user_data[self._user_id] - return None - - @user_data.setter - def user_data(self, _: object) -> NoReturn: - raise AttributeError( - f"You can not assign a new value to user_data, see {_STORING_DATA_WIKI}" - ) - - async def refresh_data(self) -> None: - """If :attr:`application` uses persistence, calls - :meth:`telegram.ext.BasePersistence.refresh_bot_data` on :attr:`bot_data`, - :meth:`telegram.ext.BasePersistence.refresh_chat_data` on :attr:`chat_data` and - :meth:`telegram.ext.BasePersistence.refresh_user_data` on :attr:`user_data`, if - appropriate. - - Will be called by :meth:`telegram.ext.Application.process_update` and - :meth:`telegram.ext.Job.run`. - - .. versionadded:: 13.6 - """ - if self.application.persistence: - if self.application.persistence.store_data.bot_data: - await self.application.persistence.refresh_bot_data(self.bot_data) - if self.application.persistence.store_data.chat_data and self._chat_id is not None: - await self.application.persistence.refresh_chat_data( - chat_id=self._chat_id, - chat_data=self.chat_data, # type: ignore[arg-type] - ) - if self.application.persistence.store_data.user_data and self._user_id is not None: - await self.application.persistence.refresh_user_data( - user_id=self._user_id, - user_data=self.user_data, # type: ignore[arg-type] - ) - - def drop_callback_data(self, callback_query: CallbackQuery) -> None: - """ - Deletes the cached data for the specified callback query. - - .. versionadded:: 13.6 - - Note: - Will *not* raise exceptions in case the data is not found in the cache. - *Will* raise :exc:`KeyError` in case the callback query can not be found in the cache. - - .. seealso:: :wiki:`Arbitrary callback_data ` - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - Raises: - KeyError | RuntimeError: :exc:`KeyError`, if the callback query can not be found in - the cache and :exc:`RuntimeError`, if the bot doesn't allow for arbitrary - callback data. - """ - if isinstance(self.bot, ExtBot): - if self.bot.callback_data_cache is None: - raise RuntimeError( - "This telegram.ext.ExtBot instance does not use arbitrary callback data." - ) - self.bot.callback_data_cache.drop_data(callback_query) - else: - raise RuntimeError( # noqa: TRY004 - "telegram.Bot does not allow for arbitrary callback data." - ) - - @classmethod - def from_error( - cls: type["CCT"], - update: object, - error: Exception, - application: "Application[BT, CCT, UD, CD, BD, Any]", - job: Optional["Job[Any]"] = None, - coroutine: Optional[ - Union[Generator[Optional["Future[object]"], None, Any], Awaitable[Any]] - ] = None, - ) -> "CCT": - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the error - handlers. - - .. seealso:: :meth:`telegram.ext.Application.add_error_handler` - - .. versionchanged:: 20.0 - Removed arguments ``async_args`` and ``async_kwargs``. - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update associated with the - error. May be :obj:`None`, e.g. for errors in job callbacks. - error (:obj:`Exception`): The error. - application (:class:`telegram.ext.Application`): The application associated with this - context. - job (:class:`telegram.ext.Job`, optional): The job associated with the error. - - .. versionadded:: 20.0 - coroutine (:term:`awaitable`, optional): The awaitable associated - with this error if the error was caused by a coroutine run with - :meth:`Application.create_task` or a handler callback with - :attr:`block=False `. - - .. versionadded:: 20.0 - - .. versionchanged:: 20.2 - Accepts :class:`asyncio.Future` and generator-based coroutine functions. - Returns: - :class:`telegram.ext.CallbackContext` - """ - # update and job will never be present at the same time - if update is not None: - self = cls.from_update(update, application) - elif job is not None: - self = cls.from_job(job, application) - else: - self = cls(application) # type: ignore - - self.error = error - self.coroutine = coroutine - return self - - @classmethod - def from_update( - cls: type["CCT"], - update: object, - application: "Application[Any, CCT, Any, Any, Any, Any]", - ) -> "CCT": - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the - handlers. - - .. seealso:: :meth:`telegram.ext.Application.add_handler` - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update. - application (:class:`telegram.ext.Application`): The application associated with this - context. - - Returns: - :class:`telegram.ext.CallbackContext` - """ - if isinstance(update, Update): - chat = update.effective_chat - user = update.effective_user - - chat_id = chat.id if chat else None - user_id = user.id if user else None - - return cls(application, chat_id=chat_id, user_id=user_id) # type: ignore - return cls(application) # type: ignore - - @classmethod - def from_job( - cls: type["CCT"], - job: "Job[CCT]", - application: "Application[Any, CCT, Any, Any, Any, Any]", - ) -> "CCT": - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to a - job callback. - - .. seealso:: :meth:`telegram.ext.JobQueue` - - Args: - job (:class:`telegram.ext.Job`): The job. - application (:class:`telegram.ext.Application`): The application associated with this - context. - - Returns: - :class:`telegram.ext.CallbackContext` - """ - self = cls(application, chat_id=job.chat_id, user_id=job.user_id) # type: ignore - self.job = job - return self - - def update(self, data: dict[str, object]) -> None: - """Updates ``self.__slots__`` with the passed data. - - Args: - data (dict[:obj:`str`, :obj:`object`]): The data. - """ - for key, value in data.items(): - setattr(self, key, value) - - @property - def bot(self) -> BT: - """:class:`telegram.Bot`: The bot associated with this context.""" - return self._application.bot - - @property - def job_queue(self) -> Optional["JobQueue[ST]"]: - """ - :class:`telegram.ext.JobQueue`: The :class:`JobQueue` used by the - :class:`telegram.ext.Application`. - - .. seealso:: :wiki:`Job Queue ` - """ - if self._application._job_queue is None: # pylint: disable=protected-access - warn( - "No `JobQueue` set up. To use `JobQueue`, you must install PTB via " - '`pip install "python-telegram-bot[job-queue]"`.', - stacklevel=2, - ) - return self._application._job_queue # pylint: disable=protected-access - - @property - def update_queue(self) -> "Queue[object]": - """ - :class:`asyncio.Queue`: The :class:`asyncio.Queue` instance used by the - :class:`telegram.ext.Application` and (usually) the :class:`telegram.ext.Updater` - associated with this context. - - """ - return self._application.update_queue - - @property - def match(self) -> Optional[Match[str]]: - """ - :meth:`re.Match `: The first match from :attr:`matches`. - Useful if you are only filtering using a single regex filter. - Returns :obj:`None` if :attr:`matches` is empty. - """ - try: - return self.matches[0] # type: ignore[index] # pylint: disable=unsubscriptable-object - except (IndexError, TypeError): - return None diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_callbackdatacache.py b/venv/lib/python3.11/site-packages/telegram/ext/_callbackdatacache.py deleted file mode 100755 index 1052bd5..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_callbackdatacache.py +++ /dev/null @@ -1,469 +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 -# -# 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 CallbackDataCache class.""" -import datetime as dtm -import time -from collections.abc import MutableMapping -from typing import TYPE_CHECKING, Any, Optional, Union, cast -from uuid import uuid4 - -try: - from cachetools import LRUCache - - CACHE_TOOLS_AVAILABLE = True -except ImportError: - CACHE_TOOLS_AVAILABLE = False - - -import contextlib - -from telegram import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message, User -from telegram._utils.datetime import to_float_timestamp -from telegram.error import TelegramError -from telegram.ext._utils.types import CDCData - -if TYPE_CHECKING: - from telegram.ext import ExtBot - - -class InvalidCallbackData(TelegramError): - """ - Raised when the received callback data has been tampered with or deleted from cache. - - Examples: - :any:`Arbitrary Callback Data Bot ` - - .. seealso:: :wiki:`Arbitrary callback_data ` - - .. versionadded:: 13.6 - - Args: - callback_data (:obj:`int`, optional): The button data of which the callback data could not - be found. - - Attributes: - callback_data (:obj:`int`): Optional. The button data of which the callback data could not - be found. - """ - - __slots__ = ("callback_data",) - - def __init__(self, callback_data: Optional[str] = None) -> None: - super().__init__( - "The object belonging to this callback_data was deleted or the callback_data was " - "manipulated." - ) - self.callback_data: Optional[str] = callback_data - - def __reduce__(self) -> tuple[type, tuple[Optional[str]]]: # type: ignore[override] - """Defines how to serialize the exception for pickle. See - :py:meth:`object.__reduce__` for more info. - - Returns: - :obj:`tuple` - """ - return self.__class__, (self.callback_data,) - - -class _KeyboardData: - __slots__ = ("access_time", "button_data", "keyboard_uuid") - - def __init__( - self, - keyboard_uuid: str, - access_time: Optional[float] = None, - button_data: Optional[dict[str, object]] = None, - ): - self.keyboard_uuid = keyboard_uuid - self.button_data = button_data or {} - self.access_time = access_time or time.time() - - def update_access_time(self) -> None: - """Updates the access time with the current time.""" - self.access_time = time.time() - - def to_tuple(self) -> tuple[str, float, dict[str, object]]: - """Gives a tuple representation consisting of the keyboard uuid, the access time and the - button data. - """ - return self.keyboard_uuid, self.access_time, self.button_data - - -class CallbackDataCache: - """A custom cache for storing the callback data of a :class:`telegram.ext.ExtBot`. Internally, - it keeps two mappings with fixed maximum size: - - * One for mapping the data received in callback queries to the cached objects - * One for mapping the IDs of received callback queries to the cached objects - - The second mapping allows to manually drop data that has been cached for keyboards of messages - sent via inline mode. - If necessary, will drop the least recently used items. - - Important: - If you want to use this class, you must install PTB with the optional requirement - ``callback-data``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[callback-data]" - - Examples: - :any:`Arbitrary Callback Data Bot ` - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Arbitrary callback_data ` - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - To use this class, PTB must be installed via - ``pip install "python-telegram-bot[callback-data]"``. - - Args: - bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. - maxsize (:obj:`int`, optional): Maximum number of items in each of the internal mappings. - Defaults to ``1024``. - - persistent_data (tuple[list[tuple[:obj:`str`, :obj:`float`, \ - dict[:obj:`str`, :class:`object`]]], dict[:obj:`str`, :obj:`str`]], optional): \ - Data to initialize the cache with, as returned by \ - :meth:`telegram.ext.BasePersistence.get_callback_data`. - - Attributes: - bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. - - """ - - __slots__ = ("_callback_queries", "_keyboard_data", "_maxsize", "bot") - - def __init__( - self, - bot: "ExtBot[Any]", - maxsize: int = 1024, - persistent_data: Optional[CDCData] = None, - ): - if not CACHE_TOOLS_AVAILABLE: - raise RuntimeError( - "To use `CallbackDataCache`, PTB must be installed via `pip install " - '"python-telegram-bot[callback-data]"`.' - ) - - self.bot: ExtBot[Any] = bot - self._maxsize: int = maxsize - self._keyboard_data: MutableMapping[str, _KeyboardData] = LRUCache(maxsize=maxsize) - self._callback_queries: MutableMapping[str, str] = LRUCache(maxsize=maxsize) - - if persistent_data: - self.load_persistence_data(persistent_data) - - def load_persistence_data(self, persistent_data: CDCData) -> None: - """Loads data into the cache. - - Warning: - This method is not intended to be called by users directly. - - .. versionadded:: 20.0 - - Args: - persistent_data (tuple[list[tuple[:obj:`str`, :obj:`float`, \ - dict[:obj:`str`, :class:`object`]]], dict[:obj:`str`, :obj:`str`]], optional): \ - Data to load, as returned by \ - :meth:`telegram.ext.BasePersistence.get_callback_data`. - """ - keyboard_data, callback_queries = persistent_data - for key, value in callback_queries.items(): - self._callback_queries[key] = value - for uuid, access_time, data in keyboard_data: - self._keyboard_data[uuid] = _KeyboardData( - keyboard_uuid=uuid, access_time=access_time, button_data=data - ) - - @property - def maxsize(self) -> int: - """:obj:`int`: The maximum size of the cache. - - .. versionchanged:: 20.0 - This property is now read-only. - """ - return self._maxsize - - @property - def persistence_data(self) -> CDCData: - """tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], - dict[:obj:`str`, :obj:`str`]]: The data that needs to be persisted to allow - caching callback data across bot reboots. - """ - # While building a list/dict from the LRUCaches has linear runtime (in the number of - # entries), the runtime is bounded by maxsize and it has the big upside of not throwing a - # highly customized data structure at users trying to implement a custom persistence class - return [data.to_tuple() for data in self._keyboard_data.values()], dict( - self._callback_queries.items() - ) - - def process_keyboard(self, reply_markup: InlineKeyboardMarkup) -> InlineKeyboardMarkup: - """Registers the reply markup to the cache. If any of the buttons have - :attr:`~telegram.InlineKeyboardButton.callback_data`, stores that data and builds a new - keyboard with the correspondingly replaced buttons. Otherwise, does nothing and returns - the original reply markup. - - Args: - reply_markup (:class:`telegram.InlineKeyboardMarkup`): The keyboard. - - Returns: - :class:`telegram.InlineKeyboardMarkup`: The keyboard to be passed to Telegram. - - """ - keyboard_uuid = uuid4().hex - keyboard_data = _KeyboardData(keyboard_uuid) - - # Built a new nested list of buttons by replacing the callback data if needed - buttons = [ - [ - ( - # We create a new button instead of replacing callback_data in case the - # same object is used elsewhere - InlineKeyboardButton( - btn.text, - callback_data=self.__put_button(btn.callback_data, keyboard_data), - ) - if btn.callback_data - else btn - ) - for btn in column - ] - for column in reply_markup.inline_keyboard - ] - - if not keyboard_data.button_data: - # If we arrive here, no data had to be replaced and we can return the input - return reply_markup - - self._keyboard_data[keyboard_uuid] = keyboard_data - return InlineKeyboardMarkup(buttons) - - @staticmethod - def __put_button(callback_data: object, keyboard_data: _KeyboardData) -> str: - """Stores the data for a single button in :attr:`keyboard_data`. - Returns the string that should be passed instead of the callback_data, which is - ``keyboard_uuid + button_uuids``. - """ - uuid = uuid4().hex - keyboard_data.button_data[uuid] = callback_data - return f"{keyboard_data.keyboard_uuid}{uuid}" - - def __get_keyboard_uuid_and_button_data( - self, callback_data: str - ) -> Union[tuple[str, object], tuple[None, InvalidCallbackData]]: - keyboard, button = self.extract_uuids(callback_data) - try: - # we get the values before calling update() in case KeyErrors are raised - # we don't want to update in that case - keyboard_data = self._keyboard_data[keyboard] - button_data = keyboard_data.button_data[button] - # Update the timestamp for the LRU - keyboard_data.update_access_time() - except KeyError: - return None, InvalidCallbackData(callback_data) - return keyboard, button_data - - @staticmethod - def extract_uuids(callback_data: str) -> tuple[str, str]: - """Extracts the keyboard uuid and the button uuid from the given :paramref:`callback_data`. - - Args: - callback_data (:obj:`str`): The - :paramref:`~telegram.InlineKeyboardButton.callback_data` as present in the button. - - Returns: - (:obj:`str`, :obj:`str`): Tuple of keyboard and button uuid - - """ - # Extract the uuids as put in __put_button - return callback_data[:32], callback_data[32:] - - def process_message(self, message: Message) -> None: - """Replaces the data in the inline keyboard attached to the message with the cached - objects, if necessary. If the data could not be found, - :class:`telegram.ext.InvalidCallbackData` will be inserted. - - Note: - Checks :attr:`telegram.Message.via_bot` and :attr:`telegram.Message.from_user` to check - if the reply markup (if any) was actually sent by this cache's bot. If it was not, the - message will be returned unchanged. - - Note that this will fail for channel posts, as :attr:`telegram.Message.from_user` is - :obj:`None` for those! In the corresponding reply markups the callback data will be - replaced by :class:`telegram.ext.InvalidCallbackData`. - - Warning: - * Does *not* consider :attr:`telegram.Message.reply_to_message` and - :attr:`telegram.Message.pinned_message`. Pass them to this method separately. - * *In place*, i.e. the passed :class:`telegram.Message` will be changed! - - Args: - message (:class:`telegram.Message`): The message. - - """ - self.__process_message(message) - - def __process_message(self, message: Message) -> Optional[str]: - """As documented in process_message, but returns the uuid of the attached keyboard, if any, - which is relevant for process_callback_query. - - **IN PLACE** - """ - if not message.reply_markup: - return None - - if message.via_bot: - sender: Optional[User] = message.via_bot - elif message.from_user: - sender = message.from_user - else: - sender = None - - if sender is not None and sender != self.bot.bot: - return None - - keyboard_uuid = None - - for row in message.reply_markup.inline_keyboard: - for button in row: - if button.callback_data: - button_data = cast(str, button.callback_data) - keyboard_id, callback_data = self.__get_keyboard_uuid_and_button_data( - button_data - ) - # update_callback_data makes sure that the _id_attrs are updated - button.update_callback_data(callback_data) - - # This is lazy loaded. The firsts time we find a button - # we load the associated keyboard - afterwards, there is - if not keyboard_uuid and not isinstance(callback_data, InvalidCallbackData): - keyboard_uuid = keyboard_id - - return keyboard_uuid - - def process_callback_query(self, callback_query: CallbackQuery) -> None: - """Replaces the data in the callback query and the attached messages keyboard with the - cached objects, if necessary. If the data could not be found, - :class:`telegram.ext.InvalidCallbackData` will be inserted. - If :attr:`telegram.CallbackQuery.data` or :attr:`telegram.CallbackQuery.message` is - present, this also saves the callback queries ID in order to be able to resolve it to the - stored data. - - Note: - Also considers inserts data into the buttons of - :attr:`telegram.Message.reply_to_message` and :attr:`telegram.Message.pinned_message` - if necessary. - - Warning: - *In place*, i.e. the passed :class:`telegram.CallbackQuery` will be changed! - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - """ - mapped = False - - if callback_query.data: - data = callback_query.data - - # Get the cached callback data for the CallbackQuery - keyboard_uuid, button_data = self.__get_keyboard_uuid_and_button_data(data) - with callback_query._unfrozen(): - callback_query.data = button_data # type: ignore[assignment] - - # Map the callback queries ID to the keyboards UUID for later use - if not mapped and not isinstance(button_data, InvalidCallbackData): - self._callback_queries[callback_query.id] = keyboard_uuid # type: ignore - mapped = True - - # Get the cached callback data for the inline keyboard attached to the - # CallbackQuery. - if isinstance(callback_query.message, Message): - self.__process_message(callback_query.message) - for maybe_message in ( - callback_query.message.pinned_message, - callback_query.message.reply_to_message, - ): - if isinstance(maybe_message, Message): - self.__process_message(maybe_message) - - def drop_data(self, callback_query: CallbackQuery) -> None: - """Deletes the data for the specified callback query. - - Note: - Will *not* raise exceptions in case the callback data is not found in the cache. - *Will* raise :exc:`KeyError` in case the callback query can not be found in the - cache. - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - Raises: - KeyError: If the callback query can not be found in the cache - """ - try: - keyboard_uuid = self._callback_queries.pop(callback_query.id) - self.__drop_keyboard(keyboard_uuid) - except KeyError as exc: - raise KeyError("CallbackQuery was not found in cache.") from exc - - def __drop_keyboard(self, keyboard_uuid: str) -> None: - with contextlib.suppress(KeyError): - self._keyboard_data.pop(keyboard_uuid) - - def clear_callback_data( - self, time_cutoff: Optional[Union[float, dtm.datetime]] = None - ) -> None: - """Clears the stored callback data. - - Args: - time_cutoff (:obj:`float` | :obj:`datetime.datetime`, optional): Pass a UNIX timestamp - or a :obj:`datetime.datetime` to clear only entries which are older. - |tz-naive-dtms| - - """ - self.__clear(self._keyboard_data, time_cutoff=time_cutoff) - - def clear_callback_queries(self) -> None: - """Clears the stored callback query IDs.""" - self.__clear(self._callback_queries) - - def __clear( - self, mapping: MutableMapping, time_cutoff: Optional[Union[float, dtm.datetime]] = None - ) -> None: - if not time_cutoff: - mapping.clear() - return - - if isinstance(time_cutoff, dtm.datetime): - effective_cutoff = to_float_timestamp( - time_cutoff, tzinfo=self.bot.defaults.tzinfo if self.bot.defaults else None - ) - else: - effective_cutoff = time_cutoff - - # We need a list instead of a generator here, as the list doesn't change it's size - # during the iteration - to_drop = [key for key, data in mapping.items() if data.access_time < effective_cutoff] - for key in to_drop: - mapping.pop(key) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_contexttypes.py b/venv/lib/python3.11/site-packages/telegram/ext/_contexttypes.py deleted file mode 100755 index 2d3a8b3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_contexttypes.py +++ /dev/null @@ -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 -# -# 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 auxiliary class ContextTypes.""" -from typing import Any, Generic, overload - -from telegram.ext._callbackcontext import CallbackContext -from telegram.ext._extbot import ExtBot -from telegram.ext._utils.types import BD, CCT, CD, UD - -ADict = dict[Any, Any] - - -class ContextTypes(Generic[CCT, UD, CD, BD]): - """ - Convenience class to gather customizable types of the :class:`telegram.ext.CallbackContext` - interface. - - Examples: - :any:`ContextTypes Bot ` - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Storing Bot, User and Chat Related Data ` - - .. versionadded:: 13.6 - - Args: - context (:obj:`type`, optional): Determines the type of the ``context`` argument of all - (error-)handler callbacks and job callbacks. Must be a subclass of - :class:`telegram.ext.CallbackContext`. Defaults to - :class:`telegram.ext.CallbackContext`. - bot_data (:obj:`type`, optional): Determines the type of - :attr:`context.bot_data ` of all (error-)handler callbacks - and job callbacks. Defaults to :obj:`dict`. Must support instantiating without - arguments. - chat_data (:obj:`type`, optional): Determines the type of - :attr:`context.chat_data ` of all (error-)handler callbacks - and job callbacks. Defaults to :obj:`dict`. Must support instantiating without - arguments. - user_data (:obj:`type`, optional): Determines the type of - :attr:`context.user_data ` of all (error-)handler callbacks - and job callbacks. Defaults to :obj:`dict`. Must support instantiating without - arguments. - - """ - - DEFAULT_TYPE = CallbackContext[ExtBot[None], ADict, ADict, ADict] - """Shortcut for the type annotation for the ``context`` argument that's correct for the - default settings, i.e. if :class:`telegram.ext.ContextTypes` is not used. - - Example: - .. code:: python - - async def callback(update: Update, context: ContextTypes.DEFAULT_TYPE): - ... - - .. versionadded: 20.0 - """ - - __slots__ = ("_bot_data", "_chat_data", "_context", "_user_data") - - # overload signatures generated with - # https://gist.github.com/Bibo-Joshi/399382cda537fb01bd86b13c3d03a956 - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], ADict, ADict, ADict], ADict, ADict, ADict]", # pylint: disable=line-too-long # noqa: E501 - ): ... - - @overload - def __init__(self: "ContextTypes[CCT, ADict, ADict, ADict]", context: type[CCT]): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], UD, ADict, ADict], UD, ADict, ADict]", - user_data: type[UD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], ADict, CD, ADict], ADict, CD, ADict]", - chat_data: type[CD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], ADict, ADict, BD], ADict, ADict, BD]", - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, UD, ADict, ADict]", context: type[CCT], user_data: type[UD] - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, ADict, CD, ADict]", context: type[CCT], chat_data: type[CD] - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, ADict, ADict, BD]", context: type[CCT], bot_data: type[BD] - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], UD, CD, ADict], UD, CD, ADict]", - user_data: type[UD], - chat_data: type[CD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], UD, ADict, BD], UD, ADict, BD]", - user_data: type[UD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], ADict, CD, BD], ADict, CD, BD]", - chat_data: type[CD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, UD, CD, ADict]", - context: type[CCT], - user_data: type[UD], - chat_data: type[CD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, UD, ADict, BD]", - context: type[CCT], - user_data: type[UD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, ADict, CD, BD]", - context: type[CCT], - chat_data: type[CD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], UD, CD, BD], UD, CD, BD]", - user_data: type[UD], - chat_data: type[CD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, UD, CD, BD]", - context: type[CCT], - user_data: type[UD], - chat_data: type[CD], - bot_data: type[BD], - ): ... - - def __init__( # type: ignore[misc] - self, - context: "type[CallbackContext[ExtBot[Any], ADict, ADict, ADict]]" = CallbackContext, - bot_data: type[ADict] = dict, - chat_data: type[ADict] = dict, - user_data: type[ADict] = dict, - ): - if not issubclass(context, CallbackContext): - raise TypeError("context must be a subclass of CallbackContext.") - - # We make all those only accessible via properties because we don't currently support - # changing this at runtime, so overriding the attributes doesn't make sense - self._context = context - self._bot_data = bot_data - self._chat_data = chat_data - self._user_data = user_data - - @property - def context(self) -> type[CCT]: - """The type of the ``context`` argument of all (error-)handler callbacks and job - callbacks. - """ - return self._context # type: ignore[return-value] - - @property - def bot_data(self) -> type[BD]: - """The type of :attr:`context.bot_data ` of all (error-)handler - callbacks and job callbacks. - """ - return self._bot_data # type: ignore[return-value] - - @property - def chat_data(self) -> type[CD]: - """The type of :attr:`context.chat_data ` of all (error-)handler - callbacks and job callbacks. - """ - return self._chat_data # type: ignore[return-value] - - @property - def user_data(self) -> type[UD]: - """The type of :attr:`context.user_data ` of all (error-)handler - callbacks and job callbacks. - """ - return self._user_data # type: ignore[return-value] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_defaults.py b/venv/lib/python3.11/site-packages/telegram/ext/_defaults.py deleted file mode 100755 index 86fb59a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_defaults.py +++ /dev/null @@ -1,429 +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 -# -# 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 class Defaults, which allows passing default values to Application.""" -import datetime as dtm -from typing import Any, NoReturn, Optional, final - -from telegram import LinkPreviewOptions -from telegram._utils.datetime import UTC -from telegram._utils.types import ODVInput -from telegram._utils.warnings import warn -from telegram.warnings import PTBDeprecationWarning - - -@final -class Defaults: - """Convenience Class to gather all parameters with a (user defined) default value - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Adding Defaults to Your Bot ` - - .. versionchanged:: 20.0 - Removed the argument and attribute ``timeout``. Specify default timeout behavior for the - networking backend directly via :class:`telegram.ext.ApplicationBuilder` instead. - - Parameters: - parse_mode (:obj:`str`, optional): |parse_mode| - disable_notification (:obj:`bool`, optional): |disable_notification| - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this - message. Mutually exclusive with :paramref:`link_preview_options`. - - .. deprecated:: 20.8 - Use :paramref:`link_preview_options` instead. This parameter will be removed in - future versions. - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|. - Will be used for :attr:`telegram.ReplyParameters.allow_sending_without_reply`. - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - Use :paramref:`do_quote` instead. This parameter will be removed in future - versions. - tzinfo (:class:`datetime.tzinfo`, optional): A timezone to be used for all date(time) - inputs appearing throughout PTB, i.e. if a timezone naive date(time) object is passed - somewhere, it will be assumed to be in :paramref:`tzinfo`. Defaults to - :attr:`datetime.timezone.utc` otherwise. - - .. deprecated:: 21.10 - Support for ``pytz`` timezones is deprecated and will be removed in future - versions. - - block (:obj:`bool`, optional): Default setting for the :paramref:`BaseHandler.block` - parameter - of handlers and error handlers registered through :meth:`Application.add_handler` and - :meth:`Application.add_error_handler`. Defaults to :obj:`True`. - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 20.0 - link_preview_options (:class:`telegram.LinkPreviewOptions`, optional): - Link preview generation options for all outgoing messages. Mutually exclusive with - :paramref:`disable_web_page_preview`. - This object is used for the corresponding parameter of - :meth:`telegram.Bot.send_message`, :meth:`telegram.Bot.edit_message_text`, - and :class:`telegram.InputTextMessageContent` if not specified. If a value is specified - for the corresponding parameter, only those parameters of - :class:`telegram.LinkPreviewOptions` will be overridden that are not - explicitly set. - - Example: - - .. code-block:: python - - from telegram import LinkPreviewOptions - from telegram.ext import Defaults, ExtBot - - defaults = Defaults( - link_preview_options=LinkPreviewOptions(show_above_text=True) - ) - chat_id = 123 - - async def main(): - async with ExtBot("Token", defaults=defaults) as bot: - # The link preview will be shown above the text. - await bot.send_message(chat_id, "https://python-telegram-bot.org") - - # The link preview will be shown below the text. - await bot.send_message( - chat_id, - "https://python-telegram-bot.org", - link_preview_options=LinkPreviewOptions(show_above_text=False) - ) - - # The link preview will be shown above the text, but the preview will - # show Telegram. - await bot.send_message( - chat_id, - "https://python-telegram-bot.org", - link_preview_options=LinkPreviewOptions(url="https://telegram.org") - ) - - .. versionadded:: 20.8 - do_quote(:obj:`bool`, optional): |reply_quote| - - .. versionadded:: 20.8 - """ - - __slots__ = ( - "_allow_sending_without_reply", - "_api_defaults", - "_block", - "_disable_notification", - "_do_quote", - "_link_preview_options", - "_parse_mode", - "_protect_content", - "_tzinfo", - ) - - def __init__( - self, - parse_mode: Optional[str] = None, - disable_notification: Optional[bool] = None, - disable_web_page_preview: Optional[bool] = None, - quote: Optional[bool] = None, - tzinfo: dtm.tzinfo = UTC, - block: bool = True, - allow_sending_without_reply: Optional[bool] = None, - protect_content: Optional[bool] = None, - link_preview_options: Optional["LinkPreviewOptions"] = None, - do_quote: Optional[bool] = None, - ): - self._parse_mode: Optional[str] = parse_mode - self._disable_notification: Optional[bool] = disable_notification - self._allow_sending_without_reply: Optional[bool] = allow_sending_without_reply - self._tzinfo: dtm.tzinfo = tzinfo - self._block: bool = block - self._protect_content: Optional[bool] = protect_content - - if "pytz" in str(self._tzinfo.__class__): - # TODO: When dropping support, make sure to update _utils.datetime accordingly - warn( - message=PTBDeprecationWarning( - version="21.10", - message=( - "Support for pytz timezones is deprecated and will be removed in " - "future versions." - ), - ), - stacklevel=2, - ) - - if disable_web_page_preview is not None and link_preview_options is not None: - raise ValueError( - "`disable_web_page_preview` and `link_preview_options` are mutually exclusive." - ) - if quote is not None and do_quote is not None: - raise ValueError("`quote` and `do_quote` are mutually exclusive") - if disable_web_page_preview is not None: - warn( - PTBDeprecationWarning( - "20.8", - "`Defaults.disable_web_page_preview` is deprecated. Use " - "`Defaults.link_preview_options` instead.", - ), - stacklevel=2, - ) - self._link_preview_options: Optional[LinkPreviewOptions] = LinkPreviewOptions( - is_disabled=disable_web_page_preview - ) - else: - self._link_preview_options = link_preview_options - - if quote is not None: - warn( - PTBDeprecationWarning( - "20.8", "`Defaults.quote` is deprecated. Use `Defaults.do_quote` instead." - ), - stacklevel=2, - ) - self._do_quote: Optional[bool] = quote - else: - self._do_quote = do_quote - # Gather all defaults that actually have a default value - self._api_defaults = {} - for kwarg in ( - "allow_sending_without_reply", - "disable_notification", - "do_quote", - "explanation_parse_mode", - "link_preview_options", - "parse_mode", - "text_parse_mode", - "protect_content", - "question_parse_mode", - ): - value = getattr(self, kwarg) - if value is not None: - self._api_defaults[kwarg] = value - - 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` The hash value of the object. - """ - return hash( - ( - self._parse_mode, - self._disable_notification, - self.disable_web_page_preview, - self._allow_sending_without_reply, - self.quote, - self._tzinfo, - self._block, - self._protect_content, - ) - ) - - def __eq__(self, other: object) -> bool: - """Defines equality condition for the :class:`Defaults` object. - Two objects of this class are considered to be equal if all their parameters - are identical. - - Returns: - :obj:`True` if both objects have all parameters identical. :obj:`False` otherwise. - """ - if isinstance(other, Defaults): - return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__) - return False - - @property - def api_defaults(self) -> dict[str, Any]: # skip-cq: PY-D0003 - return self._api_defaults - - @property - def parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or URLs in your bot's message. - """ - return self._parse_mode - - @parse_mode.setter - def parse_mode(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to parse_mode after initialization.") - - @property - def explanation_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :meth:`telegram.Bot.send_poll`. - """ - return self._parse_mode - - @explanation_parse_mode.setter - def explanation_parse_mode(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to explanation_parse_mode after initialization." - ) - - @property - def quote_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :meth:`telegram.ReplyParameters`. - """ - return self._parse_mode - - @quote_parse_mode.setter - def quote_parse_mode(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to quote_parse_mode after initialization." - ) - - @property - def text_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :class:`telegram.InputPollOption` and - :meth:`telegram.Bot.send_gift`. - - .. versionadded:: 21.2 - """ - return self._parse_mode - - @text_parse_mode.setter - def text_parse_mode(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to text_parse_mode after initialization." - ) - - @property - def question_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :meth:`telegram.Bot.send_poll`. - - .. versionadded:: 21.2 - """ - return self._parse_mode - - @question_parse_mode.setter - def question_parse_mode(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to question_parse_mode after initialization." - ) - - @property - def disable_notification(self) -> Optional[bool]: - """:obj:`bool`: Optional. Sends the message silently. Users will - receive a notification with no sound. - """ - return self._disable_notification - - @disable_notification.setter - def disable_notification(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to disable_notification after initialization." - ) - - @property - def disable_web_page_preview(self) -> ODVInput[bool]: - """:obj:`bool`: Optional. Disables link previews for links in all outgoing - messages. - - .. deprecated:: 20.8 - Use :attr:`link_preview_options` instead. This attribute will be removed in future - versions. - """ - return self._link_preview_options.is_disabled if self._link_preview_options else None - - @disable_web_page_preview.setter - def disable_web_page_preview(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to disable_web_page_preview after initialization." - ) - - @property - def allow_sending_without_reply(self) -> Optional[bool]: - """:obj:`bool`: Optional. Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - """ - return self._allow_sending_without_reply - - @allow_sending_without_reply.setter - def allow_sending_without_reply(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to allow_sending_without_reply after initialization." - ) - - @property - def quote(self) -> Optional[bool]: - """:obj:`bool`: Optional. |reply_quote| - - .. deprecated:: 20.8 - Use :attr:`do_quote` instead. This attribute will be removed in future - versions. - """ - return self._do_quote if self._do_quote is not None else None - - @quote.setter - def quote(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to quote after initialization.") - - @property - def tzinfo(self) -> dtm.tzinfo: - """:obj:`tzinfo`: A timezone to be used for all date(time) objects appearing - throughout PTB. - """ - return self._tzinfo - - @tzinfo.setter - def tzinfo(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to tzinfo after initialization.") - - @property - def block(self) -> bool: - """:obj:`bool`: Optional. Default setting for the :paramref:`BaseHandler.block` parameter - of handlers and error handlers registered through :meth:`Application.add_handler` and - :meth:`Application.add_error_handler`. - """ - return self._block - - @block.setter - def block(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to block after initialization.") - - @property - def protect_content(self) -> Optional[bool]: - """:obj:`bool`: Optional. Protects the contents of the sent message from forwarding and - saving. - - .. versionadded:: 20.0 - """ - return self._protect_content - - @protect_content.setter - def protect_content(self, _: object) -> NoReturn: - raise AttributeError( - "You can't assign a new value to protect_content after initialization." - ) - - @property - def link_preview_options(self) -> Optional["LinkPreviewOptions"]: - """:class:`telegram.LinkPreviewOptions`: Optional. Link preview generation options for all - outgoing messages. - - .. versionadded:: 20.8 - """ - return self._link_preview_options - - @property - def do_quote(self) -> Optional[bool]: - """:obj:`bool`: Optional. |reply_quote| - - .. versionadded:: 20.8 - """ - return self._do_quote diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_dictpersistence.py b/venv/lib/python3.11/site-packages/telegram/ext/_dictpersistence.py deleted file mode 100755 index da9749d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_dictpersistence.py +++ /dev/null @@ -1,481 +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 -# -# 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 DictPersistence class.""" -import json -from copy import deepcopy -from typing import TYPE_CHECKING, Any, Optional, cast - -from telegram.ext import BasePersistence, PersistenceInput -from telegram.ext._utils.types import CDCData, ConversationDict, ConversationKey - -if TYPE_CHECKING: - from telegram._utils.types import JSONDict - - -class DictPersistence(BasePersistence[dict[Any, Any], dict[Any, Any], dict[Any, Any]]): - """Using Python's :obj:`dict` and :mod:`json` for making your bot persistent. - - Attention: - The interface provided by this class is intended to be accessed exclusively by - :class:`~telegram.ext.Application`. Calling any of the methods below manually might - interfere with the integration of persistence into :class:`~telegram.ext.Application`. - - Note: - * Data managed by :class:`DictPersistence` is in-memory only and will be lost when the bot - shuts down. This is, because :class:`DictPersistence` is mainly intended as starting - point for custom persistence classes that need to JSON-serialize the stored data before - writing them to file/database. - - * This implementation of :class:`BasePersistence` does not handle data that cannot be - serialized by :func:`json.dumps`. - - .. seealso:: :wiki:`Making Your Bot Persistent ` - - .. versionchanged:: 20.0 - The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`. - - Args: - store_data (:class:`~telegram.ext.PersistenceInput`, optional): Specifies which kinds of - data will be saved by this persistence instance. By default, all available kinds of - data will be saved. - user_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - user_data on creating this persistence. Default is ``""``. - chat_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - chat_data on creating this persistence. Default is ``""``. - bot_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - bot_data on creating this persistence. Default is ``""``. - conversations_json (:obj:`str`, optional): JSON string that will be used to reconstruct - conversation on creating this persistence. Default is ``""``. - callback_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - callback_data on creating this persistence. Default is ``""``. - - .. versionadded:: 13.6 - update_interval (:obj:`int` | :obj:`float`, optional): The - :class:`~telegram.ext.Application` will update - the persistence in regular intervals. This parameter specifies the time (in seconds) to - wait between two consecutive runs of updating the persistence. Defaults to 60 seconds. - - .. versionadded:: 20.0 - Attributes: - store_data (:class:`~telegram.ext.PersistenceInput`): Specifies which kinds of data will - be saved by this persistence instance. - """ - - __slots__ = ( - "_bot_data", - "_bot_data_json", - "_callback_data", - "_callback_data_json", - "_chat_data", - "_chat_data_json", - "_conversations", - "_conversations_json", - "_user_data", - "_user_data_json", - ) - - def __init__( - self, - store_data: Optional[PersistenceInput] = None, - user_data_json: str = "", - chat_data_json: str = "", - bot_data_json: str = "", - conversations_json: str = "", - callback_data_json: str = "", - update_interval: float = 60, - ): - super().__init__(store_data=store_data, update_interval=update_interval) - self._user_data = None - self._chat_data = None - self._bot_data = None - self._callback_data = None - self._conversations = None - self._user_data_json: Optional[str] = None - self._chat_data_json: Optional[str] = None - self._bot_data_json: Optional[str] = None - self._callback_data_json: Optional[str] = None - self._conversations_json: Optional[str] = None - if user_data_json: - try: - self._user_data = self._decode_user_chat_data_from_json(user_data_json) - self._user_data_json = user_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize user_data_json. Not valid JSON") from exc - if chat_data_json: - try: - self._chat_data = self._decode_user_chat_data_from_json(chat_data_json) - self._chat_data_json = chat_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize chat_data_json. Not valid JSON") from exc - if bot_data_json: - try: - self._bot_data = json.loads(bot_data_json) - self._bot_data_json = bot_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize bot_data_json. Not valid JSON") from exc - if not isinstance(self._bot_data, dict): - raise TypeError("bot_data_json must be serialized dict") - if callback_data_json: - try: - data = json.loads(callback_data_json) - except (ValueError, AttributeError) as exc: - raise TypeError( - "Unable to deserialize callback_data_json. Not valid JSON" - ) from exc - # We are a bit more thorough with the checking of the format here, because it's - # more complicated than for the other things - try: - if data is None: - self._callback_data = None - else: - self._callback_data = cast( - CDCData, - ([(one, float(two), three) for one, two, three in data[0]], data[1]), - ) - self._callback_data_json = callback_data_json - except (ValueError, IndexError) as exc: - raise TypeError("callback_data_json is not in the required format") from exc - if self._callback_data is not None and ( - not all( - isinstance(entry[2], dict) and isinstance(entry[0], str) - for entry in self._callback_data[0] - ) - or not isinstance(self._callback_data[1], dict) - ): - raise TypeError("callback_data_json is not in the required format") - - if conversations_json: - try: - self._conversations = self._decode_conversations_from_json(conversations_json) - self._conversations_json = conversations_json - except (ValueError, AttributeError) as exc: - raise TypeError( - "Unable to deserialize conversations_json. Not valid JSON" - ) from exc - - @property - def user_data(self) -> Optional[dict[int, dict[Any, Any]]]: - """:obj:`dict`: The user_data as a dict.""" - return self._user_data - - @property - def user_data_json(self) -> str: - """:obj:`str`: The user_data serialized as a JSON-string.""" - if self._user_data_json: - return self._user_data_json - return json.dumps(self.user_data) - - @property - def chat_data(self) -> Optional[dict[int, dict[Any, Any]]]: - """:obj:`dict`: The chat_data as a dict.""" - return self._chat_data - - @property - def chat_data_json(self) -> str: - """:obj:`str`: The chat_data serialized as a JSON-string.""" - if self._chat_data_json: - return self._chat_data_json - return json.dumps(self.chat_data) - - @property - def bot_data(self) -> Optional[dict[Any, Any]]: - """:obj:`dict`: The bot_data as a dict.""" - return self._bot_data - - @property - def bot_data_json(self) -> str: - """:obj:`str`: The bot_data serialized as a JSON-string.""" - if self._bot_data_json: - return self._bot_data_json - return json.dumps(self.bot_data) - - @property - def callback_data(self) -> Optional[CDCData]: - """tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], \ - dict[:obj:`str`, :obj:`str`]]: The metadata on the stored callback data. - - .. versionadded:: 13.6 - """ - return self._callback_data - - @property - def callback_data_json(self) -> str: - """:obj:`str`: The metadata on the stored callback data as a JSON-string. - - .. versionadded:: 13.6 - """ - if self._callback_data_json: - return self._callback_data_json - return json.dumps(self.callback_data) - - @property - def conversations(self) -> Optional[dict[str, ConversationDict]]: - """:obj:`dict`: The conversations as a dict.""" - return self._conversations - - @property - def conversations_json(self) -> str: - """:obj:`str`: The conversations serialized as a JSON-string.""" - if self._conversations_json: - return self._conversations_json - if self.conversations: - return self._encode_conversations_to_json(self.conversations) - return json.dumps(self.conversations) - - async def get_user_data(self) -> dict[int, dict[object, object]]: - """Returns the user_data created from the ``user_data_json`` or an empty :obj:`dict`. - - Returns: - :obj:`dict`: The restored user data. - """ - if self.user_data is None: - self._user_data = {} - return deepcopy(self.user_data) # type: ignore[arg-type] - - async def get_chat_data(self) -> dict[int, dict[object, object]]: - """Returns the chat_data created from the ``chat_data_json`` or an empty :obj:`dict`. - - Returns: - :obj:`dict`: The restored chat data. - """ - if self.chat_data is None: - self._chat_data = {} - return deepcopy(self.chat_data) # type: ignore[arg-type] - - async def get_bot_data(self) -> dict[object, object]: - """Returns the bot_data created from the ``bot_data_json`` or an empty :obj:`dict`. - - Returns: - :obj:`dict`: The restored bot data. - """ - if self.bot_data is None: - self._bot_data = {} - return deepcopy(self.bot_data) # type: ignore[arg-type] - - async def get_callback_data(self) -> Optional[CDCData]: - """Returns the callback_data created from the ``callback_data_json`` or :obj:`None`. - - .. versionadded:: 13.6 - - Returns: - tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], \ - dict[:obj:`str`, :obj:`str`]]: The restored metadata or :obj:`None`, \ - if no data was stored. - """ - if self.callback_data is None: - self._callback_data = None - return None - return deepcopy(self.callback_data) - - async def get_conversations(self, name: str) -> ConversationDict: - """Returns the conversations created from the ``conversations_json`` or an empty - :obj:`dict`. - - Returns: - :obj:`dict`: The restored conversations data. - """ - if self.conversations is None: - self._conversations = {} - return self.conversations.get(name, {}).copy() # type: ignore[union-attr] - - async def update_conversation( - self, name: str, key: ConversationKey, new_state: Optional[object] - ) -> None: - """Will update the conversations for the given handler. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:obj:`tuple` | :class:`object`): The new state for the given key. - """ - if not self._conversations: - self._conversations = {} - if self._conversations.setdefault(name, {}).get(key) == new_state: - return - self._conversations[name][key] = new_state - self._conversations_json = None - - async def update_user_data(self, user_id: int, data: dict[Any, Any]) -> None: - """Will update the user_data (if changed). - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.Application.user_data` ``[user_id]``. - """ - if self._user_data is None: - self._user_data = {} - if self._user_data.get(user_id) == data: - return - self._user_data[user_id] = data - self._user_data_json = None - - async def update_chat_data(self, chat_id: int, data: dict[Any, Any]) -> None: - """Will update the chat_data (if changed). - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.Application.chat_data` ``[chat_id]``. - """ - if self._chat_data is None: - self._chat_data = {} - if self._chat_data.get(chat_id) == data: - return - self._chat_data[chat_id] = data - self._chat_data_json = None - - async def update_bot_data(self, data: dict[Any, Any]) -> None: - """Will update the bot_data (if changed). - - Args: - data (:obj:`dict`): The :attr:`telegram.ext.Application.bot_data`. - """ - if self._bot_data == data: - return - self._bot_data = data - self._bot_data_json = None - - async def update_callback_data(self, data: CDCData) -> None: - """Will update the callback_data (if changed). - - .. versionadded:: 13.6 - - Args: - data (tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], \ - dict[:obj:`str`, :obj:`str`]]): The relevant data to restore - :class:`telegram.ext.CallbackDataCache`. - """ - if self._callback_data == data: - return - self._callback_data = data - self._callback_data_json = None - - async def drop_chat_data(self, chat_id: int) -> None: - """Will delete the specified key from the :attr:`chat_data`. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`): The chat id to delete from the persistence. - """ - if self._chat_data is None: - return - self._chat_data.pop(chat_id, None) - self._chat_data_json = None - - async def drop_user_data(self, user_id: int) -> None: - """Will delete the specified key from the :attr:`user_data`. - - .. versionadded:: 20.0 - - Args: - user_id (:obj:`int`): The user id to delete from the persistence. - """ - if self._user_data is None: - return - self._user_data.pop(user_id, None) - self._user_data_json = None - - async def refresh_user_data(self, user_id: int, user_data: dict[Any, Any]) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data` - """ - - async def refresh_chat_data(self, chat_id: int, chat_data: dict[Any, Any]) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data` - """ - - async def refresh_bot_data(self, bot_data: dict[Any, Any]) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data` - """ - - async def flush(self) -> None: - """Does nothing. - - .. versionadded:: 20.0 - .. seealso:: :meth:`telegram.ext.BasePersistence.flush` - """ - - @staticmethod - def _encode_conversations_to_json(conversations: dict[str, ConversationDict]) -> str: - """Helper method to encode a conversations dict (that uses tuples as keys) to a - JSON-serializable way. Use :meth:`self._decode_conversations_from_json` to decode. - - Args: - conversations (:obj:`dict`): The conversations dict to transform to JSON. - - Returns: - :obj:`str`: The JSON-serialized conversations dict - """ - tmp: dict[str, JSONDict] = {} - for handler, states in conversations.items(): - tmp[handler] = {} - for key, state in states.items(): - tmp[handler][json.dumps(key)] = state - return json.dumps(tmp) - - @staticmethod - def _decode_conversations_from_json(json_string: str) -> dict[str, ConversationDict]: - """Helper method to decode a conversations dict (that uses tuples as keys) from a - JSON-string created with :meth:`self._encode_conversations_to_json`. - - Args: - json_string (:obj:`str`): The conversations dict as JSON string. - - Returns: - :obj:`dict`: The conversations dict after decoding - """ - tmp = json.loads(json_string) - conversations: dict[str, ConversationDict] = {} - for handler, states in tmp.items(): - conversations[handler] = {} - for key, state in states.items(): - conversations[handler][tuple(json.loads(key))] = state - return conversations - - @staticmethod - def _decode_user_chat_data_from_json(data: str) -> dict[int, dict[object, object]]: - """Helper method to decode chat or user data (that uses ints as keys) from a - JSON-string. - - Args: - data (:obj:`str`): The user/chat_data dict as JSON string. - - Returns: - :obj:`dict`: The user/chat_data defaultdict after decoding - """ - tmp: dict[int, dict[object, object]] = {} - decoded_data = json.loads(data) - for user, user_data in decoded_data.items(): - int_user_id = int(user) - tmp[int_user_id] = {} - for key, value in user_data.items(): - try: - _id = int(key) - except ValueError: - _id = key - tmp[int_user_id][_id] = value - return tmp diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_extbot.py b/venv/lib/python3.11/site-packages/telegram/ext/_extbot.py deleted file mode 100755 index d21b1f7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_extbot.py +++ /dev/null @@ -1,4709 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=too-many-arguments -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# 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 Bot with convenience extensions.""" -import datetime as dtm -from collections.abc import Sequence -from copy import copy -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Generic, - Optional, - TypeVar, - Union, - cast, - no_type_check, - overload, -) -from uuid import uuid4 - -from telegram import ( - Animation, - Audio, - Bot, - BotCommand, - BotCommandScope, - BotDescription, - BotName, - BotShortDescription, - BusinessConnection, - CallbackQuery, - ChatAdministratorRights, - ChatFullInfo, - ChatInviteLink, - ChatMember, - ChatPermissions, - ChatPhoto, - Contact, - Document, - File, - ForumTopic, - GameHighScore, - Gift, - Gifts, - InlineKeyboardMarkup, - InlineQueryResultsButton, - InputMedia, - InputPollOption, - LinkPreviewOptions, - Location, - MaskPosition, - MenuButton, - Message, - MessageId, - PhotoSize, - Poll, - PreparedInlineMessage, - ReactionType, - ReplyParameters, - SentWebAppMessage, - StarTransactions, - Sticker, - StickerSet, - TelegramObject, - Update, - User, - UserChatBoosts, - UserProfilePhotos, - Venue, - Video, - VideoNote, - Voice, - WebhookInfo, -) -from telegram._utils.datetime import to_timestamp -from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup -from telegram.ext._callbackdatacache import CallbackDataCache -from telegram.ext._utils.types import RLARGS -from telegram.request import BaseRequest -from telegram.warnings import PTBUserWarning - -if TYPE_CHECKING: - from telegram import ( - InlineQueryResult, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - InputPaidMedia, - InputSticker, - LabeledPrice, - MessageEntity, - PassportElementError, - ShippingOption, - ) - from telegram.ext import BaseRateLimiter, Defaults - -HandledTypes = TypeVar("HandledTypes", bound=Union[Message, CallbackQuery, ChatFullInfo]) -KT = TypeVar("KT", bound=ReplyMarkup) - - -class ExtBot(Bot, Generic[RLARGS]): - """This object represents a Telegram Bot with convenience extensions. - - Warning: - Not to be confused with :class:`telegram.Bot`. - - For the documentation of the arguments, methods and attributes, please see - :class:`telegram.Bot`. - - All API methods of this class have an additional keyword argument ``rate_limit_args``. - This can be used to pass additional information to the rate limiter, specifically to - :paramref:`telegram.ext.BaseRateLimiter.process_request.rate_limit_args`. - - This class is a :class:`~typing.Generic` class and accepts one type variable that specifies - the generic type of the :attr:`rate_limiter` used by the bot. Use :obj:`None` if no rate - limiter is used. - - Warning: - * The keyword argument ``rate_limit_args`` can `not` be used, if :attr:`rate_limiter` - is :obj:`None`. - * The method :meth:`~telegram.Bot.get_updates` is the only method that does not have the - additional argument, as this method will never be rate limited. - - Examples: - :any:`Arbitrary Callback Data Bot ` - - .. seealso:: :wiki:`Arbitrary callback_data ` - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Removed the attribute ``arbitrary_callback_data``. You can instead use - :attr:`bot.callback_data_cache.maxsize ` to - access the size of the cache. - - .. versionchanged:: 20.5 - Removed deprecated methods ``set_sticker_set_thumb`` and ``setStickerSetThumb``. - - Args: - defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to - be used if not set explicitly in the bot methods. - arbitrary_callback_data (:obj:`bool` | :obj:`int`, optional): Whether to - allow arbitrary objects as callback data for :class:`telegram.InlineKeyboardButton`. - Pass an integer to specify the maximum number of objects cached in memory. - Defaults to :obj:`False`. - - .. seealso:: :wiki:`Arbitrary callback_data ` - rate_limiter (:class:`telegram.ext.BaseRateLimiter`, optional): A rate limiter to use for - limiting the number of requests made by the bot per time interval. - - .. versionadded:: 20.0 - - """ - - __slots__ = ("_callback_data_cache", "_defaults", "_rate_limiter") - - _LOGGER = get_logger(__name__, class_name="ExtBot") - - # using object() would be a tiny bit safer, but a string plays better with the typing setup - __RL_KEY = uuid4().hex - - @overload - def __init__( - self: "ExtBot[None]", - token: str, - base_url: str = "https://api.telegram.org/bot", - base_file_url: str = "https://api.telegram.org/file/bot", - request: Optional[BaseRequest] = None, - get_updates_request: Optional[BaseRequest] = None, - private_key: Optional[bytes] = None, - private_key_password: Optional[bytes] = None, - defaults: Optional["Defaults"] = None, - arbitrary_callback_data: Union[bool, int] = False, - local_mode: bool = False, - ): ... - - @overload - def __init__( - self: "ExtBot[RLARGS]", - token: str, - base_url: str = "https://api.telegram.org/bot", - base_file_url: str = "https://api.telegram.org/file/bot", - request: Optional[BaseRequest] = None, - get_updates_request: Optional[BaseRequest] = None, - private_key: Optional[bytes] = None, - private_key_password: Optional[bytes] = None, - defaults: Optional["Defaults"] = None, - arbitrary_callback_data: Union[bool, int] = False, - local_mode: bool = False, - rate_limiter: Optional["BaseRateLimiter[RLARGS]"] = None, - ): ... - - def __init__( - self, - token: str, - base_url: str = "https://api.telegram.org/bot", - base_file_url: str = "https://api.telegram.org/file/bot", - request: Optional[BaseRequest] = None, - get_updates_request: Optional[BaseRequest] = None, - private_key: Optional[bytes] = None, - private_key_password: Optional[bytes] = None, - defaults: Optional["Defaults"] = None, - arbitrary_callback_data: Union[bool, int] = False, - local_mode: bool = False, - rate_limiter: Optional["BaseRateLimiter[RLARGS]"] = None, - ): - super().__init__( - token=token, - base_url=base_url, - base_file_url=base_file_url, - request=request, - get_updates_request=get_updates_request, - private_key=private_key, - private_key_password=private_key_password, - local_mode=local_mode, - ) - with self._unfrozen(): - self._defaults: Optional[Defaults] = defaults - self._rate_limiter: Optional[BaseRateLimiter] = rate_limiter - self._callback_data_cache: Optional[CallbackDataCache] = None - - # set up callback_data - if arbitrary_callback_data is False: - return - - if not isinstance(arbitrary_callback_data, bool): - maxsize = cast(int, arbitrary_callback_data) - else: - maxsize = 1024 - - self._callback_data_cache = CallbackDataCache(bot=self, maxsize=maxsize) - - def __repr__(self) -> str: - """Give a string representation of the bot in the form ``ExtBot[token=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs(self, token=self.token) - - @classmethod - def _warn( - cls, - message: Union[str, PTBUserWarning], - category: type[Warning] = PTBUserWarning, - stacklevel: int = 0, - ) -> None: - """We override this method to add one more level to the stacklevel, so that the warning - points to the user's code, not to the PTB code. - """ - super()._warn(message=message, category=category, stacklevel=stacklevel + 2) - - @property - def callback_data_cache(self) -> Optional[CallbackDataCache]: - """:class:`telegram.ext.CallbackDataCache`: Optional. The cache for - objects passed as callback data for :class:`telegram.InlineKeyboardButton`. - - Examples: - :any:`Arbitrary Callback Data Bot ` - - .. versionchanged:: 20.0 - * This property is now read-only. - * This property is now optional and can be :obj:`None` if - :paramref:`~telegram.ext.ExtBot.arbitrary_callback_data` is set to :obj:`False`. - """ - return self._callback_data_cache - - async def initialize(self) -> None: - """See :meth:`telegram.Bot.initialize`. Also initializes the - :paramref:`ExtBot.rate_limiter` (if set) - by calling :meth:`telegram.ext.BaseRateLimiter.initialize`. - """ - # Initialize before calling super, because super calls get_me - if self.rate_limiter: - await self.rate_limiter.initialize() - await super().initialize() - - async def shutdown(self) -> None: - """See :meth:`telegram.Bot.shutdown`. Also shuts down the - :paramref:`ExtBot.rate_limiter` (if set) by - calling :meth:`telegram.ext.BaseRateLimiter.shutdown`. - """ - # Shut down the rate limiter before shutting down the request objects! - if self.rate_limiter: - await self.rate_limiter.shutdown() - await super().shutdown() - - @classmethod - def _merge_api_rl_kwargs( - cls, api_kwargs: Optional[JSONDict], rate_limit_args: Optional[RLARGS] - ) -> Optional[JSONDict]: - """Inserts the `rate_limit_args` into `api_kwargs` with the special key `__RL_KEY` so - that we can extract them later without having to modify the `telegram.Bot` class. - """ - if not rate_limit_args: - return api_kwargs - if api_kwargs is None: - api_kwargs = {} - api_kwargs[cls.__RL_KEY] = rate_limit_args - return api_kwargs - - @classmethod - def _extract_rl_kwargs(cls, data: Optional[JSONDict]) -> Optional[RLARGS]: - """Extracts the `rate_limit_args` from `data` if it exists.""" - if not data: - return None - return data.pop(cls.__RL_KEY, None) - - async def _do_post( - self, - endpoint: str, - data: JSONDict, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - ) -> Union[bool, JSONDict, list[JSONDict]]: - """Order of method calls is: Bot.some_method -> Bot._post -> Bot._do_post. - So we can override Bot._do_post to add rate limiting. - """ - rate_limit_args = self._extract_rl_kwargs(data) - if not self.rate_limiter and rate_limit_args is not None: - raise ValueError( - "`rate_limit_args` can only be used if a `ExtBot.rate_limiter` is set." - ) - - # getting updates should not be rate limited! - if endpoint == "getUpdates" or not self.rate_limiter: - return await super()._do_post( - endpoint=endpoint, - data=data, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - read_timeout=read_timeout, - ) - - kwargs = { - "read_timeout": read_timeout, - "write_timeout": write_timeout, - "connect_timeout": connect_timeout, - "pool_timeout": pool_timeout, - } - self._LOGGER.debug( - "Passing request through rate limiter of type %s with rate_limit_args %s", - type(self.rate_limiter), - rate_limit_args, - ) - return await self.rate_limiter.process_request( - callback=super()._do_post, - args=(endpoint, data), - kwargs=kwargs, - endpoint=endpoint, - data=data, - rate_limit_args=rate_limit_args, - ) - - @property - def defaults(self) -> Optional["Defaults"]: - """The :class:`telegram.ext.Defaults` used by this bot, if any.""" - # This is a property because defaults shouldn't be changed at runtime - return self._defaults - - @property - def rate_limiter(self) -> Optional["BaseRateLimiter[RLARGS]"]: - """The :class:`telegram.ext.BaseRateLimiter` used by this bot, if any. - - .. versionadded:: 20.0 - """ - # This is a property because the rate limiter shouldn't be changed at runtime - return self._rate_limiter - - def _merge_lpo_defaults( - self, lpo: ODVInput[LinkPreviewOptions] - ) -> Optional[LinkPreviewOptions]: - # This is a standalone method because both _insert_defaults and - # _insert_defaults_for_ilq_results need this logic - # - # If Defaults.LPO is set, and LPO is passed in the bot method we should fuse - # them, giving precedence to passed values. - # Defaults.LPO(True, "google.com", True) & LPO=LPO(True, ..., False) -> - # LPO(True, "google.com", False) - if self.defaults is None or (defaults_lpo := self.defaults.link_preview_options) is None: - return DefaultValue.get_value(lpo) - return LinkPreviewOptions( - **{ - attr: ( - getattr(defaults_lpo, attr) - # only use the default value - # if the value was explicitly passed to the LPO object - if isinstance(orig_attr := getattr(lpo, attr), DefaultValue) - else orig_attr - ) - for attr in defaults_lpo.__slots__ - } - ) - - def _insert_defaults(self, data: dict[str, object]) -> None: - """Inserts the defaults values for optional kwargs for which tg.ext.Defaults provides - convenience functionality, i.e. the kwargs with a tg.utils.helpers.DefaultValue default - - data is edited in-place. As timeout is not passed via the kwargs, it needs to be passed - separately and gets returned. - - This can only work, if all kwargs that may have defaults are passed in data! - """ - if self.defaults is None: - # If we have no defaults to insert, the behavior is the same as in `tg.Bot` - super()._insert_defaults(data) - return - - # if we have Defaults, we - # 1) replace all DefaultValue instances with the relevant Defaults value. If there is none, - # we fall back to the default value of the bot method - # 2) convert all datetime.datetime objects to timestamps wrt the correct default timezone - # 3) set the correct parse_mode for all InputMedia objects - # 4) handle the LinkPreviewOptions case (see below) - # 5) handle the ReplyParameters case (see below) - # 6) handle text_parse_mode in InputPollOption - for key, val in data.items(): - # 1) - if isinstance(val, DefaultValue): - data[key] = self.defaults.api_defaults.get(key, val.value) - - # 2) - elif isinstance(val, dtm.datetime): - data[key] = to_timestamp(val, tzinfo=self.defaults.tzinfo) - - # 3) - elif isinstance(val, InputMedia) and val.parse_mode is DEFAULT_NONE: - # Copy object as not to edit it in-place - copied_val = copy(val) - with copied_val._unfrozen(): - copied_val.parse_mode = self.defaults.parse_mode - data[key] = copied_val - elif key == "media" and isinstance(val, Sequence): - # Copy objects as not to edit them in-place - copy_list = [copy(media) for media in val] - for media in copy_list: - if media.parse_mode is DEFAULT_NONE: - with media._unfrozen(): - media.parse_mode = self.defaults.parse_mode - - data[key] = copy_list - - # 4) LinkPreviewOptions: - elif isinstance(val, LinkPreviewOptions): - data[key] = self._merge_lpo_defaults(val) - - # 5) - # Similar to LinkPreviewOptions, but only two of the arguments of RPs have a default - elif isinstance(val, ReplyParameters) and ( - (defaults_aswr := self.defaults.allow_sending_without_reply) is not None - or self.defaults.quote_parse_mode is not None - ): - new_value = copy(val) - with new_value._unfrozen(): - new_value.allow_sending_without_reply = ( - defaults_aswr - if isinstance(val.allow_sending_without_reply, DefaultValue) - else val.allow_sending_without_reply - ) - new_value.quote_parse_mode = ( - self.defaults.quote_parse_mode - if isinstance(val.quote_parse_mode, DefaultValue) - else val.quote_parse_mode - ) - - data[key] = new_value - - # 6) - elif isinstance(val, Sequence) and all( - isinstance(obj, InputPollOption) for obj in val - ): - new_val = [] - for option in val: - if not isinstance(option.text_parse_mode, DefaultValue): - new_val.append(option) - else: - new_option = copy(option) - with new_option._unfrozen(): - new_option.text_parse_mode = self.defaults.text_parse_mode - new_val.append(new_option) - data[key] = new_val - - def _replace_keyboard(self, reply_markup: Optional[KT]) -> Optional[KT]: - # If the reply_markup is an inline keyboard and we allow arbitrary callback data, let the - # CallbackDataCache build a new keyboard with the data replaced. Otherwise return the input - if isinstance(reply_markup, InlineKeyboardMarkup) and self.callback_data_cache is not None: - # for some reason mypy doesn't understand that IKB is a subtype of Optional[KT] - return self.callback_data_cache.process_keyboard( # type: ignore[return-value] - reply_markup - ) - - return reply_markup - - def insert_callback_data(self, update: Update) -> None: - """If this bot allows for arbitrary callback data, this inserts the cached data into all - corresponding buttons within this update. - - Note: - Checks :attr:`telegram.Message.via_bot` and :attr:`telegram.Message.from_user` - to figure out if a) a reply markup exists and b) it was actually sent by this - bot. If not, the message will be returned unchanged. - - Note that this will fail for channel posts, as :attr:`telegram.Message.from_user` is - :obj:`None` for those! In the corresponding reply markups, the callback data will be - replaced by :class:`telegram.ext.InvalidCallbackData`. - - Warning: - *In place*, i.e. the passed :class:`telegram.Message` will be changed! - - Args: - update (:class:`telegram.Update`): The update. - - """ - # The only incoming updates that can directly contain a message sent by the bot itself are: - # * CallbackQueries - # * Messages where the pinned_message is sent by the bot - # * Messages where the reply_to_message is sent by the bot - # * Messages where via_bot is the bot - # Finally there is effective_chat.pinned message, but that's only returned in get_chat - if update.callback_query: - self._insert_callback_data(update.callback_query) - # elif instead of if, as effective_message includes callback_query.message - # and that has already been processed - elif update.effective_message: - self._insert_callback_data(update.effective_message) - - def _insert_callback_data(self, obj: HandledTypes) -> HandledTypes: - if self.callback_data_cache is None: - return obj - - if isinstance(obj, CallbackQuery): - self.callback_data_cache.process_callback_query(obj) - return obj # type: ignore[return-value] - - if isinstance(obj, Message): - if obj.reply_to_message: - # reply_to_message can't contain further reply_to_messages, so no need to check - self.callback_data_cache.process_message(obj.reply_to_message) - if isinstance(obj.reply_to_message.pinned_message, Message): - # pinned messages can't contain reply_to_message, no need to check - self.callback_data_cache.process_message(obj.reply_to_message.pinned_message) - if isinstance(obj.pinned_message, Message): - # pinned messages can't contain reply_to_message, no need to check - self.callback_data_cache.process_message(obj.pinned_message) - - # Finally, handle the message itself - self.callback_data_cache.process_message(message=obj) - return obj # type: ignore[return-value] - - if isinstance(obj, ChatFullInfo) and obj.pinned_message: - self.callback_data_cache.process_message(obj.pinned_message) - - return obj - - async def _send_message( - self, - endpoint: str, - data: JSONDict, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> Any: - # We override this method to call self._replace_keyboard and self._insert_callback_data. - # This covers most methods that have a reply_markup - result = await super()._send_message( - endpoint=endpoint, - data=data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=self._replace_keyboard(reply_markup), - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - link_preview_options=link_preview_options, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - if isinstance(result, Message): - self._insert_callback_data(result) - return result - - async def get_updates( - self, - offset: Optional[int] = None, - limit: Optional[int] = None, - timeout: Optional[int] = None, # noqa: ASYNC109 - allowed_updates: Optional[Sequence[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, - ) -> tuple[Update, ...]: - updates = await super().get_updates( - offset=offset, - limit=limit, - timeout=timeout, - allowed_updates=allowed_updates, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - for update in updates: - self.insert_callback_data(update) - - return updates - - def _effective_inline_results( - self, - results: Union[ - Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]] - ], - next_offset: Optional[str] = None, - current_offset: Optional[str] = None, - ) -> tuple[Sequence["InlineQueryResult"], Optional[str]]: - """This method is called by Bot.answer_inline_query to build the actual results list. - Overriding this to call self._replace_keyboard suffices - """ - effective_results, next_offset = super()._effective_inline_results( - results=results, next_offset=next_offset, current_offset=current_offset - ) - - # Process arbitrary callback - if self.callback_data_cache is None: - return effective_results, next_offset - results = [] - for result in effective_results: - # All currently existingInlineQueryResults have a reply_markup, but future ones - # might not have. Better be save than sorry - if not hasattr(result, "reply_markup"): - results.append(result) - else: - # We build a new result in case the user wants to use the same object in - # different places - new_result = copy(result) - with new_result._unfrozen(): - markup = self._replace_keyboard(result.reply_markup) - new_result.reply_markup = markup - - results.append(new_result) - - return results, next_offset - - @no_type_check # mypy doesn't play too well with hasattr - def _insert_defaults_for_ilq_results(self, res: "InlineQueryResult") -> "InlineQueryResult": - """This method is called by Bot.answer_inline_query to replace `DefaultValue(obj)` with - `obj`. - Overriding this to call insert the actual desired default values. - """ - if self.defaults is None: - # If we have no defaults to insert, the behavior is the same as in `tg.Bot` - return super()._insert_defaults_for_ilq_results(res) - - # Copy the objects that need modification to avoid modifying the original object - copied = False - if hasattr(res, "parse_mode") and res.parse_mode is DEFAULT_NONE: - res = copy(res) - with res._unfrozen(): - copied = True - res.parse_mode = self.defaults.parse_mode - if hasattr(res, "input_message_content") and res.input_message_content: - if ( - hasattr(res.input_message_content, "parse_mode") - and res.input_message_content.parse_mode is DEFAULT_NONE - ): - if not copied: - res = copy(res) - copied = True - with res.input_message_content._unfrozen(): - res.input_message_content.parse_mode = self.defaults.parse_mode - if hasattr(res.input_message_content, "link_preview_options"): - if not copied: - res = copy(res) - with res.input_message_content._unfrozen(): - if res.input_message_content.link_preview_options is DEFAULT_NONE: - res.input_message_content.link_preview_options = ( - self.defaults.link_preview_options - ) - else: - # merge the existing options with the defaults - res.input_message_content.link_preview_options = self._merge_lpo_defaults( - res.input_message_content.link_preview_options - ) - - return res - - async def do_api_request( - self, - endpoint: str, - api_kwargs: Optional[JSONDict] = None, - return_type: Optional[type[TelegramObject]] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Any: - return await super().do_api_request( - endpoint=endpoint, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - return_type=return_type, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - - async def stop_poll( - self, - chat_id: Union[int, str], - message_id: int, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Poll: - # We override this method to call self._replace_keyboard - return await super().stop_poll( - chat_id=chat_id, - message_id=message_id, - reply_markup=self._replace_keyboard(reply_markup), - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def copy_message( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_id: int, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - show_caption_above_media: Optional[bool] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - rate_limit_args: Optional[RLARGS] = None, - ) -> MessageId: - # We override this method to call self._replace_keyboard - return await super().copy_message( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=self._replace_keyboard(reply_markup), - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - show_caption_above_media=show_caption_above_media, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def copy_messages( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - remove_caption: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple["MessageId", ...]: - # We override this method to call self._replace_keyboard - return await super().copy_messages( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - remove_caption=remove_caption, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatFullInfo: - # We override this method to call self._insert_callback_data - result = await super().get_chat( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - return self._insert_callback_data(result) - - async def add_sticker_to_set( - self, - user_id: int, - name: str, - sticker: "InputSticker", - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().add_sticker_to_set( - user_id=user_id, - name=name, - sticker=sticker, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_callback_query( - self, - callback_query_id: str, - text: Optional[str] = None, - show_alert: Optional[bool] = None, - url: Optional[str] = None, - cache_time: Optional[int] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().answer_callback_query( - callback_query_id=callback_query_id, - text=text, - show_alert=show_alert, - url=url, - cache_time=cache_time, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_inline_query( - self, - inline_query_id: str, - results: Union[ - Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]] - ], - cache_time: Optional[int] = None, - is_personal: Optional[bool] = None, - next_offset: Optional[str] = None, - button: Optional[InlineQueryResultsButton] = None, - *, - current_offset: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().answer_inline_query( - inline_query_id=inline_query_id, - results=results, - cache_time=cache_time, - is_personal=is_personal, - next_offset=next_offset, - current_offset=current_offset, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - button=button, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def save_prepared_inline_message( - self, - user_id: int, - result: "InlineQueryResult", - allow_user_chats: Optional[bool] = None, - allow_bot_chats: Optional[bool] = None, - allow_group_chats: Optional[bool] = None, - allow_channel_chats: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> PreparedInlineMessage: - return await super().save_prepared_inline_message( - user_id=user_id, - result=result, - allow_user_chats=allow_user_chats, - allow_bot_chats=allow_bot_chats, - allow_group_chats=allow_group_chats, - allow_channel_chats=allow_channel_chats, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_pre_checkout_query( - self, - pre_checkout_query_id: str, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().answer_pre_checkout_query( - pre_checkout_query_id=pre_checkout_query_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=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_shipping_query( - self, - shipping_query_id: str, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().answer_shipping_query( - shipping_query_id=shipping_query_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=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_web_app_query( - self, - web_app_query_id: str, - result: "InlineQueryResult", - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> SentWebAppMessage: - return await super().answer_web_app_query( - web_app_query_id=web_app_query_id, - result=result, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def approve_chat_join_request( - self, - chat_id: Union[str, int], - user_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().approve_chat_join_request( - chat_id=chat_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def ban_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - until_date: Optional[Union[int, dtm.datetime]] = None, - revoke_messages: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().ban_chat_member( - chat_id=chat_id, - user_id=user_id, - until_date=until_date, - revoke_messages=revoke_messages, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def ban_chat_sender_chat( - self, - chat_id: Union[str, int], - sender_chat_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().ban_chat_sender_chat( - chat_id=chat_id, - sender_chat_id=sender_chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def create_chat_invite_link( - self, - chat_id: Union[str, int], - expire_date: Optional[Union[int, dtm.datetime]] = None, - member_limit: Optional[int] = None, - name: Optional[str] = None, - creates_join_request: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().create_chat_invite_link( - chat_id=chat_id, - expire_date=expire_date, - member_limit=member_limit, - name=name, - creates_join_request=creates_join_request, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def create_invoice_link( - self, - title: str, - description: str, - payload: str, - provider_token: Optional[str], - currency: str, - prices: Sequence["LabeledPrice"], - max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[Sequence[int]] = None, - provider_data: Optional[Union[str, object]] = None, - photo_url: Optional[str] = None, - photo_size: Optional[int] = None, - photo_width: Optional[int] = None, - photo_height: Optional[int] = None, - need_name: Optional[bool] = None, - need_phone_number: Optional[bool] = None, - need_email: Optional[bool] = None, - need_shipping_address: Optional[bool] = None, - send_phone_number_to_provider: Optional[bool] = None, - send_email_to_provider: Optional[bool] = None, - is_flexible: Optional[bool] = None, - subscription_period: Optional[Union[int, dtm.timedelta]] = None, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> str: - return await super().create_invoice_link( - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - provider_data=provider_data, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - is_flexible=is_flexible, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - subscription_period=subscription_period, - business_connection_id=business_connection_id, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def create_new_sticker_set( - self, - user_id: int, - name: str, - title: str, - stickers: Sequence["InputSticker"], - sticker_type: Optional[str] = None, - needs_repainting: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().create_new_sticker_set( - user_id=user_id, - name=name, - title=title, - stickers=stickers, - sticker_type=sticker_type, - needs_repainting=needs_repainting, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def decline_chat_join_request( - self, - chat_id: Union[str, int], - user_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().decline_chat_join_request( - chat_id=chat_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_chat_photo( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_chat_photo( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_chat_sticker_set( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_chat_sticker_set( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_forum_topic( - self, - chat_id: Union[str, int], - message_thread_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_forum_topic( - chat_id=chat_id, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_message( - self, - chat_id: Union[str, int], - message_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_message( - chat_id=chat_id, - message_id=message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_messages( - self, - chat_id: Union[str, int], - message_ids: Sequence[int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_messages( - chat_id=chat_id, - message_ids=message_ids, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_my_commands( - self, - scope: Optional[BotCommandScope] = None, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_my_commands( - scope=scope, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_sticker_from_set( - self, - sticker: Union[str, "Sticker"], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_sticker_from_set( - sticker=sticker, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_webhook( - self, - drop_pending_updates: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_webhook( - drop_pending_updates=drop_pending_updates, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_chat_invite_link( - self, - chat_id: Union[str, int], - invite_link: Union[str, "ChatInviteLink"], - expire_date: Optional[Union[int, dtm.datetime]] = None, - member_limit: Optional[int] = None, - name: Optional[str] = None, - creates_join_request: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().edit_chat_invite_link( - chat_id=chat_id, - invite_link=invite_link, - expire_date=expire_date, - member_limit=member_limit, - name=name, - creates_join_request=creates_join_request, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_forum_topic( - self, - chat_id: Union[str, int], - message_thread_id: int, - name: Optional[str] = None, - icon_custom_emoji_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().edit_forum_topic( - chat_id=chat_id, - message_thread_id=message_thread_id, - name=name, - icon_custom_emoji_id=icon_custom_emoji_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_general_forum_topic( - self, - chat_id: Union[str, int], - name: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().edit_general_forum_topic( - chat_id=chat_id, - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_message_caption( - self, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - show_caption_above_media: Optional[bool] = None, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_caption( - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - caption=caption, - reply_markup=reply_markup, - parse_mode=parse_mode, - caption_entities=caption_entities, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - show_caption_above_media=show_caption_above_media, - ) - - async def edit_message_live_location( - self, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - latitude: Optional[float] = None, - longitude: Optional[float] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - horizontal_accuracy: Optional[float] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - live_period: Optional[int] = None, - business_connection_id: Optional[str] = None, - *, - location: Optional[Location] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_live_location( - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - latitude=latitude, - longitude=longitude, - reply_markup=reply_markup, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - live_period=live_period, - location=location, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_message_media( - self, - media: "InputMedia", - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_media( - media=media, - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_message_reply_markup( - self, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_reply_markup( - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_message_text( - self, - text: str, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - entities: Optional[Sequence["MessageEntity"]] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, - business_connection_id: Optional[str] = None, - *, - disable_web_page_preview: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_text( - text=text, - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - reply_markup=reply_markup, - entities=entities, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - link_preview_options=link_preview_options, - ) - - async def export_chat_invite_link( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> str: - return await super().export_chat_invite_link( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def forward_message( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().forward_message( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_id=message_id, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def forward_messages( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[MessageId, ...]: - return await super().forward_messages( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat_administrators( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[ChatMember, ...]: - return await super().get_chat_administrators( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatMember: - return await super().get_chat_member( - chat_id=chat_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat_member_count( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> int: - return await super().get_chat_member_count( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat_menu_button( - self, - chat_id: Optional[int] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> MenuButton: - return await super().get_chat_menu_button( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_file( - self, - file_id: Union[ - str, Animation, Audio, ChatPhoto, Document, PhotoSize, Sticker, Video, VideoNote, Voice - ], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> File: - return await super().get_file( - file_id=file_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_forum_topic_icon_stickers( - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[Sticker, ...]: - return await super().get_forum_topic_icon_stickers( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_game_high_scores( - self, - user_id: int, - chat_id: Optional[int] = None, - message_id: Optional[int] = None, - inline_message_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[GameHighScore, ...]: - return await super().get_game_high_scores( - user_id=user_id, - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_me( - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> User: - return await super().get_me( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_commands( - self, - scope: Optional[BotCommandScope] = None, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[BotCommand, ...]: - return await super().get_my_commands( - scope=scope, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_default_administrator_rights( - self, - for_channels: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatAdministratorRights: - return await super().get_my_default_administrator_rights( - for_channels=for_channels, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_sticker_set( - self, - name: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> StickerSet: - return await super().get_sticker_set( - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_custom_emoji_stickers( - self, - custom_emoji_ids: Sequence[str], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[Sticker, ...]: - return await super().get_custom_emoji_stickers( - custom_emoji_ids=custom_emoji_ids, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_user_profile_photos( - self, - user_id: int, - offset: Optional[int] = None, - limit: Optional[int] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> UserProfilePhotos: - return await super().get_user_profile_photos( - user_id=user_id, - offset=offset, - limit=limit, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_webhook_info( - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> WebhookInfo: - return await super().get_webhook_info( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def leave_chat( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().leave_chat( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def log_out( - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().log_out( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def close( - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().close( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def close_forum_topic( - self, - chat_id: Union[str, int], - message_thread_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().close_forum_topic( - chat_id=chat_id, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def close_general_forum_topic( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().close_general_forum_topic( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def create_forum_topic( - self, - chat_id: Union[str, int], - name: str, - icon_color: Optional[int] = None, - icon_custom_emoji_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ForumTopic: - return await super().create_forum_topic( - chat_id=chat_id, - name=name, - icon_color=icon_color, - icon_custom_emoji_id=icon_custom_emoji_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def reopen_general_forum_topic( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().reopen_general_forum_topic( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def hide_general_forum_topic( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().hide_general_forum_topic( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unhide_general_forum_topic( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unhide_general_forum_topic( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def pin_chat_message( - self, - chat_id: Union[str, int], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().pin_chat_message( - chat_id=chat_id, - message_id=message_id, - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - business_connection_id=business_connection_id, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def promote_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - can_change_info: Optional[bool] = None, - can_post_messages: Optional[bool] = None, - can_edit_messages: Optional[bool] = None, - can_delete_messages: Optional[bool] = None, - can_invite_users: Optional[bool] = None, - can_restrict_members: Optional[bool] = None, - can_pin_messages: Optional[bool] = None, - can_promote_members: Optional[bool] = None, - is_anonymous: Optional[bool] = None, - can_manage_chat: Optional[bool] = None, - can_manage_video_chats: Optional[bool] = None, - can_manage_topics: Optional[bool] = None, - can_post_stories: Optional[bool] = None, - can_edit_stories: Optional[bool] = None, - can_delete_stories: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().promote_chat_member( - chat_id=chat_id, - user_id=user_id, - can_change_info=can_change_info, - can_post_messages=can_post_messages, - can_edit_messages=can_edit_messages, - can_delete_messages=can_delete_messages, - can_invite_users=can_invite_users, - can_restrict_members=can_restrict_members, - can_pin_messages=can_pin_messages, - can_promote_members=can_promote_members, - is_anonymous=is_anonymous, - can_manage_chat=can_manage_chat, - can_manage_video_chats=can_manage_video_chats, - can_manage_topics=can_manage_topics, - can_post_stories=can_post_stories, - can_edit_stories=can_edit_stories, - can_delete_stories=can_delete_stories, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def reopen_forum_topic( - self, - chat_id: Union[str, int], - message_thread_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().reopen_forum_topic( - chat_id=chat_id, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def restrict_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - permissions: ChatPermissions, - until_date: Optional[Union[int, dtm.datetime]] = None, - use_independent_chat_permissions: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().restrict_chat_member( - chat_id=chat_id, - user_id=user_id, - permissions=permissions, - until_date=until_date, - use_independent_chat_permissions=use_independent_chat_permissions, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def revoke_chat_invite_link( - self, - chat_id: Union[str, int], - invite_link: Union[str, "ChatInviteLink"], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().revoke_chat_invite_link( - chat_id=chat_id, - invite_link=invite_link, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def send_animation( - self, - chat_id: Union[int, str], - animation: Union[FileInput, "Animation"], - duration: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_animation( - chat_id=chat_id, - animation=animation, - duration=duration, - width=width, - height=height, - caption=caption, - parse_mode=parse_mode, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - has_spoiler=has_spoiler, - thumbnail=thumbnail, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - business_connection_id=business_connection_id, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_audio( - self, - chat_id: Union[int, str], - audio: Union[FileInput, "Audio"], - duration: Optional[int] = None, - performer: Optional[str] = None, - title: Optional[str] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_audio( - chat_id=chat_id, - audio=audio, - duration=duration, - performer=performer, - business_connection_id=business_connection_id, - title=title, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - thumbnail=thumbnail, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_chat_action( - self, - chat_id: Union[str, int], - action: str, - message_thread_id: Optional[int] = None, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().send_chat_action( - chat_id=chat_id, - business_connection_id=business_connection_id, - action=action, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def send_contact( - self, - chat_id: Union[int, str], - phone_number: Optional[str] = None, - first_name: Optional[str] = None, - last_name: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - vcard: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - contact: Optional[Contact] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_contact( - chat_id=chat_id, - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - vcard=vcard, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - contact=contact, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - business_connection_id=business_connection_id, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_dice( - self, - chat_id: Union[int, str], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - emoji: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_dice( - chat_id=chat_id, - disable_notification=disable_notification, - business_connection_id=business_connection_id, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - emoji=emoji, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_document( - self, - chat_id: Union[int, str], - document: Union[FileInput, "Document"], - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_content_type_detection: Optional[bool] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_document( - chat_id=chat_id, - document=document, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - parse_mode=parse_mode, - disable_content_type_detection=disable_content_type_detection, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - business_connection_id=business_connection_id, - message_thread_id=message_thread_id, - thumbnail=thumbnail, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_game( - self, - chat_id: int, - game_short_name: str, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_game( - chat_id=chat_id, - game_short_name=game_short_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_invoice( - self, - chat_id: Union[int, str], - title: str, - description: str, - payload: str, - provider_token: Optional[str], - currency: str, - prices: Sequence["LabeledPrice"], - start_parameter: Optional[str] = None, - photo_url: Optional[str] = None, - photo_size: Optional[int] = None, - photo_width: Optional[int] = None, - photo_height: Optional[int] = None, - need_name: Optional[bool] = None, - need_phone_number: Optional[bool] = None, - need_email: Optional[bool] = None, - need_shipping_address: Optional[bool] = None, - is_flexible: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - provider_data: Optional[Union[str, object]] = None, - send_phone_number_to_provider: Optional[bool] = None, - send_email_to_provider: Optional[bool] = None, - max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[Sequence[int]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_invoice( - chat_id=chat_id, - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - start_parameter=start_parameter, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - is_flexible=is_flexible, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - provider_data=provider_data, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - allow_sending_without_reply=allow_sending_without_reply, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_location( - self, - chat_id: Union[int, str], - latitude: Optional[float] = None, - longitude: Optional[float] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - live_period: Optional[int] = None, - horizontal_accuracy: Optional[float] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - location: Optional[Location] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_location( - chat_id=chat_id, - latitude=latitude, - longitude=longitude, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - live_period=live_period, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - location=location, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - business_connection_id=business_connection_id, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_media_group( - self, - chat_id: Union[int, str], - media: Sequence[ - Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] - ], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - rate_limit_args: Optional[RLARGS] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - ) -> tuple[Message, ...]: - return await super().send_media_group( - chat_id=chat_id, - media=media, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - caption=caption, - business_connection_id=business_connection_id, - parse_mode=parse_mode, - caption_entities=caption_entities, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_message( - self, - chat_id: Union[int, str], - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - entities: Optional[Sequence["MessageEntity"]] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - message_thread_id: Optional[int] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - disable_web_page_preview: Optional[bool] = None, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_message( - chat_id=chat_id, - text=text, - parse_mode=parse_mode, - entities=entities, - disable_web_page_preview=disable_web_page_preview, - disable_notification=disable_notification, - business_connection_id=business_connection_id, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - link_preview_options=link_preview_options, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_photo( - self, - chat_id: Union[int, str], - photo: Union[FileInput, "PhotoSize"], - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_photo( - chat_id=chat_id, - photo=photo, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - has_spoiler=has_spoiler, - reply_parameters=reply_parameters, - filename=filename, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_poll( - self, - chat_id: Union[int, str], - question: str, - options: Sequence[Union[str, "InputPollOption"]], - is_anonymous: Optional[bool] = None, - type: Optional[str] = None, # pylint: disable=redefined-builtin - allows_multiple_answers: Optional[bool] = None, - correct_option_id: Optional[CorrectOptionID] = None, - is_closed: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - explanation: Optional[str] = None, - explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, - open_period: Optional[int] = None, - close_date: Optional[Union[int, dtm.datetime]] = None, - explanation_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - question_parse_mode: ODVInput[str] = DEFAULT_NONE, - question_entities: Optional[Sequence["MessageEntity"]] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_poll( - chat_id=chat_id, - question=question, - options=options, - is_anonymous=is_anonymous, - type=type, - allows_multiple_answers=allows_multiple_answers, - correct_option_id=correct_option_id, - is_closed=is_closed, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - explanation=explanation, - explanation_parse_mode=explanation_parse_mode, - open_period=open_period, - close_date=close_date, - allow_sending_without_reply=allow_sending_without_reply, - explanation_entities=explanation_entities, - business_connection_id=business_connection_id, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - question_parse_mode=question_parse_mode, - question_entities=question_entities, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_sticker( - self, - chat_id: Union[int, str], - sticker: Union[FileInput, "Sticker"], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - emoji: Optional[str] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_sticker( - chat_id=chat_id, - sticker=sticker, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - emoji=emoji, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_venue( - self, - chat_id: Union[int, str], - latitude: Optional[float] = None, - longitude: Optional[float] = None, - title: Optional[str] = None, - address: Optional[str] = None, - foursquare_id: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - foursquare_type: Optional[str] = None, - google_place_id: Optional[str] = None, - google_place_type: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - venue: Optional[Venue] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_venue( - chat_id=chat_id, - latitude=latitude, - longitude=longitude, - title=title, - address=address, - foursquare_id=foursquare_id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - foursquare_type=foursquare_type, - google_place_id=google_place_id, - google_place_type=google_place_type, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - business_connection_id=business_connection_id, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - venue=venue, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_video( - self, - chat_id: Union[int, str], - video: Union[FileInput, "Video"], - duration: Optional[int] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - width: Optional[int] = None, - height: Optional[int] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - supports_streaming: Optional[bool] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_video( - chat_id=chat_id, - video=video, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - width=width, - height=height, - parse_mode=parse_mode, - supports_streaming=supports_streaming, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - has_spoiler=has_spoiler, - thumbnail=thumbnail, - filename=filename, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_video_note( - self, - chat_id: Union[int, str], - video_note: Union[FileInput, "VideoNote"], - duration: Optional[int] = None, - length: Optional[int] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_video_note( - chat_id=chat_id, - video_note=video_note, - duration=duration, - length=length, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - thumbnail=thumbnail, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_voice( - self, - chat_id: Union[int, str], - voice: Union[FileInput, "Voice"], - duration: Optional[int] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_voice( - chat_id=chat_id, - voice=voice, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def set_chat_administrator_custom_title( - self, - chat_id: Union[int, str], - user_id: int, - custom_title: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_administrator_custom_title( - chat_id=chat_id, - user_id=user_id, - custom_title=custom_title, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_description( - self, - chat_id: Union[str, int], - description: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_description( - chat_id=chat_id, - description=description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_user_emoji_status( - self, - user_id: int, - emoji_status_custom_emoji_id: Optional[str] = None, - emoji_status_expiration_date: Optional[Union[int, dtm.datetime]] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_user_emoji_status( - user_id=user_id, - emoji_status_custom_emoji_id=emoji_status_custom_emoji_id, - emoji_status_expiration_date=emoji_status_expiration_date, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_menu_button( - self, - chat_id: Optional[int] = None, - menu_button: Optional[MenuButton] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_menu_button( - chat_id=chat_id, - menu_button=menu_button, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_permissions( - self, - chat_id: Union[str, int], - permissions: ChatPermissions, - use_independent_chat_permissions: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_permissions( - chat_id=chat_id, - permissions=permissions, - use_independent_chat_permissions=use_independent_chat_permissions, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_photo( - self, - chat_id: Union[str, int], - photo: FileInput, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_photo( - chat_id=chat_id, - photo=photo, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_sticker_set( - self, - chat_id: Union[str, int], - sticker_set_name: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_sticker_set( - chat_id=chat_id, - sticker_set_name=sticker_set_name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_title( - self, - chat_id: Union[str, int], - title: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_title( - chat_id=chat_id, - title=title, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_game_score( - self, - user_id: int, - score: int, - chat_id: Optional[int] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - force: Optional[bool] = None, - disable_edit_message: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().set_game_score( - user_id=user_id, - score=score, - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - force=force, - disable_edit_message=disable_edit_message, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_commands( - self, - commands: Sequence[Union[BotCommand, tuple[str, str]]], - scope: Optional[BotCommandScope] = None, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_commands( - commands=commands, - scope=scope, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_default_administrator_rights( - self, - rights: Optional[ChatAdministratorRights] = None, - for_channels: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_default_administrator_rights( - rights=rights, - for_channels=for_channels, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_passport_data_errors( - self, - user_id: int, - errors: Sequence["PassportElementError"], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_passport_data_errors( - user_id=user_id, - errors=errors, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_position_in_set( - self, - sticker: Union[str, "Sticker"], - position: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_position_in_set( - sticker=sticker, - position=position, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_set_thumbnail( - self, - name: str, - user_id: int, - format: str, # pylint: disable=redefined-builtin - thumbnail: Optional[FileInput] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_set_thumbnail( - name=name, - user_id=user_id, - thumbnail=thumbnail, - format=format, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_webhook( - self, - url: str, - certificate: Optional[FileInput] = None, - max_connections: Optional[int] = None, - allowed_updates: Optional[Sequence[str]] = None, - ip_address: Optional[str] = None, - drop_pending_updates: Optional[bool] = None, - secret_token: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_webhook( - url=url, - certificate=certificate, - max_connections=max_connections, - allowed_updates=allowed_updates, - ip_address=ip_address, - drop_pending_updates=drop_pending_updates, - secret_token=secret_token, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def stop_message_live_location( - self, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().stop_message_live_location( - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unban_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - only_if_banned: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unban_chat_member( - chat_id=chat_id, - user_id=user_id, - only_if_banned=only_if_banned, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unban_chat_sender_chat( - self, - chat_id: Union[str, int], - sender_chat_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unban_chat_sender_chat( - chat_id=chat_id, - sender_chat_id=sender_chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unpin_all_chat_messages( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unpin_all_chat_messages( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unpin_chat_message( - self, - chat_id: Union[str, int], - message_id: Optional[int] = None, - business_connection_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unpin_chat_message( - chat_id=chat_id, - message_id=message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - business_connection_id=business_connection_id, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unpin_all_forum_topic_messages( - self, - chat_id: Union[str, int], - message_thread_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unpin_all_forum_topic_messages( - chat_id=chat_id, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unpin_all_general_forum_topic_messages( - self, - chat_id: Union[str, int], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unpin_all_general_forum_topic_messages( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def upload_sticker_file( - self, - user_id: int, - sticker: FileInput, - sticker_format: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> File: - return await super().upload_sticker_file( - user_id=user_id, - sticker=sticker, - sticker_format=sticker_format, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_description( - self, - description: Optional[str] = None, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_description( - description=description, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_short_description( - self, - short_description: Optional[str] = None, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_short_description( - short_description=short_description, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_description( - self, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> BotDescription: - return await super().get_my_description( - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_short_description( - self, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> BotShortDescription: - return await super().get_my_short_description( - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_name( - self, - name: Optional[str] = None, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_name( - name=name, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_name( - self, - language_code: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> BotName: - return await super().get_my_name( - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_custom_emoji_sticker_set_thumbnail( - self, - name: str, - custom_emoji_id: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_custom_emoji_sticker_set_thumbnail( - name=name, - custom_emoji_id=custom_emoji_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_set_title( - self, - name: str, - title: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_set_title( - name=name, - title=title, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_sticker_set( - self, - name: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_sticker_set( - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_emoji_list( - self, - sticker: Union[str, "Sticker"], - emoji_list: Sequence[str], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_emoji_list( - sticker=sticker, - emoji_list=emoji_list, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_keywords( - self, - sticker: Union[str, "Sticker"], - keywords: Optional[Sequence[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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_keywords( - sticker=sticker, - keywords=keywords, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_mask_position( - self, - sticker: Union[str, "Sticker"], - mask_position: Optional[MaskPosition] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_mask_position( - sticker=sticker, - mask_position=mask_position, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_user_chat_boosts( - self, - chat_id: Union[str, int], - user_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> UserChatBoosts: - return await super().get_user_chat_boosts( - chat_id=chat_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_message_reaction( - self, - chat_id: Union[str, int], - message_id: int, - reaction: Optional[Union[Sequence[Union[ReactionType, str]], ReactionType, str]] = None, - is_big: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_message_reaction( - chat_id=chat_id, - message_id=message_id, - reaction=reaction, - is_big=is_big, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_business_connection( - self, - business_connection_id: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> BusinessConnection: - return await super().get_business_connection( - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def replace_sticker_in_set( - self, - user_id: int, - name: str, - old_sticker: Union[str, "Sticker"], - sticker: "InputSticker", - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().replace_sticker_in_set( - user_id=user_id, - name=name, - old_sticker=old_sticker, - sticker=sticker, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def refund_star_payment( - self, - user_id: int, - telegram_payment_charge_id: str, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().refund_star_payment( - user_id=user_id, - telegram_payment_charge_id=telegram_payment_charge_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_star_transactions( - self, - offset: Optional[int] = None, - limit: Optional[int] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> StarTransactions: - return await super().get_star_transactions( - offset=offset, - limit=limit, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_user_star_subscription( - self, - user_id: int, - telegram_payment_charge_id: str, - is_canceled: bool, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().edit_user_star_subscription( - user_id=user_id, - telegram_payment_charge_id=telegram_payment_charge_id, - is_canceled=is_canceled, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def send_paid_media( - self, - chat_id: Union[str, int], - star_count: int, - media: Sequence["InputPaidMedia"], - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - show_caption_above_media: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - reply_parameters: Optional["ReplyParameters"] = None, - reply_markup: Optional[ReplyMarkup] = None, - business_connection_id: Optional[str] = None, - payload: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_paid_media( - chat_id=chat_id, - star_count=star_count, - media=media, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - show_caption_above_media=show_caption_above_media, - disable_notification=disable_notification, - protect_content=protect_content, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - reply_to_message_id=reply_to_message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - business_connection_id=business_connection_id, - payload=payload, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def create_chat_subscription_invite_link( - self, - chat_id: Union[str, int], - subscription_period: int, - subscription_price: int, - name: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().create_chat_subscription_invite_link( - chat_id=chat_id, - subscription_period=subscription_period, - subscription_price=subscription_price, - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_chat_subscription_invite_link( - self, - chat_id: Union[str, int], - invite_link: Union[str, "ChatInviteLink"], - name: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().edit_chat_subscription_invite_link( - chat_id=chat_id, - invite_link=invite_link, - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_available_gifts( - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> Gifts: - return await super().get_available_gifts( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def send_gift( - self, - user_id: int, - gift_id: Union[str, Gift], - text: Optional[str] = None, - text_parse_mode: ODVInput[str] = DEFAULT_NONE, - text_entities: Optional[Sequence["MessageEntity"]] = None, - pay_for_upgrade: Optional[bool] = 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().send_gift( - user_id=user_id, - gift_id=gift_id, - text=text, - text_parse_mode=text_parse_mode, - text_entities=text_entities, - pay_for_upgrade=pay_for_upgrade, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def verify_chat( - self, - chat_id: Union[int, str], - custom_description: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().verify_chat( - chat_id=chat_id, - custom_description=custom_description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def verify_user( - self, - user_id: int, - custom_description: 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().verify_user( - user_id=user_id, - custom_description=custom_description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def remove_chat_verification( - self, - chat_id: Union[int, str], - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().remove_chat_verification( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def remove_user_verification( - self, - user_id: int, - *, - 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, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().remove_user_verification( - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - # updated camelCase aliases - getMe = get_me - sendMessage = send_message - deleteMessage = delete_message - deleteMessages = delete_messages - forwardMessage = forward_message - forwardMessages = forward_messages - sendPhoto = send_photo - sendAudio = send_audio - sendDocument = send_document - sendSticker = send_sticker - sendVideo = send_video - sendAnimation = send_animation - sendVoice = send_voice - sendVideoNote = send_video_note - sendMediaGroup = send_media_group - sendLocation = send_location - editMessageLiveLocation = edit_message_live_location - stopMessageLiveLocation = stop_message_live_location - sendVenue = send_venue - sendContact = send_contact - sendGame = send_game - sendChatAction = send_chat_action - answerInlineQuery = answer_inline_query - savePreparedInlineMessage = save_prepared_inline_message - getUserProfilePhotos = get_user_profile_photos - getFile = get_file - banChatMember = ban_chat_member - banChatSenderChat = ban_chat_sender_chat - unbanChatMember = unban_chat_member - unbanChatSenderChat = unban_chat_sender_chat - answerCallbackQuery = answer_callback_query - editMessageText = edit_message_text - editMessageCaption = edit_message_caption - editMessageMedia = edit_message_media - editMessageReplyMarkup = edit_message_reply_markup - getUpdates = get_updates - setWebhook = set_webhook - deleteWebhook = delete_webhook - leaveChat = leave_chat - getChat = get_chat - getChatAdministrators = get_chat_administrators - getChatMember = get_chat_member - setChatStickerSet = set_chat_sticker_set - deleteChatStickerSet = delete_chat_sticker_set - getChatMemberCount = get_chat_member_count - getWebhookInfo = get_webhook_info - setGameScore = set_game_score - getGameHighScores = get_game_high_scores - sendInvoice = send_invoice - answerShippingQuery = answer_shipping_query - answerPreCheckoutQuery = answer_pre_checkout_query - answerWebAppQuery = answer_web_app_query - restrictChatMember = restrict_chat_member - promoteChatMember = promote_chat_member - setChatPermissions = set_chat_permissions - setChatAdministratorCustomTitle = set_chat_administrator_custom_title - exportChatInviteLink = export_chat_invite_link - createChatInviteLink = create_chat_invite_link - editChatInviteLink = edit_chat_invite_link - revokeChatInviteLink = revoke_chat_invite_link - approveChatJoinRequest = approve_chat_join_request - declineChatJoinRequest = decline_chat_join_request - setChatPhoto = set_chat_photo - deleteChatPhoto = delete_chat_photo - setChatTitle = set_chat_title - setChatDescription = set_chat_description - setUserEmojiStatus = set_user_emoji_status - pinChatMessage = pin_chat_message - unpinChatMessage = unpin_chat_message - unpinAllChatMessages = unpin_all_chat_messages - getStickerSet = get_sticker_set - getCustomEmojiStickers = get_custom_emoji_stickers - uploadStickerFile = upload_sticker_file - createNewStickerSet = create_new_sticker_set - addStickerToSet = add_sticker_to_set - setStickerPositionInSet = set_sticker_position_in_set - deleteStickerFromSet = delete_sticker_from_set - setStickerSetThumbnail = set_sticker_set_thumbnail - setPassportDataErrors = set_passport_data_errors - sendPoll = send_poll - stopPoll = stop_poll - sendDice = send_dice - getMyCommands = get_my_commands - setMyCommands = set_my_commands - deleteMyCommands = delete_my_commands - logOut = log_out - copyMessage = copy_message - copyMessages = copy_messages - getChatMenuButton = get_chat_menu_button - setChatMenuButton = set_chat_menu_button - getMyDefaultAdministratorRights = get_my_default_administrator_rights - setMyDefaultAdministratorRights = set_my_default_administrator_rights - createInvoiceLink = create_invoice_link - getForumTopicIconStickers = get_forum_topic_icon_stickers - createForumTopic = create_forum_topic - editForumTopic = edit_forum_topic - closeForumTopic = close_forum_topic - reopenForumTopic = reopen_forum_topic - deleteForumTopic = delete_forum_topic - unpinAllForumTopicMessages = unpin_all_forum_topic_messages - editGeneralForumTopic = edit_general_forum_topic - closeGeneralForumTopic = close_general_forum_topic - reopenGeneralForumTopic = reopen_general_forum_topic - hideGeneralForumTopic = hide_general_forum_topic - unhideGeneralForumTopic = unhide_general_forum_topic - setMyDescription = set_my_description - getMyDescription = get_my_description - setMyShortDescription = set_my_short_description - getMyShortDescription = get_my_short_description - setCustomEmojiStickerSetThumbnail = set_custom_emoji_sticker_set_thumbnail - setStickerSetTitle = set_sticker_set_title - deleteStickerSet = delete_sticker_set - setStickerEmojiList = set_sticker_emoji_list - setStickerKeywords = set_sticker_keywords - setStickerMaskPosition = set_sticker_mask_position - setMyName = set_my_name - getMyName = get_my_name - unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages - getUserChatBoosts = get_user_chat_boosts - setMessageReaction = set_message_reaction - getBusinessConnection = get_business_connection - replaceStickerInSet = replace_sticker_in_set - refundStarPayment = refund_star_payment - getStarTransactions = get_star_transactions - editUserStarSubscription = edit_user_star_subscription - createChatSubscriptionInviteLink = create_chat_subscription_invite_link - editChatSubscriptionInviteLink = edit_chat_subscription_invite_link - sendPaidMedia = send_paid_media - getAvailableGifts = get_available_gifts - sendGift = send_gift - verifyChat = verify_chat - verifyUser = verify_user - removeChatVerification = remove_chat_verification - removeUserVerification = remove_user_verification diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__init__.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index fd201bf..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/basehandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/basehandler.cpython-311.pyc deleted file mode 100755 index 8f3aee8..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/basehandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessconnectionhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessconnectionhandler.cpython-311.pyc deleted file mode 100755 index 01e3322..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessconnectionhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessmessagesdeletedhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessmessagesdeletedhandler.cpython-311.pyc deleted file mode 100755 index 451c32d..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessmessagesdeletedhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/callbackqueryhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/callbackqueryhandler.cpython-311.pyc deleted file mode 100755 index 877a0b2..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/callbackqueryhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatboosthandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatboosthandler.cpython-311.pyc deleted file mode 100755 index b5f5ff5..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatboosthandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatjoinrequesthandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatjoinrequesthandler.cpython-311.pyc deleted file mode 100755 index 7aafe90..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatjoinrequesthandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatmemberhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatmemberhandler.cpython-311.pyc deleted file mode 100755 index 9690b24..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatmemberhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/choseninlineresulthandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/choseninlineresulthandler.cpython-311.pyc deleted file mode 100755 index 292b132..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/choseninlineresulthandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/commandhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/commandhandler.cpython-311.pyc deleted file mode 100755 index 7e24707..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/commandhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/conversationhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/conversationhandler.cpython-311.pyc deleted file mode 100755 index 7abc6a0..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/conversationhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/inlinequeryhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/inlinequeryhandler.cpython-311.pyc deleted file mode 100755 index 2485fe0..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/inlinequeryhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagehandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagehandler.cpython-311.pyc deleted file mode 100755 index ac530af..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagehandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagereactionhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagereactionhandler.cpython-311.pyc deleted file mode 100755 index bc68c73..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagereactionhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/paidmediapurchasedhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/paidmediapurchasedhandler.cpython-311.pyc deleted file mode 100755 index a380a6c..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/paidmediapurchasedhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollanswerhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollanswerhandler.cpython-311.pyc deleted file mode 100755 index edcaa90..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollanswerhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollhandler.cpython-311.pyc deleted file mode 100755 index 280057d..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/precheckoutqueryhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/precheckoutqueryhandler.cpython-311.pyc deleted file mode 100755 index 19e61bb..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/precheckoutqueryhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/prefixhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/prefixhandler.cpython-311.pyc deleted file mode 100755 index 11d7b6b..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/prefixhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/shippingqueryhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/shippingqueryhandler.cpython-311.pyc deleted file mode 100755 index 763892a..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/shippingqueryhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringcommandhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringcommandhandler.cpython-311.pyc deleted file mode 100755 index c4c592e..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringcommandhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringregexhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringregexhandler.cpython-311.pyc deleted file mode 100755 index 8e57cd9..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringregexhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/typehandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/typehandler.cpython-311.pyc deleted file mode 100755 index 6303fbe..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/typehandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/basehandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/basehandler.py deleted file mode 100755 index b6353f2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/basehandler.py +++ /dev/null @@ -1,175 +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 -# -# 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 base class for handlers as used by the Application.""" -from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union - -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import DVType -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") -UT = TypeVar("UT") - - -class BaseHandler(Generic[UT, CCT, RT], ABC): - """The base class for all update handlers. Create custom handlers by inheriting from it. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - This class is a :class:`~typing.Generic` class and accepts three type variables: - - 1. The type of the updates that this handler will handle. Must coincide with the type of the - first argument of :paramref:`callback`. :meth:`check_update` must only accept - updates of this type. - 2. The type of the second argument of :paramref:`callback`. Must coincide with the type of the - parameters :paramref:`handle_update.context` and - :paramref:`collect_additional_context.context` as well as the second argument of - :paramref:`callback`. Must be either :class:`~telegram.ext.CallbackContext` or a subclass - of that class. - - .. tip:: - For this type variable, one should usually provide a :class:`~typing.TypeVar` that is - also used for the mentioned method arguments. That way, a type checker can check whether - this handler fits the definition of the :class:`~Application`. - 3. The return type of the :paramref:`callback` function accepted by this handler. - - .. seealso:: :wiki:`Types of Handlers ` - - .. versionchanged:: 20.0 - - * The attribute ``run_async`` is now :paramref:`block`. - * This class was previously named ``Handler``. - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way. - - """ - - __slots__ = ( - "block", - "callback", - ) - - def __init__( - self: "BaseHandler[UT, CCT, RT]", - callback: HandlerCallback[UT, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - ): - self.callback: HandlerCallback[UT, CCT, RT] = callback - self.block: DVType[bool] = block - - def __repr__(self) -> str: - """Give a string representation of the handler in the form ``ClassName[callback=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - try: - callback_name = self.callback.__qualname__ - except AttributeError: - callback_name = repr(self.callback) - return build_repr_with_selected_attrs(self, callback=callback_name) - - @abstractmethod - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """ - This method is called to determine if an update should be handled by - this handler instance. It should always be overridden. - - Note: - Custom updates types can be handled by the application. Therefore, an implementation of - this method should always check the type of :paramref:`update`. - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update to be tested. - - Returns: - Either :obj:`None` or :obj:`False` if the update should not be handled. Otherwise an - object that will be passed to :meth:`handle_update` and - :meth:`collect_additional_context` when the update gets handled. - - """ - - async def handle_update( - self, - update: UT, - application: "Application[Any, CCT, Any, Any, Any, Any]", - check_result: object, - context: CCT, - ) -> RT: - """ - This method is called if it was determined that an update should indeed - be handled by this instance. Calls :attr:`callback` along with its respectful - arguments. To work with the :class:`telegram.ext.ConversationHandler`, this method - returns the value returned from :attr:`callback`. - Note that it can be overridden if needed by the subclassing handler. - - Args: - update (:obj:`str` | :class:`telegram.Update`): The update to be handled. - application (:class:`telegram.ext.Application`): The calling application. - check_result (:class:`object`): The result from :meth:`check_update`. - context (:class:`telegram.ext.CallbackContext`): The context as provided by - the application. - - """ - self.collect_additional_context(context, update, application, check_result) - return await self.callback(update, context) - - def collect_additional_context( - self, - context: CCT, - update: UT, - application: "Application[Any, CCT, Any, Any, Any, Any]", - check_result: Any, - ) -> None: - """Prepares additional arguments for the context. Override if needed. - - Args: - context (:class:`telegram.ext.CallbackContext`): The context object. - update (:class:`telegram.Update`): The update to gather chat/user id from. - application (:class:`telegram.ext.Application`): The calling application. - check_result: The result (return value) from :meth:`check_update`. - - """ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessconnectionhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessconnectionhandler.py deleted file mode 100755 index 975bb47..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessconnectionhandler.py +++ /dev/null @@ -1,95 +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 -# -# 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 BusinessConnectionHandler class.""" -from typing import Optional, TypeVar - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - - -class BusinessConnectionHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram - :attr:`Business Connections `. - - .. versionadded:: 21.1 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only - those which are from the specified user ID(s). - - username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only - those which are from the specified username(s). - - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - """ - - __slots__ = ( - "_user_ids", - "_usernames", - ) - - def __init__( - self: "BusinessConnectionHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - user_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - self._user_ids = parse_chat_id(user_id) - self._usernames = parse_username(username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.business_connection: - if not self._user_ids and not self._usernames: - return True - if update.business_connection.user.id in self._user_ids: - return True - return update.business_connection.user.username in self._usernames - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessmessagesdeletedhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessmessagesdeletedhandler.py deleted file mode 100755 index c2df450..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessmessagesdeletedhandler.py +++ /dev/null @@ -1,95 +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 -# -# 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 BusinessMessagesDeletedHandler class.""" -from typing import Optional, TypeVar - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - - -class BusinessMessagesDeletedHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle - :attr:`deleted Telegram Business messages `. - - .. versionadded:: 21.1 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only - those which are from the specified chat ID(s). - - username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only - those which are from the specified username(s). - - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - """ - - __slots__ = ( - "_chat_ids", - "_usernames", - ) - - def __init__( - self: "BusinessMessagesDeletedHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - self._chat_ids = parse_chat_id(chat_id) - self._usernames = parse_username(username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.deleted_business_messages: - if not self._chat_ids and not self._usernames: - return True - if update.deleted_business_messages.chat.id in self._chat_ids: - return True - return update.deleted_business_messages.chat.username in self._usernames - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/callbackqueryhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/callbackqueryhandler.py deleted file mode 100755 index b09f824..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/callbackqueryhandler.py +++ /dev/null @@ -1,208 +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 -# -# 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 CallbackQueryHandler class.""" -import asyncio -import re -from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union, cast - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class CallbackQueryHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram - :attr:`callback queries `. Optionally based on a regex. - - Read the documentation of the :mod:`re` module for more information. - - Note: - * If your bot allows arbitrary objects as - :paramref:`~telegram.InlineKeyboardButton.callback_data`, it may happen that the - original :attr:`~telegram.InlineKeyboardButton.callback_data` for the incoming - :class:`telegram.CallbackQuery` can not be found. This is the case when either a - malicious client tempered with the :attr:`telegram.CallbackQuery.data` or the data was - simply dropped from cache or not persisted. In these - cases, an instance of :class:`telegram.ext.InvalidCallbackData` will be set as - :attr:`telegram.CallbackQuery.data`. - - .. versionadded:: 13.6 - - * If neither :paramref:`pattern` nor :paramref:`game_pattern` is set, `any` - ``CallbackQuery`` will be handled. If only :paramref:`pattern` is set, queries with - :attr:`~telegram.CallbackQuery.game_short_name` will `not` be considered and vice versa. - If both patterns are set, queries with either :attr: - `~telegram.CallbackQuery.game_short_name` or :attr:`~telegram.CallbackQuery.data` - matching the defined pattern will be handled - - .. versionadded:: 21.5 - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pattern (:obj:`str` | :func:`re.Pattern ` | :obj:`callable` | :obj:`type`, \ - optional): - Pattern to test :attr:`telegram.CallbackQuery.data` against. If a string or a regex - pattern is passed, :func:`re.match` is used on :attr:`telegram.CallbackQuery.data` to - determine if an update should be handled by this handler. If your bot allows arbitrary - objects as :paramref:`~telegram.InlineKeyboardButton.callback_data`, non-strings will - be accepted. To filter arbitrary objects you may pass: - - - a callable, accepting exactly one argument, namely the - :attr:`telegram.CallbackQuery.data`. It must return :obj:`True` or - :obj:`False`/:obj:`None` to indicate, whether the update should be handled. - - a :obj:`type`. If :attr:`telegram.CallbackQuery.data` is an instance of that type - (or a subclass), the update will be handled. - - If :attr:`telegram.CallbackQuery.data` is :obj:`None`, the - :class:`telegram.CallbackQuery` update will not be handled. - - .. seealso:: :wiki:`Arbitrary callback_data ` - - .. versionchanged:: 13.6 - Added support for arbitrary callback data. - game_pattern (:obj:`str` | :func:`re.Pattern ` | optional) - Pattern to test :attr:`telegram.CallbackQuery.game_short_name` against. If a string or - a regex pattern is passed, :func:`re.match` is used on - :attr:`telegram.CallbackQuery.game_short_name` to determine if an update should be - handled by this handler. - - .. versionadded:: 21.5 - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - pattern (:func:`re.Pattern ` | :obj:`callable` | :obj:`type`): Optional. - Regex pattern, callback or type to test :attr:`telegram.CallbackQuery.data` against. - - .. versionchanged:: 13.6 - Added support for arbitrary callback data. - game_pattern (:func:`re.Pattern `): Optional. - Regex pattern to test :attr:`telegram.CallbackQuery.game_short_name` - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("game_pattern", "pattern") - - def __init__( - self: "CallbackQueryHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - pattern: Optional[ - Union[str, Pattern[str], type, Callable[[object], Optional[bool]]] - ] = None, - game_pattern: Optional[Union[str, Pattern[str]]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - if callable(pattern) and asyncio.iscoroutinefunction(pattern): - raise TypeError( - "The `pattern` must not be a coroutine function! Use an ordinary function instead." - ) - if isinstance(pattern, str): - pattern = re.compile(pattern) - - if isinstance(game_pattern, str): - game_pattern = re.compile(game_pattern) - self.pattern: Optional[ - Union[str, Pattern[str], type, Callable[[object], Optional[bool]]] - ] = pattern - self.game_pattern: Optional[Union[str, Pattern[str]]] = game_pattern - - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - # pylint: disable=too-many-return-statements - if not (isinstance(update, Update) and update.callback_query): - return None - - callback_data = update.callback_query.data - game_short_name = update.callback_query.game_short_name - - if not any([self.pattern, self.game_pattern]): - return True - - # we check for .data or .game_short_name from update to filter based on whats coming - # this gives xor-like behavior - if callback_data: - if not self.pattern: - return False - if isinstance(self.pattern, type): - return isinstance(callback_data, self.pattern) - if callable(self.pattern): - return self.pattern(callback_data) - if not isinstance(callback_data, str): - return False - if match := re.match(self.pattern, callback_data): - return match - - elif game_short_name: - if not self.game_pattern: - return False - if match := re.match(self.game_pattern, game_short_name): - return match - else: - return True - return False - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Union[bool, Match[str]], - ) -> None: - """Add the result of ``re.match(pattern, update.callback_query.data)`` to - :attr:`CallbackContext.matches` as list with one element. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatboosthandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatboosthandler.py deleted file mode 100755 index 2fce8c4..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatboosthandler.py +++ /dev/null @@ -1,130 +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 -# -# 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 ChatBoostHandler class.""" - -from typing import Final, Optional - -from telegram import Update -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, RT, HandlerCallback - - -class ChatBoostHandler(BaseHandler[Update, CCT, RT]): - """ - Handler class to handle Telegram updates that contain a chat boost. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - .. versionadded:: 20.8 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - chat_boost_types (:obj:`int`, optional): Pass one of - :attr:`CHAT_BOOST`, :attr:`REMOVED_CHAT_BOOST` or - :attr:`ANY_CHAT_BOOST` to specify if this handler should handle only updates with - :attr:`telegram.Update.chat_boost`, - :attr:`telegram.Update.removed_chat_boost` or both. Defaults to - :attr:`CHAT_BOOST`. - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters reactions to allow - only those which happen in the specified chat ID(s). - chat_username (:obj:`str` | Collection[:obj:`str`], optional): Filters reactions to allow - only those which happen in the specified username(s). - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - chat_boost_types (:obj:`int`): Optional. Specifies if this handler should handle only - updates with :attr:`telegram.Update.chat_boost`, - :attr:`telegram.Update.removed_chat_boost` or both. - block (:obj:`bool`): Determines whether the callback will run in a blocking way. - """ - - __slots__ = ( - "_chat_ids", - "_chat_usernames", - "chat_boost_types", - ) - - CHAT_BOOST: Final[int] = -1 - """ :obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_boost`.""" - REMOVED_CHAT_BOOST: Final[int] = 0 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.removed_chat_boost`.""" - ANY_CHAT_BOOST: Final[int] = 1 - """:obj:`int`: Used as a constant to handle both :attr:`telegram.Update.chat_boost` - and :attr:`telegram.Update.removed_chat_boost`.""" - - def __init__( - self: "ChatBoostHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_boost_types: int = CHAT_BOOST, - chat_id: Optional[int] = None, - chat_username: Optional[str] = None, - block: bool = True, - ): - super().__init__(callback, block=block) - self.chat_boost_types: int = chat_boost_types - self._chat_ids = parse_chat_id(chat_id) - self._chat_usernames = parse_username(chat_username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return False - - if not (update.chat_boost or update.removed_chat_boost): - return False - - if self.chat_boost_types == self.CHAT_BOOST and not update.chat_boost: - return False - - if self.chat_boost_types == self.REMOVED_CHAT_BOOST and not update.removed_chat_boost: - return False - - if not any((self._chat_ids, self._chat_usernames)): - return True - - # Extract chat and user IDs and usernames from the update for comparison - chat_id = chat.id if (chat := update.effective_chat) else None - chat_username = chat.username if chat else None - - return bool(self._chat_ids and (chat_id in self._chat_ids)) or bool( - self._chat_usernames and (chat_username in self._chat_usernames) - ) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatjoinrequesthandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatjoinrequesthandler.py deleted file mode 100755 index 849020f..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatjoinrequesthandler.py +++ /dev/null @@ -1,111 +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 -# -# 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 ChatJoinRequestHandler class.""" - -from typing import Optional - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import RT, SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, HandlerCallback - - -class ChatJoinRequestHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain - :attr:`telegram.Update.chat_join_request`. - - Note: - If neither of :paramref:`username` and the :paramref:`chat_id` are passed, this handler - accepts *any* join request. Otherwise, this handler accepts all requests to join chats - for which the chat ID is listed in :paramref:`chat_id` or the username is listed in - :paramref:`username`, or both. - - .. versionadded:: 20.0 - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - .. versionadded:: 13.8 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only - those which are asking to join the specified chat ID(s). - - .. versionadded:: 20.0 - username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only - those which are asking to join the specified username(s). - - .. versionadded:: 20.0 - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - - """ - - __slots__ = ( - "_chat_ids", - "_usernames", - ) - - def __init__( - self: "ChatJoinRequestHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - self._chat_ids = parse_chat_id(chat_id) - self._usernames = parse_username(username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.chat_join_request: - if not self._chat_ids and not self._usernames: - return True - if update.chat_join_request.chat.id in self._chat_ids: - return True - return update.chat_join_request.from_user.username in self._usernames - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatmemberhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatmemberhandler.py deleted file mode 100755 index a2b281c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatmemberhandler.py +++ /dev/null @@ -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 -# -# 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 ChatMemberHandler class.""" -from typing import Final, Optional, TypeVar - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - - -class ChatMemberHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain a chat member update. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Chat Member Bot ` - - .. versionadded:: 13.4 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - chat_member_types (:obj:`int`, optional): Pass one of :attr:`MY_CHAT_MEMBER`, - :attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle - only updates with :attr:`telegram.Update.my_chat_member`, - :attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters chat member updates from - specified chat ID(s) only. - .. versionadded:: 21.3 - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - chat_member_types (:obj:`int`): Optional. Specifies if this handler should handle - only updates with :attr:`telegram.Update.my_chat_member`, - :attr:`telegram.Update.chat_member` or both. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ( - "_chat_ids", - "chat_member_types", - ) - MY_CHAT_MEMBER: Final[int] = -1 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`.""" - CHAT_MEMBER: Final[int] = 0 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_member`.""" - ANY_CHAT_MEMBER: Final[int] = 1 - """:obj:`int`: Used as a constant to handle both :attr:`telegram.Update.my_chat_member` - and :attr:`telegram.Update.chat_member`.""" - - def __init__( - self: "ChatMemberHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_member_types: int = MY_CHAT_MEMBER, - block: DVType[bool] = DEFAULT_TRUE, - chat_id: Optional[SCT[int]] = None, - ): - super().__init__(callback, block=block) - - self.chat_member_types: Optional[int] = chat_member_types - self._chat_ids = parse_chat_id(chat_id) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return False - if not (update.my_chat_member or update.chat_member): - return False - if ( - self._chat_ids - and update.effective_chat - and update.effective_chat.id not in self._chat_ids - ): - return False - if self.chat_member_types == self.ANY_CHAT_MEMBER: - return True - if self.chat_member_types == self.CHAT_MEMBER: - return bool(update.chat_member) - return bool(update.my_chat_member) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/choseninlineresulthandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/choseninlineresulthandler.py deleted file mode 100755 index 3bc80ed..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/choseninlineresulthandler.py +++ /dev/null @@ -1,122 +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 -# -# 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 ChosenInlineResultHandler class.""" -import re -from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union, cast - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - -if TYPE_CHECKING: - from telegram.ext import Application - - -class ChosenInlineResultHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain - :attr:`telegram.Update.chosen_inline_result`. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - pattern (:obj:`str` | :func:`re.Pattern `, optional): Regex pattern. If not - :obj:`None`, :func:`re.match` - is used on :attr:`telegram.ChosenInlineResult.result_id` to determine if an update - should be handled by this handler. This is accessible in the callback as - :attr:`telegram.ext.CallbackContext.matches`. - - .. versionadded:: 13.6 - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - pattern (`Pattern`): Optional. Regex pattern to test - :attr:`telegram.ChosenInlineResult.result_id` against. - - .. versionadded:: 13.6 - - """ - - __slots__ = ("pattern",) - - def __init__( - self: "ChosenInlineResultHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - pattern: Optional[Union[str, Pattern[str]]] = None, - ): - super().__init__(callback, block=block) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern: Optional[Union[str, Pattern[str]]] = pattern - - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` | :obj:`re.match` - - """ - if isinstance(update, Update) and update.chosen_inline_result: - if self.pattern: - if match := re.match(self.pattern, update.chosen_inline_result.result_id): - return match - else: - return True - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Union[bool, Match[str]], - ) -> None: - """This function adds the matched regex pattern result to - :attr:`telegram.ext.CallbackContext.matches`. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/commandhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/commandhandler.py deleted file mode 100755 index 27f7a42..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/commandhandler.py +++ /dev/null @@ -1,223 +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 -# -# 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 CommandHandler class.""" -import re -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union - -from telegram import MessageEntity, Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext import filters as filters_module -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, FilterDataDict, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class CommandHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram commands. - - Commands are Telegram messages that start with a :attr:`telegram.MessageEntity.BOT_COMMAND` - (so with ``/``, optionally followed by an ``@`` and the bot's name and/or some additional - text). The handler will add a :obj:`list` to the :class:`CallbackContext` named - :attr:`CallbackContext.args`. It will contain a list of strings, which is the text following - the command split on single or consecutive whitespace characters. - - By default, the handler listens to messages as well as edited messages. To change this behavior - use :attr:`~filters.UpdateType.EDITED_MESSAGE ` - in the filter argument. - - Note: - :class:`CommandHandler` does *not* handle (edited) channel posts and does *not* handle - commands that are part of a caption. Please use :class:`~telegram.ext.MessageHandler` - with a suitable combination of filters (e.g. - :attr:`telegram.ext.filters.UpdateType.CHANNEL_POSTS`, - :attr:`telegram.ext.filters.CAPTION` and :class:`telegram.ext.filters.Regex`) to handle - those messages. - - Note: - If you want to support a different entity in the beginning, e.g. if a command message is - wrapped in a :attr:`telegram.MessageEntity.CODE`, use the - :class:`telegram.ext.PrefixHandler`. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - * :any:`Timer Bot ` - * :any:`Error Handler Bot ` - - .. versionchanged:: 20.0 - - * Renamed the attribute ``command`` to :attr:`commands`, which now is always a - :class:`frozenset` - * Updating the commands this handler listens to is no longer possible. - - Args: - command (:obj:`str` | Collection[:obj:`str`]): - The command or list of commands this handler should listen for. Case-insensitive. - Limitations are the same as for :attr:`telegram.BotCommand.command`. - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - filters (:class:`telegram.ext.filters.BaseFilter`, optional): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :mod:`telegram.ext.filters`. Filters can be combined using bitwise - operators (``&`` for :keyword:`and`, ``|`` for :keyword:`or`, ``~`` for :keyword:`not`) - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - has_args (:obj:`bool` | :obj:`int`, optional): - Determines whether the command handler should process the update or not. - If :obj:`True`, the handler will process any non-zero number of args. - If :obj:`False`, the handler will only process if there are no args. - if :obj:`int`, the handler will only process if there are exactly that many args. - Defaults to :obj:`None`, which means the handler will process any or no args. - - .. versionadded:: 20.5 - - Raises: - :exc:`ValueError`: When the command is too long or has illegal chars. - - Attributes: - commands (frozenset[:obj:`str`]): The set of commands this handler should listen for. - callback (:term:`coroutine function`): The callback function for this handler. - filters (:class:`telegram.ext.filters.BaseFilter`): Optional. Only allow updates with these - filters. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - has_args (:obj:`bool` | :obj:`int` | None): - Optional argument, otherwise all implementations of :class:`CommandHandler` will break. - Defaults to :obj:`None`, which means the handler will process any args or no args. - - .. versionadded:: 20.5 - """ - - __slots__ = ("commands", "filters", "has_args") - - def __init__( - self: "CommandHandler[CCT, RT]", - command: SCT[str], - callback: HandlerCallback[Update, CCT, RT], - filters: Optional[filters_module.BaseFilter] = None, - block: DVType[bool] = DEFAULT_TRUE, - has_args: Optional[Union[bool, int]] = None, - ): - super().__init__(callback, block=block) - - if isinstance(command, str): - commands = frozenset({command.lower()}) - else: - commands = frozenset(x.lower() for x in command) - for comm in commands: - if not re.match(r"^[\da-z_]{1,32}$", comm): - raise ValueError(f"Command `{comm}` is not a valid bot command") - self.commands: frozenset[str] = commands - - self.filters: filters_module.BaseFilter = ( - filters if filters is not None else filters_module.UpdateType.MESSAGES - ) - - self.has_args: Optional[Union[bool, int]] = has_args - - if (isinstance(self.has_args, int)) and (self.has_args < 0): - raise ValueError("CommandHandler argument has_args cannot be a negative integer") - - def _check_correct_args(self, args: list[str]) -> Optional[bool]: - """Determines whether the args are correct for this handler. Implemented in check_update(). - Args: - args (:obj:`list`): The args for the handler. - Returns: - :obj:`bool`: Whether the args are valid for this handler. - """ - return bool( - (self.has_args is None) - or (self.has_args is True and args) - or (self.has_args is False and not args) - or (isinstance(self.has_args, int) and len(args) == self.has_args) - ) - - def check_update( - self, update: object - ) -> Optional[Union[bool, tuple[list[str], Optional[Union[bool, FilterDataDict]]]]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`list`: The list of args for the handler. - - """ - if isinstance(update, Update) and update.effective_message: - message = update.effective_message - - if ( - message.entities - and message.entities[0].type == MessageEntity.BOT_COMMAND - and message.entities[0].offset == 0 - and message.text - and message.get_bot() - ): - command = message.text[1 : message.entities[0].length] - args = message.text.split()[1:] - command_parts = command.split("@") - command_parts.append(message.get_bot().username) - - if not ( - command_parts[0].lower() in self.commands - and command_parts[1].lower() == message.get_bot().username.lower() - ): - return None - - if not self._check_correct_args(args): - return None - - filter_result = self.filters.check_update(update) - if filter_result: - return args, filter_result - return False - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Union[bool, tuple[list[str], Optional[bool]]]], - ) -> None: - """Add text after the command to :attr:`CallbackContext.args` as list, split on single - whitespaces and add output of data filters to :attr:`CallbackContext` as well. - """ - if isinstance(check_result, tuple): - context.args = check_result[0] - if isinstance(check_result[1], dict): - context.update(check_result[1]) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/conversationhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/conversationhandler.py deleted file mode 100755 index 1bc5f03..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/conversationhandler.py +++ /dev/null @@ -1,958 +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 -# -# 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 ConversationHandler.""" -import asyncio -import datetime as dtm -from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Final, Generic, NoReturn, Optional, Union, cast - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE, DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import DVType -from telegram._utils.warnings import warn -from telegram.ext._application import ApplicationHandlerStop -from telegram.ext._extbot import ExtBot -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._handlers.callbackqueryhandler import CallbackQueryHandler -from telegram.ext._handlers.choseninlineresulthandler import ChosenInlineResultHandler -from telegram.ext._handlers.inlinequeryhandler import InlineQueryHandler -from telegram.ext._handlers.stringcommandhandler import StringCommandHandler -from telegram.ext._handlers.stringregexhandler import StringRegexHandler -from telegram.ext._handlers.typehandler import TypeHandler -from telegram.ext._utils.trackingdict import TrackingDict -from telegram.ext._utils.types import CCT, ConversationDict, ConversationKey - -if TYPE_CHECKING: - from telegram.ext import Application, Job, JobQueue -_CheckUpdateType = tuple[object, ConversationKey, BaseHandler[Update, CCT, object], object] - -_LOGGER = get_logger(__name__, class_name="ConversationHandler") - - -@dataclass -class _ConversationTimeoutContext(Generic[CCT]): - """Used as a datastore for conversation timeouts. Passed in the - :paramref:`JobQueue.run_once.data` parameter. See :meth:`_trigger_timeout`. - """ - - __slots__ = ("application", "callback_context", "conversation_key", "update") - - conversation_key: ConversationKey - update: Update - application: "Application[Any, CCT, Any, Any, Any, JobQueue]" - callback_context: CCT - - -@dataclass -class PendingState: - """Thin wrapper around :class:`asyncio.Task` to handle block=False handlers. Note that this is - a public class of this module, since :meth:`Application.update_persistence` needs to access it. - It's still hidden from users, since this module itself is private. - """ - - __slots__ = ("old_state", "task") - - task: asyncio.Task - old_state: object - - def done(self) -> bool: - return self.task.done() - - def resolve(self) -> object: - """Returns the new state of the :class:`ConversationHandler` if available. If there was an - exception during the task execution, then return the old state. If both the new and old - state are :obj:`None`, return `CH.END`. If only the new state is :obj:`None`, return the - old state. - - Raises: - :exc:`RuntimeError`: If the current task has not yet finished. - """ - if not self.task.done(): - raise RuntimeError("New state is not yet available") - - exc = self.task.exception() - if exc: - _LOGGER.exception( - "Task function raised exception. Falling back to old state %s", - self.old_state, - ) - return self.old_state - - res = self.task.result() - if res is None and self.old_state is None: - res = ConversationHandler.END - elif res is None: - # returning None from a callback means that we want to stay in the old state - return self.old_state - - return res - - -class ConversationHandler(BaseHandler[Update, CCT, object]): - """ - A handler to hold a conversation with a single or multiple users through Telegram updates by - managing three collections of other handlers. - - Warning: - :class:`ConversationHandler` heavily relies on incoming updates being processed one by one. - When using this handler, :attr:`telegram.ext.ApplicationBuilder.concurrent_updates` should - be set to :obj:`False`. - - Note: - :class:`ConversationHandler` will only accept updates that are (subclass-)instances of - :class:`telegram.Update`. This is, because depending on the :attr:`per_user` and - :attr:`per_chat`, :class:`ConversationHandler` relies on - :attr:`telegram.Update.effective_user` and/or :attr:`telegram.Update.effective_chat` in - order to determine which conversation an update should belong to. For - :attr:`per_message=True `, :class:`ConversationHandler` uses - :attr:`update.callback_query.message.message_id ` when - :attr:`per_chat=True ` and - :attr:`update.callback_query.inline_message_id <.CallbackQuery.inline_message_id>` when - :attr:`per_chat=False `. For a more detailed explanation, please see our `FAQ`_. - - Finally, :class:`ConversationHandler`, does *not* handle (edited) channel posts. - - .. _`FAQ`: https://github.com/python-telegram-bot/python-telegram-bot/wiki\ - /Frequently-Asked-Questions#what-do-the-per_-settings-in-conversation handler-do - - The first collection, a :obj:`list` named :attr:`entry_points`, is used to initiate the - conversation, for example with a :class:`telegram.ext.CommandHandler` or - :class:`telegram.ext.MessageHandler`. - - The second collection, a :obj:`dict` named :attr:`states`, contains the different conversation - steps and one or more associated handlers that should be used if the user sends a message when - the conversation with them is currently in that state. Here you can also define a state for - :attr:`TIMEOUT` to define the behavior when :attr:`conversation_timeout` is exceeded, and a - state for :attr:`WAITING` to define behavior when a new update is received while the previous - :attr:`block=False ` handler is not finished. - - The third collection, a :obj:`list` named :attr:`fallbacks`, is used if the user is currently - in a conversation but the state has either no associated handler or the handler that is - associated to the state is inappropriate for the update, for example if the update contains a - command, but a regular text message is expected. You could use this for a ``/cancel`` command - or to let the user know their message was not recognized. - - To change the state of conversation, the callback function of a handler must return the new - state after responding to the user. If it does not return anything (returning :obj:`None` by - default), the state will not change. If an entry point callback function returns :obj:`None`, - the conversation ends immediately after the execution of this callback function. - To end the conversation, the callback function must return :attr:`END` or ``-1``. To - handle the conversation timeout, use handler :attr:`TIMEOUT` or ``-2``. - Finally, :class:`telegram.ext.ApplicationHandlerStop` can be used in conversations as described - in its documentation. - - Note: - In each of the described collections of handlers, a handler may in turn be a - :class:`ConversationHandler`. In that case, the child :class:`ConversationHandler` should - have the attribute :attr:`map_to_parent` which allows returning to the parent conversation - at specified states within the child conversation. - - Note that the keys in :attr:`map_to_parent` must not appear as keys in :attr:`states` - attribute or else the latter will be ignored. You may map :attr:`END` to one of the parents - states to continue the parent conversation after the child conversation has ended or even - map a state to :attr:`END` to end the *parent* conversation from within the child - conversation. For an example on nested :class:`ConversationHandler` s, see - :any:`examples.nestedconversationbot`. - - Examples: - * :any:`Conversation Bot ` - * :any:`Conversation Bot 2 ` - * :any:`Nested Conversation Bot ` - * :any:`Persistent Conversation Bot ` - - Args: - entry_points (list[:class:`telegram.ext.BaseHandler`]): A list of :obj:`BaseHandler` - objects that - can trigger the start of the conversation. The first handler whose :meth:`check_update` - method returns :obj:`True` will be used. If all return :obj:`False`, the update is not - handled. - states (dict[:obj:`object`, list[:class:`telegram.ext.BaseHandler`]]): A :obj:`dict` that - defines the different states of conversation a user can be in and one or more - associated :obj:`BaseHandler` objects that should be used in that state. The first - handler whose :meth:`check_update` method returns :obj:`True` will be used. - fallbacks (list[:class:`telegram.ext.BaseHandler`]): A list of handlers that might be used - if the user is in a conversation, but every handler for their current state returned - :obj:`False` on :meth:`check_update`. The first handler which :meth:`check_update` - method returns :obj:`True` will be used. If all return :obj:`False`, the update is not - handled. - allow_reentry (:obj:`bool`, optional): If set to :obj:`True`, a user that is currently in a - conversation can restart the conversation by triggering one of the entry points. - Default is :obj:`False`. - per_chat (:obj:`bool`, optional): If the conversation key should contain the Chat's ID. - Default is :obj:`True`. - per_user (:obj:`bool`, optional): If the conversation key should contain the User's ID. - Default is :obj:`True`. - per_message (:obj:`bool`, optional): If the conversation key should contain the Message's - ID. Default is :obj:`False`. - conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`, optional): When this - handler is inactive more than this timeout (in seconds), it will be automatically - ended. If this value is ``0`` or :obj:`None` (default), there will be no timeout. The - last received update and the corresponding :class:`context <.CallbackContext>` will be - handled by *ALL* the handler's whose :meth:`check_update` method returns :obj:`True` - that are in the state :attr:`ConversationHandler.TIMEOUT`. - - Caution: - * This feature relies on the :attr:`telegram.ext.Application.job_queue` being set - and hence requires that the dependencies that :class:`telegram.ext.JobQueue` - relies on are installed. - * Using :paramref:`conversation_timeout` with nested conversations is currently - not supported. You can still try to use it, but it will likely behave - differently from what you expect. - - name (:obj:`str`, optional): The name for this conversation handler. Required for - persistence. - persistent (:obj:`bool`, optional): If the conversation's dict for this handler should be - saved. :paramref:`name` is required and persistence has to be set in - :attr:`Application <.Application.persistence>`. - - .. versionchanged:: 20.0 - Was previously named as ``persistence``. - map_to_parent (dict[:obj:`object`, :obj:`object`], optional): A :obj:`dict` that can be - used to instruct a child conversation handler to transition into a mapped state on - its parent conversation handler in place of a specified nested state. - block (:obj:`bool`, optional): Pass :obj:`False` or :obj:`True` to set a default value for - the :attr:`BaseHandler.block` setting of all handlers (in :attr:`entry_points`, - :attr:`states` and :attr:`fallbacks`). The resolution order for checking if a handler - should be run non-blocking is: - - 1. :attr:`telegram.ext.BaseHandler.block` (if set) - 2. the value passed to this parameter (if any) - 3. :attr:`telegram.ext.Defaults.block` (if defaults are used) - - .. seealso:: :wiki:`Concurrency` - - .. versionchanged:: 20.0 - No longer overrides the handlers settings. Resolution order was changed. - - Raises: - :exc:`ValueError`: If :paramref:`persistent` is used but :paramref:`name` was not set, or - when :attr:`per_message`, :attr:`per_chat`, :attr:`per_user` are all :obj:`False`. - - Attributes: - block (:obj:`bool`): Determines whether the callback will run in a blocking way. Always - :obj:`True` since conversation handlers handle any non-blocking callbacks internally. - - """ - - __slots__ = ( - "_allow_reentry", - "_block", - "_child_conversations", - "_conversation_timeout", - "_conversations", - "_entry_points", - "_fallbacks", - "_map_to_parent", - "_name", - "_per_chat", - "_per_message", - "_per_user", - "_persistent", - "_states", - "_timeout_jobs_lock", - "timeout_jobs", - ) - - END: Final[int] = -1 - """:obj:`int`: Used as a constant to return when a conversation is ended.""" - TIMEOUT: Final[int] = -2 - """:obj:`int`: Used as a constant to handle state when a conversation is timed out - (exceeded :attr:`conversation_timeout`). - """ - WAITING: Final[int] = -3 - """:obj:`int`: Used as a constant to handle state when a conversation is still waiting on the - previous :attr:`block=False ` handler to finish.""" - - # pylint: disable=super-init-not-called - def __init__( - self: "ConversationHandler[CCT]", - entry_points: list[BaseHandler[Update, CCT, object]], - states: dict[object, list[BaseHandler[Update, CCT, object]]], - fallbacks: list[BaseHandler[Update, CCT, object]], - allow_reentry: bool = False, - per_chat: bool = True, - per_user: bool = True, - per_message: bool = False, - conversation_timeout: Optional[Union[float, dtm.timedelta]] = None, - name: Optional[str] = None, - persistent: bool = False, - map_to_parent: Optional[dict[object, object]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - # these imports need to be here because of circular import error otherwise - from telegram.ext import ( # pylint: disable=import-outside-toplevel - PollAnswerHandler, - PollHandler, - PreCheckoutQueryHandler, - ShippingQueryHandler, - ) - - # self.block is what the Application checks and we want it to always run CH in a blocking - # way so that CH can take care of any non-blocking logic internally - self.block: DVType[bool] = True - # Store the actual setting in a protected variable instead - self._block: DVType[bool] = block - - self._entry_points: list[BaseHandler[Update, CCT, object]] = entry_points - self._states: dict[object, list[BaseHandler[Update, CCT, object]]] = states - self._fallbacks: list[BaseHandler[Update, CCT, object]] = fallbacks - - self._allow_reentry: bool = allow_reentry - self._per_user: bool = per_user - self._per_chat: bool = per_chat - self._per_message: bool = per_message - self._conversation_timeout: Optional[Union[float, dtm.timedelta]] = conversation_timeout - self._name: Optional[str] = name - self._map_to_parent: Optional[dict[object, object]] = map_to_parent - - # if conversation_timeout is used, this dict is used to schedule a job which runs when the - # conv has timed out. - self.timeout_jobs: dict[ConversationKey, Job[Any]] = {} - self._timeout_jobs_lock = asyncio.Lock() - self._conversations: ConversationDict = {} - self._child_conversations: set[ConversationHandler] = set() - - if persistent and not self.name: - raise ValueError("Conversations can't be persistent when handler is unnamed.") - self._persistent: bool = persistent - - if not any((self.per_user, self.per_chat, self.per_message)): - raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'") - - if self.per_message and not self.per_chat: - warn( - "If 'per_message=True' is used, 'per_chat=True' should also be used, " - "since message IDs are not globally unique.", - stacklevel=2, - ) - - all_handlers: list[BaseHandler[Update, CCT, object]] = [] - all_handlers.extend(entry_points) - all_handlers.extend(fallbacks) - - for state_handlers in states.values(): - all_handlers.extend(state_handlers) - - self._child_conversations.update( - handler for handler in all_handlers if isinstance(handler, ConversationHandler) - ) - - # this link will be added to all warnings tied to per_* setting - per_faq_link = ( - " Read this FAQ entry to learn more about the per_* settings: " - "https://github.com/python-telegram-bot/python-telegram-bot/wiki" - "/Frequently-Asked-Questions#what-do-the-per_-settings-in-conversationhandler-do." - ) - - # this loop is going to warn the user about handlers which can work unexpectedly - # in conversations - for handler in all_handlers: - if isinstance(handler, (StringCommandHandler, StringRegexHandler)): - warn( - "The `ConversationHandler` only handles updates of type `telegram.Update`. " - f"{handler.__class__.__name__} handles updates of type `str`.", - stacklevel=2, - ) - elif isinstance(handler, TypeHandler) and not issubclass(handler.type, Update): - warn( - "The `ConversationHandler` only handles updates of type `telegram.Update`." - f" The TypeHandler is set to handle {handler.type.__name__}.", - stacklevel=2, - ) - elif isinstance(handler, PollHandler): - warn( - "PollHandler will never trigger in a conversation since it has no information " - "about the chat or the user who voted in it. Do you mean the " - "`PollAnswerHandler`?", - stacklevel=2, - ) - - elif self.per_chat and ( - isinstance( - handler, - ( - ShippingQueryHandler, - InlineQueryHandler, - ChosenInlineResultHandler, - PreCheckoutQueryHandler, - PollAnswerHandler, - ), - ) - ): - warn( - f"Updates handled by {handler.__class__.__name__} only have information about " - "the user, so this handler won't ever be triggered if `per_chat=True`." - f"{per_faq_link}", - stacklevel=2, - ) - - elif self.per_message and not isinstance(handler, CallbackQueryHandler): - warn( - "If 'per_message=True', all entry points, state handlers, and fallbacks" - " must be 'CallbackQueryHandler', since no other handlers " - f"have a message context.{per_faq_link}", - stacklevel=2, - ) - elif not self.per_message and isinstance(handler, CallbackQueryHandler): - warn( - "If 'per_message=False', 'CallbackQueryHandler' will not be " - f"tracked for every message.{per_faq_link}", - stacklevel=2, - ) - - if self.conversation_timeout and isinstance(handler, self.__class__): - warn( - "Using `conversation_timeout` with nested conversations is currently not " - "supported. You can still try to use it, but it will likely behave " - "differently from what you expect.", - stacklevel=2, - ) - - def __repr__(self) -> str: - """Give a string representation of the ConversationHandler in the form - ``ConversationHandler[name=..., states={...}]``. - - If there are more than 3 states, only the first 3 states are listed. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - truncation_threshold = 3 - states = dict(list(self.states.items())[:truncation_threshold]) - states_string = str(states) - if len(self.states) > truncation_threshold: - states_string = states_string[:-1] + ", ...}" - - return build_repr_with_selected_attrs( - self, - name=self.name, - states=states_string, - ) - - @property - def entry_points(self) -> list[BaseHandler[Update, CCT, object]]: - """list[:class:`telegram.ext.BaseHandler`]: A list of :obj:`BaseHandler` objects that can - trigger the start of the conversation. - """ - return self._entry_points - - @entry_points.setter - def entry_points(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to entry_points after initialization." - ) - - @property - def states(self) -> dict[object, list[BaseHandler[Update, CCT, object]]]: - """dict[:obj:`object`, list[:class:`telegram.ext.BaseHandler`]]: A :obj:`dict` that - defines the different states of conversation a user can be in and one or more - associated :obj:`BaseHandler` objects that should be used in that state. - """ - return self._states - - @states.setter - def states(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to states after initialization.") - - @property - def fallbacks(self) -> list[BaseHandler[Update, CCT, object]]: - """list[:class:`telegram.ext.BaseHandler`]: A list of handlers that might be used if - the user is in a conversation, but every handler for their current state returned - :obj:`False` on :meth:`check_update`. - """ - return self._fallbacks - - @fallbacks.setter - def fallbacks(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to fallbacks after initialization.") - - @property - def allow_reentry(self) -> bool: - """:obj:`bool`: Determines if a user can restart a conversation with an entry point.""" - return self._allow_reentry - - @allow_reentry.setter - def allow_reentry(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to allow_reentry after initialization." - ) - - @property - def per_user(self) -> bool: - """:obj:`bool`: If the conversation key should contain the User's ID.""" - return self._per_user - - @per_user.setter - def per_user(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to per_user after initialization.") - - @property - def per_chat(self) -> bool: - """:obj:`bool`: If the conversation key should contain the Chat's ID.""" - return self._per_chat - - @per_chat.setter - def per_chat(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to per_chat after initialization.") - - @property - def per_message(self) -> bool: - """:obj:`bool`: If the conversation key should contain the message's ID.""" - return self._per_message - - @per_message.setter - def per_message(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to per_message after initialization.") - - @property - def conversation_timeout( - self, - ) -> Optional[Union[float, dtm.timedelta]]: - """:obj:`float` | :obj:`datetime.timedelta`: Optional. When this - handler is inactive more than this timeout (in seconds), it will be automatically - ended. - """ - return self._conversation_timeout - - @conversation_timeout.setter - def conversation_timeout(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to conversation_timeout after initialization." - ) - - @property - def name(self) -> Optional[str]: - """:obj:`str`: Optional. The name for this :class:`ConversationHandler`.""" - return self._name - - @name.setter - def name(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to name after initialization.") - - @property - def persistent(self) -> bool: - """:obj:`bool`: Optional. If the conversations dict for this handler should be - saved. :attr:`name` is required and persistence has to be set in - :attr:`Application <.Application.persistence>`. - """ - return self._persistent - - @persistent.setter - def persistent(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to persistent after initialization.") - - @property - def map_to_parent(self) -> Optional[dict[object, object]]: - """dict[:obj:`object`, :obj:`object`]: Optional. A :obj:`dict` that can be - used to instruct a nested :class:`ConversationHandler` to transition into a mapped state on - its parent :class:`ConversationHandler` in place of a specified nested state. - """ - return self._map_to_parent - - @map_to_parent.setter - def map_to_parent(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to map_to_parent after initialization." - ) - - async def _initialize_persistence( - self, application: "Application" - ) -> dict[str, TrackingDict[ConversationKey, object]]: - """Initializes the persistence for this handler and its child conversations. - While this method is marked as protected, we expect it to be called by the - Application/parent conversations. It's just protected to hide it from users. - - Args: - application (:class:`telegram.ext.Application`): The application. - - Returns: - A dict {conversation.name -> TrackingDict}, which contains all dict of this - conversation and possible child conversations. - - """ - if not (self.persistent and self.name and application.persistence): - raise RuntimeError( - "This handler is not persistent, has no name or the application has no " - "persistence!" - ) - - current_conversations = self._conversations - self._conversations = cast( - TrackingDict[ConversationKey, object], - TrackingDict(), - ) - # In the conversation already processed updates - self._conversations.update(current_conversations) - # above might be partly overridden but that's okay since we warn about that in - # add_handler - stored_data = await application.persistence.get_conversations(self.name) - self._conversations.update_no_track(stored_data) - - # Since CH.END is stored as normal state, we need to properly parse it here in order to - # actually end the conversation, i.e. delete the key from the _conversations dict - # This also makes sure that these entries are deleted from the persisted data on the next - # run of Application.update_persistence - for key, state in stored_data.items(): - if state == self.END: - self._update_state(new_state=self.END, key=key) - - out = {self.name: self._conversations} - - for handler in self._child_conversations: - out.update( - await handler._initialize_persistence( # pylint: disable=protected-access - application=application - ) - ) - - return out - - def _get_key(self, update: Update) -> ConversationKey: - """Builds the conversation key associated with the update.""" - chat = update.effective_chat - user = update.effective_user - - key: list[Union[int, str]] = [] - - if self.per_chat: - if chat is None: - raise RuntimeError("Can't build key for update without effective chat!") - key.append(chat.id) - - if self.per_user: - if user is None: - raise RuntimeError("Can't build key for update without effective user!") - key.append(user.id) - - if self.per_message: - if update.callback_query is None: - raise RuntimeError("Can't build key for update without CallbackQuery!") - if update.callback_query.inline_message_id: - key.append(update.callback_query.inline_message_id) - else: - key.append(update.callback_query.message.message_id) # type: ignore[union-attr] - - return tuple(key) - - async def _schedule_job_delayed( - self, - new_state: asyncio.Task, - application: "Application[Any, CCT, Any, Any, Any, JobQueue]", - update: Update, - context: CCT, - conversation_key: ConversationKey, - ) -> None: - try: - effective_new_state = await new_state - except Exception as exc: - _LOGGER.debug( - "Non-blocking handler callback raised exception. Not scheduling conversation " - "timeout.", - exc_info=exc, - ) - return None - return self._schedule_job( - new_state=effective_new_state, - application=application, - update=update, - context=context, - conversation_key=conversation_key, - ) - - def _schedule_job( - self, - new_state: object, - application: "Application[Any, CCT, Any, Any, Any, JobQueue]", - update: Update, - context: CCT, - conversation_key: ConversationKey, - ) -> None: - """Schedules a job which executes :meth:`_trigger_timeout` upon conversation timeout.""" - if new_state == self.END: - return - - try: - # both job_queue & conversation_timeout are checked before calling _schedule_job - j_queue = application.job_queue - self.timeout_jobs[conversation_key] = j_queue.run_once( # type: ignore[union-attr] - self._trigger_timeout, - self.conversation_timeout, # type: ignore[arg-type] - data=_ConversationTimeoutContext(conversation_key, update, application, context), - ) - except Exception as exc: - _LOGGER.exception("Failed to schedule timeout.", exc_info=exc) - - # pylint: disable=too-many-return-statements - def check_update(self, update: object) -> Optional[_CheckUpdateType[CCT]]: - """ - Determines whether an update should be handled by this conversation handler, and if so in - which state the conversation currently is. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return None - # Ignore messages in channels - if update.channel_post or update.edited_channel_post: - return None - if self.per_chat and not update.effective_chat: - return None - if self.per_user and not update.effective_user: - return None - if self.per_message and not update.callback_query: - return None - if update.callback_query and self.per_chat and not update.callback_query.message: - return None - - key = self._get_key(update) - state = self._conversations.get(key) - check: Optional[object] = None - - # Resolve futures - if isinstance(state, PendingState): - _LOGGER.debug("Waiting for asyncio Task to finish ...") - - # check if future is finished or not - if state.done(): - res = state.resolve() - # Special case if an error was raised in a non-blocking entry-point - if state.old_state is None and state.task.exception(): - self._conversations.pop(key, None) - state = None - else: - self._update_state(res, key) - state = self._conversations.get(key) - - # if not then handle WAITING state instead - else: - handlers = self.states.get(self.WAITING, []) - for handler_ in handlers: - check = handler_.check_update(update) - if check is not None and check is not False: - return self.WAITING, key, handler_, check - return None - - _LOGGER.debug("Selecting conversation %s with state %s", str(key), str(state)) - - handler: Optional[BaseHandler] = None - - # Search entry points for a match - if state is None or self.allow_reentry: - for entry_point in self.entry_points: - check = entry_point.check_update(update) - if check is not None and check is not False: - handler = entry_point - break - - else: - if state is None: - return None - - # Get the handler list for current state, if we didn't find one yet and we're still here - if state is not None and handler is None: - for candidate in self.states.get(state, []): - check = candidate.check_update(update) - if check is not None and check is not False: - handler = candidate - break - - # Find a fallback handler if all other handlers fail - else: - for fallback in self.fallbacks: - check = fallback.check_update(update) - if check is not None and check is not False: - handler = fallback - break - - else: - return None - - return state, key, handler, check # type: ignore[return-value] - - async def handle_update( # type: ignore[override] - self, - update: Update, - application: "Application[Any, CCT, Any, Any, Any, Any]", - check_result: _CheckUpdateType[CCT], - context: CCT, - ) -> Optional[object]: - """Send the update to the callback for the current state and BaseHandler - - Args: - check_result: The result from :meth:`check_update`. For this handler it's a tuple of - the conversation state, key, handler, and the handler's check result. - update (:class:`telegram.Update`): Incoming telegram update. - application (:class:`telegram.ext.Application`): Application that originated the - update. - context (:class:`telegram.ext.CallbackContext`): The context as provided by - the application. - - """ - current_state, conversation_key, handler, handler_check_result = check_result - raise_dp_handler_stop = False - - async with self._timeout_jobs_lock: - # Remove the old timeout job (if present) - timeout_job = self.timeout_jobs.pop(conversation_key, None) - - if timeout_job is not None: - timeout_job.schedule_removal() - - # Resolution order of "block": - # 1. Setting of the selected handler - # 2. Setting of the ConversationHandler - # 3. Default values of the bot - if handler.block is not DEFAULT_TRUE: - block = handler.block - elif self._block is not DEFAULT_TRUE: - block = self._block - elif isinstance(application.bot, ExtBot) and application.bot.defaults is not None: - block = application.bot.defaults.block - else: - block = DefaultValue.get_value(handler.block) - - try: # Now create task or await the callback - if block: - new_state: object = await handler.handle_update( - update, application, handler_check_result, context - ) - else: - new_state = application.create_task( - coroutine=handler.handle_update( - update, application, handler_check_result, context - ), - update=update, - name=f"ConversationHandler:{update.update_id}:handle_update:non_blocking_cb", - ) - except ApplicationHandlerStop as exception: - new_state = exception.state - raise_dp_handler_stop = True - async with self._timeout_jobs_lock: - if self.conversation_timeout: - if application.job_queue is None: - warn( - "Ignoring `conversation_timeout` because the Application has no JobQueue.", - stacklevel=1, - ) - elif not application.job_queue.scheduler.running: - warn( - "Ignoring `conversation_timeout` because the Applications JobQueue is " - "not running.", - stacklevel=1, - ) - elif isinstance(new_state, asyncio.Task): - # Add the new timeout job - # checking if the new state is self.END is done in _schedule_job - application.create_task( - self._schedule_job_delayed( - new_state, application, update, context, conversation_key - ), - update=update, - name=f"ConversationHandler:{update.update_id}:handle_update:timeout_job", - ) - else: - self._schedule_job(new_state, application, update, context, conversation_key) - - if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent: - self._update_state(self.END, conversation_key, handler) - if raise_dp_handler_stop: - raise ApplicationHandlerStop(self.map_to_parent.get(new_state)) - return self.map_to_parent.get(new_state) - - if current_state != self.WAITING: - self._update_state(new_state, conversation_key, handler) - - if raise_dp_handler_stop: - # Don't pass the new state here. If we're in a nested conversation, the parent is - # expecting None as return value. - raise ApplicationHandlerStop - # Signals a possible parent conversation to stay in the current state - return None - - def _update_state( - self, new_state: object, key: ConversationKey, handler: Optional[BaseHandler] = None - ) -> None: - if new_state == self.END: - if key in self._conversations: - # If there is no key in conversations, nothing is done. - del self._conversations[key] - - elif isinstance(new_state, asyncio.Task): - self._conversations[key] = PendingState( - old_state=self._conversations.get(key), task=new_state - ) - - elif new_state is not None: - if new_state not in self.states: - warn( - f"{repr(handler.callback.__name__) if handler is not None else 'BaseHandler'} " - f"returned state {new_state} which is unknown to the " - f"ConversationHandler{' ' + self.name if self.name is not None else ''}.", - stacklevel=2, - ) - self._conversations[key] = new_state - - async def _trigger_timeout(self, context: CCT) -> None: - """This is run whenever a conversation has timed out. Also makes sure that all handlers - which are in the :attr:`TIMEOUT` state and whose :meth:`BaseHandler.check_update` returns - :obj:`True` is handled. - """ - job = cast("Job", context.job) - ctxt = cast(_ConversationTimeoutContext, job.data) - - _LOGGER.debug( - "Conversation timeout was triggered for conversation %s!", ctxt.conversation_key - ) - - callback_context = ctxt.callback_context - - async with self._timeout_jobs_lock: - found_job = self.timeout_jobs.get(ctxt.conversation_key) - if found_job is not job: - # The timeout has been cancelled in handle_update - return - del self.timeout_jobs[ctxt.conversation_key] - - # Now run all handlers which are in TIMEOUT state - handlers = self.states.get(self.TIMEOUT, []) - for handler in handlers: - check = handler.check_update(ctxt.update) - if check is not None and check is not False: - try: - await handler.handle_update( - ctxt.update, ctxt.application, check, callback_context - ) - except ApplicationHandlerStop: - warn( - "ApplicationHandlerStop in TIMEOUT state of " - "ConversationHandler has no effect. Ignoring.", - stacklevel=2, - ) - - self._update_state(self.END, ctxt.conversation_key) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/inlinequeryhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/inlinequeryhandler.py deleted file mode 100755 index 31106ba..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/inlinequeryhandler.py +++ /dev/null @@ -1,143 +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 -# -# 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 InlineQueryHandler class.""" -import re -from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union, cast - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class InlineQueryHandler(BaseHandler[Update, CCT, RT]): - """ - BaseHandler class to handle Telegram updates that contain a - :attr:`telegram.Update.inline_query`. - Optionally based on a regex. Read the documentation of the :mod:`re` module for more - information. - - Warning: - * When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - * :attr:`telegram.InlineQuery.chat_type` will not be set for inline queries from secret - chats and may not be set for inline queries coming from third-party clients. These - updates won't be handled, if :attr:`chat_types` is passed. - - Examples: - :any:`Inline Bot ` - - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pattern (:obj:`str` | :func:`re.Pattern `, optional): Regex pattern. - If not :obj:`None`, :func:`re.match` is used on :attr:`telegram.InlineQuery.query` - to determine if an update should be handled by this handler. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - chat_types (list[:obj:`str`], optional): List of allowed chat types. If passed, will only - handle inline queries with the appropriate :attr:`telegram.InlineQuery.chat_type`. - - .. versionadded:: 13.5 - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - pattern (:obj:`str` | :func:`re.Pattern `): Optional. Regex pattern to test - :attr:`telegram.InlineQuery.query` against. - chat_types (list[:obj:`str`]): Optional. List of allowed chat types. - - .. versionadded:: 13.5 - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("chat_types", "pattern") - - def __init__( - self: "InlineQueryHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - pattern: Optional[Union[str, Pattern[str]]] = None, - block: DVType[bool] = DEFAULT_TRUE, - chat_types: Optional[list[str]] = None, - ): - super().__init__(callback, block=block) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern: Optional[Union[str, Pattern[str]]] = pattern - self.chat_types: Optional[list[str]] = chat_types - - def check_update(self, update: object) -> Optional[Union[bool, Match[str]]]: - """ - Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` | :obj:`re.match` - - """ - if isinstance(update, Update) and update.inline_query: - if (self.chat_types is not None) and ( - update.inline_query.chat_type not in self.chat_types - ): - return False - if ( - self.pattern - and update.inline_query.query - and (match := re.match(self.pattern, update.inline_query.query)) - ): - return match - if not self.pattern: - return True - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Union[bool, Match[str]]], - ) -> None: - """Add the result of ``re.match(pattern, update.inline_query.query)`` to - :attr:`CallbackContext.matches` as list with one element. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagehandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagehandler.py deleted file mode 100755 index 625531a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagehandler.py +++ /dev/null @@ -1,111 +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 -# -# 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 MessageHandler class.""" -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext import filters as filters_module -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class MessageHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram messages. They might contain text, media or status - updates. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - filters (:class:`telegram.ext.filters.BaseFilter`): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :mod:`telegram.ext.filters`. Filters can be combined using bitwise - operators (& for and, | for or, ~ for not). Passing :obj:`None` is a shortcut - to passing :class:`telegram.ext.filters.ALL`. - - .. seealso:: :wiki:`Advanced Filters ` - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - filters (:class:`telegram.ext.filters.BaseFilter`): Only allow updates with these Filters. - See :mod:`telegram.ext.filters` for a full list of all available filters. - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("filters",) - - def __init__( - self: "MessageHandler[CCT, RT]", - filters: Optional[filters_module.BaseFilter], - callback: HandlerCallback[Update, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - self.filters: filters_module.BaseFilter = ( - filters if filters is not None else filters_module.ALL - ) - - def check_update(self, update: object) -> Optional[Union[bool, dict[str, list[Any]]]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update): - return self.filters.check_update(update) or False - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Union[bool, dict[str, object]]], - ) -> None: - """Adds possible output of data filters to the :class:`CallbackContext`.""" - if isinstance(check_result, dict): - context.update(check_result) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagereactionhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagereactionhandler.py deleted file mode 100755 index 15f4f3d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagereactionhandler.py +++ /dev/null @@ -1,180 +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 -# -# 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 MessageReactionHandler class.""" - -from typing import Final, Optional - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import RT, SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, HandlerCallback - - -class MessageReactionHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain a message reaction. - - Note: - The following rules apply to both ``username`` and the ``chat_id`` param groups, - respectively: - - * If none of them are passed, the handler does not filter the update for that specific - attribute. - * If a chat ID **or** a username is passed, the updates will be filtered with that - specific attribute. - * If a chat ID **and** a username are passed, an update containing **any** of them will be - filtered. - * :attr:`telegram.MessageReactionUpdated.actor_chat` is *not* considered for - :paramref:`user_id` and :paramref:`user_username` filtering. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - .. versionadded:: 20.8 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - message_reaction_types (:obj:`int`, optional): Pass one of - :attr:`MESSAGE_REACTION_UPDATED`, :attr:`MESSAGE_REACTION_COUNT_UPDATED` or - :attr:`MESSAGE_REACTION` to specify if this handler should handle only updates with - :attr:`telegram.Update.message_reaction`, - :attr:`telegram.Update.message_reaction_count` or both. Defaults to - :attr:`MESSAGE_REACTION`. - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters reactions to allow - only those which happen in the specified chat ID(s). - chat_username (:obj:`str` | Collection[:obj:`str`], optional): Filters reactions to allow - only those which happen in the specified username(s). - user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters reactions to allow - only those which are set by the specified chat ID(s) (this can be the chat itself in - the case of anonymous users, see the - :paramref:`telegram.MessageReactionUpdated.actor_chat`). - user_username (:obj:`str` | Collection[:obj:`str`], optional): Filters reactions to allow - only those which are set by the specified username(s) (this can be the chat itself in - the case of anonymous users, see the - :paramref:`telegram.MessageReactionUpdated.actor_chat`). - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - message_reaction_types (:obj:`int`): Optional. Specifies if this handler should handle only - updates with :attr:`telegram.Update.message_reaction`, - :attr:`telegram.Update.message_reaction_count` or both. - block (:obj:`bool`): Determines whether the callback will run in a blocking way. - - """ - - __slots__ = ( - "_chat_ids", - "_chat_usernames", - "_user_ids", - "_user_usernames", - "message_reaction_types", - ) - - MESSAGE_REACTION_UPDATED: Final[int] = -1 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.message_reaction`.""" - MESSAGE_REACTION_COUNT_UPDATED: Final[int] = 0 - """:obj:`int`: Used as a constant to handle only - :attr:`telegram.Update.message_reaction_count`.""" - MESSAGE_REACTION: Final[int] = 1 - """:obj:`int`: Used as a constant to handle both :attr:`telegram.Update.message_reaction` - and :attr:`telegram.Update.message_reaction_count`.""" - - def __init__( - self: "MessageReactionHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_id: Optional[SCT[int]] = None, - chat_username: Optional[SCT[str]] = None, - user_id: Optional[SCT[int]] = None, - user_username: Optional[SCT[str]] = None, - message_reaction_types: int = MESSAGE_REACTION, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - self.message_reaction_types: int = message_reaction_types - - self._chat_ids = parse_chat_id(chat_id) - self._chat_usernames = parse_username(chat_username) - if (user_id or user_username) and message_reaction_types in ( - self.MESSAGE_REACTION, - self.MESSAGE_REACTION_COUNT_UPDATED, - ): - raise ValueError( - "You can not filter for users and include anonymous reactions. Set " - "`message_reaction_types` to MESSAGE_REACTION_UPDATED." - ) - self._user_ids = parse_chat_id(user_id) - self._user_usernames = parse_username(user_username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return False - - if not (update.message_reaction or update.message_reaction_count): - return False - - if ( - self.message_reaction_types == self.MESSAGE_REACTION_UPDATED - and update.message_reaction_count - ): - return False - - if ( - self.message_reaction_types == self.MESSAGE_REACTION_COUNT_UPDATED - and update.message_reaction - ): - return False - - if not any((self._chat_ids, self._chat_usernames, self._user_ids, self._user_usernames)): - return True - - # Extract chat and user IDs and usernames from the update for comparison - chat_id = chat.id if (chat := update.effective_chat) else None - chat_username = chat.username if chat else None - user_id = user.id if (user := update.effective_user) else None - user_username = user.username if user else None - - return ( - bool(self._chat_ids and (chat_id in self._chat_ids)) - or bool(self._chat_usernames and (chat_username in self._chat_usernames)) - or bool(self._user_ids and (user_id in self._user_ids)) - or bool(self._user_usernames and (user_username in self._user_usernames)) - ) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/paidmediapurchasedhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/paidmediapurchasedhandler.py deleted file mode 100755 index 2f273e9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/paidmediapurchasedhandler.py +++ /dev/null @@ -1,95 +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 -# -# 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 PaidMediaPurchased class.""" - -from typing import Optional - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, RT, HandlerCallback - - -class PaidMediaPurchasedHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram - :attr:`purchased paid media `. - - .. versionadded:: 21.6 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only - those which are from the specified user ID(s). - - username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only - those which are from the specified username(s). - - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - """ - - __slots__ = ( - "_user_ids", - "_usernames", - ) - - def __init__( - self: "PaidMediaPurchasedHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - user_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - self._user_ids = parse_chat_id(user_id) - self._usernames = parse_username(username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update) or not update.purchased_paid_media: - return False - - if not self._user_ids and not self._usernames: - return True - if update.purchased_paid_media.from_user.id in self._user_ids: - return True - return update.purchased_paid_media.from_user.username in self._usernames diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollanswerhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollanswerhandler.py deleted file mode 100755 index 69f1893..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollanswerhandler.py +++ /dev/null @@ -1,71 +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 -# -# 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 PollAnswerHandler class.""" - - -from telegram import Update -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, RT - - -class PollAnswerHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain a - :attr:`poll answer `. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Poll Bot ` - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.poll_answer) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollhandler.py deleted file mode 100755 index 36fc9bc..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollhandler.py +++ /dev/null @@ -1,71 +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 -# -# 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 PollHandler class.""" - - -from telegram import Update -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, RT - - -class PollHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain a - :attr:`poll `. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Poll Bot ` - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.poll) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/precheckoutqueryhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/precheckoutqueryhandler.py deleted file mode 100755 index 04bf395..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/precheckoutqueryhandler.py +++ /dev/null @@ -1,103 +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 -# -# 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 PreCheckoutQueryHandler class.""" - - -import re -from re import Pattern -from typing import Optional, TypeVar, Union - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - - -class PreCheckoutQueryHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram :attr:`telegram.Update.pre_checkout_query`. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Payment Bot ` - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - pattern (:obj:`str` | :func:`re.Pattern `, optional): Optional. Regex pattern - to test :attr:`telegram.PreCheckoutQuery.invoice_payload` against. - - .. versionadded:: 20.8 - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - pattern (:obj:`str` | :func:`re.Pattern `, optional): Optional. Regex pattern - to test :attr:`telegram.PreCheckoutQuery.invoice_payload` against. - - .. versionadded:: 20.8 - - """ - - __slots__ = ("pattern",) - - def __init__( - self: "PreCheckoutQueryHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - pattern: Optional[Union[str, Pattern[str]]] = None, - ): - super().__init__(callback, block=block) - - self.pattern: Optional[Pattern[str]] = re.compile(pattern) if pattern is not None else None - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.pre_checkout_query: - invoice_payload = update.pre_checkout_query.invoice_payload - if self.pattern: - if self.pattern.match(invoice_payload): - return True - else: - return True - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/prefixhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/prefixhandler.py deleted file mode 100755 index a6e4f38..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/prefixhandler.py +++ /dev/null @@ -1,184 +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 -# -# 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 PrefixHandler class.""" -import itertools -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext import filters as filters_module -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class PrefixHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle custom prefix commands. - - This is an intermediate handler between :class:`MessageHandler` and :class:`CommandHandler`. - It supports configurable commands with the same options as :class:`CommandHandler`. It will - respond to every combination of :paramref:`prefix` and :paramref:`command`. - It will add a :obj:`list` to the :class:`CallbackContext` named :attr:`CallbackContext.args`, - containing a list of strings, which is the text following the command split on single or - consecutive whitespace characters. - - Examples: - - Single prefix and command: - - .. code:: python - - PrefixHandler("!", "test", callback) # will respond to '!test'. - - Multiple prefixes, single command: - - .. code:: python - - PrefixHandler(["!", "#"], "test", callback) # will respond to '!test' and '#test'. - - Multiple prefixes and commands: - - .. code:: python - - PrefixHandler( - ["!", "#"], ["test", "help"], callback - ) # will respond to '!test', '#test', '!help' and '#help'. - - - By default, the handler listens to messages as well as edited messages. To change this behavior - use :attr:`~filters.UpdateType.EDITED_MESSAGE ` - - Note: - * :class:`PrefixHandler` does *not* handle (edited) channel posts. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - .. versionchanged:: 20.0 - - * :class:`PrefixHandler` is no longer a subclass of :class:`CommandHandler`. - * Removed the attributes ``command`` and ``prefix``. Instead, the new :attr:`commands` - contains all commands that this handler listens to as a :class:`frozenset`, which - includes the prefixes. - * Updating the prefixes and commands this handler listens to is no longer possible. - - Args: - prefix (:obj:`str` | Collection[:obj:`str`]): - The prefix(es) that will precede :paramref:`command`. - command (:obj:`str` | Collection[:obj:`str`]): - The command or list of commands this handler should listen for. Case-insensitive. - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - filters (:class:`telegram.ext.filters.BaseFilter`, optional): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :mod:`telegram.ext.filters`. Filters can be combined using bitwise - operators (``&`` for :keyword:`and`, ``|`` for :keyword:`or`, ``~`` for :keyword:`not`) - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - commands (frozenset[:obj:`str`]): The commands that this handler will listen for, i.e. the - combinations of :paramref:`prefix` and :paramref:`command`. - callback (:term:`coroutine function`): The callback function for this handler. - filters (:class:`telegram.ext.filters.BaseFilter`): Optional. Only allow updates with these - Filters. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - # 'prefix' is a class property, & 'command' is included in the superclass, so they're left out. - __slots__ = ("commands", "filters") - - def __init__( - self: "PrefixHandler[CCT, RT]", - prefix: SCT[str], - command: SCT[str], - callback: HandlerCallback[Update, CCT, RT], - filters: Optional[filters_module.BaseFilter] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback=callback, block=block) - - prefixes = {prefix.lower()} if isinstance(prefix, str) else {x.lower() for x in prefix} - - commands = {command.lower()} if isinstance(command, str) else {x.lower() for x in command} - - self.commands: frozenset[str] = frozenset( - p + c for p, c in itertools.product(prefixes, commands) - ) - self.filters: filters_module.BaseFilter = ( - filters if filters is not None else filters_module.UpdateType.MESSAGES - ) - - def check_update( - self, update: object - ) -> Optional[Union[bool, tuple[list[str], Optional[Union[bool, dict[Any, Any]]]]]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`list`: The list of args for the handler. - - """ - if isinstance(update, Update) and update.effective_message: - message = update.effective_message - - if message.text: - text_list = message.text.split() - if text_list[0].lower() not in self.commands: - return None - filter_result = self.filters.check_update(update) - if filter_result: - return text_list[1:], filter_result - return False - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Union[bool, tuple[list[str], Optional[bool]]]], - ) -> None: - """Add text after the command to :attr:`CallbackContext.args` as list, split on single - whitespaces and add output of data filters to :attr:`CallbackContext` as well. - """ - if isinstance(check_result, tuple): - context.args = check_result[0] - if isinstance(check_result[1], dict): - context.update(check_result[1]) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/shippingqueryhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/shippingqueryhandler.py deleted file mode 100755 index 1795a93..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/shippingqueryhandler.py +++ /dev/null @@ -1,70 +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 -# -# 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 ShippingQueryHandler class.""" - - -from telegram import Update -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, RT - - -class ShippingQueryHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram :attr:`telegram.Update.shipping_query`. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Payment Bot ` - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.shipping_query) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringcommandhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringcommandhandler.py deleted file mode 100755 index 4ce7a9b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringcommandhandler.py +++ /dev/null @@ -1,108 +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 -# -# 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 StringCommandHandler class.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, RT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - - -class StringCommandHandler(BaseHandler[str, CCT, RT]): - """Handler class to handle string commands. Commands are string updates that start with - ``/``. The handler will add a :obj:`list` to the - :class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings, - which is the text following the command split on single whitespace characters. - - Note: - This handler is not used to handle Telegram :class:`telegram.Update`, but strings manually - put in the queue. For example to send messages with the bot using command line or API. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - command (:obj:`str`): The command this handler should listen for. - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: str, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - command (:obj:`str`): The command this handler should listen for. - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("command",) - - def __init__( - self: "StringCommandHandler[CCT, RT]", - command: str, - callback: HandlerCallback[str, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - self.command: str = command - - def check_update(self, update: object) -> Optional[list[str]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:obj:`object`): The incoming update. - - Returns: - list[:obj:`str`]: List containing the text command split on whitespace. - - """ - if isinstance(update, str) and update.startswith("/"): - args = update[1:].split(" ") - if args[0] == self.command: - return args[1:] - return None - - def collect_additional_context( - self, - context: CCT, - update: str, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[list[str]], - ) -> None: - """Add text after the command to :attr:`CallbackContext.args` as list, split on single - whitespaces. - """ - context.args = check_result diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringregexhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringregexhandler.py deleted file mode 100755 index dda0052..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringregexhandler.py +++ /dev/null @@ -1,115 +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 -# -# 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 StringRegexHandler class.""" - -import re -from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union - -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class StringRegexHandler(BaseHandler[str, CCT, RT]): - """Handler class to handle string updates based on a regex which checks the update content. - - Read the documentation of the :mod:`re` module for more information. The :func:`re.match` - function is used to determine if an update should be handled by this handler. - - Note: - This handler is not used to handle Telegram :class:`telegram.Update`, but strings manually - put in the queue. For example to send messages with the bot using command line or API. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - pattern (:obj:`str` | :func:`re.Pattern `): The regex pattern. - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: str, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - pattern (:obj:`str` | :func:`re.Pattern `): The regex pattern. - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("pattern",) - - def __init__( - self: "StringRegexHandler[CCT, RT]", - pattern: Union[str, Pattern[str]], - callback: HandlerCallback[str, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern: Union[str, Pattern[str]] = pattern - - def check_update(self, update: object) -> Optional[Match[str]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:obj:`object`): The incoming update. - - Returns: - :obj:`None` | :obj:`re.match` - - """ - if isinstance(update, str) and (match := re.match(self.pattern, update)): - return match - return None - - def collect_additional_context( - self, - context: CCT, - update: str, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Match[str]], - ) -> None: - """Add the result of ``re.match(pattern, update)`` to :attr:`CallbackContext.matches` as - list with one element. - """ - if self.pattern and check_result: - context.matches = [check_result] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/typehandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/typehandler.py deleted file mode 100755 index 0d6ce78..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/typehandler.py +++ /dev/null @@ -1,98 +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 -# -# 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 TypeHandler class.""" - -from typing import Optional, TypeVar - -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") -UT = TypeVar("UT") -# If this is written directly next to the type variable mypy gets confused with [valid-type]. This -# could be reported to them, but I doubt they would change this since we override a builtin type -GenericUT = type[UT] - - -class TypeHandler(BaseHandler[UT, CCT, RT]): - """Handler class to handle updates of custom types. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - type (:external:class:`type`): The :external:class:`type` of updates this handler should - process, as determined by :obj:`isinstance` - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: object, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - strict (:obj:`bool`, optional): Use ``type`` instead of :obj:`isinstance`. - Default is :obj:`False`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - type (:external:class:`type`): The :external:class:`type` of updates this handler should - process. - callback (:term:`coroutine function`): The callback function for this handler. - strict (:obj:`bool`): Use :external:class:`type` instead of :obj:`isinstance`. Default is - :obj:`False`. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("strict", "type") - - def __init__( - self: "TypeHandler[UT, CCT, RT]", - type: GenericUT[UT], # pylint: disable=redefined-builtin - callback: HandlerCallback[UT, CCT, RT], - strict: bool = False, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - self.type: GenericUT[UT] = type - self.strict: Optional[bool] = strict - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not self.strict: - return isinstance(update, self.type) - return type(update) is self.type # pylint: disable=unidiomatic-typecheck diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_jobqueue.py b/venv/lib/python3.11/site-packages/telegram/ext/_jobqueue.py deleted file mode 100755 index 70c6405..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_jobqueue.py +++ /dev/null @@ -1,1013 +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 -# -# 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 JobQueue and Job.""" -import asyncio -import datetime as dtm -import re -import weakref -from typing import TYPE_CHECKING, Any, Generic, Optional, Union, cast, overload - -try: - from apscheduler.executors.asyncio import AsyncIOExecutor - from apscheduler.schedulers.asyncio import AsyncIOScheduler - - APS_AVAILABLE = True -except ImportError: - APS_AVAILABLE = False - -from telegram._utils.datetime import UTC, localize -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import JSONDict -from telegram.ext._extbot import ExtBot -from telegram.ext._utils.types import CCT, JobCallback - -if TYPE_CHECKING: - from collections.abc import Iterable - - if APS_AVAILABLE: - from apscheduler.job import Job as APSJob - - from telegram.ext import Application - - -_ALL_DAYS = tuple(range(7)) -_LOGGER = get_logger(__name__, class_name="JobQueue") - - -class JobQueue(Generic[CCT]): - """This class allows you to periodically perform tasks with the bot. It is a convenience - wrapper for the APScheduler library. - - This class is a :class:`~typing.Generic` class and accepts one type variable that specifies - the type of the argument ``context`` of the job callbacks (:paramref:`~run_once.callback`) of - :meth:`run_once` and the other scheduling methods. - - Important: - If you want to use this class, you must install PTB with the optional requirement - ``job-queue``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[job-queue]" - - Examples: - :any:`Timer Bot ` - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Job Queue ` - - .. versionchanged:: 20.0 - To use this class, PTB must be installed via - ``pip install "python-telegram-bot[job-queue]"``. - - Attributes: - scheduler (:class:`apscheduler.schedulers.asyncio.AsyncIOScheduler`): The scheduler. - - Warning: - This scheduler is configured by :meth:`set_application`. Additional configuration - settings can be made by users. However, calling - :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` will delete any - previous configuration settings. Therefore, please make sure to pass the values - returned by :attr:`scheduler_configuration` to the method call in addition to your - custom values. - Alternatively, you can also use methods like - :meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using - :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether. - - .. versionchanged:: 20.0 - Uses :class:`~apscheduler.schedulers.asyncio.AsyncIOScheduler` instead of - :class:`~apscheduler.schedulers.background.BackgroundScheduler` - - """ - - __slots__ = ("_application", "_executor", "scheduler") - _CRON_MAPPING = ("sun", "mon", "tue", "wed", "thu", "fri", "sat") - - def __init__(self) -> None: - if not APS_AVAILABLE: - raise RuntimeError( - "To use `JobQueue`, PTB must be installed via `pip install " - '"python-telegram-bot[job-queue]"`.' - ) - - self._application: Optional[weakref.ReferenceType[Application]] = None - self._executor = AsyncIOExecutor() - self.scheduler: "AsyncIOScheduler" = AsyncIOScheduler( # noqa: UP037 - **self.scheduler_configuration - ) - - def __repr__(self) -> str: - """Give a string representation of the JobQueue in the form ``JobQueue[application=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs(self, application=self.application) - - @property - def application(self) -> "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]": - """The application this JobQueue is associated with.""" - if self._application is None: - raise RuntimeError("No application was set for this JobQueue.") - application = self._application() - if application is not None: - return application - raise RuntimeError("The application instance is no longer alive.") - - @property - def scheduler_configuration(self) -> JSONDict: - """Provides configuration values that are used by :class:`JobQueue` for :attr:`scheduler`. - - Tip: - Since calling - :meth:`scheduler.configure() ` - deletes any previous setting, please make sure to pass these values to the method call - in addition to your custom values: - - .. code-block:: python - - scheduler.configure(..., **job_queue.scheduler_configuration) - - Alternatively, you can also use methods like - :meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using - :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether. - - .. versionadded:: 20.7 - - Returns: - dict[:obj:`str`, :obj:`object`]: The configuration values as dictionary. - - """ - timezone: dtm.tzinfo = UTC - if ( - self._application - and isinstance(self.application.bot, ExtBot) - and self.application.bot.defaults - ): - timezone = self.application.bot.defaults.tzinfo or UTC - - return { - "timezone": timezone, - "executors": {"default": self._executor}, - } - - def _tz_now(self) -> dtm.datetime: - return dtm.datetime.now(self.scheduler.timezone) - - @overload - def _parse_time_input(self, time: None, shift_day: bool = False) -> None: ... - - @overload - def _parse_time_input( - self, - time: Union[float, dtm.timedelta, dtm.datetime, dtm.time], - shift_day: bool = False, - ) -> dtm.datetime: ... - - def _parse_time_input( - self, - time: Union[float, dtm.timedelta, dtm.datetime, dtm.time, None], - shift_day: bool = False, - ) -> Optional[dtm.datetime]: - if time is None: - return None - if isinstance(time, (int, float)): - return self._tz_now() + dtm.timedelta(seconds=time) - if isinstance(time, dtm.timedelta): - return self._tz_now() + time - if isinstance(time, dtm.time): - date_time = dtm.datetime.combine( - dtm.datetime.now(tz=time.tzinfo or self.scheduler.timezone).date(), time - ) - if date_time.tzinfo is None: - # dtm.combine uses the tzinfo of `time`, which might be None, so we still have - # to localize it - date_time = localize(date_time, self.scheduler.timezone) - if shift_day and date_time <= dtm.datetime.now(UTC): - date_time += dtm.timedelta(days=1) - return date_time - return time - - def set_application( - self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]" - ) -> None: - """Set the application to be used by this JobQueue. - - Args: - application (:class:`telegram.ext.Application`): The application. - - """ - self._application = weakref.ref(application) - self.scheduler.configure(**self.scheduler_configuration) - - @staticmethod - async def job_callback(job_queue: "JobQueue[CCT]", job: "Job[CCT]") -> None: - """This method is used as a callback for the APScheduler jobs. - - More precisely, the ``func`` argument of :class:`apscheduler.job.Job` is set to this method - and the ``arg`` argument (representing positional arguments to ``func``) is set to a tuple - containing the :class:`JobQueue` itself and the :class:`~telegram.ext.Job` instance. - - Tip: - This method is a static method rather than a bound method. This makes the arguments - more transparent and allows for easier handling of PTBs integration of APScheduler - when utilizing advanced features of APScheduler. - - Hint: - This method is effectively a wrapper for :meth:`telegram.ext.Job.run`. - - .. versionadded:: 20.4 - - Args: - job_queue (:class:`JobQueue`): The job queue that created the job. - job (:class:`~telegram.ext.Job`): The job to run. - """ - await job.run(job_queue.application) - - def run_once( - self, - callback: JobCallback[CCT], - when: Union[float, dtm.timedelta, dtm.datetime, dtm.time], - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - job_kwargs: Optional[JSONDict] = None, - ) -> "Job[CCT]": - """Creates a new :class:`Job` instance that runs once and adds it to the queue. - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - when (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`): - Time in or at which the job should run. This parameter will be interpreted - depending on its type. - - * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the - job should run. - * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the - job should run. - * :obj:`datetime.datetime` will be interpreted as a specific date and time at - which the job should run. If the timezone (:attr:`datetime.datetime.tzinfo`) is - :obj:`None`, the default timezone of the bot will be used, which is UTC unless - :attr:`telegram.ext.Defaults.tzinfo` is used. - * :obj:`datetime.time` will be interpreted as a specific time of day at which the - job should run. This could be either today or, if the time has already passed, - tomorrow. If the timezone (:attr:`datetime.time.tzinfo`) is :obj:`None`, the - default timezone of the bot will be used, which is UTC unless - :attr:`telegram.ext.Defaults.tzinfo` is used. - - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`. - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - date_time = self._parse_time_input(when, shift_day=True) - - j = self.scheduler.add_job( - self.job_callback, - name=name, - trigger="date", - run_date=date_time, - args=(self, job), - timezone=date_time.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - - job._job = j # pylint: disable=protected-access - return job - - def run_repeating( - self, - callback: JobCallback[CCT], - interval: Union[float, dtm.timedelta], - first: Optional[Union[float, dtm.timedelta, dtm.datetime, dtm.time]] = None, - last: Optional[Union[float, dtm.timedelta, dtm.datetime, dtm.time]] = None, - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - job_kwargs: Optional[JSONDict] = None, - ) -> "Job[CCT]": - """Creates a new :class:`Job` instance that runs at specified intervals and adds it to the - queue. - - Note: - For a note about DST, please see the documentation of `APScheduler`_. - - .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html - #daylight-saving-time-behavior - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`): The interval in which - the job will run. If it is an :obj:`int` or a :obj:`float`, it will be interpreted - as seconds. - first (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`, optional): - Time in or at which the job should run. This parameter will be interpreted - depending on its type. - - * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the - job should run. - * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the - job should run. - * :obj:`datetime.datetime` will be interpreted as a specific date and time at - which the job should run. If the timezone (:attr:`datetime.datetime.tzinfo`) is - :obj:`None`, the default timezone of the bot will be used. - * :obj:`datetime.time` will be interpreted as a specific time of day at which the - job should run. This could be either today or, if the time has already passed, - tomorrow. If the timezone (:attr:`datetime.time.tzinfo`) is :obj:`None`, the - default timezone of the bot will be used, which is UTC unless - :attr:`telegram.ext.Defaults.tzinfo` is used. - - Defaults to :paramref:`interval` - - Note: - Setting :paramref:`first` to ``0``, ``datetime.datetime.now()`` or another - value that indicates that the job should run immediately will not work due - to how the APScheduler library works. If you want to run a job immediately, - we recommend to use an approach along the lines of:: - - job = context.job_queue.run_repeating(callback, interval=5) - await job.run(context.application) - - .. seealso:: :meth:`telegram.ext.Job.run` - - last (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`, optional): - Latest possible time for the job to run. This parameter will be interpreted - depending on its type. See :paramref:`first` for details. - - If :paramref:`last` is :obj:`datetime.datetime` or :obj:`datetime.time` type - and ``last.tzinfo`` is :obj:`None`, the default timezone of the bot will be - assumed, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used. - - Defaults to :obj:`None`. - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`. - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - - dt_first = self._parse_time_input(first) - dt_last = self._parse_time_input(last) - - if dt_last and dt_first and dt_last < dt_first: - raise ValueError("'last' must not be before 'first'!") - - if isinstance(interval, dtm.timedelta): - interval = interval.total_seconds() - - j = self.scheduler.add_job( - self.job_callback, - trigger="interval", - args=(self, job), - start_date=dt_first, - end_date=dt_last, - seconds=interval, - name=name, - **job_kwargs, - ) - - job._job = j # pylint: disable=protected-access - return job - - def run_monthly( - self, - callback: JobCallback[CCT], - when: dtm.time, - day: int, - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - job_kwargs: Optional[JSONDict] = None, - ) -> "Job[CCT]": - """Creates a new :class:`Job` that runs on a monthly basis and adds it to the queue. - - .. versionchanged:: 20.0 - The ``day_is_strict`` argument was removed. Instead one can now pass ``-1`` to the - :paramref:`day` parameter to have the job run on the last day of the month. - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - when (:obj:`datetime.time`): Time of day at which the job should run. If the timezone - (``when.tzinfo``) is :obj:`None`, the default timezone of the bot will be used, - which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used. - day (:obj:`int`): Defines the day of the month whereby the job would run. It should - be within the range of ``1`` and ``31``, inclusive. If a month has fewer days than - this number, the job will not run in this month. Passing ``-1`` leads to the job - running on the last day of the month. - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`. - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - - j = self.scheduler.add_job( - self.job_callback, - trigger="cron", - args=(self, job), - name=name, - day="last" if day == -1 else day, - hour=when.hour, - minute=when.minute, - second=when.second, - timezone=when.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - job._job = j # pylint: disable=protected-access - return job - - def run_daily( - self, - callback: JobCallback[CCT], - time: dtm.time, - days: tuple[int, ...] = _ALL_DAYS, - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - job_kwargs: Optional[JSONDict] = None, - ) -> "Job[CCT]": - """Creates a new :class:`Job` that runs on a daily basis and adds it to the queue. - - Note: - For a note about DST, please see the documentation of `APScheduler`_. - - .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html - #daylight-saving-time-behavior - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone - (:obj:`datetime.time.tzinfo`) is :obj:`None`, the default timezone of the bot will - be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used. - days (tuple[:obj:`int`], optional): Defines on which days of the week the job should - run (where ``0-6`` correspond to sunday - saturday). By default, the job will run - every day. - - .. versionchanged:: 20.0 - Changed day of the week mapping of 0-6 from monday-sunday to sunday-saturday. - - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`. - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - - j = self.scheduler.add_job( - self.job_callback, - name=name, - args=(self, job), - trigger="cron", - day_of_week=",".join([self._CRON_MAPPING[d] for d in days]), - hour=time.hour, - minute=time.minute, - second=time.second, - timezone=time.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - - job._job = j # pylint: disable=protected-access - return job - - def run_custom( - self, - callback: JobCallback[CCT], - job_kwargs: JSONDict, - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - ) -> "Job[CCT]": - """Creates a new custom defined :class:`Job`. - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - job_kwargs (:obj:`dict`): Arbitrary keyword arguments. Used as arguments for - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job`. - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - - j = self.scheduler.add_job(self.job_callback, args=(self, job), name=name, **job_kwargs) - - job._job = j # pylint: disable=protected-access - return job - - async def start(self) -> None: - # this method async just in case future versions need that - """Starts the :class:`~telegram.ext.JobQueue`.""" - if not self.scheduler.running: - self.scheduler.start() - - async def stop(self, wait: bool = True) -> None: - """Shuts down the :class:`~telegram.ext.JobQueue`. - - Args: - wait (:obj:`bool`, optional): Whether to wait until all currently running jobs - have finished. Defaults to :obj:`True`. - - """ - # the interface methods of AsyncIOExecutor are currently not really asyncio-compatible - # so we apply some small tweaks here to try and smoothen the integration into PTB - # TODO: When APS 4.0 hits, we should be able to remove the tweaks - if wait: - # Unfortunately AsyncIOExecutor just cancels them all ... - await asyncio.gather( - *self._executor._pending_futures, # pylint: disable=protected-access - return_exceptions=True, - ) - if self.scheduler.running: - self.scheduler.shutdown(wait=wait) - # scheduler.shutdown schedules a task in the event loop but immediately returns - # so give it a tiny bit of time to actually shut down. - await asyncio.sleep(0.01) - - def jobs(self, pattern: Union[str, re.Pattern[str], None] = None) -> tuple["Job[CCT]", ...]: - """Returns a tuple of all *scheduled* jobs that are currently in the :class:`JobQueue`. - - Args: - pattern (:obj:`str` | :obj:`re.Pattern`, optional): A regular expression pattern. If - passed, only jobs whose name matches the pattern will be returned. - Defaults to :obj:`None`. - - Hint: - This uses :func:`re.search` and not :func:`re.match`. - - .. versionadded:: 21.10 - - Returns: - tuple[:class:`Job`]: Tuple of all *scheduled* jobs. - """ - jobs_generator: Iterable[Job] = ( - Job.from_aps_job(job) for job in self.scheduler.get_jobs() - ) - if pattern is None: - return tuple(jobs_generator) - return tuple( - job for job in jobs_generator if (job.name and re.compile(pattern).search(job.name)) - ) - - def get_jobs_by_name(self, name: str) -> tuple["Job[CCT]", ...]: - """Returns a tuple of all *scheduled* jobs with the given name that are currently - in the :class:`JobQueue`. - - Hint: - This method is a convenience wrapper for :meth:`jobs` with a pattern that matches the - given name. - - Returns: - tuple[:class:`Job`]: Tuple of all *scheduled* jobs matching the name. - """ - return self.jobs(f"^{re.escape(name)}$") - - -class Job(Generic[CCT]): - """This class is a convenience wrapper for the jobs held in a :class:`telegram.ext.JobQueue`. - With the current backend APScheduler, :attr:`job` holds a :class:`apscheduler.job.Job` - instance. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :class:`id ` is equal. - - This class is a :class:`~typing.Generic` class and accepts one type variable that specifies - the type of the argument ``context`` of :paramref:`callback`. - - Important: - If you want to use this class, you must install PTB with the optional requirement - ``job-queue``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[job-queue]" - - Note: - All attributes and instance methods of :attr:`job` are also directly available as - attributes/methods of the corresponding :class:`telegram.ext.Job` object. - - Warning: - This class should not be instantiated manually. - Use the methods of :class:`telegram.ext.JobQueue` to schedule jobs. - - .. seealso:: :wiki:`Job Queue ` - - .. versionchanged:: 20.0 - - * Removed argument and attribute ``job_queue``. - * Renamed ``Job.context`` to :attr:`Job.data`. - * Removed argument ``job`` - * To use this class, PTB must be installed via - ``pip install "python-telegram-bot[job-queue]"``. - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by the - new job. Callback signature:: - - async def callback(context: CallbackContext) - - data (:obj:`object`, optional): Additional data needed for the :paramref:`callback` - function. Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:obj:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat that this job is associated with. - - .. versionadded:: 20.0 - user_id (:obj:`int`, optional): User id of the user that this job is associated with. - - .. versionadded:: 20.0 - Attributes: - callback (:term:`coroutine function`): The callback function that should be executed by the - new job. - data (:obj:`object`): Optional. Additional data needed for the :attr:`callback` function. - name (:obj:`str`): Optional. The name of the new job. - chat_id (:obj:`int`): Optional. Chat id of the chat that this job is associated with. - - .. versionadded:: 20.0 - user_id (:obj:`int`): Optional. User id of the user that this job is associated with. - - .. versionadded:: 20.0 - """ - - __slots__ = ( - "_enabled", - "_job", - "_removed", - "callback", - "chat_id", - "data", - "name", - "user_id", - ) - - def __init__( - self, - callback: JobCallback[CCT], - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - ): - if not APS_AVAILABLE: - raise RuntimeError( - "To use `Job`, PTB must be installed via `pip install " - '"python-telegram-bot[job-queue]"`.' - ) - - self.callback: JobCallback[CCT] = callback - self.data: Optional[object] = data - self.name: Optional[str] = name or callback.__name__ - self.chat_id: Optional[int] = chat_id - self.user_id: Optional[int] = user_id - - self._removed = False - self._enabled = False - - self._job = cast("APSJob", None) - - def __getattr__(self, item: str) -> object: - """Overrides :py:meth:`object.__getattr__` to get specific attribute of the - :class:`telegram.ext.Job` object or of its attribute :class:`apscheduler.job.Job`, - if exists. - - Args: - item (:obj:`str`): The name of the attribute. - - Returns: - :object: The value of the attribute. - - Raises: - :exc:`AttributeError`: If the attribute does not exist in both - :class:`telegram.ext.Job` and :class:`apscheduler.job.Job` objects. - """ - try: - return getattr(self.job, item) - except AttributeError as exc: - raise AttributeError( - f"Neither 'telegram.ext.Job' nor 'apscheduler.job.Job' has attribute '{item}'" - ) from exc - - def __eq__(self, other: object) -> bool: - """Defines equality condition for the :class:`telegram.ext.Job` object. - Two objects of this class are considered to be equal if their - :class:`id ` are equal. - - Returns: - :obj:`True` if both objects have :paramref:`id` parameters identical. - :obj:`False` otherwise. - """ - if isinstance(other, self.__class__): - return self.id == other.id - return False - - 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`: The hash value of the object. - """ - return hash(self.id) - - def __repr__(self) -> str: - """Give a string representation of the job in the form - ``Job[id=..., name=..., callback=..., trigger=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs( - self, - id=self.job.id, - name=self.name, - callback=self.callback.__name__, - trigger=self.job.trigger, - ) - - @property - def job(self) -> "APSJob": - """:class:`apscheduler.job.Job`: The APS Job this job is a wrapper for. - - .. versionchanged:: 20.0 - This property is now read-only. - """ - return self._job - - @property - def removed(self) -> bool: - """:obj:`bool`: Whether this job is due to be removed.""" - return self._removed - - @property - def enabled(self) -> bool: - """:obj:`bool`: Whether this job is enabled.""" - return self._enabled - - @enabled.setter - def enabled(self, status: bool) -> None: - if status: - self.job.resume() - else: - self.job.pause() - self._enabled = status - - @property - def next_t(self) -> Optional[dtm.datetime]: - """ - :class:`datetime.datetime`: Datetime for the next job execution. - Datetime is localized according to :attr:`datetime.datetime.tzinfo`. - If job is removed or already ran it equals to :obj:`None`. - - Warning: - This attribute is only available, if the :class:`telegram.ext.JobQueue` this job - belongs to is already started. Otherwise APScheduler raises an :exc:`AttributeError`. - """ - return self.job.next_run_time - - @classmethod - def from_aps_job(cls, aps_job: "APSJob") -> "Job[CCT]": - """Provides the :class:`telegram.ext.Job` that is associated with the given APScheduler - job. - - Tip: - This method can be useful when using advanced APScheduler features along with - :class:`telegram.ext.JobQueue`. - - .. versionadded:: 20.4 - - Args: - aps_job (:class:`apscheduler.job.Job`): The APScheduler job - - Returns: - :class:`telegram.ext.Job` - """ - ext_job = aps_job.args[1] - ext_job._job = aps_job # pylint: disable=protected-access - return ext_job - - async def run( - self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]" - ) -> None: - """Executes the callback function independently of the jobs schedule. Also calls - :meth:`telegram.ext.Application.update_persistence`. - - .. versionchanged:: 20.0 - Calls :meth:`telegram.ext.Application.update_persistence`. - - Args: - application (:class:`telegram.ext.Application`): The application this job is associated - with. - """ - # We shield the task such that the job isn't cancelled mid-run - await asyncio.shield(self._run(application)) - - async def _run( - self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]" - ) -> None: - try: - try: - context = application.context_types.context.from_job(self, application) - except Exception as exc: - _LOGGER.critical( - "Error while building CallbackContext for job %s. Job will not be run.", - self._job, - exc_info=exc, - ) - return - - await context.refresh_data() - await self.callback(context) - except Exception as exc: - await application.create_task( - application.process_error(None, exc, job=self), - name=f"Job:{self.id}:run:process_error", - ) - finally: - # This is internal logic of application - let's keep it private for now - application._mark_for_persistence_update(job=self) # pylint: disable=protected-access - - def schedule_removal(self) -> None: - """ - Schedules this job for removal from the :class:`JobQueue`. It will be removed without - executing its callback function again. - """ - self.job.remove() - self._removed = True diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_picklepersistence.py b/venv/lib/python3.11/site-packages/telegram/ext/_picklepersistence.py deleted file mode 100755 index c2f4c01..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_picklepersistence.py +++ /dev/null @@ -1,562 +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 -# -# 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 PicklePersistence class.""" -import pickle -from copy import deepcopy -from pathlib import Path -from typing import Any, Callable, Optional, TypeVar, Union, cast, overload - -from telegram import Bot, TelegramObject -from telegram._utils.types import FilePathInput -from telegram._utils.warnings import warn -from telegram.ext import BasePersistence, PersistenceInput -from telegram.ext._contexttypes import ContextTypes -from telegram.ext._utils.types import BD, CD, UD, CDCData, ConversationDict, ConversationKey - -_REPLACED_KNOWN_BOT = "a known bot replaced by PTB's PicklePersistence" -_REPLACED_UNKNOWN_BOT = "an unknown bot replaced by PTB's PicklePersistence" - -TelegramObj = TypeVar("TelegramObj", bound=TelegramObject) - - -def _all_subclasses(cls: type[TelegramObj]) -> set[type[TelegramObj]]: - """Gets all subclasses of the specified object, recursively. from - https://stackoverflow.com/a/3862957/9706202 - """ - subclasses = cls.__subclasses__() - return set(subclasses).union([s for c in subclasses for s in _all_subclasses(c)]) - - -def _reconstruct_to(cls: type[TelegramObj], kwargs: dict) -> TelegramObj: - """ - This method is used for unpickling. The data, which is in the form a dictionary, is - converted back into a class. Works mostly the same as :meth:`TelegramObject.__setstate__`. - This function should be kept in place for backwards compatibility even if the pickling logic - is changed, since `_custom_reduction` places references to this function into the pickled data. - """ - obj = cls.__new__(cls) - obj.__setstate__(kwargs) - return obj - - -def _custom_reduction(cls: TelegramObj) -> tuple[Callable, tuple[type[TelegramObj], dict]]: - """ - This method is used for pickling. The bot attribute is preserved so _BotPickler().persistent_id - works as intended. - """ - data = cls._get_attrs(include_private=True) # pylint: disable=protected-access - # MappingProxyType is not pickable, so we convert it to a dict - # no need to convert back to MPT in _reconstruct_to, since it's done in __setstate__ - data["api_kwargs"] = dict(data["api_kwargs"]) # type: ignore[arg-type] - return _reconstruct_to, (cls.__class__, data) - - -class _BotPickler(pickle.Pickler): - __slots__ = ("_bot",) - - def __init__(self, bot: Bot, *args: Any, **kwargs: Any): - self._bot = bot - super().__init__(*args, **kwargs) - - def reducer_override( - self, obj: TelegramObj - ) -> tuple[Callable, tuple[type[TelegramObj], dict]]: - """ - This method is used for pickling. The bot attribute is preserved so - _BotPickler().persistent_id works as intended. - """ - if not isinstance(obj, TelegramObject): - return NotImplemented - - return _custom_reduction(obj) - - def persistent_id(self, obj: object) -> Optional[str]: - """Used to 'mark' the Bot, so it can be replaced later. See - https://docs.python.org/3/library/pickle.html#pickle.Pickler.persistent_id for more info - """ - if obj is self._bot: - return _REPLACED_KNOWN_BOT - if isinstance(obj, Bot): - warn( - "Unknown bot instance found. Will be replaced by `None` during unpickling", - stacklevel=2, - ) - return _REPLACED_UNKNOWN_BOT - return None # pickles as usual - - -class _BotUnpickler(pickle.Unpickler): - __slots__ = ("_bot",) - - def __init__(self, bot: Bot, *args: Any, **kwargs: Any): - self._bot = bot - super().__init__(*args, **kwargs) - - def persistent_load(self, pid: str) -> Optional[Bot]: - """Replaces the bot with the current bot if known, else it is replaced by :obj:`None`.""" - if pid == _REPLACED_KNOWN_BOT: - return self._bot - if pid == _REPLACED_UNKNOWN_BOT: - return None - raise pickle.UnpicklingError("Found unknown persistent id when unpickling!") - - -class PicklePersistence(BasePersistence[UD, CD, BD]): - """Using python's builtin :mod:`pickle` for making your bot persistent. - - Attention: - The interface provided by this class is intended to be accessed exclusively by - :class:`~telegram.ext.Application`. Calling any of the methods below manually might - interfere with the integration of persistence into :class:`~telegram.ext.Application`. - - Note: - This implementation of :class:`BasePersistence` uses the functionality of the pickle module - to support serialization of bot instances. Specifically any reference to - :attr:`~BasePersistence.bot` will be replaced by a placeholder before pickling and - :attr:`~BasePersistence.bot` will be inserted back when loading the data. - - Examples: - :any:`Persistent Conversation Bot ` - - .. seealso:: :wiki:`Making Your Bot Persistent ` - - .. versionchanged:: 20.0 - - * The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`. - * The parameter and attribute ``filename`` were replaced by :attr:`filepath`. - * :attr:`filepath` now also accepts :obj:`pathlib.Path` as argument. - - Args: - filepath (:obj:`str` | :obj:`pathlib.Path`): The filepath for storing the pickle files. - When :attr:`single_file` is :obj:`False` this will be used as a prefix. - store_data (:class:`~telegram.ext.PersistenceInput`, optional): Specifies which kinds of - data will be saved by this persistence instance. By default, all available kinds of - data will be saved. - single_file (:obj:`bool`, optional): When :obj:`False` will store 5 separate files of - `filename_user_data`, `filename_bot_data`, `filename_chat_data`, - `filename_callback_data` and `filename_conversations`. Default is :obj:`True`. - on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when - :meth:`flush` is called and keep data in memory until that happens. When - :obj:`False` will store data on any transaction *and* on call to :meth:`flush`. - Default is :obj:`False`. - context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance - of :class:`telegram.ext.ContextTypes` to customize the types used in the - ``context`` interface. If not passed, the defaults documented in - :class:`telegram.ext.ContextTypes` will be used. - - .. versionadded:: 13.6 - update_interval (:obj:`int` | :obj:`float`, optional): The - :class:`~telegram.ext.Application` will update - the persistence in regular intervals. This parameter specifies the time (in seconds) to - wait between two consecutive runs of updating the persistence. Defaults to 60 seconds. - - .. versionadded:: 20.0 - Attributes: - filepath (:obj:`str` | :obj:`pathlib.Path`): The filepath for storing the pickle files. - When :attr:`single_file` is :obj:`False` this will be used as a prefix. - store_data (:class:`~telegram.ext.PersistenceInput`): Specifies which kinds of data will - be saved by this persistence instance. - single_file (:obj:`bool`): Optional. When :obj:`False` will store 5 separate files of - `filename_user_data`, `filename_bot_data`, `filename_chat_data`, - `filename_callback_data` and `filename_conversations`. Default is :obj:`True`. - on_flush (:obj:`bool`): Optional. When :obj:`True` will only save to file when - :meth:`flush` is called and keep data in memory until that happens. When - :obj:`False` will store data on any transaction *and* on call to :meth:`flush`. - Default is :obj:`False`. - context_types (:class:`telegram.ext.ContextTypes`): Container for the types used - in the ``context`` interface. - - .. versionadded:: 13.6 - """ - - __slots__ = ( - "bot_data", - "callback_data", - "chat_data", - "context_types", - "conversations", - "filepath", - "on_flush", - "single_file", - "user_data", - ) - - @overload - def __init__( - self: "PicklePersistence[dict[Any, Any], dict[Any, Any], dict[Any, Any]]", - filepath: FilePathInput, - store_data: Optional[PersistenceInput] = None, - single_file: bool = True, - on_flush: bool = False, - update_interval: float = 60, - ): ... - - @overload - def __init__( - self: "PicklePersistence[UD, CD, BD]", - filepath: FilePathInput, - store_data: Optional[PersistenceInput] = None, - single_file: bool = True, - on_flush: bool = False, - update_interval: float = 60, - context_types: Optional[ContextTypes[Any, UD, CD, BD]] = None, - ): ... - - def __init__( - self, - filepath: FilePathInput, - store_data: Optional[PersistenceInput] = None, - single_file: bool = True, - on_flush: bool = False, - update_interval: float = 60, - context_types: Optional[ContextTypes[Any, UD, CD, BD]] = None, - ): - super().__init__(store_data=store_data, update_interval=update_interval) - self.filepath: Path = Path(filepath) - self.single_file: Optional[bool] = single_file - self.on_flush: Optional[bool] = on_flush - self.user_data: Optional[dict[int, UD]] = None - self.chat_data: Optional[dict[int, CD]] = None - self.bot_data: Optional[BD] = None - self.callback_data: Optional[CDCData] = None - self.conversations: Optional[dict[str, dict[tuple[Union[int, str], ...], object]]] = None - self.context_types: ContextTypes[Any, UD, CD, BD] = cast( - ContextTypes[Any, UD, CD, BD], context_types or ContextTypes() - ) - - def _load_singlefile(self) -> None: - try: - with self.filepath.open("rb") as file: - data = _BotUnpickler(self.bot, file).load() - - self.user_data = data["user_data"] - self.chat_data = data["chat_data"] - # For backwards compatibility with files not containing bot data - self.bot_data = data.get("bot_data", self.context_types.bot_data()) - self.callback_data = data.get("callback_data", {}) - self.conversations = data["conversations"] - except OSError: - self.conversations = {} - self.user_data = {} - self.chat_data = {} - self.bot_data = self.context_types.bot_data() - self.callback_data = None - except pickle.UnpicklingError as exc: - filename = self.filepath.name - raise TypeError(f"File {filename} does not contain valid pickle data") from exc - except Exception as exc: - raise TypeError(f"Something went wrong unpickling {self.filepath.name}") from exc - - def _load_file(self, filepath: Path) -> Any: - try: - with filepath.open("rb") as file: - return _BotUnpickler(self.bot, file).load() - - except OSError: - return None - except pickle.UnpicklingError as exc: - raise TypeError(f"File {filepath.name} does not contain valid pickle data") from exc - except Exception as exc: - raise TypeError(f"Something went wrong unpickling {filepath.name}") from exc - - def _dump_singlefile(self) -> None: - data = { - "conversations": self.conversations, - "user_data": self.user_data, - "chat_data": self.chat_data, - "bot_data": self.bot_data, - "callback_data": self.callback_data, - } - with self.filepath.open("wb") as file: - _BotPickler(self.bot, file, protocol=pickle.HIGHEST_PROTOCOL).dump(data) - - def _dump_file(self, filepath: Path, data: object) -> None: - with filepath.open("wb") as file: - _BotPickler(self.bot, file, protocol=pickle.HIGHEST_PROTOCOL).dump(data) - - async def get_user_data(self) -> dict[int, UD]: - """Returns the user_data from the pickle file if it exists or an empty :obj:`dict`. - - Returns: - dict[:obj:`int`, :obj:`dict`]: The restored user data. - """ - if self.user_data: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_user_data")) - if not data: - data = {} - self.user_data = data - else: - self._load_singlefile() - return deepcopy(self.user_data) # type: ignore[arg-type] - - async def get_chat_data(self) -> dict[int, CD]: - """Returns the chat_data from the pickle file if it exists or an empty :obj:`dict`. - - Returns: - dict[:obj:`int`, :obj:`dict`]: The restored chat data. - """ - if self.chat_data: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_chat_data")) - if not data: - data = {} - self.chat_data = data - else: - self._load_singlefile() - return deepcopy(self.chat_data) # type: ignore[arg-type] - - async def get_bot_data(self) -> BD: - """Returns the bot_data from the pickle file if it exists or an empty object of type - :obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`. - - Returns: - :obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`: The restored bot data. - """ - if self.bot_data: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_bot_data")) - if not data: - data = self.context_types.bot_data() - self.bot_data = data - else: - self._load_singlefile() - return deepcopy(self.bot_data) # type: ignore[return-value] - - async def get_callback_data(self) -> Optional[CDCData]: - """Returns the callback data from the pickle file if it exists or :obj:`None`. - - .. versionadded:: 13.6 - - Returns: - tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], - dict[:obj:`str`, :obj:`str`]] | :obj:`None`: The restored metadata or :obj:`None`, - if no data was stored. - """ - if self.callback_data: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_callback_data")) - if not data: - data = None - self.callback_data = data - else: - self._load_singlefile() - if self.callback_data is None: - return None - return deepcopy(self.callback_data) - - async def get_conversations(self, name: str) -> ConversationDict: - """Returns the conversations from the pickle file if it exists or an empty dict. - - Args: - name (:obj:`str`): The handlers name. - - Returns: - :obj:`dict`: The restored conversations for the handler. - """ - if self.conversations: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_conversations")) - if not data: - data = {name: {}} - self.conversations = data - else: - self._load_singlefile() - return self.conversations.get(name, {}).copy() # type: ignore[union-attr] - - async def update_conversation( - self, name: str, key: ConversationKey, new_state: Optional[object] - ) -> None: - """Will update the conversations for the given handler and depending on :attr:`on_flush` - save the pickle file. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:class:`object`): The new state for the given key. - """ - if not self.conversations: - self.conversations = {} - if self.conversations.setdefault(name, {}).get(key) == new_state: - return - self.conversations[name][key] = new_state - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_conversations"), self.conversations) - else: - self._dump_singlefile() - - async def update_user_data(self, user_id: int, data: UD) -> None: - """Will update the user_data and depending on :attr:`on_flush` save the pickle file. - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.Application.user_data` ``[user_id]``. - """ - if self.user_data is None: - self.user_data = {} - if self.user_data.get(user_id) == data: - return - self.user_data[user_id] = data - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_user_data"), self.user_data) - else: - self._dump_singlefile() - - async def update_chat_data(self, chat_id: int, data: CD) -> None: - """Will update the chat_data and depending on :attr:`on_flush` save the pickle file. - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.Application.chat_data` ``[chat_id]``. - """ - if self.chat_data is None: - self.chat_data = {} - if self.chat_data.get(chat_id) == data: - return - self.chat_data[chat_id] = data - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_chat_data"), self.chat_data) - else: - self._dump_singlefile() - - async def update_bot_data(self, data: BD) -> None: - """Will update the bot_data and depending on :attr:`on_flush` save the pickle file. - - Args: - data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`): The - :attr:`telegram.ext.Application.bot_data`. - """ - if self.bot_data == data: - return - self.bot_data = data - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_bot_data"), self.bot_data) - else: - self._dump_singlefile() - - async def update_callback_data(self, data: CDCData) -> None: - """Will update the callback_data (if changed) and depending on :attr:`on_flush` save the - pickle file. - - .. versionadded:: 13.6 - - Args: - data (tuple[list[tuple[:obj:`str`, :obj:`float`, \ - dict[:obj:`str`, :class:`object`]]], dict[:obj:`str`, :obj:`str`]]): - The relevant data to restore :class:`telegram.ext.CallbackDataCache`. - """ - if self.callback_data == data: - return - self.callback_data = data - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_callback_data"), self.callback_data) - else: - self._dump_singlefile() - - async def drop_chat_data(self, chat_id: int) -> None: - """Will delete the specified key from the ``chat_data`` and depending on - :attr:`on_flush` save the pickle file. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`): The chat id to delete from the persistence. - """ - if self.chat_data is None: - return - self.chat_data.pop(chat_id, None) - - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_chat_data"), self.chat_data) - else: - self._dump_singlefile() - - async def drop_user_data(self, user_id: int) -> None: - """Will delete the specified key from the ``user_data`` and depending on - :attr:`on_flush` save the pickle file. - - .. versionadded:: 20.0 - - Args: - user_id (:obj:`int`): The user id to delete from the persistence. - """ - if self.user_data is None: - return - self.user_data.pop(user_id, None) - - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_user_data"), self.user_data) - else: - self._dump_singlefile() - - async def refresh_user_data(self, user_id: int, user_data: UD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data` - """ - - async def refresh_chat_data(self, chat_id: int, chat_data: CD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data` - """ - - async def refresh_bot_data(self, bot_data: BD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data` - """ - - async def flush(self) -> None: - """Will save all data in memory to pickle file(s).""" - if self.single_file: - if ( - self.user_data - or self.chat_data - or self.bot_data - or self.callback_data - or self.conversations - ): - self._dump_singlefile() - else: - if self.user_data: - self._dump_file(Path(f"{self.filepath}_user_data"), self.user_data) - if self.chat_data: - self._dump_file(Path(f"{self.filepath}_chat_data"), self.chat_data) - if self.bot_data: - self._dump_file(Path(f"{self.filepath}_bot_data"), self.bot_data) - if self.callback_data: - self._dump_file(Path(f"{self.filepath}_callback_data"), self.callback_data) - if self.conversations: - self._dump_file(Path(f"{self.filepath}_conversations"), self.conversations) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_updater.py b/venv/lib/python3.11/site-packages/telegram/ext/_updater.py deleted file mode 100755 index 11c225c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_updater.py +++ /dev/null @@ -1,904 +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 -# -# 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 class Updater, which tries to make creating Telegram bots intuitive.""" - -import asyncio -import contextlib -import ssl -from collections.abc import Coroutine, Sequence -from pathlib import Path -from types import TracebackType -from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union - -from telegram._utils.defaultvalue import DEFAULT_80, DEFAULT_IP, DEFAULT_NONE, DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import DVType, ODVInput -from telegram.error import InvalidToken, RetryAfter, TelegramError, TimedOut - -try: - from telegram.ext._utils.webhookhandler import WebhookAppClass, WebhookServer - - WEBHOOKS_AVAILABLE = True -except ImportError: - WEBHOOKS_AVAILABLE = False - -if TYPE_CHECKING: - from socket import socket - - from telegram import Bot - - -_UpdaterType = TypeVar("_UpdaterType", bound="Updater") # pylint: disable=invalid-name -_LOGGER = get_logger(__name__) - - -class Updater(contextlib.AbstractAsyncContextManager["Updater"]): - """This class fetches updates for the bot either via long polling or by starting a webhook - server. Received updates are enqueued into the :attr:`update_queue` and may be fetched from - there to handle them appropriately. - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with updater: - # code - - is roughly equivalent to - - .. code:: python - - try: - await updater.initialize() - # code - finally: - await updater.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Builder Pattern ` - - .. versionchanged:: 20.0 - - * Removed argument and attribute ``user_sig_handler`` - * The only arguments and attributes are now :attr:`bot` and :attr:`update_queue` as now - the sole purpose of this class is to fetch updates. The entry point to a PTB application - is now :class:`telegram.ext.Application`. - - Args: - bot (:class:`telegram.Bot`): The bot used with this Updater. - update_queue (:class:`asyncio.Queue`): Queue for the updates. - - Attributes: - bot (:class:`telegram.Bot`): The bot used with this Updater. - update_queue (:class:`asyncio.Queue`): Queue for the updates. - - """ - - __slots__ = ( - "__lock", - "__polling_cleanup_cb", - "__polling_task", - "__polling_task_stop_event", - "_httpd", - "_initialized", - "_last_update_id", - "_running", - "bot", - "update_queue", - ) - - def __init__( - self, - bot: "Bot", - update_queue: "asyncio.Queue[object]", - ): - self.bot: Bot = bot - self.update_queue: asyncio.Queue[object] = update_queue - - self._last_update_id = 0 - self._running = False - self._initialized = False - self._httpd: Optional[WebhookServer] = None - self.__lock = asyncio.Lock() - self.__polling_task: Optional[asyncio.Task] = None - self.__polling_task_stop_event: asyncio.Event = asyncio.Event() - self.__polling_cleanup_cb: Optional[Callable[[], Coroutine[Any, Any, None]]] = None - - async def __aenter__(self: _UpdaterType) -> _UpdaterType: # noqa: PYI019 - """ - |async_context_manager| :meth:`initializes ` the Updater. - - Returns: - The initialized Updater instance. - - Raises: - :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. - """ - try: - await self.initialize() - except Exception: - await self.shutdown() - raise - return self - - async def __aexit__( - self, - exc_type: Optional[type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - """|async_context_manager| :meth:`shuts down ` the Updater.""" - # Make sure not to return `True` so that exceptions are not suppressed - # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ - await self.shutdown() - - def __repr__(self) -> str: - """Give a string representation of the updater in the form ``Updater[bot=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs(self, bot=self.bot) - - @property - def running(self) -> bool: - return self._running - - async def initialize(self) -> None: - """Initializes the Updater & the associated :attr:`bot` by calling - :meth:`telegram.Bot.initialize`. - - .. seealso:: - :meth:`shutdown` - """ - if self._initialized: - _LOGGER.debug("This Updater is already initialized.") - return - - await self.bot.initialize() - self._initialized = True - - async def shutdown(self) -> None: - """ - Shutdown the Updater & the associated :attr:`bot` by calling :meth:`telegram.Bot.shutdown`. - - .. seealso:: - :meth:`initialize` - - Raises: - :exc:`RuntimeError`: If the updater is still running. - """ - if self.running: - raise RuntimeError("This Updater is still running!") - - if not self._initialized: - _LOGGER.debug("This Updater is already shut down. Returning.") - return - - await self.bot.shutdown() - self._initialized = False - _LOGGER.debug("Shut down of Updater complete") - - async def start_polling( - self, - poll_interval: float = 0.0, - timeout: int = 10, # noqa: ASYNC109 - bootstrap_retries: int = -1, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - allowed_updates: Optional[Sequence[str]] = None, - drop_pending_updates: Optional[bool] = None, - error_callback: Optional[Callable[[TelegramError], None]] = None, - ) -> "asyncio.Queue[object]": - """Starts polling updates from Telegram. - - .. versionchanged:: 20.0 - Removed the ``clean`` argument in favor of :paramref:`drop_pending_updates`. - - Args: - poll_interval (:obj:`float`, optional): Time to wait between polling updates from - Telegram in seconds. Default is ``0.0``. - timeout (:obj:`int`, optional): Passed to - :paramref:`telegram.Bot.get_updates.timeout`. Defaults to ``10`` seconds. - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely (default) - * 0 - no retries - * > 0 - retry up to X times - read_timeout (:obj:`float`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.read_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. versionchanged:: 20.7 - Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE` instead of - ``2``. - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_read_timeout` or - :paramref:`telegram.Bot.get_updates_request`. - write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.write_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_write_timeout` or - :paramref:`telegram.Bot.get_updates_request`. - connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.connect_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_connect_timeout` or - :paramref:`telegram.Bot.get_updates_request`. - pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.pool_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_pool_timeout` or - :paramref:`telegram.Bot.get_updates_request`. - allowed_updates (Sequence[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.get_updates`. - - .. versionchanged:: 21.9 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - - .. versionadded :: 13.4 - error_callback (Callable[[:exc:`telegram.error.TelegramError`], :obj:`None`], \ - optional): Callback to handle :exc:`telegram.error.TelegramError` s that occur - while calling :meth:`telegram.Bot.get_updates` during polling. Defaults to - :obj:`None`, in which case errors will be logged. Callback signature:: - - def callback(error: telegram.error.TelegramError) - - Note: - The :paramref:`error_callback` must *not* be a :term:`coroutine function`! If - asynchronous behavior of the callback is wanted, please schedule a task from - within the callback. - - Returns: - :class:`asyncio.Queue`: The update queue that can be filled from the main thread. - - Raises: - :exc:`RuntimeError`: If the updater is already running or was not initialized. - - """ - # We refrain from issuing deprecation warnings for the timeout parameters here, as we - # already issue them in `Application`. This means that there are no warnings when using - # `Updater` without `Application`, but this is a rather special use case. - - if error_callback and asyncio.iscoroutinefunction(error_callback): - raise TypeError( - "The `error_callback` must not be a coroutine function! Use an ordinary function " - "instead. " - ) - - async with self.__lock: - if self.running: - raise RuntimeError("This Updater is already running!") - if not self._initialized: - raise RuntimeError("This Updater was not initialized via `Updater.initialize`!") - - self._running = True - - try: - # Create & start tasks - polling_ready = asyncio.Event() - - await self._start_polling( - poll_interval=poll_interval, - timeout=timeout, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - bootstrap_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - allowed_updates=allowed_updates, - ready=polling_ready, - error_callback=error_callback, - ) - - _LOGGER.debug("Waiting for polling to start") - await polling_ready.wait() - _LOGGER.debug("Polling updates from Telegram started") - except Exception: - self._running = False - raise - return self.update_queue - - async def _start_polling( - self, - poll_interval: float, - timeout: int, # noqa: ASYNC109 - read_timeout: ODVInput[float], - write_timeout: ODVInput[float], - connect_timeout: ODVInput[float], - pool_timeout: ODVInput[float], - bootstrap_retries: int, - drop_pending_updates: Optional[bool], - allowed_updates: Optional[Sequence[str]], - ready: asyncio.Event, - error_callback: Optional[Callable[[TelegramError], None]], - ) -> None: - _LOGGER.debug("Updater started (polling)") - - # the bootstrapping phase does two things: - # 1) make sure there is no webhook set - # 2) apply drop_pending_updates - await self._bootstrap( - bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url="", - allowed_updates=None, - ) - - _LOGGER.debug("Bootstrap done") - - async def polling_action_cb() -> bool: - try: - updates = await self.bot.get_updates( - offset=self._last_update_id, - timeout=timeout, - read_timeout=read_timeout, - connect_timeout=connect_timeout, - write_timeout=write_timeout, - pool_timeout=pool_timeout, - allowed_updates=allowed_updates, - ) - except TelegramError: - # TelegramErrors should be processed by the network retry loop - raise - except Exception as exc: - # Other exceptions should not. Let's log them for now. - _LOGGER.critical( - "Something went wrong processing the data received from Telegram. " - "Received data was *not* processed!", - exc_info=exc, - ) - return True - - if updates: - if not self.running: - _LOGGER.critical( - "Updater stopped unexpectedly. Pulled updates will be ignored and pulled " - "again on restart." - ) - else: - for update in updates: - await self.update_queue.put(update) - self._last_update_id = updates[-1].update_id + 1 # Add one to 'confirm' it - - return True # Keep fetching updates & don't quit. Polls with poll_interval. - - def default_error_callback(exc: TelegramError) -> None: - _LOGGER.exception("Exception happened while polling for updates.", exc_info=exc) - - # Start task that runs in background, pulls - # updates from Telegram and inserts them in the update queue of the - # Application. - self.__polling_task = asyncio.create_task( - self._network_loop_retry( - action_cb=polling_action_cb, - on_err_cb=error_callback or default_error_callback, - description="getting Updates", - interval=poll_interval, - stop_event=self.__polling_task_stop_event, - ), - name="Updater:start_polling:polling_task", - ) - - # Prepare a cleanup callback to await on _stop_polling - # Calling get_updates one more time with the latest `offset` parameter ensures that - # all updates that where put into the update queue are also marked as "read" to TG, - # so we do not receive them again on the next startup - # We define this here so that we can use the same parameters as in the polling task - async def _get_updates_cleanup() -> None: - _LOGGER.debug( - "Calling `get_updates` one more time to mark all fetched updates as read." - ) - try: - await self.bot.get_updates( - offset=self._last_update_id, - # We don't want to do long polling here! - timeout=0, - read_timeout=read_timeout, - connect_timeout=connect_timeout, - write_timeout=write_timeout, - pool_timeout=pool_timeout, - allowed_updates=allowed_updates, - ) - except TelegramError: - _LOGGER.exception( - "Error while calling `get_updates` one more time to mark all fetched updates " - "as read: %s. Suppressing error to ensure graceful shutdown. When polling for " - "updates is restarted, updates may be fetched again. Please adjust timeouts " - "via `ApplicationBuilder` or the parameter `get_updates_request` of `Bot`.", - ) - - self.__polling_cleanup_cb = _get_updates_cleanup - - if ready is not None: - ready.set() - - async def start_webhook( - self, - listen: DVType[str] = DEFAULT_IP, - port: DVType[int] = DEFAULT_80, - url_path: str = "", - cert: Optional[Union[str, Path]] = None, - key: Optional[Union[str, Path]] = None, - bootstrap_retries: int = 0, - webhook_url: Optional[str] = None, - allowed_updates: Optional[Sequence[str]] = None, - drop_pending_updates: Optional[bool] = None, - ip_address: Optional[str] = None, - max_connections: int = 40, - secret_token: Optional[str] = None, - unix: Optional[Union[str, Path, "socket"]] = None, - ) -> "asyncio.Queue[object]": - """ - Starts a small http server to listen for updates via webhook. If :paramref:`cert` - and :paramref:`key` are not provided, the webhook will be started directly on - ``http://listen:port/url_path``, so SSL can be handled by another - application. Else, the webhook will be started on - ``https://listen:port/url_path``. Also calls :meth:`telegram.Bot.set_webhook` as required. - - Important: - If you want to use this method, you must install PTB with the optional requirement - ``webhooks``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[webhooks]" - - .. seealso:: :wiki:`Webhooks` - - .. versionchanged:: 13.4 - :meth:`start_webhook` now *always* calls :meth:`telegram.Bot.set_webhook`, so pass - ``webhook_url`` instead of calling ``updater.bot.set_webhook(webhook_url)`` manually. - .. versionchanged:: 20.0 - - * Removed the ``clean`` argument in favor of :paramref:`drop_pending_updates` and - removed the deprecated argument ``force_event_loop``. - - Args: - listen (:obj:`str`, optional): IP-Address to listen on. Defaults to - `127.0.0.1 `_. - port (:obj:`int`, optional): Port the bot should be listening on. Must be one of - :attr:`telegram.constants.SUPPORTED_WEBHOOK_PORTS` unless the bot is running - behind a proxy. Defaults to ``80``. - url_path (:obj:`str`, optional): Path inside url (http(s)://listen:port/). - Defaults to ``''``. - cert (:class:`pathlib.Path` | :obj:`str`, optional): Path to the SSL certificate file. - key (:class:`pathlib.Path` | :obj:`str`, optional): Path to the SSL key file. - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - - .. versionadded :: 13.4 - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely - * 0 - no retries (default) - * > 0 - retry up to X times - webhook_url (:obj:`str`, optional): Explicitly specify the webhook url. Useful behind - NAT, reverse proxy, etc. Default is derived from :paramref:`listen`, - :paramref:`port`, :paramref:`url_path`, :paramref:`cert`, and :paramref:`key`. - ip_address (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`. - Defaults to :obj:`None`. - - .. versionadded :: 13.4 - allowed_updates (Sequence[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.set_webhook`. Defaults to :obj:`None`. - - .. versionchanged:: 21.9 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - max_connections (:obj:`int`, optional): Passed to - :meth:`telegram.Bot.set_webhook`. Defaults to ``40``. - - .. versionadded:: 13.6 - secret_token (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`. - Defaults to :obj:`None`. - - When added, the web server started by this call will expect the token to be set in - the ``X-Telegram-Bot-Api-Secret-Token`` header of an incoming request and will - raise a :class:`http.HTTPStatus.FORBIDDEN ` error if either the - header isn't set or it is set to a wrong token. - - .. versionadded:: 20.0 - unix (:class:`pathlib.Path` | :obj:`str` | :class:`socket.socket`, optional): Can be - either: - - * the path to the unix socket file as :class:`pathlib.Path` or :obj:`str`. This - will be passed to `tornado.netutil.bind_unix_socket `_ to create the socket. - If the Path does not exist, the file will be created. - - * or the socket itself. This option allows you to e.g. restrict the permissions of - the socket for improved security. Note that you need to pass the correct family, - type and socket options yourself. - - Caution: - This parameter is a replacement for the default TCP bind. Therefore, it is - mutually exclusive with :paramref:`listen` and :paramref:`port`. When using - this param, you must also run a reverse proxy to the unix socket and set the - appropriate :paramref:`webhook_url`. - - .. versionadded:: 20.8 - .. versionchanged:: 21.1 - Added support to pass a socket instance itself. - Returns: - :class:`queue.Queue`: The update queue that can be filled from the main thread. - - Raises: - :exc:`RuntimeError`: If the updater is already running or was not initialized. - """ - if not WEBHOOKS_AVAILABLE: - raise RuntimeError( - "To use `start_webhook`, PTB must be installed via `pip install " - '"python-telegram-bot[webhooks]"`.' - ) - # unix has special requirements what must and mustn't be set when using it - if unix: - error_msg = ( - "You can not pass unix and {0}, only use one. Unix if you want to " - "initialize a unix socket, or {0} for a standard TCP server." - ) - if not isinstance(listen, DefaultValue): - raise RuntimeError(error_msg.format("listen")) - if not isinstance(port, DefaultValue): - raise RuntimeError(error_msg.format("port")) - if not webhook_url: - raise RuntimeError( - "Since you set unix, you also need to set the URL to the webhook " - "of the proxy you run in front of the unix socket." - ) - - async with self.__lock: - if self.running: - raise RuntimeError("This Updater is already running!") - if not self._initialized: - raise RuntimeError("This Updater was not initialized via `Updater.initialize`!") - - self._running = True - - try: - # Create & start tasks - webhook_ready = asyncio.Event() - - await self._start_webhook( - listen=DefaultValue.get_value(listen), - port=DefaultValue.get_value(port), - url_path=url_path, - cert=cert, - key=key, - bootstrap_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url=webhook_url, - allowed_updates=allowed_updates, - ready=webhook_ready, - ip_address=ip_address, - max_connections=max_connections, - secret_token=secret_token, - unix=unix, - ) - - _LOGGER.debug("Waiting for webhook server to start") - await webhook_ready.wait() - _LOGGER.debug("Webhook server started") - except Exception: - self._running = False - raise - - # Return the update queue so the main thread can insert updates - return self.update_queue - - async def _start_webhook( - self, - listen: str, - port: int, - url_path: str, - bootstrap_retries: int, - allowed_updates: Optional[Sequence[str]], - cert: Optional[Union[str, Path]] = None, - key: Optional[Union[str, Path]] = None, - drop_pending_updates: Optional[bool] = None, - webhook_url: Optional[str] = None, - ready: Optional[asyncio.Event] = None, - ip_address: Optional[str] = None, - max_connections: int = 40, - secret_token: Optional[str] = None, - unix: Optional[Union[str, Path, "socket"]] = None, - ) -> None: - _LOGGER.debug("Updater thread started (webhook)") - - if not url_path.startswith("/"): - url_path = f"/{url_path}" - - # Create Tornado app instance - app = WebhookAppClass(url_path, self.bot, self.update_queue, secret_token) - - # Form SSL Context - # An SSLError is raised if the private key does not match with the certificate - # Note that we only use the SSL certificate for the WebhookServer, if the key is also - # present. This is because the WebhookServer may not actually be in charge of performing - # the SSL handshake, e.g. in case a reverse proxy is used - if cert is not None and key is not None: - try: - ssl_ctx: Optional[ssl.SSLContext] = ssl.create_default_context( - ssl.Purpose.CLIENT_AUTH - ) - ssl_ctx.load_cert_chain(cert, key) # type: ignore[union-attr] - except ssl.SSLError as exc: - raise TelegramError("Invalid SSL Certificate") from exc - else: - ssl_ctx = None - # Create and start server - self._httpd = WebhookServer(listen, port, app, ssl_ctx, unix) - - if not webhook_url: - webhook_url = self._gen_webhook_url( - protocol="https" if ssl_ctx else "http", - listen=DefaultValue.get_value(listen), - port=port, - url_path=url_path, - ) - - # We pass along the cert to the webhook if present. - await self._bootstrap( - # Passing a Path or string only works if the bot is running against a local bot API - # server, so let's read the contents - cert=Path(cert).read_bytes() if cert else None, - max_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url=webhook_url, - allowed_updates=allowed_updates, - ip_address=ip_address, - max_connections=max_connections, - secret_token=secret_token, - ) - - await self._httpd.serve_forever(ready=ready) - - @staticmethod - def _gen_webhook_url(protocol: str, listen: str, port: int, url_path: str) -> str: - # TODO: double check if this should be https in any case - the docs of start_webhook - # say differently! - return f"{protocol}://{listen}:{port}{url_path}" - - async def _network_loop_retry( - self, - action_cb: Callable[..., Coroutine], - on_err_cb: Callable[[TelegramError], None], - description: str, - interval: float, - stop_event: Optional[asyncio.Event], - ) -> None: - """Perform a loop calling `action_cb`, retrying after network errors. - - Stop condition for loop: `self.running` evaluates :obj:`False` or return value of - `action_cb` evaluates :obj:`False`. - - Args: - action_cb (:term:`coroutine function`): Network oriented callback function to call. - on_err_cb (:obj:`callable`): Callback to call when TelegramError is caught. Receives - the exception object as a parameter. - description (:obj:`str`): Description text to use for logs and exception raised. - interval (:obj:`float` | :obj:`int`): Interval to sleep between each call to - `action_cb`. - stop_event (:class:`asyncio.Event` | :obj:`None`): Event to wait on for stopping the - loop. Setting the event will make the loop exit even if `action_cb` is currently - running. - - """ - - async def do_action() -> bool: - if not stop_event: - return await action_cb() - - action_cb_task = asyncio.create_task(action_cb()) - stop_task = asyncio.create_task(stop_event.wait()) - done, pending = await asyncio.wait( - (action_cb_task, stop_task), return_when=asyncio.FIRST_COMPLETED - ) - with contextlib.suppress(asyncio.CancelledError): - for task in pending: - task.cancel() - - if stop_task in done: - _LOGGER.debug("Network loop retry %s was cancelled", description) - return False - - return action_cb_task.result() - - _LOGGER.debug("Start network loop retry %s", description) - cur_interval = interval - while self.running: - try: - if not await do_action(): - break - except RetryAfter as exc: - _LOGGER.info("%s", exc) - cur_interval = 0.5 + exc.retry_after - except TimedOut as toe: - _LOGGER.debug("Timed out %s: %s", description, toe) - # If failure is due to timeout, we should retry asap. - cur_interval = 0 - except InvalidToken: - _LOGGER.exception("Invalid token; aborting") - raise - except TelegramError as telegram_exc: - on_err_cb(telegram_exc) - - # increase waiting times on subsequent errors up to 30secs - cur_interval = 1 if cur_interval == 0 else min(30, 1.5 * cur_interval) - else: - cur_interval = interval - - if cur_interval: - await asyncio.sleep(cur_interval) - - async def _bootstrap( - self, - max_retries: int, - webhook_url: Optional[str], - allowed_updates: Optional[Sequence[str]], - drop_pending_updates: Optional[bool] = None, - cert: Optional[bytes] = None, - bootstrap_interval: float = 1, - ip_address: Optional[str] = None, - max_connections: int = 40, - secret_token: Optional[str] = None, - ) -> None: - """Prepares the setup for fetching updates: delete or set the webhook and drop pending - updates if appropriate. If there are unsuccessful attempts, this will retry as specified by - :paramref:`max_retries`. - """ - retries = 0 - - async def bootstrap_del_webhook() -> bool: - _LOGGER.debug("Deleting webhook") - if drop_pending_updates: - _LOGGER.debug("Dropping pending updates from Telegram server") - await self.bot.delete_webhook(drop_pending_updates=drop_pending_updates) - return False - - async def bootstrap_set_webhook() -> bool: - _LOGGER.debug("Setting webhook") - if drop_pending_updates: - _LOGGER.debug("Dropping pending updates from Telegram server") - await self.bot.set_webhook( - url=webhook_url, # type: ignore[arg-type] - certificate=cert, - allowed_updates=allowed_updates, - ip_address=ip_address, - drop_pending_updates=drop_pending_updates, - max_connections=max_connections, - secret_token=secret_token, - ) - return False - - def bootstrap_on_err_cb(exc: Exception) -> None: - # We need this since retries is an immutable object otherwise and the changes - # wouldn't propagate outside of thi function - nonlocal retries - - if not isinstance(exc, InvalidToken) and (max_retries < 0 or retries < max_retries): - retries += 1 - _LOGGER.warning( - "Failed bootstrap phase; try=%s max_retries=%s", retries, max_retries - ) - else: - _LOGGER.error("Failed bootstrap phase after %s retries (%s)", retries, exc) - raise exc - - # Dropping pending updates from TG can be efficiently done with the drop_pending_updates - # parameter of delete/start_webhook, even in the case of polling. Also, we want to make - # sure that no webhook is configured in case of polling, so we just always call - # delete_webhook for polling - if drop_pending_updates or not webhook_url: - await self._network_loop_retry( - bootstrap_del_webhook, - bootstrap_on_err_cb, - "bootstrap del webhook", - bootstrap_interval, - stop_event=None, - ) - - # Reset the retries counter for the next _network_loop_retry call - retries = 0 - - # Restore/set webhook settings, if needed. Again, we don't know ahead if a webhook is set, - # so we set it anyhow. - if webhook_url: - await self._network_loop_retry( - bootstrap_set_webhook, - bootstrap_on_err_cb, - "bootstrap set webhook", - bootstrap_interval, - stop_event=None, - ) - - async def stop(self) -> None: - """Stops the polling/webhook. - - .. seealso:: - :meth:`start_polling`, :meth:`start_webhook` - - Raises: - :exc:`RuntimeError`: If the updater is not running. - """ - async with self.__lock: - if not self.running: - raise RuntimeError("This Updater is not running!") - - _LOGGER.debug("Stopping Updater") - - self._running = False - - await self._stop_httpd() - await self._stop_polling() - - _LOGGER.debug("Updater.stop() is complete") - - async def _stop_httpd(self) -> None: - """Stops the Webhook server by calling ``WebhookServer.shutdown()``""" - if self._httpd: - _LOGGER.debug("Waiting for current webhook connection to be closed.") - await self._httpd.shutdown() - self._httpd = None - - async def _stop_polling(self) -> None: - """Stops the polling task by awaiting it.""" - if self.__polling_task: - _LOGGER.debug("Waiting background polling task to finish up.") - self.__polling_task_stop_event.set() - - with contextlib.suppress(asyncio.CancelledError): - await self.__polling_task - # It only fails in rare edge-cases, e.g. when `stop()` is called directly - # after start_polling(), but lets better be safe than sorry ... - - self.__polling_task = None - self.__polling_task_stop_event.clear() - - if self.__polling_cleanup_cb: - await self.__polling_cleanup_cb() - self.__polling_cleanup_cb = None - else: - _LOGGER.warning( - "No polling cleanup callback defined. The last fetched updates may be " - "fetched again on the next polling start." - ) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__init__.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__init__.py deleted file mode 100755 index da47adb..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# 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/]. diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index bf51ff9..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/_update_parsing.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/_update_parsing.cpython-311.pyc deleted file mode 100755 index ef12082..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/_update_parsing.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/stack.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/stack.cpython-311.pyc deleted file mode 100755 index 711be37..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/stack.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/trackingdict.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/trackingdict.cpython-311.pyc deleted file mode 100755 index b74b8f8..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/trackingdict.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/types.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/types.cpython-311.pyc deleted file mode 100755 index 25d0c26..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/types.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/webhookhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/webhookhandler.cpython-311.pyc deleted file mode 100755 index a856b72..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/webhookhandler.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/_update_parsing.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/_update_parsing.py deleted file mode 100755 index 2d62a6b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/_update_parsing.py +++ /dev/null @@ -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 -# -# 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 updates and their contents. - -.. versionadded:: 20.8 - -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 Optional - -from telegram._utils.types import SCT - - -def parse_chat_id(chat_id: Optional[SCT[int]]) -> frozenset[int]: - """Accepts a chat id or collection of chat ids and returns a frozenset of chat ids.""" - if chat_id is None: - return frozenset() - if isinstance(chat_id, int): - return frozenset({chat_id}) - return frozenset(chat_id) - - -def parse_username(username: Optional[SCT[str]]) -> frozenset[str]: - """Accepts a username or collection of usernames and returns a frozenset of usernames. - Strips the leading ``@`` if present. - """ - if username is None: - return frozenset() - if isinstance(username, str): - return frozenset({username.removeprefix("@")}) - return frozenset(usr.removeprefix("@") for usr in username) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/stack.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/stack.py deleted file mode 100755 index e4eef2b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/stack.py +++ /dev/null @@ -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 -# -# 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 inspecting the program stack. - -.. 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. -""" -from pathlib import Path -from types import FrameType -from typing import Optional - -from telegram._utils.logging import get_logger - -_LOGGER = get_logger(__name__) - - -def was_called_by(frame: Optional[FrameType], caller: Path) -> bool: - """Checks if the passed frame was called by the specified file. - - Example: - .. code:: pycon - - >>> was_called_by(inspect.currentframe(), Path(__file__)) - True - - Arguments: - frame (:obj:`FrameType`): The frame - usually the return value of - ``inspect.currentframe()``. If :obj:`None` is passed, the return value will be - :obj:`False`. - caller (:obj:`pathlib.Path`): File that should be the caller. - - Returns: - :obj:`bool`: Whether the frame was called by the specified file. - """ - if frame is None: - return False - - try: - return _was_called_by(frame, caller) - except Exception as exc: - _LOGGER.debug( - "Failed to check if frame was called by `caller`. Assuming that it was not.", - exc_info=exc, - ) - return False - - -def _was_called_by(frame: FrameType, caller: Path) -> bool: - # https://stackoverflow.com/a/57712700/10606962 - if Path(frame.f_code.co_filename).resolve() == caller: - return True - while frame.f_back: - frame = frame.f_back - if Path(frame.f_code.co_filename).resolve() == caller: - return True - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/trackingdict.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/trackingdict.py deleted file mode 100755 index 810ecc6..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/trackingdict.py +++ /dev/null @@ -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 -# -# 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 mutable mapping that keeps track of the keys that where accessed. - -.. 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. -""" -from collections import UserDict -from collections.abc import Mapping -from typing import Final, Generic, Optional, TypeVar, Union - -from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue - -_VT = TypeVar("_VT") -_KT = TypeVar("_KT") -_T = TypeVar("_T") - - -class TrackingDict(UserDict, Generic[_KT, _VT]): - """Mutable mapping that keeps track of which keys where accessed with write access. - Read-access is not tracked. - - Note: - * ``setdefault()`` and ``pop`` are considered writing only depending on whether the - key is present - * deleting values is considered writing - """ - - DELETED: Final = object() - """Special marker indicating that an entry was deleted.""" - - __slots__ = ("_write_access_keys",) - - def __init__(self) -> None: - super().__init__() - self._write_access_keys: set[_KT] = set() - - def __setitem__(self, key: _KT, value: _VT) -> None: - self.__track_write(key) - super().__setitem__(key, value) - - def __delitem__(self, key: _KT) -> None: - self.__track_write(key) - super().__delitem__(key) - - def __track_write(self, key: Union[_KT, set[_KT]]) -> None: - if isinstance(key, set): - self._write_access_keys |= key - else: - self._write_access_keys.add(key) - - def pop_accessed_keys(self) -> set[_KT]: - """Returns all keys that were write-accessed since the last time this method was called.""" - out = self._write_access_keys - self._write_access_keys = set() - return out - - def pop_accessed_write_items(self) -> list[tuple[_KT, _VT]]: - """ - Returns all keys & corresponding values as set of tuples that were write-accessed since - the last time this method was called. If a key was deleted, the value will be - :attr:`DELETED`. - """ - keys = self.pop_accessed_keys() - return [(key, self.get(key, self.DELETED)) for key in keys] - - def mark_as_accessed(self, key: _KT) -> None: - """Use this method have the key returned again in the next call to - :meth:`pop_accessed_write_items` or :meth:`pop_accessed_keys` - """ - self._write_access_keys.add(key) - - # Override methods to track access - - def update_no_track(self, mapping: Mapping[_KT, _VT]) -> None: - """Like ``update``, but doesn't count towards write access.""" - for key, value in mapping.items(): - self.data[key] = value - - # Mypy seems a bit inconsistent about what it wants as types for `default` and return value - # so we just ignore a bit - def pop( # type: ignore[override] - self, - key: _KT, - default: _VT = DEFAULT_NONE, # type: ignore[assignment] - ) -> _VT: - if key in self: - self.__track_write(key) - if isinstance(default, DefaultValue): - return super().pop(key) - return super().pop(key, default=default) - - def clear(self) -> None: - self.__track_write(set(super().keys())) - super().clear() - - # Mypy seems a bit inconsistent about what it wants as types for `default` and return value - # so we just ignore a bit - def setdefault(self: "TrackingDict[_KT, _T]", key: _KT, default: Optional[_T] = None) -> _T: - if key in self: - return self[key] - - self.__track_write(key) - self[key] = default # type: ignore[assignment] - return default # type: ignore[return-value] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/types.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/types.py deleted file mode 100755 index 6aa35c8..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/types.py +++ /dev/null @@ -1,106 +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 -# -# 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. - -.. versionadded:: 13.6 - -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 Coroutine, MutableMapping -from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union - -if TYPE_CHECKING: - from typing import Optional - - from telegram import Bot - from telegram.ext import BaseRateLimiter, CallbackContext, JobQueue - -CCT = TypeVar("CCT", bound="CallbackContext[Any, Any, Any, Any]") -"""An instance of :class:`telegram.ext.CallbackContext` or a custom subclass. - -.. versionadded:: 13.6 -""" - -RT = TypeVar("RT") -UT = TypeVar("UT") -HandlerCallback = Callable[[UT, CCT], Coroutine[Any, Any, RT]] -"""Type of a handler callback - - .. versionadded:: 20.0 -""" -JobCallback = Callable[[CCT], Coroutine[Any, Any, Any]] -"""Type of a job callback - - .. versionadded:: 20.0 -""" - -ConversationKey = tuple[Union[int, str], ...] -ConversationDict = MutableMapping[ConversationKey, object] -"""dict[tuple[:obj:`int` | :obj:`str`, ...], Optional[:obj:`object`]]: - Dicts as maintained by the :class:`telegram.ext.ConversationHandler`. - - .. versionadded:: 13.6 -""" - -CDCData = tuple[list[tuple[str, float, dict[str, Any]]], dict[str, str]] -"""tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], \ - dict[:obj:`str`, :obj:`str`]]: Data returned by - :attr:`telegram.ext.CallbackDataCache.persistence_data`. - - .. versionadded:: 13.6 -""" - -BT = TypeVar("BT", bound="Bot") -"""Type of the bot. - -.. versionadded:: 20.0 -""" -UD = TypeVar("UD") -"""Type of the user data for a single user. - -.. versionadded:: 13.6 -""" -CD = TypeVar("CD") -"""Type of the chat data for a single user. - -.. versionadded:: 13.6 -""" -BD = TypeVar("BD") -"""Type of the bot data. - -.. versionadded:: 13.6 -""" -JQ = TypeVar("JQ", bound=Union[None, "JobQueue"]) -"""Type of the job queue. - -.. versionadded:: 20.0""" - -RL = TypeVar("RL", bound="Optional[BaseRateLimiter]") -"""Type of the rate limiter. - -.. versionadded:: 20.0""" - -RLARGS = TypeVar("RLARGS") -"""Type of the rate limiter arguments. - -.. versionadded:: 20.0""" -FilterDataDict = dict[str, list[Any]] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/webhookhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/webhookhandler.py deleted file mode 100755 index 0c101c8..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/webhookhandler.py +++ /dev/null @@ -1,223 +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 -# -# 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 -import asyncio -import json -from http import HTTPStatus -from pathlib import Path -from socket import socket -from ssl import SSLContext -from types import TracebackType -from typing import TYPE_CHECKING, Optional, Union - -# Instead of checking for ImportError here, we do that in `updater.py`, where we import from -# this module. Doing it here would be tricky, as the classes below subclass tornado classes -import tornado.web -from tornado.httpserver import HTTPServer - -try: - from tornado.netutil import bind_unix_socket - - UNIX_AVAILABLE = True -except ImportError: - UNIX_AVAILABLE = False - -from telegram import Update -from telegram._utils.logging import get_logger -from telegram.ext._extbot import ExtBot - -if TYPE_CHECKING: - from telegram import Bot - -# This module is not visible to users, so we log as Updater -_LOGGER = get_logger(__name__, class_name="Updater") - - -class WebhookServer: - """Thin wrapper around ``tornado.httpserver.HTTPServer``.""" - - __slots__ = ( - "_http_server", - "_server_lock", - "_shutdown_lock", - "is_running", - "listen", - "port", - "unix", - ) - - def __init__( - self, - listen: str, - port: int, - webhook_app: "WebhookAppClass", - ssl_ctx: Optional[SSLContext], - unix: Optional[Union[str, Path, socket]] = None, - ): - if unix and not UNIX_AVAILABLE: - raise RuntimeError("This OS does not support binding unix sockets.") - self._http_server = HTTPServer(webhook_app, ssl_options=ssl_ctx) - self.listen = listen - self.port = port - self.is_running = False - self.unix = None - if unix and isinstance(unix, socket): - self.unix = unix - elif unix: - self.unix = bind_unix_socket(str(unix)) - self._server_lock = asyncio.Lock() - self._shutdown_lock = asyncio.Lock() - - async def serve_forever(self, ready: Optional[asyncio.Event] = None) -> None: - async with self._server_lock: - if self.unix: - self._http_server.add_socket(self.unix) - else: - self._http_server.listen(self.port, address=self.listen) - - self.is_running = True - if ready is not None: - ready.set() - - _LOGGER.debug("Webhook Server started.") - - async def shutdown(self) -> None: - async with self._shutdown_lock: - if not self.is_running: - _LOGGER.debug("Webhook Server is already shut down. Returning") - return - self.is_running = False - self._http_server.stop() - await self._http_server.close_all_connections() - _LOGGER.debug("Webhook Server stopped") - - -class WebhookAppClass(tornado.web.Application): - """Application used in the Webserver""" - - def __init__( - self, - webhook_path: str, - bot: "Bot", - update_queue: asyncio.Queue, - secret_token: Optional[str] = None, - ): - self.shared_objects = { - "bot": bot, - "update_queue": update_queue, - "secret_token": secret_token, - } - handlers = [(rf"{webhook_path}/?", TelegramHandler, self.shared_objects)] - tornado.web.Application.__init__(self, handlers) # type: ignore - - def log_request(self, handler: tornado.web.RequestHandler) -> None: - """Overrides the default implementation since we have our own logging setup.""" - - -# pylint: disable=abstract-method -class TelegramHandler(tornado.web.RequestHandler): - """BaseHandler that processes incoming requests from Telegram""" - - __slots__ = ("bot", "secret_token", "update_queue") - - SUPPORTED_METHODS = ("POST",) # type: ignore[assignment] - - def initialize(self, bot: "Bot", update_queue: asyncio.Queue, secret_token: str) -> None: - """Initialize for each request - that's the interface provided by tornado""" - # pylint: disable=attribute-defined-outside-init - self.bot = bot - self.update_queue = update_queue - self.secret_token = secret_token - if secret_token: - _LOGGER.debug( - "The webhook server has a secret token, expecting it in incoming requests now" - ) - - def set_default_headers(self) -> None: - """Sets default headers""" - self.set_header("Content-Type", 'application/json; charset="utf-8"') - - async def post(self) -> None: - """Handle incoming POST request""" - _LOGGER.debug("Webhook triggered") - self._validate_post() - - json_string = self.request.body.decode() - data = json.loads(json_string) - self.set_status(HTTPStatus.OK) - _LOGGER.debug("Webhook received data: %s", json_string) - - try: - update = Update.de_json(data, self.bot) - except Exception as exc: - _LOGGER.critical( - "Something went wrong processing the data received from Telegram. " - "Received data was *not* processed! Received data was: %r", - data, - exc_info=exc, - ) - raise tornado.web.HTTPError( - HTTPStatus.BAD_REQUEST, reason="Update could not be processed" - ) from exc - - if update: - _LOGGER.debug( - "Received Update with ID %d on Webhook", - # For some reason pylint thinks update is a general TelegramObject - update.update_id, # pylint: disable=no-member - ) - - # handle arbitrary callback data, if necessary - if isinstance(self.bot, ExtBot): - self.bot.insert_callback_data(update) - - await self.update_queue.put(update) - - def _validate_post(self) -> None: - """Only accept requests with content type JSON""" - ct_header = self.request.headers.get("Content-Type", None) - if ct_header != "application/json": - raise tornado.web.HTTPError(HTTPStatus.FORBIDDEN) - # verifying that the secret token is the one the user set when the user set one - if self.secret_token is not None: - token = self.request.headers.get("X-Telegram-Bot-Api-Secret-Token") - if not token: - _LOGGER.debug("Request did not include the secret token") - raise tornado.web.HTTPError( - HTTPStatus.FORBIDDEN, reason="Request did not include the secret token" - ) - if token != self.secret_token: - _LOGGER.debug("Request had the wrong secret token: %s", token) - raise tornado.web.HTTPError( - HTTPStatus.FORBIDDEN, reason="Request had the wrong secret token" - ) - - def log_exception( - self, - typ: Optional[type[BaseException]], - value: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - """Override the default logging and instead use our custom logging.""" - _LOGGER.debug( - "%s - %s", - self.request.remote_ip, - "Exception in TelegramHandler", - exc_info=(typ, value, tb) if typ and value and tb else value, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/filters.py b/venv/lib/python3.11/site-packages/telegram/ext/filters.py deleted file mode 100755 index e1e16c6..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/filters.py +++ /dev/null @@ -1,2939 +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 -# -# 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 filters for use with :class:`telegram.ext.MessageHandler`, -:class:`telegram.ext.CommandHandler`, or :class:`telegram.ext.PrefixHandler`. - -.. versionchanged:: 20.0 - - #. Filters are no longer callable, if you're using a custom filter and are calling an existing - filter, then switch to the new syntax: ``filters.{filter}.check_update(update)``. - #. Removed the ``Filters`` class. The filters are now directly attributes/classes of the - :mod:`~telegram.ext.filters` module. - #. The names of all filters has been updated: - - * Filter classes which are ready for use, e.g ``Filters.all`` are now capitalized, e.g - ``filters.ALL``. - * Filters which need to be initialized are now in CamelCase. E.g. ``filters.User(...)``. - * Filters which do both (like ``Filters.text``) are now split as ready-to-use version - ``filters.TEXT`` and class version ``filters.Text(...)``. - -""" - -__all__ = ( - "ALL", - "ANIMATION", - "ATTACHMENT", - "AUDIO", - "BOOST_ADDED", - "CAPTION", - "CHAT", - "COMMAND", - "CONTACT", - "EFFECT_ID", - "FORWARDED", - "GAME", - "GIVEAWAY", - "GIVEAWAY_WINNERS", - "HAS_MEDIA_SPOILER", - "HAS_PROTECTED_CONTENT", - "INVOICE", - "IS_AUTOMATIC_FORWARD", - "IS_FROM_OFFLINE", - "IS_TOPIC_MESSAGE", - "LOCATION", - "PAID_MEDIA", - "PASSPORT_DATA", - "PHOTO", - "POLL", - "PREMIUM_USER", - "REPLY", - "REPLY_TO_STORY", - "SENDER_BOOST_COUNT", - "STORY", - "SUCCESSFUL_PAYMENT", - "TEXT", - "USER", - "USER_ATTACHMENT", - "VENUE", - "VIA_BOT", - "VIDEO", - "VIDEO_NOTE", - "VOICE", - "BaseFilter", - "Caption", - "CaptionEntity", - "CaptionRegex", - "Chat", - "ChatType", - "Command", - "Dice", - "Document", - "Entity", - "ForwardedFrom", - "Language", - "Mention", - "MessageFilter", - "Regex", - "SenderChat", - "StatusUpdate", - "Sticker", - "SuccessfulPayment", - "Text", - "UpdateFilter", - "UpdateType", - "User", - "ViaBot", -) -import mimetypes -import re -from abc import ABC, abstractmethod -from collections.abc import Collection, Iterable, Sequence -from re import Match, Pattern -from typing import NoReturn, Optional, Union, cast - -from telegram import Chat as TGChat -from telegram import ( - Message, - MessageEntity, - MessageOriginChannel, - MessageOriginChat, - MessageOriginUser, - Update, -) -from telegram import User as TGUser -from telegram._utils.types import SCT -from telegram.constants import DiceEmoji as DiceEmojiEnum -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import FilterDataDict - - -class BaseFilter: - """Base class for all Filters. - - Filters subclassing from this class can combined using bitwise operators: - - And:: - - filters.TEXT & filters.Entity(MENTION) - - Or:: - - filters.AUDIO | filters.VIDEO - - Exclusive Or:: - - filters.Regex('To Be') ^ filters.Regex('Not 2B') - - Not:: - - ~ filters.COMMAND - - Also works with more than two filters:: - - filters.TEXT & (filters.Entity("url") | filters.Entity("text_link")) - filters.TEXT & (~ filters.FORWARDED) - - Note: - Filters use the same short circuiting logic as python's :keyword:`and`, :keyword:`or` and - :keyword:`not`. This means that for example:: - - filters.Regex(r'(a?x)') | filters.Regex(r'(b?x)') - - With ``message.text == 'x'``, will only ever return the matches for the first filter, - since the second one is never evaluated. - - If you want to create your own filters create a class inheriting from either - :class:`MessageFilter` or :class:`UpdateFilter` and implement a ``filter()`` - method that returns a boolean: :obj:`True` if the message should be - handled, :obj:`False` otherwise. - Note that the filters work only as class instances, not actual class objects (so remember to - initialize your filter classes). - - By default, the filters name (what will get printed when converted to a string for display) - will be the class name. If you want to overwrite this assign a better name to the :attr:`name` - class variable. - - .. versionadded:: 20.0 - Added the arguments :attr:`name` and :attr:`data_filter`. - - Args: - name (:obj:`str`): Name for this filter. Defaults to the type of filter. - data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should - return a dict with lists. The dict will be merged with - :class:`telegram.ext.CallbackContext`'s internal dict in most cases - (depends on the handler). - """ - - __slots__ = ("_data_filter", "_name") - - def __init__(self, name: Optional[str] = None, data_filter: bool = False): - self._name = self.__class__.__name__ if name is None else name - self._data_filter = data_filter - - def __and__(self, other: "BaseFilter") -> "BaseFilter": - """Defines `AND` bitwise operator for :class:`BaseFilter` object. - The combined filter accepts an update only if it is accepted by both filters. - For example, ``filters.PHOTO & filters.CAPTION`` will only accept messages that contain - both a photo and a caption. - - Returns: - :obj:`BaseFilter` - """ - return _MergedFilter(self, and_filter=other) - - def __or__(self, other: "BaseFilter") -> "BaseFilter": - """Defines `OR` bitwise operator for :class:`BaseFilter` object. - The combined filter accepts an update only if it is accepted by any of the filters. - For example, ``filters.PHOTO | filters.CAPTION`` will only accept messages that contain - photo or caption or both. - - Returns: - :obj:`BaseFilter` - """ - return _MergedFilter(self, or_filter=other) - - def __xor__(self, other: "BaseFilter") -> "BaseFilter": - """Defines `XOR` bitwise operator for :class:`BaseFilter` object. - The combined filter accepts an update only if it is accepted by any of the filters and - not both of them. For example, ``filters.PHOTO ^ filters.CAPTION`` will only accept - messages that contain photo or caption, not both of them. - - Returns: - :obj:`BaseFilter` - """ - return _XORFilter(self, other) - - def __invert__(self) -> "BaseFilter": - """Defines `NOT` bitwise operator for :class:`BaseFilter` object. - The combined filter accepts an update only if it is accepted by any of the filters. - For example, ``~ filters.PHOTO`` will only accept messages that do not contain photo. - - Returns: - :obj:`BaseFilter` - """ - return _InvertedFilter(self) - - def __repr__(self) -> str: - """Gives name for this filter. - - .. seealso:: - :meth:`name` - - Returns: - :obj:`str`: - """ - return self.name - - @property - def data_filter(self) -> bool: - """:obj:`bool`: Whether this filter is a data filter.""" - return self._data_filter - - @data_filter.setter - def data_filter(self, value: bool) -> None: - self._data_filter = value - - @property - def name(self) -> str: - """:obj:`str`: Name for this filter.""" - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - - def check_update(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - """Checks if the specified update should be handled by this filter. - - .. versionchanged:: 21.1 - This filter now also returns :obj:`True` if the update contains - :attr:`~telegram.Update.business_message` - or :attr:`~telegram.Update.edited_business_message`. - - Args: - update (:class:`telegram.Update`): The update to check. - - Returns: - :obj:`bool`: :obj:`True` if the update contains one of - :attr:`~telegram.Update.channel_post`, :attr:`~telegram.Update.message`, - :attr:`~telegram.Update.edited_channel_post`, - :attr:`~telegram.Update.edited_message`, :attr:`telegram.Update.business_message`, - :attr:`telegram.Update.edited_business_message`, or :obj:`False` otherwise. - """ - return bool( # Only message updates should be handled. - update.channel_post - or update.message - or update.edited_channel_post - or update.edited_message - or update.business_message - or update.edited_business_message - ) - - -class MessageFilter(BaseFilter): - """Base class for all Message Filters. In contrast to :class:`UpdateFilter`, the object passed - to :meth:`filter` is :attr:`telegram.Update.effective_message`. - - Please see :class:`BaseFilter` for details on how to create custom filters. - - .. seealso:: :wiki:`Advanced Filters ` - - """ - - __slots__ = () - - def check_update(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - """Checks if the specified update should be handled by this filter by passing - :attr:`~telegram.Update.effective_message` to :meth:`filter`. - - Args: - update (:class:`telegram.Update`): The update to check. - - Returns: - :obj:`bool` | dict[:obj:`str`, :obj:`list`] | :obj:`None`: If the update should be - handled by this filter, returns :obj:`True` or a dict with lists, in case the filter - is a data filter. If the update should not be handled by this filter, :obj:`False` or - :obj:`None`. - """ - if super().check_update(update): - return self.filter(update.effective_message) # type: ignore[arg-type] - return False - - @abstractmethod - def filter(self, message: Message) -> Optional[Union[bool, FilterDataDict]]: - """This method must be overwritten. - - Args: - message (:class:`telegram.Message`): The message that is tested. - - Returns: - :obj:`dict` or :obj:`bool` - - """ - - -class UpdateFilter(BaseFilter): - """Base class for all Update Filters. In contrast to :class:`MessageFilter`, the object - passed to :meth:`filter` is an instance of :class:`telegram.Update`, which allows to create - filters like :attr:`telegram.ext.filters.UpdateType.EDITED_MESSAGE`. - - Please see :class:`telegram.ext.filters.BaseFilter` for details on how to create custom - filters. - - """ - - __slots__ = () - - def check_update(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - """Checks if the specified update should be handled by this filter. - - Args: - update (:class:`telegram.Update`): The update to check. - - Returns: - :obj:`bool` | dict[:obj:`str`, :obj:`list`] | :obj:`None`: If the update should be - handled by this filter, returns :obj:`True` or a dict with lists, in case the filter - is a data filter. If the update should not be handled by this filter, :obj:`False` or - :obj:`None`. - """ - return self.filter(update) if super().check_update(update) else False - - @abstractmethod - def filter(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - """This method must be overwritten. - - Args: - update (:class:`telegram.Update`): The update that is tested. - - Returns: - :obj:`dict` or :obj:`bool`. - - """ - - -class _InvertedFilter(UpdateFilter): - """Represents a filter that has been inverted. - - Args: - f: The filter to invert. - - """ - - __slots__ = ("inv_filter",) - - def __init__(self, f: BaseFilter): - super().__init__() - self.inv_filter = f - - def filter(self, update: Update) -> bool: - return not bool(self.inv_filter.check_update(update)) - - @property - def name(self) -> str: - return f"" - - @name.setter - def name(self, _: str) -> NoReturn: - raise RuntimeError("Cannot set name for combined filters.") - - -class _MergedFilter(UpdateFilter): - """Represents a filter consisting of two other filters. - - Args: - base_filter: Filter 1 of the merged filter. - and_filter: Optional filter to "and" with base_filter. Mutually exclusive with or_filter. - or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter. - - """ - - __slots__ = ("and_filter", "base_filter", "or_filter") - - def __init__( - self, - base_filter: BaseFilter, - and_filter: Optional[BaseFilter] = None, - or_filter: Optional[BaseFilter] = None, - ): - super().__init__() - self.base_filter = base_filter - if self.base_filter.data_filter: - self.data_filter = True - self.and_filter = and_filter - if ( - self.and_filter - and not isinstance(self.and_filter, bool) - and self.and_filter.data_filter - ): - self.data_filter = True - self.or_filter = or_filter - if self.or_filter and not isinstance(self.and_filter, bool) and self.or_filter.data_filter: - self.data_filter = True - - @staticmethod - def _merge(base_output: Union[bool, dict], comp_output: Union[bool, dict]) -> FilterDataDict: - base = base_output if isinstance(base_output, dict) else {} - comp = comp_output if isinstance(comp_output, dict) else {} - for k in comp: - # Make sure comp values are lists - comp_value = comp[k] if isinstance(comp[k], list) else [] - try: - # If base is a list then merge - if isinstance(base[k], list): - base[k] += comp_value - else: - base[k] = [base[k], *comp_value] - except KeyError: - base[k] = comp_value - return base - - # pylint: disable=too-many-return-statements - def filter(self, update: Update) -> Union[bool, FilterDataDict]: - base_output = self.base_filter.check_update(update) - # We need to check if the filters are data filters and if so return the merged data. - # If it's not a data filter or an or_filter but no matches return bool - if self.and_filter: - # And filter needs to short circuit if base is falsy - if base_output: - comp_output = self.and_filter.check_update(update) - if comp_output: - if self.data_filter: - merged = self._merge(base_output, comp_output) - if merged: - return merged - return True - elif self.or_filter: - # Or filter needs to short circuit if base is truthy - if base_output: - if self.data_filter: - return base_output - return True - - comp_output = self.or_filter.check_update(update) - if comp_output: - if self.data_filter: - return comp_output - return True - return False - - @property - def name(self) -> str: - return ( - f"<{self.base_filter} {'and' if self.and_filter else 'or'} " - f"{self.and_filter or self.or_filter}>" - ) - - @name.setter - def name(self, _: str) -> NoReturn: - raise RuntimeError("Cannot set name for combined filters.") - - -class _XORFilter(UpdateFilter): - """Convenience filter acting as wrapper for :class:`MergedFilter` representing the an XOR gate - for two filters. - - Args: - base_filter: Filter 1 of the merged filter. - xor_filter: Filter 2 of the merged filter. - - """ - - __slots__ = ("base_filter", "merged_filter", "xor_filter") - - def __init__(self, base_filter: BaseFilter, xor_filter: BaseFilter): - super().__init__() - self.base_filter = base_filter - self.xor_filter = xor_filter - self.merged_filter = (base_filter & ~xor_filter) | (~base_filter & xor_filter) - - def filter(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - return self.merged_filter.check_update(update) - - @property - def name(self) -> str: - return f"<{self.base_filter} xor {self.xor_filter}>" - - @name.setter - def name(self, _: str) -> NoReturn: - raise RuntimeError("Cannot set name for combined filters.") - - -class _All(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: # noqa: ARG002 - return True - - -ALL = _All(name="filters.ALL") -"""All Messages.""" - - -class _Animation(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.animation) - - -ANIMATION = _Animation(name="filters.ANIMATION") -"""Messages that contain :attr:`telegram.Message.animation`.""" - - -class _Attachment(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.effective_attachment) - - -ATTACHMENT = _Attachment(name="filters.ATTACHMENT") -"""Messages that contain :meth:`telegram.Message.effective_attachment`. - -.. versionadded:: 13.6""" - - -class _Audio(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.audio) - - -AUDIO = _Audio(name="filters.AUDIO") -"""Messages that contain :attr:`telegram.Message.audio`.""" - - -class Caption(MessageFilter): - """Messages with a caption. If a list of strings is passed, it filters messages to only - allow those whose caption is appearing in the given list. - - Examples: - ``MessageHandler(filters.Caption(['PTB rocks!', 'PTB']), callback_method_2)`` - - .. seealso:: - :attr:`telegram.ext.filters.CAPTION` - - Args: - strings (list[:obj:`str`] | tuple[:obj:`str`], optional): Which captions to allow. Only - exact matches are allowed. If not specified, will allow any message with a caption. - """ - - __slots__ = ("strings",) - - def __init__(self, strings: Optional[Union[list[str], tuple[str, ...]]] = None): - self.strings: Optional[Sequence[str]] = strings - super().__init__(name=f"filters.Caption({strings})" if strings else "filters.CAPTION") - - def filter(self, message: Message) -> bool: - if self.strings is None: - return bool(message.caption) - return message.caption in self.strings if message.caption else False - - -CAPTION = Caption() -"""Shortcut for :class:`telegram.ext.filters.Caption()`. - -Examples: - To allow any caption, simply use ``MessageHandler(filters.CAPTION, callback_method)``. -""" - - -class CaptionEntity(MessageFilter): - """ - Filters media messages to only allow those which have a :class:`telegram.MessageEntity` - where their :class:`~telegram.MessageEntity.type` matches `entity_type`. - - Examples: - ``MessageHandler(filters.CaptionEntity("hashtag"), callback_method)`` - - Args: - entity_type (:obj:`str`): Caption Entity type to check for. All types can be found as - constants in :class:`telegram.MessageEntity`. - - """ - - __slots__ = ("entity_type",) - - def __init__(self, entity_type: str): - self.entity_type: str = entity_type - super().__init__(name=f"filters.CaptionEntity({self.entity_type})") - - def filter(self, message: Message) -> bool: - return any(entity.type == self.entity_type for entity in message.caption_entities) - - -class CaptionRegex(MessageFilter): - """ - Filters updates by searching for an occurrence of :paramref:`~CaptionRegex.pattern` in the - message caption. - - This filter works similarly to :class:`Regex`, with the only exception being that - it applies to the message caption instead of the text. - - Examples: - Use ``MessageHandler(filters.PHOTO & filters.CaptionRegex(r'help'), callback)`` - to capture all photos with caption containing the word 'help'. - - Note: - This filter will not work on simple text messages, but only on media with caption. - - Args: - pattern (:obj:`str` | :func:`re.Pattern `): The regex pattern. - """ - - __slots__ = ("pattern",) - - def __init__(self, pattern: Union[str, Pattern[str]]): - if isinstance(pattern, str): - pattern = re.compile(pattern) - self.pattern: Pattern[str] = pattern - super().__init__(name=f"filters.CaptionRegex({self.pattern})", data_filter=True) - - def filter(self, message: Message) -> Optional[dict[str, list[Match[str]]]]: - if message.caption and (match := self.pattern.search(message.caption)): - return {"matches": [match]} - return {} - - -class _ChatUserBaseFilter(MessageFilter, ABC): - __slots__ = ( - "_chat_id_name", - "_chat_ids", - "_username_name", - "_usernames", - "allow_empty", - ) - - def __init__( - self, - chat_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - allow_empty: bool = False, - ): - super().__init__() - self._chat_id_name: str = "chat_id" - self._username_name: str = "username" - self.allow_empty: bool = allow_empty - - self._chat_ids: set[int] = set() - self._usernames: set[str] = set() - - self._set_chat_ids(chat_id) - self._set_usernames(username) - - @abstractmethod - def _get_chat_or_user(self, message: Message) -> Union[TGChat, TGUser, None]: ... - - def _set_chat_ids(self, chat_id: Optional[SCT[int]]) -> None: - if chat_id and self._usernames: - raise RuntimeError( - f"Can't set {self._chat_id_name} in conjunction with (already set) " - f"{self._username_name}s." - ) - self._chat_ids = set(parse_chat_id(chat_id)) - - def _set_usernames(self, username: Optional[SCT[str]]) -> None: - if username and self._chat_ids: - raise RuntimeError( - f"Can't set {self._username_name} in conjunction with (already set) " - f"{self._chat_id_name}s." - ) - self._usernames = set(parse_username(username)) - - @property - def chat_ids(self) -> frozenset[int]: - return frozenset(self._chat_ids) - - @chat_ids.setter - def chat_ids(self, chat_id: SCT[int]) -> None: - self._set_chat_ids(chat_id) - - @property - def usernames(self) -> frozenset[str]: - """Which username(s) to allow through. - - Warning: - :attr:`usernames` will give a *copy* of the saved usernames as :obj:`frozenset`. This - is to ensure thread safety. To add/remove a user, you should use :meth:`add_usernames`, - and :meth:`remove_usernames`. Only update the entire set by - ``filter.usernames = new_set``, if you are entirely sure that it is not causing race - conditions, as this will complete replace the current set of allowed users. - - Returns: - frozenset(:obj:`str`) - """ - return frozenset(self._usernames) - - @usernames.setter - def usernames(self, username: SCT[str]) -> None: - self._set_usernames(username) - - def add_usernames(self, username: SCT[str]) -> None: - """ - Add one or more chats to the allowed usernames. - - Args: - username(:obj:`str` | Collection[:obj:`str`]): Which username(s) to - allow through. Leading ``'@'`` s in usernames will be discarded. - """ - if self._chat_ids: - raise RuntimeError( - f"Can't set {self._username_name} in conjunction with (already set) " - f"{self._chat_id_name}s." - ) - - parsed_username = set(parse_username(username)) - self._usernames |= parsed_username - - def _add_chat_ids(self, chat_id: SCT[int]) -> None: - if self._usernames: - raise RuntimeError( - f"Can't set {self._chat_id_name} in conjunction with (already set) " - f"{self._username_name}s." - ) - - parsed_chat_id = set(parse_chat_id(chat_id)) - - self._chat_ids |= parsed_chat_id - - def remove_usernames(self, username: SCT[str]) -> None: - """ - Remove one or more chats from allowed usernames. - - Args: - username(:obj:`str` | Collection[:obj:`str`]): Which username(s) to - disallow through. Leading ``'@'`` s in usernames will be discarded. - """ - if self._chat_ids: - raise RuntimeError( - f"Can't set {self._username_name} in conjunction with (already set) " - f"{self._chat_id_name}s." - ) - - parsed_username = set(parse_username(username)) - self._usernames -= parsed_username - - def _remove_chat_ids(self, chat_id: SCT[int]) -> None: - if self._usernames: - raise RuntimeError( - f"Can't set {self._chat_id_name} in conjunction with (already set) " - f"{self._username_name}s." - ) - parsed_chat_id = set(parse_chat_id(chat_id)) - self._chat_ids -= parsed_chat_id - - def filter(self, message: Message) -> bool: - chat_or_user = self._get_chat_or_user(message) - if chat_or_user: - if self.chat_ids: - return chat_or_user.id in self.chat_ids - if self.usernames: - return bool(chat_or_user.username and chat_or_user.username in self.usernames) - return self.allow_empty - return False - - @property - def name(self) -> str: - return ( - f"filters.{self.__class__.__name__}(" - f"{', '.join(str(s) for s in (self.usernames or self.chat_ids))})" - ) - - @name.setter - def name(self, _: str) -> NoReturn: - raise RuntimeError(f"Cannot set name for filters.{self.__class__.__name__}") - - -class Chat(_ChatUserBaseFilter): - """Filters messages to allow only those which are from a specified chat ID or username. - - Examples: - ``MessageHandler(filters.Chat(-1234), callback_method)`` - - Warning: - :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_chat_ids`, and - :meth:`remove_chat_ids`. Only update the entire set by ``filter.chat_ids = new_set``, - if you are entirely sure that it is not causing race conditions, as this will complete - replace the current set of allowed chats. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`], optional): - Which chat ID(s) to allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Attributes: - chat_ids (set(:obj:`int`)): Which chat ID(s) to allow through. - allow_empty (:obj:`bool`): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. - - Raises: - RuntimeError: If ``chat_id`` and ``username`` are both present. - """ - - __slots__ = () - - def _get_chat_or_user(self, message: Message) -> Optional[TGChat]: - return message.chat - - def add_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Add one or more chats to the allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which chat ID(s) to allow - through. - """ - return super()._add_chat_ids(chat_id) - - def remove_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Remove one or more chats from allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which chat ID(s) to - disallow through. - """ - return super()._remove_chat_ids(chat_id) - - -class _Chat(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.chat) - - -CHAT = _Chat(name="filters.CHAT") -"""This filter filters *any* message that has a :attr:`telegram.Message.chat`. - -.. deprecated:: 20.8 - This filter has no effect since :attr:`telegram.Message.chat` is always present. -""" - - -class ChatType: # A convenience namespace for Chat types. - """Subset for filtering the type of chat. - - Examples: - Use these filters like: ``filters.ChatType.CHANNEL`` or - ``filters.ChatType.SUPERGROUP`` etc. - - Caution: - ``filters.ChatType`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _Channel(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type == TGChat.CHANNEL - - CHANNEL = _Channel(name="filters.ChatType.CHANNEL") - """Updates from channel.""" - - class _Group(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type == TGChat.GROUP - - GROUP = _Group(name="filters.ChatType.GROUP") - """Updates from group.""" - - class _Groups(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type in [TGChat.GROUP, TGChat.SUPERGROUP] - - GROUPS = _Groups(name="filters.ChatType.GROUPS") - """Update from group *or* supergroup.""" - - class _Private(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type == TGChat.PRIVATE - - PRIVATE = _Private(name="filters.ChatType.PRIVATE") - """Update from private chats.""" - - class _SuperGroup(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type == TGChat.SUPERGROUP - - SUPERGROUP = _SuperGroup(name="filters.ChatType.SUPERGROUP") - """Updates from supergroup.""" - - -class Command(MessageFilter): - """ - Messages with a :attr:`telegram.MessageEntity.BOT_COMMAND`. By default, only allows - messages `starting` with a bot command. Pass :obj:`False` to also allow messages that contain a - bot command `anywhere` in the text. - - Examples: - ``MessageHandler(filters.Command(False), command_anywhere_callback)`` - - .. seealso:: - :attr:`telegram.ext.filters.COMMAND`. - - Note: - :attr:`telegram.ext.filters.TEXT` also accepts messages containing a command. - - Args: - only_start (:obj:`bool`, optional): Whether to only allow messages that `start` with a bot - command. Defaults to :obj:`True`. - """ - - __slots__ = ("only_start",) - - def __init__(self, only_start: bool = True): - self.only_start: bool = only_start - super().__init__(f"filters.Command({only_start})" if not only_start else "filters.COMMAND") - - def filter(self, message: Message) -> bool: - if not message.entities: - return False - - first = message.entities[0] - - if self.only_start: - return bool(first.type == MessageEntity.BOT_COMMAND and first.offset == 0) - return bool(any(e.type == MessageEntity.BOT_COMMAND for e in message.entities)) - - -COMMAND = Command() -"""Shortcut for :class:`telegram.ext.filters.Command()`. - -Examples: - To allow messages starting with a command use - ``MessageHandler(filters.COMMAND, command_at_start_callback)``. -""" - - -class _Contact(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.contact) - - -CONTACT = _Contact(name="filters.CONTACT") -"""Messages that contain :attr:`telegram.Message.contact`.""" - - -class _Dice(MessageFilter): - __slots__ = ("emoji", "values") - - def __init__(self, values: Optional[SCT[int]] = None, emoji: Optional[DiceEmojiEnum] = None): - super().__init__() - self.emoji: Optional[DiceEmojiEnum] = emoji - self.values: Optional[Collection[int]] = [values] if isinstance(values, int) else values - - if emoji: # for filters.Dice.BASKETBALL - self.name = f"filters.Dice.{emoji.name}" - if self.values and emoji: # for filters.Dice.Dice(4) SLOT_MACHINE -> SlotMachine - self.name = f"filters.Dice.{emoji.name.title().replace('_', '')}({self.values})" - elif values: # for filters.Dice(4) - self.name = f"filters.Dice({self.values})" - else: - self.name = "filters.Dice.ALL" - - def filter(self, message: Message) -> bool: - if not (dice := message.dice): # no dice - return False - - if self.emoji: - emoji_match = dice.emoji == self.emoji - if self.values: - return dice.value in self.values and emoji_match # emoji and value - return emoji_match # emoji, no value - return dice.value in self.values if self.values else True # no emoji, only value - - -class Dice(_Dice): - """Dice Messages. If an integer or a list of integers is passed, it filters messages to only - allow those whose dice value is appearing in the given list. - - .. versionadded:: 13.4 - - Examples: - To allow any dice message, simply use - ``MessageHandler(filters.Dice.ALL, callback_method)``. - - To allow any dice message, but with value 3 `or` 4, use - ``MessageHandler(filters.Dice([3, 4]), callback_method)`` - - To allow only dice messages with the emoji 🎲, but any value, use - ``MessageHandler(filters.Dice.DICE, callback_method)``. - - To allow only dice messages with the emoji 🎯 and with value 6, use - ``MessageHandler(filters.Dice.Darts(6), callback_method)``. - - To allow only dice messages with the emoji ⚽ and with value 5 `or` 6, use - ``MessageHandler(filters.Dice.Football([5, 6]), callback_method)``. - - Note: - Dice messages don't have text. If you want to filter either text or dice messages, use - ``filters.TEXT | filters.Dice.ALL``. - - Args: - values (:obj:`int` | Collection[:obj:`int`], optional): - Which values to allow. If not specified, will allow the specified dice message. - """ - - __slots__ = () - - ALL = _Dice() - """Dice messages with any value and any emoji.""" - - class Basketball(_Dice): - """Dice messages with the emoji 🏀. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.BASKETBALL) - - BASKETBALL = _Dice(emoji=DiceEmojiEnum.BASKETBALL) - """Dice messages with the emoji 🏀. Matches any dice value.""" - - class Bowling(_Dice): - """Dice messages with the emoji 🎳. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.BOWLING) - - BOWLING = _Dice(emoji=DiceEmojiEnum.BOWLING) - """Dice messages with the emoji 🎳. Matches any dice value.""" - - class Darts(_Dice): - """Dice messages with the emoji 🎯. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.DARTS) - - DARTS = _Dice(emoji=DiceEmojiEnum.DARTS) - """Dice messages with the emoji 🎯. Matches any dice value.""" - - class Dice(_Dice): - """Dice messages with the emoji 🎲. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.DICE) - - DICE = _Dice(emoji=DiceEmojiEnum.DICE) - """Dice messages with the emoji 🎲. Matches any dice value.""" - - class Football(_Dice): - """Dice messages with the emoji ⚽. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.FOOTBALL) - - FOOTBALL = _Dice(emoji=DiceEmojiEnum.FOOTBALL) - """Dice messages with the emoji ⚽. Matches any dice value.""" - - class SlotMachine(_Dice): - """Dice messages with the emoji 🎰. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.SLOT_MACHINE) - - SLOT_MACHINE = _Dice(emoji=DiceEmojiEnum.SLOT_MACHINE) - """Dice messages with the emoji 🎰. Matches any dice value.""" - - -class Document: - """ - Subset for messages containing a document/file. - - Examples: - Use these filters like: ``filters.Document.MP3``, - ``filters.Document.MimeType("text/plain")`` etc. Or just use ``filters.Document.ALL`` for - all document messages. - - Caution: - ``filters.Document`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _All(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.document) - - ALL = _All(name="filters.Document.ALL") - """Messages that contain a :attr:`telegram.Message.document`.""" - - class Category(MessageFilter): - """Filters documents by their category in the mime-type attribute. - - Args: - category (:obj:`str`): Category of the media you want to filter. - - Example: - ``filters.Document.Category('audio/')`` returns :obj:`True` for all types - of audio sent as a file, for example ``'audio/mpeg'`` or ``'audio/x-wav'``. - - Note: - This Filter only filters by the mime_type of the document, it doesn't check the - validity of the document. The user can manipulate the mime-type of a message and - send media with wrong types that don't fit to this handler. - """ - - __slots__ = ("_category",) - - def __init__(self, category: str): - self._category = category - super().__init__(name=f"filters.Document.Category('{self._category}')") - - def filter(self, message: Message) -> bool: - if message.document and message.document.mime_type: - return message.document.mime_type.startswith(self._category) - return False - - APPLICATION = Category("application/") - """Use as ``filters.Document.APPLICATION``.""" - AUDIO = Category("audio/") - """Use as ``filters.Document.AUDIO``.""" - IMAGE = Category("image/") - """Use as ``filters.Document.IMAGE``.""" - VIDEO = Category("video/") - """Use as ``filters.Document.VIDEO``.""" - TEXT = Category("text/") - """Use as ``filters.Document.TEXT``.""" - - class FileExtension(MessageFilter): - """This filter filters documents by their file ending/extension. - - Args: - file_extension (:obj:`str` | :obj:`None`): Media file extension you want to filter. - case_sensitive (:obj:`bool`, optional): Pass :obj:`True` to make the filter case - sensitive. Default: :obj:`False`. - - Example: - * ``filters.Document.FileExtension("jpg")`` - filters files with extension ``".jpg"``. - * ``filters.Document.FileExtension(".jpg")`` - filters files with extension ``"..jpg"``. - * ``filters.Document.FileExtension("Dockerfile", case_sensitive=True)`` - filters files with extension ``".Dockerfile"`` minding the case. - * ``filters.Document.FileExtension(None)`` - filters files without a dot in the filename. - - Note: - * This Filter only filters by the file ending/extension of the document, - it doesn't check the validity of document. - * The user can manipulate the file extension of a document and - send media with wrong types that don't fit to this handler. - * Case insensitive by default, - you may change this with the flag ``case_sensitive=True``. - * Extension should be passed without leading dot - unless it's a part of the extension. - * Pass :obj:`None` to filter files with no extension, - i.e. without a dot in the filename. - """ - - __slots__ = ("_file_extension", "is_case_sensitive") - - def __init__(self, file_extension: Optional[str], case_sensitive: bool = False): - super().__init__() - self.is_case_sensitive: bool = case_sensitive - if file_extension is None: - self._file_extension = None - self.name = "filters.Document.FileExtension(None)" - elif self.is_case_sensitive: - self._file_extension = f".{file_extension}" - self.name = ( - f"filters.Document.FileExtension({file_extension!r}, case_sensitive=True)" - ) - else: - self._file_extension = f".{file_extension}".lower() - self.name = f"filters.Document.FileExtension({file_extension.lower()!r})" - - def filter(self, message: Message) -> bool: - if message.document is None or message.document.file_name is None: - return False - if self._file_extension is None: - return "." not in message.document.file_name - if self.is_case_sensitive: - filename = message.document.file_name - else: - filename = message.document.file_name.lower() - return filename.endswith(self._file_extension) - - class MimeType(MessageFilter): - """This Filter filters documents by their mime-type attribute. - - Args: - mimetype (:obj:`str`): The mimetype to filter. - - Example: - ``filters.Document.MimeType('audio/mpeg')`` filters all audio in `.mp3` format. - - Note: - This Filter only filters by the mime_type of the document, it doesn't check the - validity of document. The user can manipulate the mime-type of a message and - send media with wrong types that don't fit to this handler. - """ - - __slots__ = ("mimetype",) - - def __init__(self, mimetype: str): - self.mimetype: str = mimetype - super().__init__(name=f"filters.Document.MimeType('{self.mimetype}')") - - def filter(self, message: Message) -> bool: - if message.document: - return message.document.mime_type == self.mimetype - return False - - APK = MimeType("application/vnd.android.package-archive") - """Use as ``filters.Document.APK``.""" - DOC = MimeType(mimetypes.types_map[".doc"]) - """Use as ``filters.Document.DOC``.""" - DOCX = MimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.document") - """Use as ``filters.Document.DOCX``.""" - EXE = MimeType(mimetypes.types_map[".exe"]) - """Use as ``filters.Document.EXE``.""" - MP4 = MimeType(mimetypes.types_map[".mp4"]) - """Use as ``filters.Document.MP4``.""" - GIF = MimeType(mimetypes.types_map[".gif"]) - """Use as ``filters.Document.GIF``.""" - JPG = MimeType(mimetypes.types_map[".jpg"]) - """Use as ``filters.Document.JPG``.""" - MP3 = MimeType(mimetypes.types_map[".mp3"]) - """Use as ``filters.Document.MP3``.""" - PDF = MimeType(mimetypes.types_map[".pdf"]) - """Use as ``filters.Document.PDF``.""" - PY = MimeType(mimetypes.types_map[".py"]) - """Use as ``filters.Document.PY``.""" - SVG = MimeType(mimetypes.types_map[".svg"]) - """Use as ``filters.Document.SVG``.""" - TXT = MimeType(mimetypes.types_map[".txt"]) - """Use as ``filters.Document.TXT``.""" - TARGZ = MimeType("application/x-compressed-tar") - """Use as ``filters.Document.TARGZ``.""" - WAV = MimeType(mimetypes.types_map[".wav"]) - """Use as ``filters.Document.WAV``.""" - XML = MimeType(mimetypes.types_map[".xml"]) - """Use as ``filters.Document.XML``.""" - ZIP = MimeType(mimetypes.types_map[".zip"]) - """Use as ``filters.Document.ZIP``.""" - - -class _EffectId(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.effect_id) - - -EFFECT_ID = _EffectId(name="filters.EFFECT_ID") -"""Messages that contain :attr:`telegram.Message.effect_id`. - -.. versionadded:: 21.3""" - - -class Entity(MessageFilter): - """ - Filters messages to only allow those which have a :class:`telegram.MessageEntity` - where their :class:`~telegram.MessageEntity.type` matches `entity_type`. - - Examples: - ``MessageHandler(filters.Entity("hashtag"), callback_method)`` - - Args: - entity_type (:obj:`str`): Entity type to check for. All types can be found as constants - in :class:`telegram.MessageEntity`. - - """ - - __slots__ = ("entity_type",) - - def __init__(self, entity_type: str): - self.entity_type: str = entity_type - super().__init__(name=f"filters.Entity({self.entity_type})") - - def filter(self, message: Message) -> bool: - return any(entity.type == self.entity_type for entity in message.entities) - - -class _Forwarded(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forward_origin) - - -FORWARDED = _Forwarded(name="filters.FORWARDED") -"""Messages that contain :attr:`telegram.Message.forward_origin`. - -.. versionchanged:: 20.8 - Now based on :attr:`telegram.Message.forward_origin` instead of - ``telegram.Message.forward_date``. -""" - - -class ForwardedFrom(_ChatUserBaseFilter): - """Filters messages to allow only those which are forwarded from the specified chat ID(s) - or username(s) based on :attr:`telegram.Message.forward_origin` and in particular - - * :attr:`telegram.MessageOriginUser.sender_user` - * :attr:`telegram.MessageOriginChat.sender_chat` - * :attr:`telegram.MessageOriginChannel.chat` - - .. versionadded:: 13.5 - - .. versionchanged:: 20.8 - Was previously based on ``telegram.Message.forward_from`` and - ``telegram.Message.forward_from_chat``. - - Examples: - ``MessageHandler(filters.ForwardedFrom(chat_id=1234), callback_method)`` - - Note: - When a user has disallowed adding a link to their account while forwarding their - messages, this filter will *not* work since - :attr:`telegram.Message.forward_origin` will be of type - :class:`telegram.MessageOriginHiddenUser`. However, this behaviour - is undocumented and might be changed by Telegram. - - Warning: - :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_chat_ids`, and - :meth:`remove_chat_ids`. Only update the entire set by ``filter.chat_ids = new_set``, if - you are entirely sure that it is not causing race conditions, as this will complete replace - the current set of allowed chats. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`], optional): - Which chat/user ID(s) to allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be - discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Attributes: - chat_ids (set(:obj:`int`)): Which chat/user ID(s) to allow through. - allow_empty (:obj:`bool`): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. - - Raises: - RuntimeError: If both ``chat_id`` and ``username`` are present. - """ - - __slots__ = () - - def _get_chat_or_user(self, message: Message) -> Union[TGUser, TGChat, None]: - if (forward_origin := message.forward_origin) is None: - return None - - if isinstance(forward_origin, MessageOriginUser): - return forward_origin.sender_user - if isinstance(forward_origin, MessageOriginChat): - return forward_origin.sender_chat - if isinstance(forward_origin, MessageOriginChannel): - return forward_origin.chat - - return None - - def add_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Add one or more chats to the allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which chat/user ID(s) to - allow through. - """ - return super()._add_chat_ids(chat_id) - - def remove_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Remove one or more chats from allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which chat/user ID(s) to - disallow through. - """ - return super()._remove_chat_ids(chat_id) - - -class _Game(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.game) - - -GAME = _Game(name="filters.GAME") -"""Messages that contain :attr:`telegram.Message.game`.""" - - -class _Giveaway(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.giveaway) - - -GIVEAWAY = _Giveaway(name="filters.GIVEAWAY") -"""Messages that contain :attr:`telegram.Message.giveaway`.""" - - -class _GiveawayWinners(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.giveaway_winners) - - -GIVEAWAY_WINNERS = _GiveawayWinners(name="filters.GIVEAWAY_WINNERS") -"""Messages that contain :attr:`telegram.Message.giveaway_winners`.""" - - -class _HasMediaSpoiler(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.has_media_spoiler) - - -HAS_MEDIA_SPOILER = _HasMediaSpoiler(name="filters.HAS_MEDIA_SPOILER") -"""Messages that contain :attr:`telegram.Message.has_media_spoiler`. - - .. versionadded:: 20.0 -""" - - -class _HasProtectedContent(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.has_protected_content) - - -HAS_PROTECTED_CONTENT = _HasProtectedContent(name="filters.HAS_PROTECTED_CONTENT") -"""Messages that contain :attr:`telegram.Message.has_protected_content`. - - .. versionadded:: 13.9 -""" - - -class _Invoice(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.invoice) - - -INVOICE = _Invoice(name="filters.INVOICE") -"""Messages that contain :attr:`telegram.Message.invoice`.""" - - -class _IsAutomaticForward(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.is_automatic_forward) - - -IS_AUTOMATIC_FORWARD = _IsAutomaticForward(name="filters.IS_AUTOMATIC_FORWARD") -"""Messages that contain :attr:`telegram.Message.is_automatic_forward`. - - .. versionadded:: 13.9 -""" - - -class _IsTopicMessage(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.is_topic_message) - - -IS_TOPIC_MESSAGE = _IsTopicMessage(name="filters.IS_TOPIC_MESSAGE") -"""Messages that contain :attr:`telegram.Message.is_topic_message`. - - .. versionadded:: 20.0 -""" - - -class _IsFromOffline(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.is_from_offline) - - -IS_FROM_OFFLINE = _IsFromOffline(name="filters.IS_FROM_OFFLINE") -"""Messages that contain :attr:`telegram.Message.is_from_offline`. - - .. versionadded:: 21.1 -""" - - -class Language(MessageFilter): - """Filters messages to only allow those which are from users with a certain language code. - - Note: - According to official Telegram Bot API documentation, not every single user has the - `language_code` attribute. Do not count on this filter working on all users. - - Examples: - ``MessageHandler(filters.Language("en"), callback_method)`` - - Args: - lang (:obj:`str` | Collection[:obj:`str`]): - Which language code(s) to allow through. - This will be matched using :obj:`str.startswith` meaning that - 'en' will match both 'en_US' and 'en_GB'. - - """ - - __slots__ = ("lang",) - - def __init__(self, lang: SCT[str]): - if isinstance(lang, str): - lang = cast(str, lang) - self.lang: Sequence[str] = [lang] - else: - lang = cast(list[str], lang) - self.lang = lang - super().__init__(name=f"filters.Language({self.lang})") - - def filter(self, message: Message) -> bool: - return bool( - message.from_user - and message.from_user.language_code - and any(message.from_user.language_code.startswith(x) for x in self.lang) - ) - - -class _Location(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.location) - - -LOCATION = _Location(name="filters.LOCATION") -"""Messages that contain :attr:`telegram.Message.location`.""" - - -class Mention(MessageFilter): - """Messages containing mentions of specified users or chats. - - Examples: - .. code-block:: python - - MessageHandler(filters.Mention("username"), callback) - MessageHandler(filters.Mention(["@username", 123456]), callback) - - .. versionadded:: 20.7 - - Args: - mentions (:obj:`int` | :obj:`str` | :class:`telegram.User` | Collection[:obj:`int` | \ - :obj:`str` | :class:`telegram.User`]): - Specifies the users and chats to filter for. Messages that do not mention at least one - of the specified users or chats will not be handled. Leading ``'@'`` s in usernames - will be discarded. - """ - - __slots__ = ("_mentions",) - - def __init__(self, mentions: SCT[Union[int, str, TGUser]]): - super().__init__(name=f"filters.Mention({mentions})") - if isinstance(mentions, Iterable) and not isinstance(mentions, str): - self._mentions = {self._fix_mention_username(mention) for mention in mentions} - else: - self._mentions = {self._fix_mention_username(mentions)} - - @staticmethod - def _fix_mention_username(mention: Union[int, str, TGUser]) -> Union[int, str, TGUser]: - if not isinstance(mention, str): - return mention - return mention.lstrip("@") - - @classmethod - def _check_mention(cls, message: Message, mention: Union[int, str, TGUser]) -> bool: - if not message.entities: - return False - - entity_texts = message.parse_entities( - types=[MessageEntity.MENTION, MessageEntity.TEXT_MENTION] - ) - - if isinstance(mention, TGUser): - return any( - mention.id == entity.user.id - or mention.username == entity.user.username - or mention.username == cls._fix_mention_username(entity_texts[entity]) - for entity in message.entities - if entity.user - ) or any( - mention.username == cls._fix_mention_username(entity_text) - for entity_text in entity_texts.values() - ) - if isinstance(mention, int): - return bool( - any(mention == entity.user.id for entity in message.entities if entity.user) - ) - return any( - mention == cls._fix_mention_username(entity_text) - for entity_text in entity_texts.values() - ) - - def filter(self, message: Message) -> bool: - return any(self._check_mention(message, mention) for mention in self._mentions) - - -class _PaidMedia(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.paid_media) - - -PAID_MEDIA = _PaidMedia(name="filters.PAID_MEDIA") -"""Messages that contain :attr:`telegram.Message.paid_media`. - -.. versionadded:: 21.4 -""" - - -class _PassportData(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.passport_data) - - -PASSPORT_DATA = _PassportData(name="filters.PASSPORT_DATA") -"""Messages that contain :attr:`telegram.Message.passport_data`.""" - - -class _Photo(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.photo) - - -PHOTO = _Photo("filters.PHOTO") -"""Messages that contain :attr:`telegram.Message.photo`.""" - - -class _Poll(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.poll) - - -POLL = _Poll(name="filters.POLL") -"""Messages that contain :attr:`telegram.Message.poll`.""" - - -class Regex(MessageFilter): - """ - Filters updates by searching for an occurrence of :paramref:`~Regex.pattern` in the message - text. - The :func:`re.search` function is used to determine whether an update should be filtered. - - Refer to the documentation of the :obj:`re` module for more information. - - To get the groups and groupdict matched, see :attr:`telegram.ext.CallbackContext.matches`. - - Examples: - Use ``MessageHandler(filters.Regex(r'help'), callback)`` to capture all messages that - contain the word 'help'. You can also use - ``MessageHandler(filters.Regex(re.compile(r'help', re.IGNORECASE)), callback)`` if - you want your pattern to be case insensitive. This approach is recommended - if you need to specify flags on your pattern. - - Note: - Filters use the same short circuiting logic as python's :keyword:`and`, :keyword:`or` and - :keyword:`not`. - This means that for example: - - >>> filters.Regex(r'(a?x)') | filters.Regex(r'(b?x)') - - With a :attr:`telegram.Message.text` of `x`, will only ever return the matches for the - first filter, since the second one is never evaluated. - - .. seealso:: :wiki:`Types of Handlers ` - - Args: - pattern (:obj:`str` | :func:`re.Pattern `): The regex pattern. - """ - - __slots__ = ("pattern",) - - def __init__(self, pattern: Union[str, Pattern[str]]): - if isinstance(pattern, str): - pattern = re.compile(pattern) - self.pattern: Pattern[str] = pattern - super().__init__(name=f"filters.Regex({self.pattern})", data_filter=True) - - def filter(self, message: Message) -> Optional[dict[str, list[Match[str]]]]: - if message.text and (match := self.pattern.search(message.text)): - return {"matches": [match]} - return {} - - -class _Reply(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.reply_to_message) - - -REPLY = _Reply(name="filters.REPLY") -"""Messages that contain :attr:`telegram.Message.reply_to_message`.""" - - -class _SenderChat(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sender_chat) - - -class SenderChat(_ChatUserBaseFilter): - """Filters messages to allow only those which are from a specified sender chat's chat ID or - username. - - Examples: - * To filter for messages sent to a group by a channel with ID - ``-1234``, use ``MessageHandler(filters.SenderChat(-1234), callback_method)``. - * To filter for messages of anonymous admins in a super group with username - ``@anonymous``, use - ``MessageHandler(filters.SenderChat(username='anonymous'), callback_method)``. - * To filter for messages sent to a group by *any* channel, use - ``MessageHandler(filters.SenderChat.CHANNEL, callback_method)``. - * To filter for messages of anonymous admins in *any* super group, use - ``MessageHandler(filters.SenderChat.SUPERGROUP, callback_method)``. - * To filter for messages forwarded to a discussion group from *any* channel or of anonymous - admins in *any* super group, use ``MessageHandler(filters.SenderChat.ALL, callback)`` - - Note: - Remember, ``sender_chat`` is also set for messages in a channel as the channel itself, - so when your bot is an admin in a channel and the linked discussion group, you would - receive the message twice (once from inside the channel, once inside the discussion - group). Since v13.9, the field :attr:`telegram.Message.is_automatic_forward` will be - :obj:`True` for the discussion group message. - - .. seealso:: :attr:`telegram.ext.filters.IS_AUTOMATIC_FORWARD` - - Warning: - :attr:`chat_ids` will return a *copy* of the saved chat ids as :obj:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_chat_ids`, and - :meth:`remove_chat_ids`. Only update the entire set by ``filter.chat_ids = new_set``, if - you are entirely sure that it is not causing race conditions, as this will complete replace - the current set of allowed chats. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`], optional): - Which sender chat chat ID(s) to allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which sender chat username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender - chat is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Attributes: - chat_ids (set(:obj:`int`)): Which sender chat chat ID(s) to allow through. - allow_empty (:obj:`bool`): Whether updates should be processed, if no sender chat is - specified in :attr:`chat_ids` and :attr:`usernames`. - - Raises: - RuntimeError: If both ``chat_id`` and ``username`` are present. - """ - - __slots__ = () - - class _CHANNEL(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - if message.sender_chat: - return message.sender_chat.type == TGChat.CHANNEL - return False - - class _SUPERGROUP(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - if message.sender_chat: - return message.sender_chat.type == TGChat.SUPERGROUP - return False - - ALL = _SenderChat(name="filters.SenderChat.ALL") - """All messages with a :attr:`telegram.Message.sender_chat`.""" - SUPER_GROUP = _SUPERGROUP(name="filters.SenderChat.SUPER_GROUP") - """Messages whose sender chat is a super group.""" - CHANNEL = _CHANNEL(name="filters.SenderChat.CHANNEL") - """Messages whose sender chat is a channel.""" - - def add_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Add one or more sender chats to the allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which sender chat ID(s) to - allow through. - """ - return super()._add_chat_ids(chat_id) - - def _get_chat_or_user(self, message: Message) -> Optional[TGChat]: - return message.sender_chat - - def remove_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Remove one or more sender chats from allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which sender chat ID(s) to - disallow through. - """ - return super()._remove_chat_ids(chat_id) - - -class StatusUpdate: - """Subset for messages containing a status update. - - Examples: - Use these filters like: ``filters.StatusUpdate.NEW_CHAT_MEMBERS`` etc. Or use just - ``filters.StatusUpdate.ALL`` for all status update messages. - - Caution: - ``filters.StatusUpdate`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _All(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return bool( - # keep this alphabetically sorted for easier maintenance - StatusUpdate.CHAT_BACKGROUND_SET.check_update(update) - or StatusUpdate.CHAT_CREATED.check_update(update) - or StatusUpdate.CHAT_SHARED.check_update(update) - or StatusUpdate.CONNECTED_WEBSITE.check_update(update) - or StatusUpdate.DELETE_CHAT_PHOTO.check_update(update) - or StatusUpdate.FORUM_TOPIC_CLOSED.check_update(update) - or StatusUpdate.FORUM_TOPIC_CREATED.check_update(update) - or StatusUpdate.FORUM_TOPIC_EDITED.check_update(update) - or StatusUpdate.FORUM_TOPIC_REOPENED.check_update(update) - or StatusUpdate.GENERAL_FORUM_TOPIC_HIDDEN.check_update(update) - or StatusUpdate.GENERAL_FORUM_TOPIC_UNHIDDEN.check_update(update) - or StatusUpdate.GIVEAWAY_COMPLETED.check_update(update) - or StatusUpdate.GIVEAWAY_CREATED.check_update(update) - or StatusUpdate.LEFT_CHAT_MEMBER.check_update(update) - or StatusUpdate.MESSAGE_AUTO_DELETE_TIMER_CHANGED.check_update(update) - or StatusUpdate.MIGRATE.check_update(update) - or StatusUpdate.NEW_CHAT_MEMBERS.check_update(update) - or StatusUpdate.NEW_CHAT_PHOTO.check_update(update) - or StatusUpdate.NEW_CHAT_TITLE.check_update(update) - or StatusUpdate.PINNED_MESSAGE.check_update(update) - or StatusUpdate.PROXIMITY_ALERT_TRIGGERED.check_update(update) - or StatusUpdate.REFUNDED_PAYMENT.check_update(update) - or StatusUpdate.USERS_SHARED.check_update(update) - or StatusUpdate.USER_SHARED.check_update(update) - or StatusUpdate.VIDEO_CHAT_ENDED.check_update(update) - or StatusUpdate.VIDEO_CHAT_PARTICIPANTS_INVITED.check_update(update) - or StatusUpdate.VIDEO_CHAT_SCHEDULED.check_update(update) - or StatusUpdate.VIDEO_CHAT_STARTED.check_update(update) - or StatusUpdate.WEB_APP_DATA.check_update(update) - or StatusUpdate.WRITE_ACCESS_ALLOWED.check_update(update) - ) - - ALL = _All(name="filters.StatusUpdate.ALL") - """Messages that contain any of the below.""" - - class _ChatBackgroundSet(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.chat_background_set) - - CHAT_BACKGROUND_SET = _ChatBackgroundSet(name="filters.StatusUpdate.CHAT_BACKGROUND_SET") - """Messages that contain :attr:`telegram.Message.chat_background_set`.""" - - class _ChatCreated(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool( - message.group_chat_created - or message.supergroup_chat_created - or message.channel_chat_created - ) - - CHAT_CREATED = _ChatCreated(name="filters.StatusUpdate.CHAT_CREATED") - """Messages that contain :attr:`telegram.Message.group_chat_created`, - :attr:`telegram.Message.supergroup_chat_created` or - :attr:`telegram.Message.channel_chat_created`.""" - - class _ChatShared(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.chat_shared) - - CHAT_SHARED = _ChatShared(name="filters.StatusUpdate.CHAT_SHARED") - """Messages that contain :attr:`telegram.Message.chat_shared`. - - .. versionadded:: 20.1 - """ - - class _ConnectedWebsite(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.connected_website) - - CONNECTED_WEBSITE = _ConnectedWebsite(name="filters.StatusUpdate.CONNECTED_WEBSITE") - """Messages that contain :attr:`telegram.Message.connected_website`.""" - - class _DeleteChatPhoto(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.delete_chat_photo) - - DELETE_CHAT_PHOTO = _DeleteChatPhoto(name="filters.StatusUpdate.DELETE_CHAT_PHOTO") - """Messages that contain :attr:`telegram.Message.delete_chat_photo`.""" - - class _ForumTopicClosed(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forum_topic_closed) - - FORUM_TOPIC_CLOSED = _ForumTopicClosed(name="filters.StatusUpdate.FORUM_TOPIC_CLOSED") - """Messages that contain :attr:`telegram.Message.forum_topic_closed`. - - .. versionadded:: 20.0 - """ - - class _ForumTopicCreated(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forum_topic_created) - - FORUM_TOPIC_CREATED = _ForumTopicCreated(name="filters.StatusUpdate.FORUM_TOPIC_CREATED") - """Messages that contain :attr:`telegram.Message.forum_topic_created`. - - .. versionadded:: 20.0 - """ - - class _ForumTopicEdited(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forum_topic_edited) - - FORUM_TOPIC_EDITED = _ForumTopicEdited(name="filters.StatusUpdate.FORUM_TOPIC_EDITED") - """Messages that contain :attr:`telegram.Message.forum_topic_edited`. - - .. versionadded:: 20.0 - """ - - class _ForumTopicReopened(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forum_topic_reopened) - - FORUM_TOPIC_REOPENED = _ForumTopicReopened(name="filters.StatusUpdate.FORUM_TOPIC_REOPENED") - """Messages that contain :attr:`telegram.Message.forum_topic_reopened`. - - .. versionadded:: 20.0 - """ - - class _GeneralForumTopicHidden(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.general_forum_topic_hidden) - - GENERAL_FORUM_TOPIC_HIDDEN = _GeneralForumTopicHidden( - name="filters.StatusUpdate.GENERAL_FORUM_TOPIC_HIDDEN" - ) - """Messages that contain :attr:`telegram.Message.general_forum_topic_hidden`. - - .. versionadded:: 20.0 - """ - - class _GeneralForumTopicUnhidden(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.general_forum_topic_unhidden) - - GENERAL_FORUM_TOPIC_UNHIDDEN = _GeneralForumTopicUnhidden( - name="filters.StatusUpdate.GENERAL_FORUM_TOPIC_UNHIDDEN" - ) - """Messages that contain :attr:`telegram.Message.general_forum_topic_unhidden`. - - .. versionadded:: 20.0 - """ - - class _GiveawayCreated(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.giveaway_created) - - GIVEAWAY_CREATED = _GiveawayCreated(name="filters.StatusUpdate.GIVEAWAY_CREATED") - """Messages that contain :attr:`telegram.Message.giveaway_created`. - - .. versionadded:: 20.8 - """ - - class _GiveawayCompleted(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.giveaway_completed) - - GIVEAWAY_COMPLETED = _GiveawayCompleted(name="filters.StatusUpdate.GIVEAWAY_COMPLETED") - """Messages that contain :attr:`telegram.Message.giveaway_completed`. - .. versionadded:: 20.8 - """ - - class _LeftChatMember(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.left_chat_member) - - LEFT_CHAT_MEMBER = _LeftChatMember(name="filters.StatusUpdate.LEFT_CHAT_MEMBER") - """Messages that contain :attr:`telegram.Message.left_chat_member`.""" - - class _MessageAutoDeleteTimerChanged(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.message_auto_delete_timer_changed) - - MESSAGE_AUTO_DELETE_TIMER_CHANGED = _MessageAutoDeleteTimerChanged( - "filters.StatusUpdate.MESSAGE_AUTO_DELETE_TIMER_CHANGED" - ) - """Messages that contain :attr:`telegram.Message.message_auto_delete_timer_changed` - - .. versionadded:: 13.4 - """ - - class _Migrate(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.migrate_from_chat_id or message.migrate_to_chat_id) - - MIGRATE = _Migrate(name="filters.StatusUpdate.MIGRATE") - """Messages that contain :attr:`telegram.Message.migrate_from_chat_id` or - :attr:`telegram.Message.migrate_to_chat_id`.""" - - class _NewChatMembers(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_members) - - NEW_CHAT_MEMBERS = _NewChatMembers(name="filters.StatusUpdate.NEW_CHAT_MEMBERS") - """Messages that contain :attr:`telegram.Message.new_chat_members`.""" - - class _NewChatPhoto(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_photo) - - NEW_CHAT_PHOTO = _NewChatPhoto(name="filters.StatusUpdate.NEW_CHAT_PHOTO") - """Messages that contain :attr:`telegram.Message.new_chat_photo`.""" - - class _NewChatTitle(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_title) - - NEW_CHAT_TITLE = _NewChatTitle(name="filters.StatusUpdate.NEW_CHAT_TITLE") - """Messages that contain :attr:`telegram.Message.new_chat_title`.""" - - class _PinnedMessage(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.pinned_message) - - PINNED_MESSAGE = _PinnedMessage(name="filters.StatusUpdate.PINNED_MESSAGE") - """Messages that contain :attr:`telegram.Message.pinned_message`.""" - - class _ProximityAlertTriggered(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.proximity_alert_triggered) - - PROXIMITY_ALERT_TRIGGERED = _ProximityAlertTriggered( - "filters.StatusUpdate.PROXIMITY_ALERT_TRIGGERED" - ) - """Messages that contain :attr:`telegram.Message.proximity_alert_triggered`.""" - - class _RefundedPayment(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.refunded_payment) - - REFUNDED_PAYMENT = _RefundedPayment("filters.StatusUpdate.REFUNDED_PAYMENT") - """Messages that contain :attr:`telegram.Message.refunded_payment`. - .. versionadded:: 21.4 - """ - - class _UserShared(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.api_kwargs.get("user_shared")) - - USER_SHARED = _UserShared(name="filters.StatusUpdate.USER_SHARED") - """Messages that contain ``"user_shared"`` in :attr:`telegram.TelegramObject.api_kwargs`. - - Warning: - This will only catch the legacy ``user_shared`` field, not the - new :attr:`telegram.Message.users_shared` attribute! - - .. versionchanged:: 21.0 - Now relies on :attr:`telegram.TelegramObject.api_kwargs` as the native attribute - ``Message.user_shared`` was removed. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Use :attr:`USERS_SHARED` instead. - """ - - class _UsersShared(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.users_shared) - - USERS_SHARED = _UsersShared(name="filters.StatusUpdate.USERS_SHARED") - """Messages that contain :attr:`telegram.Message.users_shared`. - - .. versionadded:: 20.8 - """ - - class _VideoChatEnded(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_chat_ended) - - VIDEO_CHAT_ENDED = _VideoChatEnded(name="filters.StatusUpdate.VIDEO_CHAT_ENDED") - """Messages that contain :attr:`telegram.Message.video_chat_ended`. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This filter was formerly named ``VOICE_CHAT_ENDED`` - """ - - class _VideoChatScheduled(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_chat_scheduled) - - VIDEO_CHAT_SCHEDULED = _VideoChatScheduled(name="filters.StatusUpdate.VIDEO_CHAT_SCHEDULED") - """Messages that contain :attr:`telegram.Message.video_chat_scheduled`. - - .. versionadded:: 13.5 - .. versionchanged:: 20.0 - This filter was formerly named ``VOICE_CHAT_SCHEDULED`` - """ - - class _VideoChatStarted(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_chat_started) - - VIDEO_CHAT_STARTED = _VideoChatStarted(name="filters.StatusUpdate.VIDEO_CHAT_STARTED") - """Messages that contain :attr:`telegram.Message.video_chat_started`. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This filter was formerly named ``VOICE_CHAT_STARTED`` - """ - - class _VideoChatParticipantsInvited(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_chat_participants_invited) - - VIDEO_CHAT_PARTICIPANTS_INVITED = _VideoChatParticipantsInvited( - "filters.StatusUpdate.VIDEO_CHAT_PARTICIPANTS_INVITED" - ) - """Messages that contain :attr:`telegram.Message.video_chat_participants_invited`. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This filter was formerly named ``VOICE_CHAT_PARTICIPANTS_INVITED`` - """ - - class _WebAppData(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.web_app_data) - - WEB_APP_DATA = _WebAppData(name="filters.StatusUpdate.WEB_APP_DATA") - """Messages that contain :attr:`telegram.Message.web_app_data`. - - .. versionadded:: 20.0 - """ - - class _WriteAccessAllowed(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.write_access_allowed) - - WRITE_ACCESS_ALLOWED = _WriteAccessAllowed(name="filters.StatusUpdate.WRITE_ACCESS_ALLOWED") - """Messages that contain :attr:`telegram.Message.write_access_allowed`. - - .. versionadded:: 20.0 - """ - - -class Sticker: - """Filters messages which contain a sticker. - - Examples: - Use this filter like: ``filters.Sticker.VIDEO``. Or, just use ``filters.Sticker.ALL`` for - any type of sticker. - - Caution: - ``filters.Sticker`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _All(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) - - ALL = _All(name="filters.Sticker.ALL") - """Messages that contain :attr:`telegram.Message.sticker`.""" - - class _Animated(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) and bool(message.sticker.is_animated) # type: ignore - - ANIMATED = _Animated(name="filters.Sticker.ANIMATED") - """Messages that contain :attr:`telegram.Message.sticker` and - :attr:`is animated `. - - .. versionadded:: 20.0 - """ - - class _Static(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) and ( - not bool(message.sticker.is_animated) # type: ignore[union-attr] - and not bool(message.sticker.is_video) # type: ignore[union-attr] - ) - - STATIC = _Static(name="filters.Sticker.STATIC") - """Messages that contain :attr:`telegram.Message.sticker` and is a static sticker, i.e. does - not contain :attr:`telegram.Sticker.is_animated` or :attr:`telegram.Sticker.is_video`. - - .. versionadded:: 20.0 - """ - - class _Video(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) and bool(message.sticker.is_video) # type: ignore - - VIDEO = _Video(name="filters.Sticker.VIDEO") - """Messages that contain :attr:`telegram.Message.sticker` and is a - :attr:`video sticker `. - - .. versionadded:: 20.0 - """ - - class _Premium(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) and bool( - message.sticker.premium_animation # type: ignore - ) - - PREMIUM = _Premium(name="filters.Sticker.PREMIUM") - """Messages that contain :attr:`telegram.Message.sticker` and have a - :attr:`premium animation `. - - .. versionadded:: 20.0 - """ - # neither mask nor emoji can be a message.sticker, so no filters for them - - -class _Story(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.story) - - -STORY = _Story(name="filters.STORY") -"""Messages that contain :attr:`telegram.Message.story`. - -.. versionadded:: 20.5 -""" - - -class SuccessfulPayment(MessageFilter): - """Successful Payment Messages. If a list of invoice payloads is passed, it filters - messages to only allow those whose `invoice_payload` is appearing in the given list. - - Examples: - `MessageHandler(filters.SuccessfulPayment(['Custom-Payload']), callback_method)` - - .. seealso:: - :attr:`telegram.ext.filters.SUCCESSFUL_PAYMENT` - - Args: - invoice_payloads (list[:obj:`str`] | tuple[:obj:`str`], optional): Which - invoice payloads to allow. Only exact matches are allowed. If not - specified, will allow any invoice payload. - - .. versionadded:: 20.8 - """ - - __slots__ = ("invoice_payloads",) - - def __init__(self, invoice_payloads: Optional[Union[list[str], tuple[str, ...]]] = None): - self.invoice_payloads: Optional[Sequence[str]] = invoice_payloads - super().__init__( - name=( - f"filters.SuccessfulPayment({invoice_payloads})" - if invoice_payloads - else "filters.SUCCESSFUL_PAYMENT" - ) - ) - - def filter(self, message: Message) -> bool: - if self.invoice_payloads is None: - return bool(message.successful_payment) - return ( - payment.invoice_payload in self.invoice_payloads - if (payment := message.successful_payment) - else False - ) - - -SUCCESSFUL_PAYMENT = SuccessfulPayment() -"""Messages that contain :attr:`telegram.Message.successful_payment`.""" - - -class Text(MessageFilter): - """Text Messages. If a list of strings is passed, it filters messages to only allow those - whose text is appearing in the given list. - - Examples: - A simple use case for passing a list is to allow only messages that were sent by a - custom :class:`telegram.ReplyKeyboardMarkup`:: - - buttons = ['Start', 'Settings', 'Back'] - markup = ReplyKeyboardMarkup.from_column(buttons) - ... - MessageHandler(filters.Text(buttons), callback_method) - - .. seealso:: - :attr:`telegram.ext.filters.TEXT` - - - Note: - * Dice messages don't have text. If you want to filter either text or dice messages, use - ``filters.TEXT | filters.Dice.ALL``. - * Messages containing a command are accepted by this filter. Use - ``filters.TEXT & (~filters.COMMAND)``, if you want to filter only text messages without - commands. - - Args: - strings (list[:obj:`str`] | tuple[:obj:`str`], optional): Which messages to allow. Only - exact matches are allowed. If not specified, will allow any text message. - """ - - __slots__ = ("strings",) - - def __init__(self, strings: Optional[Union[list[str], tuple[str, ...]]] = None): - self.strings: Optional[Sequence[str]] = strings - super().__init__(name=f"filters.Text({strings})" if strings else "filters.TEXT") - - def filter(self, message: Message) -> bool: - if self.strings is None: - return bool(message.text) - return message.text in self.strings if message.text else False - - -TEXT = Text() -""" -Shortcut for :class:`telegram.ext.filters.Text()`. - -Examples: - To allow any text message, simply use ``MessageHandler(filters.TEXT, callback_method)``. -""" - - -class UpdateType: - """ - Subset for filtering the type of update. - - Examples: - Use these filters like: ``filters.UpdateType.MESSAGE`` or - ``filters.UpdateType.CHANNEL_POSTS`` etc. - - Caution: - ``filters.UpdateType`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _ChannelPost(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.channel_post is not None - - CHANNEL_POST = _ChannelPost(name="filters.UpdateType.CHANNEL_POST") - """Updates with :attr:`telegram.Update.channel_post`.""" - - class _ChannelPosts(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.channel_post is not None or update.edited_channel_post is not None - - CHANNEL_POSTS = _ChannelPosts(name="filters.UpdateType.CHANNEL_POSTS") - """Updates with either :attr:`telegram.Update.channel_post` or - :attr:`telegram.Update.edited_channel_post`.""" - - class _Edited(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return ( - update.edited_message is not None - or update.edited_channel_post is not None - or update.edited_business_message is not None - ) - - EDITED = _Edited(name="filters.UpdateType.EDITED") - """Updates with :attr:`telegram.Update.edited_message`, - :attr:`telegram.Update.edited_channel_post`, or - :attr:`telegram.Update.edited_business_message`. - - .. versionadded:: 20.0 - - .. versionchanged:: 21.1 - Added :attr:`telegram.Update.edited_business_message` to the filter. - """ - - class _EditedChannelPost(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.edited_channel_post is not None - - EDITED_CHANNEL_POST = _EditedChannelPost(name="filters.UpdateType.EDITED_CHANNEL_POST") - """Updates with :attr:`telegram.Update.edited_channel_post`.""" - - class _EditedMessage(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.edited_message is not None - - EDITED_MESSAGE = _EditedMessage(name="filters.UpdateType.EDITED_MESSAGE") - """Updates with :attr:`telegram.Update.edited_message`.""" - - class _Message(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.message is not None - - MESSAGE = _Message(name="filters.UpdateType.MESSAGE") - """Updates with :attr:`telegram.Update.message`.""" - - class _Messages(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.message is not None or update.edited_message is not None - - MESSAGES = _Messages(name="filters.UpdateType.MESSAGES") - """Updates with either :attr:`telegram.Update.message` or - :attr:`telegram.Update.edited_message`. - """ - - class _BusinessMessage(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.business_message is not None - - BUSINESS_MESSAGE = _BusinessMessage(name="filters.UpdateType.BUSINESS_MESSAGE") - """Updates with :attr:`telegram.Update.business_message`. - - .. versionadded:: 21.1""" - - class _EditedBusinessMessage(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.edited_business_message is not None - - EDITED_BUSINESS_MESSAGE = _EditedBusinessMessage( - name="filters.UpdateType.EDITED_BUSINESS_MESSAGE" - ) - """Updates with :attr:`telegram.Update.edited_business_message`. - - .. versionadded:: 21.1 - """ - - class _BusinessMessages(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return ( - update.business_message is not None or update.edited_business_message is not None - ) - - BUSINESS_MESSAGES = _BusinessMessages(name="filters.UpdateType.BUSINESS_MESSAGES") - """Updates with either :attr:`telegram.Update.business_message` or - :attr:`telegram.Update.edited_business_message`. - - .. versionadded:: 21.1 - """ - - -class User(_ChatUserBaseFilter): - """Filters messages to allow only those which are from specified user ID(s) or - username(s). - - Examples: - ``MessageHandler(filters.User(1234), callback_method)`` - - Args: - user_id(:obj:`int` | Collection[:obj:`int`], optional): Which user ID(s) to - allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user is - specified in :attr:`user_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Raises: - RuntimeError: If ``user_id`` and ``username`` are both present. - - Attributes: - allow_empty (:obj:`bool`): Whether updates should be processed, if no user is specified in - :attr:`user_ids` and :attr:`usernames`. - """ - - __slots__ = () - - def __init__( - self, - user_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - allow_empty: bool = False, - ): - super().__init__(chat_id=user_id, username=username, allow_empty=allow_empty) - self._chat_id_name = "user_id" - - def _get_chat_or_user(self, message: Message) -> Optional[TGUser]: - return message.from_user - - @property - def user_ids(self) -> frozenset[int]: - """ - Which user ID(s) to allow through. - - Warning: - :attr:`user_ids` will give a *copy* of the saved user ids as :obj:`frozenset`. This - is to ensure thread safety. To add/remove a user, you should use :meth:`add_user_ids`, - and :meth:`remove_user_ids`. Only update the entire set by - ``filter.user_ids = new_set``, if you are entirely sure that it is not causing race - conditions, as this will complete replace the current set of allowed users. - - Returns: - frozenset(:obj:`int`) - """ - return self.chat_ids - - @user_ids.setter - def user_ids(self, user_id: SCT[int]) -> None: - self.chat_ids = user_id # type: ignore[assignment] - - def add_user_ids(self, user_id: SCT[int]) -> None: - """ - Add one or more users to the allowed user ids. - - Args: - user_id(:obj:`int` | Collection[:obj:`int`]): Which user ID(s) to allow - through. - """ - return super()._add_chat_ids(user_id) - - def remove_user_ids(self, user_id: SCT[int]) -> None: - """ - Remove one or more users from allowed user ids. - - Args: - user_id(:obj:`int` | Collection[:obj:`int`]): Which user ID(s) to - disallow through. - """ - return super()._remove_chat_ids(user_id) - - -class _User(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.from_user) - - -USER = _User(name="filters.USER") -"""This filter filters *any* message that has a :attr:`telegram.Message.from_user`.""" - - -class _UserAttachment(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return bool(update.effective_user) and bool( - update.effective_user.added_to_attachment_menu # type: ignore - ) - - -USER_ATTACHMENT = _UserAttachment(name="filters.USER_ATTACHMENT") -"""This filter filters *any* message that have a user who added the bot to their -:attr:`attachment menu ` as -:attr:`telegram.Update.effective_user`. - -.. versionadded:: 20.0 -""" - - -class _UserPremium(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return bool(update.effective_user) and bool( - update.effective_user.is_premium # type: ignore - ) - - -PREMIUM_USER = _UserPremium(name="filters.PREMIUM_USER") -"""This filter filters *any* message from a -:attr:`Telegram Premium user ` as :attr:`telegram.Update.effective_user`. - -.. versionadded:: 20.0 -""" - - -class _Venue(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.venue) - - -VENUE = _Venue(name="filters.VENUE") -"""Messages that contain :attr:`telegram.Message.venue`.""" - - -class ViaBot(_ChatUserBaseFilter): - """Filters messages to allow only those which are from specified via_bot ID(s) or username(s). - - Examples: - ``MessageHandler(filters.ViaBot(1234), callback_method)`` - - .. seealso:: :attr:`~telegram.ext.filters.VIA_BOT` - - Args: - bot_id(:obj:`int` | Collection[:obj:`int`], optional): Which bot ID(s) to - allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be - discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user - is specified in :attr:`bot_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Raises: - RuntimeError: If ``bot_id`` and ``username`` are both present. - - Attributes: - allow_empty (:obj:`bool`): Whether updates should be processed, if no bot is specified in - :attr:`bot_ids` and :attr:`usernames`. - """ - - __slots__ = () - - def __init__( - self, - bot_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - allow_empty: bool = False, - ): - super().__init__(chat_id=bot_id, username=username, allow_empty=allow_empty) - self._chat_id_name = "bot_id" - - def _get_chat_or_user(self, message: Message) -> Optional[TGUser]: - return message.via_bot - - @property - def bot_ids(self) -> frozenset[int]: - """ - Which bot ID(s) to allow through. - - Warning: - :attr:`bot_ids` will give a *copy* of the saved bot ids as :obj:`frozenset`. This - is to ensure thread safety. To add/remove a bot, you should use :meth:`add_bot_ids`, - and :meth:`remove_bot_ids`. Only update the entire set by ``filter.bot_ids = new_set``, - if you are entirely sure that it is not causing race conditions, as this will complete - replace the current set of allowed bots. - - Returns: - frozenset(:obj:`int`) - """ - return self.chat_ids - - @bot_ids.setter - def bot_ids(self, bot_id: SCT[int]) -> None: - self.chat_ids = bot_id # type: ignore[assignment] - - def add_bot_ids(self, bot_id: SCT[int]) -> None: - """ - Add one or more bots to the allowed bot ids. - - Args: - bot_id(:obj:`int` | Collection[:obj:`int`]): Which bot ID(s) to allow - through. - """ - return super()._add_chat_ids(bot_id) - - def remove_bot_ids(self, bot_id: SCT[int]) -> None: - """ - Remove one or more bots from allowed bot ids. - - Args: - bot_id(:obj:`int` | Collection[:obj:`int`], optional): Which bot ID(s) to - disallow through. - """ - return super()._remove_chat_ids(bot_id) - - -class _ViaBot(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.via_bot) - - -VIA_BOT = _ViaBot(name="filters.VIA_BOT") -"""This filter filters for message that were sent via *any* bot. - -.. seealso:: :class:`~telegram.ext.filters.ViaBot`""" - - -class _Video(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video) - - -VIDEO = _Video(name="filters.VIDEO") -"""Messages that contain :attr:`telegram.Message.video`.""" - - -class _VideoNote(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_note) - - -VIDEO_NOTE = _VideoNote(name="filters.VIDEO_NOTE") -"""Messages that contain :attr:`telegram.Message.video_note`.""" - - -class _Voice(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.voice) - - -VOICE = _Voice("filters.VOICE") -"""Messages that contain :attr:`telegram.Message.voice`.""" - - -class _ReplyToStory(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.reply_to_story) - - -REPLY_TO_STORY = _ReplyToStory(name="filters.REPLY_TO_STORY") -"""Messages that contain :attr:`telegram.Message.reply_to_story`.""" - - -class _BoostAdded(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.boost_added) - - -BOOST_ADDED = _BoostAdded(name="filters.BOOST_ADDED") -"""Messages that contain :attr:`telegram.Message.boost_added`.""" - - -class _SenderBoostCount(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sender_boost_count) - - -SENDER_BOOST_COUNT = _SenderBoostCount(name="filters.SENDER_BOOST_COUNT") -"""Messages that contain :attr:`telegram.Message.sender_boost_count`.""" diff --git a/venv/lib/python3.11/site-packages/telegram/helpers.py b/venv/lib/python3.11/site-packages/telegram/helpers.py deleted file mode 100755 index 81dd4b6..0000000 --- a/venv/lib/python3.11/site-packages/telegram/helpers.py +++ /dev/null @@ -1,201 +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 -# -# 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 convenience helper functions. - -.. versionchanged:: 20.0 - Previously, the contents of this module were available through the (no longer existing) - module ``telegram.utils.helpers``. -""" - -__all__ = ( - "create_deep_linked_url", - "effective_message_type", - "escape_markdown", - "mention_html", - "mention_markdown", -) - -import re -from html import escape -from typing import TYPE_CHECKING, Optional, Union - -from telegram._utils.types import MarkdownVersion -from telegram.constants import MessageLimit, MessageType - -if TYPE_CHECKING: - from telegram import Message, Update - - -def escape_markdown( - text: str, version: MarkdownVersion = 1, entity_type: Optional[str] = None -) -> str: - """Helper function to escape telegram markup symbols. - - .. versionchanged:: 20.3 - Custom emoji entity escaping is now supported. - - Args: - text (:obj:`str`): The text. - version (:obj:`int` | :obj:`str`): Use to specify the version of telegrams Markdown. - Either ``1`` or ``2``. Defaults to ``1``. - entity_type (:obj:`str`, optional): For the entity types - :tg-const:`telegram.MessageEntity.PRE`, :tg-const:`telegram.MessageEntity.CODE` and - the link part of :tg-const:`telegram.MessageEntity.TEXT_LINK` and - :tg-const:`telegram.MessageEntity.CUSTOM_EMOJI`, only certain characters need to be - escaped in :tg-const:`telegram.constants.ParseMode.MARKDOWN_V2`. See the `official API - documentation `_ for details. - Only valid in combination with ``version=2``, will be ignored else. - """ - if int(version) == 1: - escape_chars = r"_*`[" - elif int(version) == 2: - if entity_type in ["pre", "code"]: - escape_chars = r"\`" - elif entity_type in ["text_link", "custom_emoji"]: - escape_chars = r"\)" - else: - escape_chars = r"\_*[]()~`>#+-=|{}.!" - else: - raise ValueError("Markdown version must be either 1 or 2!") - - return re.sub(f"([{re.escape(escape_chars)}])", r"\\\1", text) - - -def mention_html(user_id: Union[int, str], name: str) -> str: - """ - Helper function to create a user mention as HTML tag. - - Args: - user_id (:obj:`int`): The user's id which you want to mention. - name (:obj:`str`): The name the mention is showing. - - Returns: - :obj:`str`: The inline mention for the user as HTML. - """ - return f'{escape(name)}' - - -def mention_markdown(user_id: Union[int, str], name: str, version: MarkdownVersion = 1) -> str: - """ - Helper function to create a user mention in Markdown syntax. - - Args: - user_id (:obj:`int`): The user's id which you want to mention. - name (:obj:`str`): The name the mention is showing. - version (:obj:`int` | :obj:`str`): Use to specify the version of Telegram's Markdown. - Either ``1`` or ``2``. Defaults to ``1``. - - Returns: - :obj:`str`: The inline mention for the user as Markdown. - """ - tg_link = f"tg://user?id={user_id}" - if version == 1: - return f"[{name}]({tg_link})" - return f"[{escape_markdown(name, version=version)}]({tg_link})" - - -def effective_message_type(entity: Union["Message", "Update"]) -> Optional[str]: - """ - Extracts the type of message as a string identifier from a :class:`telegram.Message` or a - :class:`telegram.Update`. - - Args: - entity (:class:`telegram.Update` | :class:`telegram.Message`): The ``update`` or - ``message`` to extract from. - - Returns: - :obj:`str` | :obj:`None`: One of :class:`telegram.constants.MessageType` if the entity - contains a message that matches one of those types. :obj:`None` otherwise. - - """ - # Importing on file-level yields cyclic Import Errors - from telegram import Message, Update # pylint: disable=import-outside-toplevel - - if isinstance(entity, Message): - message = entity - elif isinstance(entity, Update): - if not entity.effective_message: - return None - message = entity.effective_message - else: - raise TypeError(f"The entity is neither Message nor Update (got: {type(entity)})") - - for message_type in MessageType: - if message[message_type]: - return message_type - - return None - - -def create_deep_linked_url( - bot_username: str, payload: Optional[str] = None, group: bool = False -) -> str: - """ - Creates a deep-linked URL for this :paramref:`~create_deep_linked_url.bot_username` with the - specified :paramref:`~create_deep_linked_url.payload`. See - https://core.telegram.org/bots/features#deep-linking to learn more. - - The :paramref:`~create_deep_linked_url.payload` may consist of the following characters: - ``A-Z, a-z, 0-9, _, -`` - - Note: - Works well in conjunction with - ``CommandHandler("start", callback, filters=filters.Regex('payload'))`` - - Examples: - * ``create_deep_linked_url(bot.get_me().username, "some-params")`` - * :any:`Deep Linking ` - - Args: - bot_username (:obj:`str`): The username to link to. - payload (:obj:`str`, optional): Parameters to encode in the created URL. - group (:obj:`bool`, optional): If :obj:`True` the user is prompted to select a group to - add the bot to. If :obj:`False`, opens a one-on-one conversation with the bot. - Defaults to :obj:`False`. - - Returns: - :obj:`str`: An URL to start the bot with specific parameters. - - Raises: - :exc:`ValueError`: If the length of the :paramref:`payload` exceeds \ - :tg-const:`telegram.constants.MessageLimit.DEEP_LINK_LENGTH` characters, - contains invalid characters, or if the :paramref:`bot_username` is less than 4 - characters. - """ - if bot_username is None or len(bot_username) <= 3: - raise ValueError("You must provide a valid bot_username.") - - base_url = f"https://t.me/{bot_username}" - if not payload: - return base_url - - if len(payload) > MessageLimit.DEEP_LINK_LENGTH: - raise ValueError( - f"The deep-linking payload must not exceed {MessageLimit.DEEP_LINK_LENGTH} characters." - ) - - if not re.match(r"^[A-Za-z0-9_-]+$", payload): - raise ValueError( - "Only the following characters are allowed for deep-linked " - "URLs: A-Z, a-z, 0-9, _ and -" - ) - - key = "startgroup" if group else "start" - - return f"{base_url}?{key}={payload}" diff --git a/venv/lib/python3.11/site-packages/telegram/py.typed b/venv/lib/python3.11/site-packages/telegram/py.typed deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/request/__init__.py b/venv/lib/python3.11/site-packages/telegram/request/__init__.py deleted file mode 100755 index 87040d7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/__init__.py +++ /dev/null @@ -1,24 +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 -# -# 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 handle the networking backend of ``python-telegram-bot``.""" - -from ._baserequest import BaseRequest -from ._httpxrequest import HTTPXRequest -from ._requestdata import RequestData - -__all__ = ("BaseRequest", "HTTPXRequest", "RequestData") diff --git a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/request/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 29230bc..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_baserequest.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_baserequest.cpython-311.pyc deleted file mode 100755 index 003daa1..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_baserequest.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_httpxrequest.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_httpxrequest.cpython-311.pyc deleted file mode 100755 index 860fd74..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_httpxrequest.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_requestdata.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_requestdata.cpython-311.pyc deleted file mode 100755 index 288ad74..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_requestdata.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_requestparameter.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_requestparameter.cpython-311.pyc deleted file mode 100755 index 5f65db8..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_requestparameter.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/request/_baserequest.py b/venv/lib/python3.11/site-packages/telegram/request/_baserequest.py deleted file mode 100755 index 3872918..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/_baserequest.py +++ /dev/null @@ -1,457 +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 -# -# 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 abstract class to make POST and GET requests.""" -import abc -import json -from contextlib import AbstractAsyncContextManager -from http import HTTPStatus -from types import TracebackType -from typing import Final, Optional, TypeVar, Union, final - -from telegram._utils.defaultvalue import DEFAULT_NONE as _DEFAULT_NONE -from telegram._utils.defaultvalue import DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.strings import TextEncoding -from telegram._utils.types import JSONDict, ODVInput -from telegram._utils.warnings import warn -from telegram._version import __version__ as ptb_ver -from telegram.error import ( - BadRequest, - ChatMigrated, - Conflict, - Forbidden, - InvalidToken, - NetworkError, - RetryAfter, - TelegramError, -) -from telegram.request._requestdata import RequestData -from telegram.warnings import PTBDeprecationWarning - -RT = TypeVar("RT", bound="BaseRequest") - -_LOGGER = get_logger(__name__, class_name="BaseRequest") - - -class BaseRequest( - AbstractAsyncContextManager["BaseRequest"], - abc.ABC, -): - """Abstract interface class that allows python-telegram-bot to make requests to the Bot API. - Can be implemented via different asyncio HTTP libraries. An implementation of this class - must implement all abstract methods and properties. - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with request_object: - # code - - is roughly equivalent to - - .. code:: python - - try: - await request_object.initialize() - # code - finally: - await request_object.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - Tip: - JSON encoding and decoding is done with the standard library's :mod:`json` by default. - To use a custom library for this, you can override :meth:`parse_json_payload` and implement - custom logic to encode the keys of :attr:`telegram.request.RequestData.parameters`. - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Builder Pattern ` - - .. versionadded:: 20.0 - """ - - __slots__ = () - - USER_AGENT: Final[str] = f"python-telegram-bot v{ptb_ver} (https://python-telegram-bot.org)" - """:obj:`str`: A description that can be used as user agent for requests made to the Bot API. - """ - DEFAULT_NONE: Final[DefaultValue[None]] = _DEFAULT_NONE - """:class:`object`: A special object that indicates that an argument of a function was not - explicitly passed. Used for the timeout parameters of :meth:`post` and :meth:`do_request`. - - Example: - When calling ``request.post(url)``, ``request`` should use the default timeouts set on - initialization. When calling ``request.post(url, connect_timeout=5, read_timeout=None)``, - ``request`` should use ``5`` for the connect timeout and :obj:`None` for the read timeout. - - Use ``if parameter is (not) BaseRequest.DEFAULT_NONE:`` to check if the parameter was set. - """ - - async def __aenter__(self: RT) -> RT: - """|async_context_manager| :meth:`initializes ` the Request. - - Returns: - The initialized Request instance. - - Raises: - :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. - """ - try: - await self.initialize() - except Exception: - await self.shutdown() - raise - return self - - async def __aexit__( - self, - exc_type: Optional[type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - """|async_context_manager| :meth:`shuts down ` the Request.""" - # Make sure not to return `True` so that exceptions are not suppressed - # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ - await self.shutdown() - - @property - def read_timeout(self) -> Optional[float]: - """This property must return the default read timeout in seconds used by this class. - More precisely, the returned value should be the one used when - :paramref:`post.read_timeout` of :meth:post` is not passed/equal to :attr:`DEFAULT_NONE`. - - .. versionadded:: 20.7 - - Warning: - For now this property does not need to be implemented by subclasses and will raise - :exc:`NotImplementedError` if accessed without being overridden. However, in future - versions, this property will be abstract and must be implemented by subclasses. - - Returns: - :obj:`float` | :obj:`None`: The read timeout in seconds. - """ - raise NotImplementedError - - @abc.abstractmethod - async def initialize(self) -> None: - """Initialize resources used by this class. Must be implemented by a subclass.""" - - @abc.abstractmethod - async def shutdown(self) -> None: - """Stop & clear resources used by this class. Must be implemented by a subclass.""" - - @final - async def post( - self, - url: str, - request_data: Optional[RequestData] = 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, - ) -> Union[JSONDict, list[JSONDict], bool]: - """Makes a request to the Bot API handles the return code and parses the answer. - - Warning: - This method will be called by the methods of :class:`telegram.Bot` and should *not* be - called manually. - - Args: - url (:obj:`str`): The URL to request. - request_data (:class:`telegram.request.RequestData`, optional): An object containing - information about parameters and files to upload for the request. - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file) instead of the time - specified during creating of this object. Defaults to :attr:`DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed instead of the time specified during creating of this object. Defaults - to :attr:`DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - - Returns: - The JSON response of the Bot API. - - """ - result = await self._request_wrapper( - url=url, - method="POST", - request_data=request_data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - json_data = self.parse_json_payload(result) - # For successful requests, the results are in the 'result' entry - # see https://core.telegram.org/bots/api#making-requests - return json_data["result"] - - @final - async def retrieve( - self, - url: str, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - ) -> bytes: - """Retrieve the contents of a file by its URL. - - Warning: - This method will be called by the methods of :class:`telegram.Bot` and should *not* be - called manually. - - Args: - url (:obj:`str`): The web location we want to retrieve. - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file) instead of the time - specified during creating of this object. Defaults to :attr:`DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed instead of the time specified during creating of this object. Defaults - to :attr:`DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - - Returns: - :obj:`bytes`: The files contents. - - """ - return await self._request_wrapper( - url=url, - method="GET", - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - - async def _request_wrapper( - self, - url: str, - method: str, - request_data: Optional[RequestData] = 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, - ) -> bytes: - """Wraps the real implementation request method. - - Performs the following tasks: - * Handle the various HTTP response codes. - * Parse the Telegram server response. - - Args: - url (:obj:`str`): The URL to request. - method (:obj:`str`): HTTP method (i.e. 'POST', 'GET', etc.). - request_data (:class:`telegram.request.RequestData`, optional): An object containing - information about parameters and files to upload for the request. - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file) instead of the time - specified during creating of this object. Defaults to :attr:`DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed instead of the time specified during creating of this object. Defaults - to :attr:`DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - - Returns: - bytes: The payload part of the HTTP server response. - - Raises: - TelegramError - - """ - # Import needs to be here since HTTPXRequest is a subclass of BaseRequest - from telegram.request import HTTPXRequest # pylint: disable=import-outside-toplevel - - # 20 is the documented default value for all the media related bot methods and custom - # implementations of BaseRequest may explicitly rely on that. Hence, we follow the - # standard deprecation policy and deprecate starting with version 20.7. - # For our own implementation HTTPXRequest, we can handle that ourselves, so we skip the - # warning in that case. - has_files = request_data and request_data.multipart_data - if ( - has_files - and not isinstance(self, HTTPXRequest) - and isinstance(write_timeout, DefaultValue) - ): - warn( - PTBDeprecationWarning( - "20.7", - f"The `write_timeout` parameter passed to {self.__class__.__name__}.do_request" - " will default to `BaseRequest.DEFAULT_NONE` instead of 20 in future versions " - "for *all* methods of the `Bot` class, including methods sending media.", - ), - stacklevel=3, - ) - write_timeout = 20 - - try: - code, payload = await self.do_request( - url=url, - method=method, - request_data=request_data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - except TelegramError: - raise - except Exception as exc: - raise NetworkError(f"Unknown error in HTTP implementation: {exc!r}") from exc - - if HTTPStatus.OK <= code <= 299: - # 200-299 range are HTTP success statuses - return payload - - response_data = self.parse_json_payload(payload) - - description = response_data.get("description") - message = description if description else "Unknown HTTPError" - - # In some special cases, we can raise more informative exceptions: - # see https://core.telegram.org/bots/api#responseparameters and - # https://core.telegram.org/bots/api#making-requests - # TGs response also has the fields 'ok' and 'error_code'. - # However, we rather rely on the HTTP status code for now. - parameters = response_data.get("parameters") - if parameters: - migrate_to_chat_id = parameters.get("migrate_to_chat_id") - if migrate_to_chat_id: - raise ChatMigrated(migrate_to_chat_id) - retry_after = parameters.get("retry_after") - if retry_after: - raise RetryAfter(retry_after) - - message += f"\nThe server response contained unknown parameters: {parameters}" - - if code == HTTPStatus.FORBIDDEN: # 403 - raise Forbidden(message) - if code in (HTTPStatus.NOT_FOUND, HTTPStatus.UNAUTHORIZED): # 404 and 401 - # TG returns 404 Not found for - # 1) malformed tokens - # 2) correct tokens but non-existing method, e.g. api.tg.org/botTOKEN/unkonwnMethod - # 2) is relevant only for Bot.do_api_request, where we have special handing for it. - # TG returns 401 Unauthorized for correctly formatted tokens that are not valid - raise InvalidToken(message) - if code == HTTPStatus.BAD_REQUEST: # 400 - raise BadRequest(message) - if code == HTTPStatus.CONFLICT: # 409 - raise Conflict(message) - if code == HTTPStatus.BAD_GATEWAY: # 502 - raise NetworkError(description or "Bad Gateway") - raise NetworkError(f"{message} ({code})") - - @staticmethod - def parse_json_payload(payload: bytes) -> JSONDict: - """Parse the JSON returned from Telegram. - - Tip: - By default, this method uses the standard library's :func:`json.loads` and - ``errors="replace"`` in :meth:`bytes.decode`. - You can override it to customize either of these behaviors. - - Args: - payload (:obj:`bytes`): The UTF-8 encoded JSON payload as returned by Telegram. - - Returns: - dict: A JSON parsed as Python dict with results. - - Raises: - TelegramError: If loading the JSON data failed - """ - decoded_s = payload.decode(TextEncoding.UTF_8, "replace") - try: - return json.loads(decoded_s) - except ValueError as exc: - _LOGGER.exception('Can not load invalid JSON data: "%s"', decoded_s) - raise TelegramError("Invalid server response") from exc - - @abc.abstractmethod - async def do_request( - self, - url: str, - method: str, - request_data: Optional[RequestData] = 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, - ) -> tuple[int, bytes]: - """Makes a request to the Bot API. Must be implemented by a subclass. - - Warning: - This method will be called by :meth:`post` and :meth:`retrieve`. It should *not* be - called manually. - - Args: - url (:obj:`str`): The URL to request. - method (:obj:`str`): HTTP method (i.e. ``'POST'``, ``'GET'``, etc.). - request_data (:class:`telegram.request.RequestData`, optional): An object containing - information about parameters and files to upload for the request. - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file) instead of the time - specified during creating of this object. Defaults to :attr:`DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed instead of the time specified during creating of this object. Defaults - to :attr:`DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - - Returns: - tuple[:obj:`int`, :obj:`bytes`]: The HTTP return code & the payload part of the server - response. - """ diff --git a/venv/lib/python3.11/site-packages/telegram/request/_httpxrequest.py b/venv/lib/python3.11/site-packages/telegram/request/_httpxrequest.py deleted file mode 100755 index b31efbf..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/_httpxrequest.py +++ /dev/null @@ -1,319 +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 -# -# 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 methods to make POST and GET requests using the httpx library.""" -from collections.abc import Collection -from typing import Any, Optional, Union - -import httpx - -from telegram._utils.defaultvalue import DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.types import HTTPVersion, ODVInput, SocketOpt -from telegram._utils.warnings import warn -from telegram.error import NetworkError, TimedOut -from telegram.request._baserequest import BaseRequest -from telegram.request._requestdata import RequestData -from telegram.warnings import PTBDeprecationWarning - -# Note to future devs: -# Proxies are currently only tested manually. The httpx development docs have a nice guide on that: -# https://www.python-httpx.org/contributing/#development-proxy-setup (also saved on archive.org) -# That also works with socks5. Just pass `--mode socks5` to mitmproxy - -_LOGGER = get_logger(__name__, "HTTPXRequest") - - -class HTTPXRequest(BaseRequest): - """Implementation of :class:`~telegram.request.BaseRequest` using the library - `httpx `_. - - .. versionadded:: 20.0 - - Args: - connection_pool_size (:obj:`int`, optional): Number of connections to keep in the - connection pool. Defaults to ``1``. - - Note: - Independent of the value, one additional connection will be reserved for - :meth:`telegram.Bot.get_updates`. - proxy_url (:obj:`str`, optional): Legacy name for :paramref:`proxy`, kept for backward - compatibility. Defaults to :obj:`None`. - - .. deprecated:: 20.7 - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server. - This value is used unless a different value is passed to :meth:`do_request`. - Defaults to ``5``. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file). - This value is used unless a different value is passed to :meth:`do_request`. - Defaults to ``5``. - - Hint: - This timeout is used for all requests except for those that upload media/files. - For the latter, :paramref:`media_write_timeout` is used. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed. This value is used unless a different value is passed to - :meth:`do_request`. Defaults to ``5``. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available. - This value is used unless a different value is passed to :meth:`do_request`. - Defaults to ``1``. - - Warning: - With a finite pool timeout, you must expect :exc:`telegram.error.TimedOut` - exceptions to be thrown when more requests are made simultaneously than there are - connections in the connection pool! - http_version (:obj:`str`, optional): If ``"2"`` or ``"2.0"``, HTTP/2 will be used instead - of HTTP/1.1. Defaults to ``"1.1"``. - - .. versionadded:: 20.1 - .. versionchanged:: 20.2 - Reset the default version to 1.1. - - .. versionchanged:: 20.5 - Accept ``"2"`` as a valid value. - socket_options (Collection[:obj:`tuple`], optional): Socket options to be passed to the - underlying `library \ - `_. - - Note: - The values accepted by this parameter depend on the operating system. - This is a low-level parameter and should only be used if you are familiar with - these concepts. - - .. versionadded:: 20.7 - proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``, optional): The URL to a proxy server, - a ``httpx.Proxy`` object or a ``httpx.URL`` object. For example - ``'http://127.0.0.1:3128'`` or ``'socks5://127.0.0.1:3128'``. Defaults to :obj:`None`. - - Note: - * The proxy URL can also be set via the environment variables ``HTTPS_PROXY`` or - ``ALL_PROXY``. See `the docs of httpx`_ for more info. - * HTTPS proxies can be configured by passing a ``httpx.Proxy`` object with - a corresponding ``ssl_context``. - * For Socks5 support, additional dependencies are required. Make sure to install - PTB via :command:`pip install "python-telegram-bot[socks]"` in this case. - * Socks5 proxies can not be set via environment variables. - - .. _the docs of httpx: https://www.python-httpx.org/environment_variables/#proxies - - .. versionadded:: 20.7 - media_write_timeout (:obj:`float` | :obj:`None`, optional): Like :paramref:`write_timeout`, - but used only for requests that upload media/files. This value is used unless a - different value is passed to :paramref:`do_request.write_timeout` of - :meth:`do_request`. Defaults to ``20`` seconds. - - .. versionadded:: 21.0 - httpx_kwargs (dict[:obj:`str`, Any], optional): Additional keyword arguments to be passed - to the `httpx.AsyncClient `_ - constructor. - - Warning: - This parameter is intended for advanced users that want to fine-tune the behavior - of the underlying ``httpx`` client. The values passed here will override all the - defaults set by ``python-telegram-bot`` and all other parameters passed to - :class:`HTTPXRequest`. The only exception is the :paramref:`media_write_timeout` - parameter, which is not passed to the client constructor. - No runtime warnings will be issued about parameters that are overridden in this - way. - - .. versionadded:: 21.6 - - """ - - __slots__ = ("_client", "_client_kwargs", "_http_version", "_media_write_timeout") - - def __init__( - self, - connection_pool_size: int = 1, - proxy_url: Optional[Union[str, httpx.Proxy, httpx.URL]] = None, - read_timeout: Optional[float] = 5.0, - write_timeout: Optional[float] = 5.0, - connect_timeout: Optional[float] = 5.0, - pool_timeout: Optional[float] = 1.0, - http_version: HTTPVersion = "1.1", - socket_options: Optional[Collection[SocketOpt]] = None, - proxy: Optional[Union[str, httpx.Proxy, httpx.URL]] = None, - media_write_timeout: Optional[float] = 20.0, - httpx_kwargs: Optional[dict[str, Any]] = None, - ): - if proxy_url is not None and proxy is not None: - raise ValueError("The parameters `proxy_url` and `proxy` are mutually exclusive.") - - if proxy_url is not None: - proxy = proxy_url - warn( - PTBDeprecationWarning( - "20.7", "The parameter `proxy_url` is deprecated. Use `proxy` instead." - ), - stacklevel=2, - ) - - self._http_version = http_version - self._media_write_timeout = media_write_timeout - timeout = httpx.Timeout( - connect=connect_timeout, - read=read_timeout, - write=write_timeout, - pool=pool_timeout, - ) - limits = httpx.Limits( - max_connections=connection_pool_size, - max_keepalive_connections=connection_pool_size, - ) - - if http_version not in ("1.1", "2", "2.0"): - raise ValueError("`http_version` must be either '1.1', '2.0' or '2'.") - - http1 = http_version == "1.1" - http_kwargs = {"http1": http1, "http2": not http1} - transport = ( - httpx.AsyncHTTPTransport( - socket_options=socket_options, - ) - if socket_options - else None - ) - self._client_kwargs = { - "timeout": timeout, - "proxy": proxy, - "limits": limits, - "transport": transport, - **http_kwargs, - **(httpx_kwargs or {}), - } - - try: - self._client = self._build_client() - except ImportError as exc: - if "httpx[http2]" not in str(exc) and "httpx[socks]" not in str(exc): - raise - - if "httpx[socks]" in str(exc): - raise RuntimeError( - "To use Socks5 proxies, PTB must be installed via `pip install " - '"python-telegram-bot[socks]"`.' - ) from exc - raise RuntimeError( - "To use HTTP/2, PTB must be installed via `pip install " - '"python-telegram-bot[http2]"`.' - ) from exc - - @property - def http_version(self) -> str: - """ - :obj:`str`: Used HTTP version, see :paramref:`http_version`. - - .. versionadded:: 20.2 - """ - return self._http_version - - @property - def read_timeout(self) -> Optional[float]: - """See :attr:`BaseRequest.read_timeout`. - - Returns: - :obj:`float` | :obj:`None`: The default read timeout in seconds as passed to - :paramref:`HTTPXRequest.read_timeout`. - """ - return self._client.timeout.read - - def _build_client(self) -> httpx.AsyncClient: - return httpx.AsyncClient(**self._client_kwargs) - - async def initialize(self) -> None: - """See :meth:`BaseRequest.initialize`.""" - if self._client.is_closed: - self._client = self._build_client() - - async def shutdown(self) -> None: - """See :meth:`BaseRequest.shutdown`.""" - if self._client.is_closed: - _LOGGER.debug("This HTTPXRequest is already shut down. Returning.") - return - - await self._client.aclose() - - async def do_request( - self, - url: str, - method: str, - request_data: Optional[RequestData] = None, - read_timeout: ODVInput[float] = BaseRequest.DEFAULT_NONE, - write_timeout: ODVInput[float] = BaseRequest.DEFAULT_NONE, - connect_timeout: ODVInput[float] = BaseRequest.DEFAULT_NONE, - pool_timeout: ODVInput[float] = BaseRequest.DEFAULT_NONE, - ) -> tuple[int, bytes]: - """See :meth:`BaseRequest.do_request`.""" - if self._client.is_closed: - raise RuntimeError("This HTTPXRequest is not initialized!") - - files = request_data.multipart_data if request_data else None - data = request_data.json_parameters if request_data else None - - # If user did not specify timeouts (for e.g. in a bot method), use the default ones when we - # created this instance. - if isinstance(read_timeout, DefaultValue): - read_timeout = self._client.timeout.read - if isinstance(connect_timeout, DefaultValue): - connect_timeout = self._client.timeout.connect - if isinstance(pool_timeout, DefaultValue): - pool_timeout = self._client.timeout.pool - - if isinstance(write_timeout, DefaultValue): - write_timeout = self._client.timeout.write if not files else self._media_write_timeout - - timeout = httpx.Timeout( - connect=connect_timeout, - read=read_timeout, - write=write_timeout, - pool=pool_timeout, - ) - - try: - res = await self._client.request( - method=method, - url=url, - headers={"User-Agent": self.USER_AGENT}, - timeout=timeout, - files=files, - data=data, - ) - except httpx.TimeoutException as err: - if isinstance(err, httpx.PoolTimeout): - raise TimedOut( - message=( - "Pool timeout: All connections in the connection pool are occupied. " - "Request was *not* sent to Telegram. Consider adjusting the connection " - "pool size or the pool timeout." - ) - ) from err - raise TimedOut from err - except httpx.HTTPError as err: - # HTTPError must come last as its the base httpx exception class - # TODO p4: do something smart here; for now just raise NetworkError - - # We include the class name for easier debugging. Especially useful if the error - # message of `err` is empty. - raise NetworkError(f"httpx.{err.__class__.__name__}: {err}") from err - - return res.status_code, res.content diff --git a/venv/lib/python3.11/site-packages/telegram/request/_requestdata.py b/venv/lib/python3.11/site-packages/telegram/request/_requestdata.py deleted file mode 100755 index b8da33c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/_requestdata.py +++ /dev/null @@ -1,142 +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 -# -# 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 class that holds the parameters of a request to the Bot API.""" -import json -from typing import Any, Optional, Union, final -from urllib.parse import urlencode - -from telegram._utils.strings import TextEncoding -from telegram._utils.types import UploadFileDict -from telegram.request._requestparameter import RequestParameter - - -@final -class RequestData: - """Instances of this class collect the data needed for one request to the Bot API, including - all parameters and files to be sent along with the request. - - .. versionadded:: 20.0 - - Warning: - How exactly instances of this are created should be considered an implementation detail - and not part of PTBs public API. Users should exclusively rely on the documented - attributes, properties and methods. - - Attributes: - contains_files (:obj:`bool`): Whether this object contains files to be uploaded via - ``multipart/form-data``. - """ - - __slots__ = ("_parameters", "contains_files") - - def __init__(self, parameters: Optional[list[RequestParameter]] = None): - self._parameters: list[RequestParameter] = parameters or [] - self.contains_files: bool = any(param.input_files for param in self._parameters) - - @property - def parameters(self) -> dict[str, Union[str, int, list[Any], dict[Any, Any]]]: - """Gives the parameters as mapping of parameter name to the parameter value, which can be - a single object of type :obj:`int`, :obj:`float`, :obj:`str` or :obj:`bool` or any - (possibly nested) composition of lists, tuples and dictionaries, where each entry, key - and value is of one of the mentioned types. - - Returns: - dict[:obj:`str`, Union[:obj:`str`, :obj:`int`, list[any], dict[any, any]]] - """ - return { - param.name: param.value # type: ignore[misc] - for param in self._parameters - if param.value is not None - } - - @property - def json_parameters(self) -> dict[str, str]: - """Gives the parameters as mapping of parameter name to the respective JSON encoded - value. - - Tip: - By default, this property uses the standard library's :func:`json.dumps`. - To use a custom library for JSON encoding, you can directly encode the keys of - :attr:`parameters` - note that string valued keys should not be JSON encoded. - - Returns: - dict[:obj:`str`, :obj:`str`] - """ - return { - param.name: param.json_value - for param in self._parameters - if param.json_value is not None - } - - def url_encoded_parameters(self, encode_kwargs: Optional[dict[str, Any]] = None) -> str: - """Encodes the parameters with :func:`urllib.parse.urlencode`. - - Args: - encode_kwargs (dict[:obj:`str`, any], optional): Additional keyword arguments to pass - along to :func:`urllib.parse.urlencode`. - - Returns: - :obj:`str` - """ - if encode_kwargs: - return urlencode(self.json_parameters, **encode_kwargs) - return urlencode(self.json_parameters) - - def parametrized_url(self, url: str, encode_kwargs: Optional[dict[str, Any]] = None) -> str: - """Shortcut for attaching the return value of :meth:`url_encoded_parameters` to the - :paramref:`url`. - - Args: - url (:obj:`str`): The URL the parameters will be attached to. - encode_kwargs (dict[:obj:`str`, any], optional): Additional keyword arguments to pass - along to :func:`urllib.parse.urlencode`. - - Returns: - :obj:`str` - """ - url_parameters = self.url_encoded_parameters(encode_kwargs=encode_kwargs) - return f"{url}?{url_parameters}" - - @property - def json_payload(self) -> bytes: - """The :attr:`parameters` as UTF-8 encoded JSON payload. - - Tip: - By default, this property uses the standard library's :func:`json.dumps`. - To use a custom library for JSON encoding, you can directly encode the keys of - :attr:`parameters` - note that string valued keys should not be JSON encoded. - - Returns: - :obj:`bytes` - """ - return json.dumps(self.json_parameters).encode(TextEncoding.UTF_8) - - @property - def multipart_data(self) -> UploadFileDict: - """Gives the files contained in this object as mapping of part name to encoded content. - - .. versionchanged:: 21.5 - Content may now be a file handle. - """ - multipart_data: UploadFileDict = {} - for param in self._parameters: - m_data = param.multipart_data - if m_data: - multipart_data.update(m_data) - return multipart_data diff --git a/venv/lib/python3.11/site-packages/telegram/request/_requestparameter.py b/venv/lib/python3.11/site-packages/telegram/request/_requestparameter.py deleted file mode 100755 index 51f9b61..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/_requestparameter.py +++ /dev/null @@ -1,175 +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 -# -# 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 class that describes a single parameter of a request to the Bot API.""" -import datetime as dtm -import json -from collections.abc import Sequence -from dataclasses import dataclass -from typing import Optional, final - -from telegram._files.inputfile import InputFile -from telegram._files.inputmedia import InputMedia, InputPaidMedia -from telegram._files.inputsticker import InputSticker -from telegram._telegramobject import TelegramObject -from telegram._utils.datetime import to_timestamp -from telegram._utils.enum import StringEnum -from telegram._utils.types import UploadFileDict - - -@final -@dataclass(repr=True, eq=False, order=False, frozen=True) -class RequestParameter: - """Instances of this class represent a single parameter to be sent along with a request to - the Bot API. - - .. versionadded:: 20.0 - - Warning: - This class intended is to be used internally by the library and *not* by the user. Changes - to this class are not considered breaking changes and may not be documented in the - changelog. - - Args: - name (:obj:`str`): The name of the parameter. - value (:obj:`object` | :obj:`None`): The value of the parameter. Must be JSON-dumpable. - input_files (list[:class:`telegram.InputFile`], optional): A list of files that should be - uploaded along with this parameter. - - Attributes: - name (:obj:`str`): The name of the parameter. - value (:obj:`object` | :obj:`None`): The value of the parameter. - input_files (list[:class:`telegram.InputFile` | :obj:`None`): A list of files that should - be uploaded along with this parameter. - """ - - __slots__ = ("input_files", "name", "value") - - name: str - value: object - input_files: Optional[list[InputFile]] - - @property - def json_value(self) -> Optional[str]: - """The JSON dumped :attr:`value` or :obj:`None` if :attr:`value` is :obj:`None`. - The latter can currently only happen if :attr:`input_files` has exactly one element that - must not be uploaded via an attach:// URI. - """ - if isinstance(self.value, str): - return self.value - if self.value is None: - return None - return json.dumps(self.value) - - @property - def multipart_data(self) -> Optional[UploadFileDict]: - """A dict with the file data to upload, if any. - - .. versionchanged:: 21.5 - Content may now be a file handle. - """ - if not self.input_files: - return None - return { - (input_file.attach_name or self.name): input_file.field_tuple - for input_file in self.input_files - } - - @staticmethod - def _value_and_input_files_from_input( # pylint: disable=too-many-return-statements - value: object, - ) -> tuple[object, list[InputFile]]: - """Converts `value` into something that we can json-dump. Returns two values: - 1. the JSON-dumpable value. May be `None` in case the value is an InputFile which must - not be uploaded via an attach:// URI - 2. A list of InputFiles that should be uploaded for this value - - Note that we handle files differently depending on whether attaching them via an URI of the - form attach:// is documented to be allowed or not. - There was some confusion whether this worked for all files, so that we stick to the - documented ways for now. - See https://github.com/tdlib/telegram-bot-api/issues/167 and - https://github.com/tdlib/telegram-bot-api/issues/259 - - This method only does some special casing for our own helper class StringEnum, but not - for general enums. This is because: - * tg.constants currently only uses IntEnum as second enum type and json dumping that - is no problem - * if a user passes a custom enum, it's unlikely that we can actually properly handle it - even with some special casing. - """ - if isinstance(value, dtm.datetime): - return to_timestamp(value), [] - if isinstance(value, StringEnum): - return value.value, [] - if isinstance(value, InputFile): - if value.attach_uri: - return value.attach_uri, [value] - return None, [value] - - if isinstance(value, (InputMedia, InputPaidMedia)) and isinstance(value.media, InputFile): - # We call to_dict and change the returned dict instead of overriding - # value.media in case the same value is reused for another request - data = value.to_dict() - if value.media.attach_uri: - data["media"] = value.media.attach_uri - else: - data.pop("media", None) - - thumbnail = data.get("thumbnail", None) - if isinstance(thumbnail, InputFile): - if thumbnail.attach_uri: - data["thumbnail"] = thumbnail.attach_uri - else: - data.pop("thumbnail", None) - return data, [value.media, thumbnail] - - return data, [value.media] - if isinstance(value, InputSticker) and isinstance(value.sticker, InputFile): - # We call to_dict and change the returned dict instead of overriding - # value.sticker in case the same value is reused for another request - data = value.to_dict() - data["sticker"] = value.sticker.attach_uri - return data, [value.sticker] - - if isinstance(value, TelegramObject): - # Needs to be last, because InputMedia is a subclass of TelegramObject - return value.to_dict(), [] - return value, [] - - @classmethod - def from_input(cls, key: str, value: object) -> "RequestParameter": - """Builds an instance of this class for a given key-value pair that represents the raw - input as passed along from a method of :class:`telegram.Bot`. - """ - if not isinstance(value, (str, bytes)) and isinstance(value, Sequence): - param_values = [] - input_files = [] - for obj in value: - param_value, input_file = cls._value_and_input_files_from_input(obj) - if param_value is not None: - param_values.append(param_value) - input_files.extend(input_file) - return RequestParameter( - name=key, value=param_values, input_files=input_files if input_files else None - ) - - param_value, input_files = cls._value_and_input_files_from_input(value) - return RequestParameter( - name=key, value=param_value, input_files=input_files if input_files else None - ) diff --git a/venv/lib/python3.11/site-packages/telegram/warnings.py b/venv/lib/python3.11/site-packages/telegram/warnings.py deleted file mode 100755 index d475eeb..0000000 --- a/venv/lib/python3.11/site-packages/telegram/warnings.py +++ /dev/null @@ -1,87 +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 -# -# 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 used for warnings issued by this library. - -.. versionadded:: 20.0 -""" - -__all__ = ["PTBDeprecationWarning", "PTBRuntimeWarning", "PTBUserWarning"] - - -class PTBUserWarning(UserWarning): - """ - Custom user warning class used for warnings in this library. - - .. seealso:: :wiki:`Exceptions, Warnings and Logging ` - - .. versionadded:: 20.0 - """ - - __slots__ = () - - -class PTBRuntimeWarning(PTBUserWarning, RuntimeWarning): - """ - Custom runtime warning class used for warnings in this library. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - -# https://www.python.org/dev/peps/pep-0565/ recommends using a custom warning class derived from -# DeprecationWarning. We also subclass from PTBUserWarning so users can easily 'switch off' -# warnings -class PTBDeprecationWarning(PTBUserWarning, DeprecationWarning): - """ - Custom warning class for deprecations in this library. - - .. versionchanged:: 20.0 - Renamed TelegramDeprecationWarning to PTBDeprecationWarning. - - Args: - version (:obj:`str`): The version in which the feature was deprecated. - - .. versionadded:: 21.2 - message (:obj:`str`): The message to display. - - .. versionadded:: 21.2 - - Attributes: - version (:obj:`str`): The version in which the feature was deprecated. - - .. versionadded:: 21.2 - message (:obj:`str`): The message to display. - - .. versionadded:: 21.2 - """ - - __slots__ = ("message", "version") - - def __init__(self, version: str, message: str) -> None: - self.version: str = version - self.message: str = message - - def __str__(self) -> str: - """Returns a string representation of the warning, using :attr:`message` and - :attr:`version`. - - .. versionadded:: 21.2 - """ - return f"Deprecated since version {self.version}: {self.message}" diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/INSTALLER b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/INSTALLER deleted file mode 100755 index a1b589e..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/METADATA b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/METADATA deleted file mode 100755 index 97fd818..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/METADATA +++ /dev/null @@ -1,73 +0,0 @@ -Metadata-Version: 2.4 -Name: typing_extensions -Version: 4.16.0 -Summary: Backported and Experimental Type Hints for Python 3.9+ -Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing -Author-email: "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -License-Expression: PSF-2.0 -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Console -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: 3.15 -Classifier: Topic :: Software Development -License-File: LICENSE -Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues -Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md -Project-URL: Documentation, https://typing-extensions.readthedocs.io/ -Project-URL: Home, https://github.com/python/typing_extensions -Project-URL: Q & A, https://github.com/python/typing/discussions -Project-URL: Repository, https://github.com/python/typing_extensions - -# Typing Extensions - -[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing) - -[Documentation](https://typing-extensions.readthedocs.io/en/latest/#) – -[PyPI](https://pypi.org/project/typing-extensions/) - -## Overview - -The `typing_extensions` module serves two related purposes: - -- Enable use of new type system features on older Python versions. For example, - `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows - users on previous Python versions to use it too. -- Enable experimentation with new type system PEPs before they are accepted and - added to the `typing` module. - -`typing_extensions` is treated specially by static type checkers such as -mypy and pyright. Objects defined in `typing_extensions` are treated the same -way as equivalent forms in `typing`. - -`typing_extensions` uses -[Semantic Versioning](https://semver.org/). The -major version will be incremented only for backwards-incompatible changes. -Therefore, it's safe to depend -on `typing_extensions` like this: `typing_extensions ~=x.y`, -where `x.y` is the first version that includes all features you need. -[This](https://packaging.python.org/en/latest/specifications/version-specifiers/#compatible-release) -is equivalent to `typing_extensions >=x.y, <(x+1)`. Do not depend on `~= x.y.z` -unless you really know what you're doing; that defeats the purpose of -semantic versioning. - -## Included items - -See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a -complete listing of module contents. - -## Contributing - -See [CONTRIBUTING.md](https://github.com/python/typing_extensions/blob/main/CONTRIBUTING.md) -for how to contribute to `typing_extensions`. - diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/RECORD b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/RECORD deleted file mode 100755 index 4b531ef..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/RECORD +++ /dev/null @@ -1,7 +0,0 @@ -__pycache__/typing_extensions.cpython-311.pyc,, -typing_extensions-4.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -typing_extensions-4.16.0.dist-info/METADATA,sha256=sFCEyh1Qh5hlF42f_5-r6rYb37HzYb-96VQh_8j5vkY,3310 -typing_extensions-4.16.0.dist-info/RECORD,, -typing_extensions-4.16.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -typing_extensions-4.16.0.dist-info/licenses/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 -typing_extensions.py,sha256=QEDKGh7L7gDROFwSqTCE0cW9RvC3dPB-WufpHE9V5pY,165012 diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/WHEEL b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/WHEEL deleted file mode 100755 index d8b9936..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/licenses/LICENSE b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/licenses/LICENSE deleted file mode 100755 index f26bcf4..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,279 +0,0 @@ -A. HISTORY OF THE SOFTWARE -========================== - -Python was created in the early 1990s by Guido van Rossum at Stichting -Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands -as a successor of a language called ABC. Guido remains Python's -principal author, although it includes many contributions from others. - -In 1995, Guido continued his work on Python at the Corporation for -National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) -in Reston, Virginia where he released several versions of the -software. - -In May 2000, Guido and the Python core development team moved to -BeOpen.com to form the BeOpen PythonLabs team. In October of the same -year, the PythonLabs team moved to Digital Creations, which became -Zope Corporation. In 2001, the Python Software Foundation (PSF, see -https://www.python.org/psf/) was formed, a non-profit organization -created specifically to own Python-related Intellectual Property. -Zope Corporation was a sponsoring member of the PSF. - -All Python releases are Open Source (see https://opensource.org for -the Open Source Definition). Historically, most, but not all, Python -releases have also been GPL-compatible; the table below summarizes -the various releases. - - Release Derived Year Owner GPL- - from compatible? (1) - - 0.9.0 thru 1.2 1991-1995 CWI yes - 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes - 1.6 1.5.2 2000 CNRI no - 2.0 1.6 2000 BeOpen.com no - 1.6.1 1.6 2001 CNRI yes (2) - 2.1 2.0+1.6.1 2001 PSF no - 2.0.1 2.0+1.6.1 2001 PSF yes - 2.1.1 2.1+2.0.1 2001 PSF yes - 2.1.2 2.1.1 2002 PSF yes - 2.1.3 2.1.2 2002 PSF yes - 2.2 and above 2.1.1 2001-now PSF yes - -Footnotes: - -(1) GPL-compatible doesn't mean that we're distributing Python under - the GPL. All Python licenses, unlike the GPL, let you distribute - a modified version without making your changes open source. The - GPL-compatible licenses make it possible to combine Python with - other software that is released under the GPL; the others don't. - -(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, - because its license has a choice of law clause. According to - CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 - is "not incompatible" with the GPL. - -Thanks to the many outside volunteers who have worked under Guido's -direction to make these releases possible. - - -B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON -=============================================================== - -Python software and documentation are licensed under the -Python Software Foundation License Version 2. - -Starting with Python 3.8.6, examples, recipes, and other code in -the documentation are dual licensed under the PSF License Version 2 -and the Zero-Clause BSD license. - -Some software incorporated into Python is under different licenses. -The licenses are listed with code falling under that license. - - -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby -grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, -analyze, test, perform and/or display publicly, prepare derivative works, -distribute, and otherwise use Python alone or in any derivative version, -provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative version -prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 -------------------------------------------- - -BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 - -1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an -office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the -Individual or Organization ("Licensee") accessing and otherwise using -this software in source or binary form and its associated -documentation ("the Software"). - -2. Subject to the terms and conditions of this BeOpen Python License -Agreement, BeOpen hereby grants Licensee a non-exclusive, -royalty-free, world-wide license to reproduce, analyze, test, perform -and/or display publicly, prepare derivative works, distribute, and -otherwise use the Software alone or in any derivative version, -provided, however, that the BeOpen Python License is retained in the -Software, alone or in any derivative version prepared by Licensee. - -3. BeOpen is making the Software available to Licensee on an "AS IS" -basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE -SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS -AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -5. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -6. This License Agreement shall be governed by and interpreted in all -respects by the law of the State of California, excluding conflict of -law provisions. Nothing in this License Agreement shall be deemed to -create any relationship of agency, partnership, or joint venture -between BeOpen and Licensee. This License Agreement does not grant -permission to use BeOpen trademarks or trade names in a trademark -sense to endorse or promote products or services of Licensee, or any -third party. As an exception, the "BeOpen Python" logos available at -http://www.pythonlabs.com/logos.html may be used according to the -permissions granted on that web page. - -7. By copying, installing or otherwise using the software, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 ---------------------------------------- - -1. This LICENSE AGREEMENT is between the Corporation for National -Research Initiatives, having an office at 1895 Preston White Drive, -Reston, VA 20191 ("CNRI"), and the Individual or Organization -("Licensee") accessing and otherwise using Python 1.6.1 software in -source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, CNRI -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 1.6.1 -alone or in any derivative version, provided, however, that CNRI's -License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) -1995-2001 Corporation for National Research Initiatives; All Rights -Reserved" are retained in Python 1.6.1 alone or in any derivative -version prepared by Licensee. Alternately, in lieu of CNRI's License -Agreement, Licensee may substitute the following text (omitting the -quotes): "Python 1.6.1 is made available subject to the terms and -conditions in CNRI's License Agreement. This Agreement together with -Python 1.6.1 may be located on the internet using the following -unique, persistent identifier (known as a handle): 1895.22/1013. This -Agreement may also be obtained from a proxy server on the internet -using the following URL: http://hdl.handle.net/1895.22/1013". - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 1.6.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 1.6.1. - -4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" -basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. This License Agreement shall be governed by the federal -intellectual property law of the United States, including without -limitation the federal copyright law, and, to the extent such -U.S. federal law does not apply, by the law of the Commonwealth of -Virginia, excluding Virginia's conflict of law provisions. -Notwithstanding the foregoing, with regard to derivative works based -on Python 1.6.1 that incorporate non-separable material that was -previously distributed under the GNU General Public License (GPL), the -law of the Commonwealth of Virginia shall govern this License -Agreement only as to issues arising under or with respect to -Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this -License Agreement shall be deemed to create any relationship of -agency, partnership, or joint venture between CNRI and Licensee. This -License Agreement does not grant permission to use CNRI trademarks or -trade name in a trademark sense to endorse or promote products or -services of Licensee, or any third party. - -8. By clicking on the "ACCEPT" button where indicated, or by copying, -installing or otherwise using Python 1.6.1, Licensee agrees to be -bound by the terms and conditions of this License Agreement. - - ACCEPT - - -CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 --------------------------------------------------- - -Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, -The Netherlands. All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION ----------------------------------------------------------------------- - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. diff --git a/venv/lib/python3.11/site-packages/typing_extensions.py b/venv/lib/python3.11/site-packages/typing_extensions.py deleted file mode 100755 index ced7837..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions.py +++ /dev/null @@ -1,4422 +0,0 @@ -import abc -import builtins -import collections -import collections.abc -import contextlib -import enum -import functools -import inspect -import io -import keyword -import operator -import sys -import types as _types -import typing -import warnings - -# Breakpoint: https://github.com/python/cpython/pull/119891 -if sys.version_info >= (3, 14): - import annotationlib - -__all__ = [ - # Super-special typing primitives. - 'Any', - 'ClassVar', - 'Concatenate', - 'Final', - 'LiteralString', - 'ParamSpec', - 'ParamSpecArgs', - 'ParamSpecKwargs', - 'Self', - 'Type', - 'TypeVar', - 'TypeVarTuple', - 'Unpack', - - # ABCs (from collections.abc). - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', - 'Coroutine', - 'AsyncGenerator', - 'AsyncContextManager', - 'Buffer', - 'ChainMap', - - # Concrete collection types. - 'ContextManager', - 'Counter', - 'Deque', - 'DefaultDict', - 'NamedTuple', - 'OrderedDict', - 'TypedDict', - - # Structural checks, a.k.a. protocols. - 'SupportsAbs', - 'SupportsBytes', - 'SupportsComplex', - 'SupportsFloat', - 'SupportsIndex', - 'SupportsInt', - 'SupportsRound', - 'Reader', - 'Writer', - - # One-off things. - 'Annotated', - 'assert_never', - 'assert_type', - 'clear_overloads', - 'dataclass_transform', - 'deprecated', - 'disjoint_base', - 'Doc', - 'evaluate_forward_ref', - 'get_overloads', - 'final', - 'Format', - 'get_annotations', - 'get_args', - 'get_origin', - 'get_original_bases', - 'get_protocol_members', - 'get_type_hints', - 'IntVar', - 'is_protocol', - 'is_typeddict', - 'Literal', - 'NewType', - 'overload', - 'override', - 'Protocol', - 'sentinel', - 'Sentinel', - 'reveal_type', - 'runtime', - 'runtime_checkable', - 'Text', - 'TypeAlias', - 'TypeAliasType', - 'TypeForm', - 'TypeGuard', - 'TypeIs', - 'TYPE_CHECKING', - 'type_repr', - 'Never', - 'NoReturn', - 'ReadOnly', - 'Required', - 'NotRequired', - 'NoDefault', - 'NoExtraItems', - - # Pure aliases, have always been in typing - 'AbstractSet', - 'AnyStr', - 'BinaryIO', - 'Callable', - 'Collection', - 'Container', - 'Dict', - 'ForwardRef', - 'FrozenSet', - 'Generator', - 'Generic', - 'Hashable', - 'IO', - 'ItemsView', - 'Iterable', - 'Iterator', - 'KeysView', - 'List', - 'Mapping', - 'MappingView', - 'Match', - 'MutableMapping', - 'MutableSequence', - 'MutableSet', - 'Optional', - 'Pattern', - 'Reversible', - 'Sequence', - 'Set', - 'Sized', - 'TextIO', - 'Tuple', - 'Union', - 'ValuesView', - 'cast', - 'no_type_check', -] - -# for backward compatibility -PEP_560 = True -GenericMeta = type -# Breakpoint: https://github.com/python/cpython/pull/116129 -_PEP_696_IMPLEMENTED = sys.version_info >= (3, 13, 0, "beta") - -# Added with bpo-45166 to 3.10.1+ and some 3.9 versions -_FORWARD_REF_HAS_CLASS = "__forward_is_class__" in typing.ForwardRef.__slots__ - - -def _caller(depth=1, default='__main__'): - try: - return sys._getframemodulename(depth + 1) or default - except AttributeError: # For platforms without _getframemodulename() - pass - try: - return sys._getframe(depth + 1).f_globals.get('__name__', default) - except (AttributeError, ValueError): # For platforms without _getframe() - pass - return None - - -# Placeholder for sentinel methods, because sentinels can not have their own sentinels -_sentinel_placeholder = object() - -if hasattr(builtins, "sentinel"): # 3.15+ - sentinel = builtins.sentinel -else: - class sentinel: - """Create a unique sentinel object. - - *name* should be the name of the variable to which the return value - shall be assigned. - """ - - def __init__( - self, - __name: str = _sentinel_placeholder, - __repr: typing.Optional[str] = _sentinel_placeholder, - /, - *, - repr: typing.Optional[str] = None, - name: str = _sentinel_placeholder, - ) -> None: - if name is not _sentinel_placeholder: - warnings.warn( - "Passing 'name' as a keyword argument is deprecated; " - "pass it positionally instead.", - DeprecationWarning, - stacklevel=2, - ) - __name = name - if __name is _sentinel_placeholder: - raise TypeError("First parameter 'name' is required") - if __repr is not _sentinel_placeholder: - warnings.warn( - "Passing 'repr' as a positional argument is deprecated; " - "pass it by keyword instead.", - DeprecationWarning, - stacklevel=2, - ) - repr = __repr - - self._name = __name - self._repr = repr if repr is not None else __name - - # For pickling as a singleton: - self.__module__ = _caller() - - def __init_subclass__(cls): - warnings.warn( - "Subclassing sentinel is deprecated " - "and will be disallowed in Python 3.15", - DeprecationWarning, - stacklevel=2, - ) - super().__init_subclass__() - - def __setattr__(self, attr: str, value: object) -> None: - if attr not in {"_name", "_repr", "__module__"}: - warnings.warn( - f"Setting attribute {attr!r} on sentinel objects is deprecated " - "and will be disallowed in Python 3.15.", - DeprecationWarning, - stacklevel=2, - ) - super().__setattr__(attr, value) - - @property - def __name__(self) -> str: - return self._name - - @__name__.setter - def __name__(self, value: str) -> None: - self._name = value - - def __repr__(self) -> str: - return self._repr - - if sys.version_info < (3, 11): - # The presence of this method convinces typing._type_check - # that Sentinels are types. - def __call__(self, *args, **kwargs): - raise TypeError(f"{type(self).__name__!r} object is not callable") - - # Breakpoint: https://github.com/python/cpython/pull/21515 - if sys.version_info >= (3, 10): - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - def __reduce__(self) -> str: - """Reduce this sentinel to a singleton.""" - return self.__name__ # Module is taken from the __module__ attribute - -Sentinel = sentinel - -_marker = sentinel("sentinel") - - -# The functions below are modified copies of typing internal helpers. -# They are needed by _ProtocolMeta and they provide support for PEP 646. - -# Breakpoint: https://github.com/python/cpython/pull/27342 -if sys.version_info >= (3, 10): - def _should_collect_from_parameters(t): - return isinstance( - t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) - ) -else: - def _should_collect_from_parameters(t): - return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) - - -NoReturn = typing.NoReturn - -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) -T = typing.TypeVar('T') # Any type. -KT = typing.TypeVar('KT') # Key type. -VT = typing.TypeVar('VT') # Value type. -T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. -T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. - - -# Breakpoint: https://github.com/python/cpython/pull/31841 -if sys.version_info >= (3, 11): - from typing import Any -else: - - class _AnyMeta(type): - def __instancecheck__(self, obj): - if self is Any: - raise TypeError("typing_extensions.Any cannot be used with isinstance()") - return super().__instancecheck__(obj) - - def __repr__(self): - if self is Any: - return "typing_extensions.Any" - return super().__repr__() - - class Any(metaclass=_AnyMeta): - """Special type indicating an unconstrained type. - - Any is compatible with every type. - - Any assumed to have all methods. - - All values assumed to be instances of Any. - Note that all the above statements are true from the point of view of - static type checkers. At runtime, Any should not be used with instance - checks. - """ - def __new__(cls, *args, **kwargs): - if cls is Any: - raise TypeError("Any cannot be instantiated") - return super().__new__(cls, *args, **kwargs) - - -ClassVar = typing.ClassVar - -# Vendored from cpython typing._SpecialFrom -# Having a separate class means that instances will not be rejected by -# typing._type_check. -class _SpecialForm(typing._Final, _root=True): - __slots__ = ('_name', '__doc__', '_getitem') - - def __init__(self, getitem): - self._getitem = getitem - self._name = getitem.__name__ - self.__doc__ = getitem.__doc__ - - def __getattr__(self, item): - if item in {'__name__', '__qualname__'}: - return self._name - - raise AttributeError(item) - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass {self!r}") - - def __repr__(self): - return f'typing_extensions.{self._name}' - - def __reduce__(self): - return self._name - - def __call__(self, *args, **kwds): - raise TypeError(f"Cannot instantiate {self!r}") - - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - def __instancecheck__(self, obj): - raise TypeError(f"{self} cannot be used with isinstance()") - - def __subclasscheck__(self, cls): - raise TypeError(f"{self} cannot be used with issubclass()") - - @typing._tp_cache - def __getitem__(self, parameters): - return self._getitem(self, parameters) - - -# Note that inheriting from this class means that the object will be -# rejected by typing._type_check, so do not use it if the special form -# is arguably valid as a type by itself. -class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - -Final = typing.Final - -# Breakpoint: https://github.com/python/cpython/pull/30530 -if sys.version_info >= (3, 11): - final = typing.final -else: - # @final exists in 3.8+, but we backport it for all versions - # before 3.11 to keep support for the __final__ attribute. - # See https://bugs.python.org/issue46342 - def final(f): - """This decorator can be used to indicate to type checkers that - the decorated method cannot be overridden, and decorated class - cannot be subclassed. For example: - - class Base: - @final - def done(self) -> None: - ... - class Sub(Base): - def done(self) -> None: # Error reported by type checker - ... - @final - class Leaf: - ... - class Other(Leaf): # Error reported by type checker - ... - - There is no runtime checking of these properties. The decorator - sets the ``__final__`` attribute to ``True`` on the decorated object - to allow runtime introspection. - """ - try: - f.__final__ = True - except (AttributeError, TypeError): - # Skip the attribute silently if it is not writable. - # AttributeError happens if the object has __slots__ or a - # read-only property, TypeError if it's a builtin class. - pass - return f - - -if hasattr(typing, "disjoint_base"): # 3.15 - disjoint_base = typing.disjoint_base -else: - def disjoint_base(cls): - """This decorator marks a class as a disjoint base. - - Child classes of a disjoint base cannot inherit from other disjoint bases that are - not parent classes of the disjoint base. - - For example: - - @disjoint_base - class Disjoint1: pass - - @disjoint_base - class Disjoint2: pass - - class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error - - Type checkers can use knowledge of disjoint bases to detect unreachable code - and determine when two types can overlap. - - See PEP 800.""" - cls.__disjoint_base__ = True - return cls - - -def IntVar(name): - return typing.TypeVar(name) - - -# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8 -# Breakpoint: https://github.com/python/cpython/pull/29334 -if sys.version_info >= (3, 10, 1): - Literal = typing.Literal -else: - def _flatten_literal_params(parameters): - """An internal helper for Literal creation: flatten Literals among parameters""" - params = [] - for p in parameters: - if isinstance(p, _LiteralGenericAlias): - params.extend(p.__args__) - else: - params.append(p) - return tuple(params) - - def _value_and_type_iter(params): - for p in params: - yield p, type(p) - - class _LiteralGenericAlias(typing._GenericAlias, _root=True): - def __eq__(self, other): - if not isinstance(other, _LiteralGenericAlias): - return NotImplemented - these_args_deduped = set(_value_and_type_iter(self.__args__)) - other_args_deduped = set(_value_and_type_iter(other.__args__)) - return these_args_deduped == other_args_deduped - - def __hash__(self): - return hash(frozenset(_value_and_type_iter(self.__args__))) - - class _LiteralForm(_ExtensionsSpecialForm, _root=True): - def __init__(self, doc: str): - self._name = 'Literal' - self._doc = self.__doc__ = doc - - def __getitem__(self, parameters): - if not isinstance(parameters, tuple): - parameters = (parameters,) - - parameters = _flatten_literal_params(parameters) - - val_type_pairs = list(_value_and_type_iter(parameters)) - try: - deduped_pairs = set(val_type_pairs) - except TypeError: - # unhashable parameters - pass - else: - # similar logic to typing._deduplicate on Python 3.9+ - if len(deduped_pairs) < len(val_type_pairs): - new_parameters = [] - for pair in val_type_pairs: - if pair in deduped_pairs: - new_parameters.append(pair[0]) - deduped_pairs.remove(pair) - assert not deduped_pairs, deduped_pairs - parameters = tuple(new_parameters) - - return _LiteralGenericAlias(self, parameters) - - Literal = _LiteralForm(doc="""\ - A type that can be used to indicate to type checkers - that the corresponding value has a value literally equivalent - to the provided parameter. For example: - - var: Literal[4] = 4 - - The type checker understands that 'var' is literally equal to - the value 4 and no other value. - - Literal[...] cannot be subclassed. There is no runtime - checking verifying that the parameter is actually a value - instead of a type.""") - - -_overload_dummy = typing._overload_dummy - - -if hasattr(typing, "get_overloads"): # 3.11+ - overload = typing.overload - get_overloads = typing.get_overloads - clear_overloads = typing.clear_overloads -else: - # {module: {qualname: {firstlineno: func}}} - _overload_registry = collections.defaultdict( - functools.partial(collections.defaultdict, dict) - ) - - def overload(func): - """Decorator for overloaded functions/methods. - - In a stub file, place two or more stub definitions for the same - function in a row, each decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - - In a non-stub file (i.e. a regular .py file), do the same but - follow it with an implementation. The implementation should *not* - be decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - def utf8(value): - # implementation goes here - - The overloads for a function can be retrieved at runtime using the - get_overloads() function. - """ - # classmethod and staticmethod - f = getattr(func, "__func__", func) - try: - _overload_registry[f.__module__][f.__qualname__][ - f.__code__.co_firstlineno - ] = func - except AttributeError: - # Not a normal function; ignore. - pass - return _overload_dummy - - def get_overloads(func): - """Return all defined overloads for *func* as a sequence.""" - # classmethod and staticmethod - f = getattr(func, "__func__", func) - if f.__module__ not in _overload_registry: - return [] - mod_dict = _overload_registry[f.__module__] - if f.__qualname__ not in mod_dict: - return [] - return list(mod_dict[f.__qualname__].values()) - - def clear_overloads(): - """Clear all overloads in the registry.""" - _overload_registry.clear() - - -# This is not a real generic class. Don't use outside annotations. -Type = typing.Type - -# Various ABCs mimicking those in collections.abc. -# A few are simply re-exported for completeness. -Awaitable = typing.Awaitable -Coroutine = typing.Coroutine -AsyncIterable = typing.AsyncIterable -AsyncIterator = typing.AsyncIterator -Deque = typing.Deque -DefaultDict = typing.DefaultDict -OrderedDict = typing.OrderedDict -Counter = typing.Counter -ChainMap = typing.ChainMap -Text = typing.Text -TYPE_CHECKING = typing.TYPE_CHECKING - - -# Breakpoint: https://github.com/python/cpython/pull/118681 -if sys.version_info >= (3, 13, 0, "beta"): - from typing import AsyncContextManager, AsyncGenerator, ContextManager, Generator -else: - def _is_dunder(attr): - return attr.startswith('__') and attr.endswith('__') - - - class _SpecialGenericAlias(typing._SpecialGenericAlias, _root=True): - def __init__(self, origin, nparams, *, defaults, inst=True, name=None): - assert nparams > 0, "`nparams` must be a positive integer" - assert defaults, "Must always specify a non-empty sequence for `defaults`" - super().__init__(origin, nparams, inst=inst, name=name) - self._defaults = defaults - - def __setattr__(self, attr, val): - allowed_attrs = {'_name', '_inst', '_nparams', '_defaults'} - if _is_dunder(attr) or attr in allowed_attrs: - object.__setattr__(self, attr, val) - else: - setattr(self.__origin__, attr, val) - - @typing._tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - msg = "Parameters to generic types must be types." - params = tuple(typing._type_check(p, msg) for p in params) - if ( - len(params) < self._nparams - and len(params) + len(self._defaults) >= self._nparams - ): - params = (*params, *self._defaults[len(params) - self._nparams:]) - actual_len = len(params) - - if actual_len != self._nparams: - expected = f"at least {self._nparams - len(self._defaults)}" - raise TypeError( - f"Too {'many' if actual_len > self._nparams else 'few'}" - f" arguments for {self};" - f" actual {actual_len}, expected {expected}" - ) - return self.copy_with(params) - - _NoneType = type(None) - Generator = _SpecialGenericAlias( - collections.abc.Generator, 3, defaults=(_NoneType, _NoneType) - ) - AsyncGenerator = _SpecialGenericAlias( - collections.abc.AsyncGenerator, 2, defaults=(_NoneType,) - ) - ContextManager = _SpecialGenericAlias( - contextlib.AbstractContextManager, - 2, - name="ContextManager", - defaults=(typing.Optional[bool],) - ) - AsyncContextManager = _SpecialGenericAlias( - contextlib.AbstractAsyncContextManager, - 2, - name="AsyncContextManager", - defaults=(typing.Optional[bool],) - ) - - -_PROTO_ALLOWLIST = { - 'collections.abc': [ - 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection', - 'Reversible', 'Buffer', - ], - 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], - 'io': ['Reader', 'Writer'], - 'typing_extensions': ['Buffer'], - 'os': ['PathLike'], -} - - -_EXCLUDED_ATTRS = frozenset(typing.EXCLUDED_ATTRIBUTES) | { - "__match_args__", "__protocol_attrs__", "__non_callable_proto_members__", - "__final__", -} - - -def _get_protocol_attrs(cls): - attrs = set() - for base in cls.__mro__[:-1]: # without object - if base.__name__ in {'Protocol', 'Generic'}: - continue - annotations = getattr(base, '__annotations__', {}) - for attr in (*base.__dict__, *annotations): - if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS): - attrs.add(attr) - return attrs - - -# `__match_args__` attribute was removed from protocol members in 3.13, -# we want to backport this change to older Python versions. -# 3.14 additionally added `io.Reader`, `io.Writer` and `os.PathLike` to -# the list of allowed protocol allowlist. -# https://github.com/python/cpython/issues/127647 -if sys.version_info >= (3, 14): - Protocol = typing.Protocol -else: - def _allow_reckless_class_checks(depth=2): - """Allow instance and class checks for special stdlib modules. - The abc and functools modules indiscriminately call isinstance() and - issubclass() on the whole MRO of a user class, which may contain protocols. - """ - return _caller(depth) in {'abc', 'functools', None} - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - def _type_check_issubclass_arg_1(arg): - """Raise TypeError if `arg` is not an instance of `type` - in `issubclass(arg, )`. - - In most cases, this is verified by type.__subclasscheck__. - Checking it again unnecessarily would slow down issubclass() checks, - so, we don't perform this check unless we absolutely have to. - - For various error paths, however, - we want to ensure that *this* error message is shown to the user - where relevant, rather than a typing.py-specific error message. - """ - if not isinstance(arg, type): - # Same error message as for issubclass(1, int). - raise TypeError('issubclass() arg 1 must be a class') - - # Inheriting from typing._ProtocolMeta isn't actually desirable, - # but is necessary to allow typing.Protocol and typing_extensions.Protocol - # to mix without getting TypeErrors about "metaclass conflict" - class _ProtocolMeta(type(typing.Protocol)): - # This metaclass is somewhat unfortunate, - # but is necessary for several reasons... - # - # NOTE: DO NOT call super() in any methods in this class - # That would call the methods on typing._ProtocolMeta on Python <=3.11 - # and those are slow - def __new__(mcls, name, bases, namespace, **kwargs): - if name == "Protocol" and len(bases) < 2: - pass - elif {Protocol, typing.Protocol} & set(bases): - for base in bases: - if not ( - base in {object, typing.Generic, Protocol, typing.Protocol} - or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, []) - or is_protocol(base) - ): - raise TypeError( - f"Protocols can only inherit from other protocols, " - f"got {base!r}" - ) - return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs) - - def __init__(cls, *args, **kwargs): - abc.ABCMeta.__init__(cls, *args, **kwargs) - if getattr(cls, "_is_protocol", False): - cls.__protocol_attrs__ = _get_protocol_attrs(cls) - - def __subclasscheck__(cls, other): - if cls is Protocol: - return type.__subclasscheck__(cls, other) - if ( - getattr(cls, '_is_protocol', False) - and not _allow_reckless_class_checks() - ): - if not getattr(cls, '_is_runtime_protocol', False): - _type_check_issubclass_arg_1(other) - raise TypeError( - "Instance and class checks can only be used with " - "@runtime_checkable protocols" - ) - if ( - # this attribute is set by @runtime_checkable: - cls.__non_callable_proto_members__ - and cls.__dict__.get("__subclasshook__") is _proto_hook - ): - _type_check_issubclass_arg_1(other) - non_method_attrs = sorted(cls.__non_callable_proto_members__) - raise TypeError( - "Protocols with non-method members don't support issubclass()." - f" Non-method members: {str(non_method_attrs)[1:-1]}." - ) - return abc.ABCMeta.__subclasscheck__(cls, other) - - def __instancecheck__(cls, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if cls is Protocol: - return type.__instancecheck__(cls, instance) - if not getattr(cls, "_is_protocol", False): - # i.e., it's a concrete subclass of a protocol - return abc.ABCMeta.__instancecheck__(cls, instance) - - if ( - not getattr(cls, '_is_runtime_protocol', False) and - not _allow_reckless_class_checks() - ): - raise TypeError("Instance and class checks can only be used with" - " @runtime_checkable protocols") - - if abc.ABCMeta.__instancecheck__(cls, instance): - return True - - for attr in cls.__protocol_attrs__: - try: - val = inspect.getattr_static(instance, attr) - except AttributeError: - break - # this attribute is set by @runtime_checkable: - if val is None and attr not in cls.__non_callable_proto_members__: - break - else: - return True - - return False - - def __eq__(cls, other): - # Hack so that typing.Generic.__class_getitem__ - # treats typing_extensions.Protocol - # as equivalent to typing.Protocol - if abc.ABCMeta.__eq__(cls, other) is True: - return True - return cls is Protocol and other is typing.Protocol - - # This has to be defined, or the abc-module cache - # complains about classes with this metaclass being unhashable, - # if we define only __eq__! - def __hash__(cls) -> int: - return type.__hash__(cls) - - @classmethod - def _proto_hook(cls, other): - if not cls.__dict__.get('_is_protocol', False): - return NotImplemented - - for attr in cls.__protocol_attrs__: - for base in other.__mro__: - # Check if the members appears in the class dictionary... - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - - # ...or in annotations, if it is a sub-protocol. - annotations = getattr(base, '__annotations__', {}) - if ( - isinstance(annotations, collections.abc.Mapping) - and attr in annotations - and is_protocol(other) - ): - break - else: - return NotImplemented - return True - - class Protocol(typing.Generic, metaclass=_ProtocolMeta): - __doc__ = typing.Protocol.__doc__ - __slots__ = () - _is_protocol = True - _is_runtime_protocol = False - - def __init_subclass__(cls, *args, **kwargs): - super().__init_subclass__(*args, **kwargs) - - # Determine if this is a protocol or a concrete subclass. - if not cls.__dict__.get('_is_protocol', False): - cls._is_protocol = any(b is Protocol for b in cls.__bases__) - - # Set (or override) the protocol subclass hook. - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - # Prohibit instantiation for protocol classes - if cls._is_protocol and cls.__init__ is Protocol.__init__: - cls.__init__ = _no_init - - -# Breakpoint: https://github.com/python/cpython/pull/113401 -if sys.version_info >= (3, 13): - runtime_checkable = typing.runtime_checkable -else: - def runtime_checkable(cls): - """Mark a protocol class as a runtime protocol. - - Such protocol can be used with isinstance() and issubclass(). - Raise TypeError if applied to a non-protocol class. - This allows a simple-minded structural check very similar to - one trick ponies in collections.abc such as Iterable. - - For example:: - - @runtime_checkable - class Closable(Protocol): - def close(self): ... - - assert isinstance(open('/some/file'), Closable) - - Warning: this will check only the presence of the required methods, - not their type signatures! - """ - if not issubclass(cls, typing.Generic) or not getattr(cls, '_is_protocol', False): - raise TypeError(f'@runtime_checkable can be only applied to protocol classes,' - f' got {cls!r}') - cls._is_runtime_protocol = True - - # typing.Protocol classes on <=3.11 break if we execute this block, - # because typing.Protocol classes on <=3.11 don't have a - # `__protocol_attrs__` attribute, and this block relies on the - # `__protocol_attrs__` attribute. Meanwhile, typing.Protocol classes on 3.12.2+ - # break if we *don't* execute this block, because *they* assume that all - # protocol classes have a `__non_callable_proto_members__` attribute - # (which this block sets) - if isinstance(cls, _ProtocolMeta) or sys.version_info >= (3, 12, 2): - # PEP 544 prohibits using issubclass() - # with protocols that have non-method members. - # See gh-113320 for why we compute this attribute here, - # rather than in `_ProtocolMeta.__init__` - cls.__non_callable_proto_members__ = set() - for attr in cls.__protocol_attrs__: - try: - is_callable = callable(getattr(cls, attr, None)) - except Exception as e: - raise TypeError( - f"Failed to determine whether protocol member {attr!r} " - "is a method member" - ) from e - else: - if not is_callable: - cls.__non_callable_proto_members__.add(attr) - - return cls - - -# The "runtime" alias exists for backwards compatibility. -runtime = runtime_checkable - - -# Our version of runtime-checkable protocols is faster on Python <=3.11 -# Breakpoint: https://github.com/python/cpython/pull/112717 -if sys.version_info >= (3, 12): - SupportsInt = typing.SupportsInt - SupportsFloat = typing.SupportsFloat - SupportsComplex = typing.SupportsComplex - SupportsBytes = typing.SupportsBytes - SupportsIndex = typing.SupportsIndex - SupportsAbs = typing.SupportsAbs - SupportsRound = typing.SupportsRound -else: - @runtime_checkable - class SupportsInt(Protocol): - """An ABC with one abstract method __int__.""" - __slots__ = () - - @abc.abstractmethod - def __int__(self) -> int: - pass - - @runtime_checkable - class SupportsFloat(Protocol): - """An ABC with one abstract method __float__.""" - __slots__ = () - - @abc.abstractmethod - def __float__(self) -> float: - pass - - @runtime_checkable - class SupportsComplex(Protocol): - """An ABC with one abstract method __complex__.""" - __slots__ = () - - @abc.abstractmethod - def __complex__(self) -> complex: - pass - - @runtime_checkable - class SupportsBytes(Protocol): - """An ABC with one abstract method __bytes__.""" - __slots__ = () - - @abc.abstractmethod - def __bytes__(self) -> bytes: - pass - - @runtime_checkable - class SupportsIndex(Protocol): - __slots__ = () - - @abc.abstractmethod - def __index__(self) -> int: - pass - - @runtime_checkable - class SupportsAbs(Protocol[T_co]): - """ - An ABC with one abstract method __abs__ that is covariant in its return type. - """ - __slots__ = () - - @abc.abstractmethod - def __abs__(self) -> T_co: - pass - - @runtime_checkable - class SupportsRound(Protocol[T_co]): - """ - An ABC with one abstract method __round__ that is covariant in its return type. - """ - __slots__ = () - - @abc.abstractmethod - def __round__(self, ndigits: int = 0) -> T_co: - pass - - -if hasattr(io, "Reader") and hasattr(io, "Writer"): - Reader = io.Reader - Writer = io.Writer -else: - @runtime_checkable - class Reader(Protocol[T_co]): - """Protocol for simple I/O reader instances. - - This protocol only supports blocking I/O. - """ - - __slots__ = () - - @abc.abstractmethod - def read(self, size: int = ..., /) -> T_co: - """Read data from the input stream and return it. - - If *size* is specified, at most *size* items (bytes/characters) will be - read. - """ - - @runtime_checkable - class Writer(Protocol[T_contra]): - """Protocol for simple I/O writer instances. - - This protocol only supports blocking I/O. - """ - - __slots__ = () - - @abc.abstractmethod - def write(self, data: T_contra, /) -> int: - """Write *data* to the output stream and return the number of items written.""" # noqa: E501 - - -_NEEDS_SINGLETONMETA = ( - not hasattr(typing, "NoDefault") or not hasattr(typing, "NoExtraItems") -) - -if _NEEDS_SINGLETONMETA: - class SingletonMeta(type): - def __setattr__(cls, attr, value): - # TypeError is consistent with the behavior of NoneType - raise TypeError( - f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}" - ) - - -if hasattr(typing, "NoDefault"): - NoDefault = typing.NoDefault -else: - class NoDefaultType(metaclass=SingletonMeta): - """The type of the NoDefault singleton.""" - - __slots__ = () - - def __new__(cls): - return globals().get("NoDefault") or object.__new__(cls) - - def __repr__(self): - return "typing_extensions.NoDefault" - - def __reduce__(self): - return "NoDefault" - - NoDefault = NoDefaultType() - del NoDefaultType - -if hasattr(typing, "NoExtraItems"): - NoExtraItems = typing.NoExtraItems -else: - class NoExtraItemsType(metaclass=SingletonMeta): - """The type of the NoExtraItems singleton.""" - - __slots__ = () - - def __new__(cls): - return globals().get("NoExtraItems") or object.__new__(cls) - - def __repr__(self): - return "typing_extensions.NoExtraItems" - - def __reduce__(self): - return "NoExtraItems" - - NoExtraItems = NoExtraItemsType() - del NoExtraItemsType - -if _NEEDS_SINGLETONMETA: - del SingletonMeta - - -# Update this to something like >=3.13.0b1 if and when -# PEP 764 is implemented in CPython -_PEP_764_IMPLEMENTED = False - -if _PEP_764_IMPLEMENTED: - # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" - # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 - # The standard library TypedDict below Python 3.11 does not store runtime - # information about optional and required keys when using Required or NotRequired. - # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. - # Aaaand on 3.12 we add __orig_bases__ to TypedDict - # to enable better runtime introspection. - # On 3.13 we deprecate some odd ways of creating TypedDicts. - # Also on 3.13, PEP 705 adds the ReadOnly[] qualifier. - # PEP 728 (Python 3.15+) adds the `extra_items` and `closed` keywords. - # PEP 764 (still pending) allows the `TypedDict` special form to be subscripted. - TypedDict = typing.TypedDict - _TypedDictMeta = typing._TypedDictMeta - is_typeddict = typing.is_typeddict -else: - # 3.10.0 and later - _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters - - def _get_typeddict_qualifiers(annotation_type): - while True: - annotation_origin = get_origin(annotation_type) - if annotation_origin is Annotated: - annotation_args = get_args(annotation_type) - if annotation_args: - annotation_type = annotation_args[0] - else: - break - elif annotation_origin is Required: - yield Required - annotation_type, = get_args(annotation_type) - elif annotation_origin is NotRequired: - yield NotRequired - annotation_type, = get_args(annotation_type) - elif annotation_origin is ReadOnly: - yield ReadOnly - annotation_type, = get_args(annotation_type) - else: - break - - class _TypedDictMeta(type): - - def __new__(cls, name, bases, ns, *, total=True, closed=None, - extra_items=NoExtraItems): - """Create new typed dict class object. - - This method is called when TypedDict is subclassed, - or when TypedDict is instantiated. This way - TypedDict supports all three syntax forms described in its docstring. - Subclasses and instances of TypedDict return actual dictionaries. - """ - for base in bases: - if type(base) is not _TypedDictMeta and base is not typing.Generic: - raise TypeError('cannot inherit from both a TypedDict type ' - 'and a non-TypedDict base class') - if closed is not None and extra_items is not NoExtraItems: - raise TypeError(f"Cannot combine closed={closed!r} and extra_items") - - if any(issubclass(b, typing.Generic) for b in bases): - generic_base = (typing.Generic,) - else: - generic_base = () - - ns_annotations = ns.pop('__annotations__', None) - - # typing.py generally doesn't let you inherit from plain Generic, unless - # the name of the class happens to be "Protocol" - tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns) - tp_dict.__name__ = name - if tp_dict.__qualname__ == "Protocol": - tp_dict.__qualname__ = name - - if not hasattr(tp_dict, '__orig_bases__'): - tp_dict.__orig_bases__ = bases - - annotations = {} - own_annotate = None - if ns_annotations is not None: - own_annotations = ns_annotations - elif sys.version_info >= (3, 14): - if hasattr(annotationlib, "get_annotate_from_class_namespace"): - own_annotate = annotationlib.get_annotate_from_class_namespace(ns) - else: - # 3.14.0a7 and earlier - own_annotate = ns.get("__annotate__") - if own_annotate is not None: - own_annotations = annotationlib.call_annotate_function( - own_annotate, Format.FORWARDREF, owner=tp_dict - ) - else: - own_annotations = {} - else: - own_annotations = {} - msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" - if _TAKES_MODULE: - own_checked_annotations = { - n: typing._type_check(tp, msg, module=tp_dict.__module__) - for n, tp in own_annotations.items() - } - else: - own_checked_annotations = { - n: typing._type_check(tp, msg) - for n, tp in own_annotations.items() - } - required_keys = set() - optional_keys = set() - readonly_keys = set() - mutable_keys = set() - extra_items_type = extra_items - - for base in bases: - base_dict = base.__dict__ - - if sys.version_info <= (3, 14): - annotations.update(base_dict.get('__annotations__', {})) - base_required = base_dict.get('__required_keys__', set()) - required_keys |= base_required - optional_keys -= base_required - - base_optional = base_dict.get('__optional_keys__', set()) - required_keys -= base_optional - optional_keys |= base_optional - - readonly_keys.update(base_dict.get('__readonly_keys__', ())) - mutable_keys.update(base_dict.get('__mutable_keys__', ())) - - # This was specified in an earlier version of PEP 728. Support - # is retained for backwards compatibility, but only for Python - # 3.13 and lower. - if (closed and sys.version_info < (3, 14) - and "__extra_items__" in own_checked_annotations): - annotation_type = own_checked_annotations.pop("__extra_items__") - qualifiers = set(_get_typeddict_qualifiers(annotation_type)) - if Required in qualifiers: - raise TypeError( - "Special key __extra_items__ does not support " - "Required" - ) - if NotRequired in qualifiers: - raise TypeError( - "Special key __extra_items__ does not support " - "NotRequired" - ) - extra_items_type = annotation_type - - annotations.update(own_checked_annotations) - for annotation_key, annotation_type in own_checked_annotations.items(): - qualifiers = set(_get_typeddict_qualifiers(annotation_type)) - - if Required in qualifiers: - is_required = True - elif NotRequired in qualifiers: - is_required = False - else: - is_required = total - - if is_required: - required_keys.add(annotation_key) - optional_keys.discard(annotation_key) - else: - optional_keys.add(annotation_key) - required_keys.discard(annotation_key) - - if ReadOnly in qualifiers: - mutable_keys.discard(annotation_key) - readonly_keys.add(annotation_key) - else: - mutable_keys.add(annotation_key) - readonly_keys.discard(annotation_key) - - # Breakpoint: https://github.com/python/cpython/pull/119891 - if sys.version_info >= (3, 14): - def __annotate__(format): - annos = {} - for base in bases: - if base is Generic: - continue - base_annotate = base.__annotate__ - if base_annotate is None: - continue - base_annos = annotationlib.call_annotate_function( - base_annotate, format, owner=base) - annos.update(base_annos) - if own_annotate is not None: - own = annotationlib.call_annotate_function( - own_annotate, format, owner=tp_dict) - if format != Format.STRING: - own = { - n: typing._type_check(tp, msg, module=tp_dict.__module__) - for n, tp in own.items() - } - elif format == Format.STRING: - own = annotationlib.annotations_to_string(own_annotations) - elif format in (Format.FORWARDREF, Format.VALUE): - own = own_checked_annotations - else: - raise NotImplementedError(format) - annos.update(own) - return annos - - tp_dict.__annotate__ = __annotate__ - else: - tp_dict.__annotations__ = annotations - tp_dict.__required_keys__ = frozenset(required_keys) - tp_dict.__optional_keys__ = frozenset(optional_keys) - tp_dict.__readonly_keys__ = frozenset(readonly_keys) - tp_dict.__mutable_keys__ = frozenset(mutable_keys) - tp_dict.__total__ = total - tp_dict.__closed__ = closed - tp_dict.__extra_items__ = extra_items_type - return tp_dict - - __call__ = dict # static method - - def __subclasscheck__(cls, other): - # Typed dicts are only for static structural subtyping. - raise TypeError('TypedDict does not support instance and class checks') - - __instancecheck__ = __subclasscheck__ - - _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) - - def _create_typeddict( - typename, - fields, - /, - *, - typing_is_inline, - total, - closed, - extra_items, - **kwargs, - ): - if fields is _marker or fields is None: - if fields is _marker: - deprecated_thing = ( - "Failing to pass a value for the 'fields' parameter" - ) - else: - deprecated_thing = "Passing `None` as the 'fields' parameter" - - example = f"`{typename} = TypedDict({typename!r}, {{}})`" - deprecation_msg = ( - f"{deprecated_thing} is deprecated and will be disallowed in " - "Python 3.15. To create a TypedDict class with 0 fields " - "using the functional syntax, pass an empty dictionary, e.g. " - ) + example + "." - warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) - # Support a field called "closed" - if closed is not False and closed is not True and closed is not None: - kwargs["closed"] = closed - closed = None - # Or "extra_items" - if extra_items is not NoExtraItems: - kwargs["extra_items"] = extra_items - extra_items = NoExtraItems - fields = kwargs - elif kwargs: - raise TypeError("TypedDict takes either a dict or keyword arguments," - " but not both") - if kwargs: - # Breakpoint: https://github.com/python/cpython/pull/104891 - if sys.version_info >= (3, 13): - raise TypeError("TypedDict takes no keyword arguments") - warnings.warn( - "The kwargs-based syntax for TypedDict definitions is deprecated " - "in Python 3.11, will be removed in Python 3.13, and may not be " - "understood by third-party type checkers.", - DeprecationWarning, - stacklevel=2, - ) - - ns = {'__annotations__': dict(fields)} - module = _caller(depth=4 if typing_is_inline else 2) - if module is not None: - # Setting correct module is necessary to make typed dict classes - # pickleable. - ns['__module__'] = module - - td = _TypedDictMeta(typename, (), ns, total=total, closed=closed, - extra_items=extra_items) - td.__orig_bases__ = (TypedDict,) - return td - - class _TypedDictSpecialForm(_SpecialForm, _root=True): - def __call__( - self, - typename, - fields=_marker, - /, - *, - total=True, - closed=None, - extra_items=NoExtraItems, - **kwargs - ): - return _create_typeddict( - typename, - fields, - typing_is_inline=False, - total=total, - closed=closed, - extra_items=extra_items, - **kwargs, - ) - - def __mro_entries__(self, bases): - return (_TypedDict,) - - @_TypedDictSpecialForm - def TypedDict(self, args): - """A simple typed namespace. At runtime it is equivalent to a plain dict. - - TypedDict creates a dictionary type such that a type checker will expect all - instances to have a certain set of keys, where each key is - associated with a value of a consistent type. This expectation - is not checked at runtime. - - Usage:: - - class Point2D(TypedDict): - x: int - y: int - label: str - - a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK - b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check - - assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') - - The type info can be accessed via the Point2D.__annotations__ dict, and - the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. - TypedDict supports an additional equivalent form:: - - Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) - - By default, all keys must be present in a TypedDict. It is possible - to override this by specifying totality:: - - class Point2D(TypedDict, total=False): - x: int - y: int - - This means that a Point2D TypedDict can have any of the keys omitted. A type - checker is only expected to support a literal False or True as the value of - the total argument. True is the default, and makes all items defined in the - class body be required. - - The Required and NotRequired special forms can also be used to mark - individual keys as being required or not required:: - - class Point2D(TypedDict): - x: int # the "x" key must always be present (Required is the default) - y: NotRequired[int] # the "y" key can be omitted - - See PEP 655 for more details on Required and NotRequired. - """ - # This runs when creating inline TypedDicts: - if not isinstance(args, dict): - raise TypeError( - "TypedDict[...] should be used with a single dict argument" - ) - - return _create_typeddict( - "", - args, - typing_is_inline=True, - total=True, - closed=True, - extra_items=NoExtraItems, - ) - - _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) - - def is_typeddict(tp): - """Check if an annotation is a TypedDict class - - For example:: - class Film(TypedDict): - title: str - year: int - - is_typeddict(Film) # => True - is_typeddict(Union[list, str]) # => False - """ - return isinstance(tp, _TYPEDDICT_TYPES) - - -if hasattr(typing, "assert_type"): - assert_type = typing.assert_type - -else: - def assert_type(val, typ, /): - """Assert (to the type checker) that the value is of the given type. - - When the type checker encounters a call to assert_type(), it - emits an error if the value is not of the specified type:: - - def greet(name: str) -> None: - assert_type(name, str) # ok - assert_type(name, int) # type checker error - - At runtime this returns the first argument unchanged and otherwise - does nothing. - """ - return val - - -if hasattr(typing, "ReadOnly"): # 3.13+ - get_type_hints = typing.get_type_hints -else: # <=3.13 - # replaces _strip_annotations() - def _strip_extras(t): - """Strips Annotated, Required and NotRequired from a given type.""" - if isinstance(t, typing._AnnotatedAlias): - return _strip_extras(t.__origin__) - if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired, ReadOnly): - return _strip_extras(t.__args__[0]) - if isinstance(t, typing._GenericAlias): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return t.copy_with(stripped_args) - if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return _types.GenericAlias(t.__origin__, stripped_args) - if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return functools.reduce(operator.or_, stripped_args) - - return t - - def get_type_hints(obj, globalns=None, localns=None, include_extras=False): - """Return type hints for an object. - - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, adds Optional[t] if a - default value equal to None is set and recursively replaces all - 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' - (unless 'include_extras=True'). - - The argument may be a module, class, method, or function. The annotations - are returned as a dictionary. For classes, annotations include also - inherited members. - - TypeError is raised if the argument is not of a type that can contain - annotations, and an empty dictionary is returned if no annotations are - present. - - BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The - search order is locals first, then globals. - - - If no dict arguments are passed, an attempt is made to use the - globals from obj (or the respective module's globals for classes), - and these are also used as the locals. If the object does not appear - to have globals, an empty dictionary is used. - - - If one dict argument is passed, it is used for both globals and - locals. - - - If two dict arguments are passed, they specify globals and - locals, respectively. - """ - hint = typing.get_type_hints( - obj, globalns=globalns, localns=localns, include_extras=True - ) - # Breakpoint: https://github.com/python/cpython/pull/30304 - if sys.version_info < (3, 11): - _clean_optional(obj, hint, globalns, localns) - if include_extras: - return hint - return {k: _strip_extras(t) for k, t in hint.items()} - - _NoneType = type(None) - - def _could_be_inserted_optional(t): - """detects Union[..., None] pattern""" - if not isinstance(t, typing._UnionGenericAlias): - return False - # Assume if last argument is not None they are user defined - if t.__args__[-1] is not _NoneType: - return False - return True - - # < 3.11 - def _clean_optional(obj, hints, globalns=None, localns=None): - # reverts injected Union[..., None] cases from typing.get_type_hints - # when a None default value is used. - # see https://github.com/python/typing_extensions/issues/310 - if not hints or isinstance(obj, type): - return - defaults = typing._get_defaults(obj) # avoid accessing __annotations___ - if not defaults: - return - original_hints = obj.__annotations__ - for name, value in hints.items(): - # Not a Union[..., None] or replacement conditions not fullfilled - if (not _could_be_inserted_optional(value) - or name not in defaults - or defaults[name] is not None - ): - continue - original_value = original_hints[name] - # value=NoneType should have caused a skip above but check for safety - if original_value is None: - original_value = _NoneType - # Forward reference - if isinstance(original_value, str): - if globalns is None: - if isinstance(obj, _types.ModuleType): - globalns = obj.__dict__ - else: - nsobj = obj - # Find globalns for the unwrapped object. - while hasattr(nsobj, '__wrapped__'): - nsobj = nsobj.__wrapped__ - globalns = getattr(nsobj, '__globals__', {}) - if localns is None: - localns = globalns - elif localns is None: - localns = globalns - - original_value = ForwardRef( - original_value, - is_argument=not isinstance(obj, _types.ModuleType) - ) - original_evaluated = typing._eval_type(original_value, globalns, localns) - # Compare if values differ. Note that even if equal - # value might be cached by typing._tp_cache contrary to original_evaluated - if original_evaluated != value or ( - # 3.10: ForwardRefs of UnionType might be turned into _UnionGenericAlias - hasattr(_types, "UnionType") - and isinstance(original_evaluated, _types.UnionType) - and not isinstance(value, _types.UnionType) - ): - hints[name] = original_evaluated - -# Python 3.9 has get_origin() and get_args() but those implementations don't support -# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. -# Breakpoint: https://github.com/python/cpython/pull/25298 -if sys.version_info >= (3, 10): - get_origin = typing.get_origin - get_args = typing.get_args -# 3.9 -else: - def get_origin(tp): - """Get the unsubscripted version of a type. - - This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar - and Annotated. Return None for unsupported types. Examples:: - - get_origin(Literal[42]) is Literal - get_origin(int) is None - get_origin(ClassVar[int]) is ClassVar - get_origin(Generic) is Generic - get_origin(Generic[T]) is Generic - get_origin(Union[T, int]) is Union - get_origin(List[Tuple[T, T]][int]) == list - get_origin(P.args) is P - """ - if isinstance(tp, typing._AnnotatedAlias): - return Annotated - if isinstance(tp, (typing._BaseGenericAlias, _types.GenericAlias, - ParamSpecArgs, ParamSpecKwargs)): - return tp.__origin__ - if tp is typing.Generic: - return typing.Generic - return None - - def get_args(tp): - """Get type arguments with all substitutions performed. - - For unions, basic simplifications used by Union constructor are performed. - Examples:: - get_args(Dict[str, int]) == (str, int) - get_args(int) == () - get_args(Union[int, Union[T, int], str][int]) == (int, str) - get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) - get_args(Callable[[], T][int]) == ([], int) - """ - if isinstance(tp, typing._AnnotatedAlias): - return (tp.__origin__, *tp.__metadata__) - if isinstance(tp, (typing._GenericAlias, _types.GenericAlias)): - res = tp.__args__ - if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: - res = (list(res[:-1]), res[-1]) - return res - return () - - -# 3.10+ -if hasattr(typing, 'TypeAlias'): - TypeAlias = typing.TypeAlias -# 3.9 -else: - @_ExtensionsSpecialForm - def TypeAlias(self, parameters): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example above. - """ - raise TypeError(f"{self} is not subscriptable") - - -def _set_default(type_param, default): - type_param.has_default = lambda: default is not NoDefault - type_param.__default__ = default - - -def _set_module(typevarlike): - # for pickling: - def_mod = _caller(depth=2) - if def_mod != 'typing_extensions': - typevarlike.__module__ = def_mod - - -class _DefaultMixin: - """Mixin for TypeVarLike defaults.""" - - __slots__ = () - __init__ = _set_default - - -# Classes using this metaclass must provide a _backported_typevarlike ClassVar -class _TypeVarLikeMeta(type): - def __instancecheck__(cls, __instance: Any) -> bool: - return isinstance(__instance, cls._backported_typevarlike) - - -if _PEP_696_IMPLEMENTED: - from typing import TypeVar -else: - # Add default and infer_variance parameters from PEP 696 and 695 - class TypeVar(metaclass=_TypeVarLikeMeta): - """Type variable.""" - - _backported_typevarlike = typing.TypeVar - - def __new__(cls, name, *constraints, bound=None, - covariant=False, contravariant=False, - default=NoDefault, infer_variance=False): - if hasattr(typing, "TypeAliasType"): - # PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar - typevar = typing.TypeVar(name, *constraints, bound=bound, - covariant=covariant, contravariant=contravariant, - infer_variance=infer_variance) - else: - typevar = typing.TypeVar(name, *constraints, bound=bound, - covariant=covariant, contravariant=contravariant) - if infer_variance and (covariant or contravariant): - raise ValueError("Variance cannot be specified with infer_variance.") - typevar.__infer_variance__ = infer_variance - - _set_default(typevar, default) - _set_module(typevar) - - def _tvar_prepare_subst(alias, args): - if ( - typevar.has_default() - and alias.__parameters__.index(typevar) == len(args) - ): - args += (typevar.__default__,) - return args - - typevar.__typing_prepare_subst__ = _tvar_prepare_subst - return typevar - - def __init_subclass__(cls) -> None: - raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type") - - -# Python 3.10+ has PEP 612 -if hasattr(typing, 'ParamSpecArgs'): - ParamSpecArgs = typing.ParamSpecArgs - ParamSpecKwargs = typing.ParamSpecKwargs -# 3.9 -else: - class _Immutable: - """Mixin to indicate that object should not be copied.""" - __slots__ = () - - def __copy__(self): - return self - - def __deepcopy__(self, memo): - return self - - class ParamSpecArgs(_Immutable): - """The args for a ParamSpec object. - - Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. - - ParamSpecArgs objects have a reference back to their ParamSpec: - - P.args.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.args" - - def __eq__(self, other): - if not isinstance(other, ParamSpecArgs): - return NotImplemented - return self.__origin__ == other.__origin__ - - class ParamSpecKwargs(_Immutable): - """The kwargs for a ParamSpec object. - - Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. - - ParamSpecKwargs objects have a reference back to their ParamSpec: - - P.kwargs.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.kwargs" - - def __eq__(self, other): - if not isinstance(other, ParamSpecKwargs): - return NotImplemented - return self.__origin__ == other.__origin__ - - -if _PEP_696_IMPLEMENTED: - from typing import ParamSpec - -# 3.10+ -elif hasattr(typing, 'ParamSpec'): - - # Add default parameter - PEP 696 - class ParamSpec(metaclass=_TypeVarLikeMeta): - """Parameter specification.""" - - _backported_typevarlike = typing.ParamSpec - - def __new__(cls, name, *, bound=None, - covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - if hasattr(typing, "TypeAliasType"): - # PEP 695 implemented, can pass infer_variance to typing.TypeVar - paramspec = typing.ParamSpec(name, bound=bound, - covariant=covariant, - contravariant=contravariant, - infer_variance=infer_variance) - else: - paramspec = typing.ParamSpec(name, bound=bound, - covariant=covariant, - contravariant=contravariant) - paramspec.__infer_variance__ = bool(infer_variance) - - _set_default(paramspec, default) - _set_module(paramspec) - - def _paramspec_prepare_subst(alias, args): - params = alias.__parameters__ - i = params.index(paramspec) - if i == len(args) and paramspec.has_default(): - args = [*args, paramspec.__default__] - if i >= len(args): - raise TypeError(f"Too few arguments for {alias}") - # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. - if len(params) == 1 and not typing._is_param_expr(args[0]): - assert i == 0 - args = (args,) - # Convert lists to tuples to help other libraries cache the results. - elif isinstance(args[i], list): - args = (*args[:i], tuple(args[i]), *args[i + 1:]) - return args - - paramspec.__typing_prepare_subst__ = _paramspec_prepare_subst - return paramspec - - def __init_subclass__(cls) -> None: - raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") - -# 3.9 -else: - - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class ParamSpec(list, _DefaultMixin): - """Parameter specification variable. - - Usage:: - - P = ParamSpec('P') - - Parameter specification variables exist primarily for the benefit of static - type checkers. They are used to forward the parameter types of one - callable to another callable, a pattern commonly found in higher order - functions and decorators. They are only valid when used in ``Concatenate``, - or s the first argument to ``Callable``. In Python 3.10 and higher, - they are also supported in user-defined Generics at runtime. - See class Generic for more information on generic types. An - example for annotating a decorator:: - - T = TypeVar('T') - P = ParamSpec('P') - - def add_logging(f: Callable[P, T]) -> Callable[P, T]: - '''A type-safe decorator to add logging to a function.''' - def inner(*args: P.args, **kwargs: P.kwargs) -> T: - logging.info(f'{f.__name__} was called') - return f(*args, **kwargs) - return inner - - @add_logging - def add_two(x: float, y: float) -> float: - '''Add two numbers together.''' - return x + y - - Parameter specification variables defined with covariant=True or - contravariant=True can be used to declare covariant or contravariant - generic types. These keyword arguments are valid, but their actual semantics - are yet to be decided. See PEP 612 for details. - - Parameter specification variables can be introspected. e.g.: - - P.__name__ == 'T' - P.__bound__ == None - P.__covariant__ == False - P.__contravariant__ == False - - Note that only parameter specification variables defined in global scope can - be pickled. - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - @property - def args(self): - return ParamSpecArgs(self) - - @property - def kwargs(self): - return ParamSpecKwargs(self) - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - list.__init__(self, [self]) - self.__name__ = name - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - self.__infer_variance__ = bool(infer_variance) - self.__bound__ = bound - _DefaultMixin.__init__(self, default) - - # for pickling: - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __repr__(self): - if self.__infer_variance__: - prefix = '' - elif self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - # Hack to get typing._type_check to pass. - def __call__(self, *args, **kwargs): - pass - - def __init_subclass__(cls) -> None: - raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") - - -# 3.9 -if not hasattr(typing, 'Concatenate'): - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - - # 3.9.0-1 - if not hasattr(typing, '_type_convert'): - def _type_convert(arg, module=None, *, allow_special_forms=False): - """For converting None to type(None), and strings to ForwardRef.""" - if arg is None: - return type(None) - if isinstance(arg, str): - if sys.version_info <= (3, 9, 6): - return ForwardRef(arg) - if sys.version_info <= (3, 9, 7): - return ForwardRef(arg, module=module) - return ForwardRef(arg, module=module, is_class=allow_special_forms) - return arg - else: - _type_convert = typing._type_convert - - class _ConcatenateGenericAlias(list): - - # Trick Generic into looking into this for __parameters__. - __class__ = typing._GenericAlias - - def __init__(self, origin, args): - # Cannot use `super().__init__` here because of the `__class__` assignment - # in the class body (https://github.com/python/typing_extensions/issues/661) - list.__init__(self, args) - self.__origin__ = origin - self.__args__ = args - - def __repr__(self): - _type_repr = typing._type_repr - return (f'{_type_repr(self.__origin__)}' - f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') - - def __hash__(self): - return hash((self.__origin__, self.__args__)) - - # Hack to get typing._type_check to pass in Generic. - def __call__(self, *args, **kwargs): - pass - - @property - def __parameters__(self): - return tuple( - tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) - ) - - # 3.9 used by __getitem__ below - def copy_with(self, params): - if isinstance(params[-1], _ConcatenateGenericAlias): - params = (*params[:-1], *params[-1].__args__) - elif isinstance(params[-1], (list, tuple)): - return (*params[:-1], *params[-1]) - elif (not (params[-1] is ... or isinstance(params[-1], ParamSpec))): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - return self.__class__(self.__origin__, params) - - # 3.9; accessed during GenericAlias.__getitem__ when substituting - def __getitem__(self, args): - if self.__origin__ in (Generic, Protocol): - # Can't subscript Generic[...] or Protocol[...]. - raise TypeError(f"Cannot subscript already-subscripted {self}") - if not self.__parameters__: - raise TypeError(f"{self} is not a generic class") - - if not isinstance(args, tuple): - args = (args,) - args = _unpack_args(*(_type_convert(p) for p in args)) - params = self.__parameters__ - for param in params: - prepare = getattr(param, "__typing_prepare_subst__", None) - if prepare is not None: - args = prepare(self, args) - # 3.9 & typing.ParamSpec - elif isinstance(param, ParamSpec): - i = params.index(param) - if ( - i == len(args) - and getattr(param, '__default__', NoDefault) is not NoDefault - ): - args = [*args, param.__default__] - if i >= len(args): - raise TypeError(f"Too few arguments for {self}") - # Special case for Z[[int, str, bool]] == Z[int, str, bool] - if len(params) == 1 and not _is_param_expr(args[0]): - assert i == 0 - args = (args,) - elif ( - isinstance(args[i], list) - # 3.9 - # This class inherits from list do not convert - and not isinstance(args[i], _ConcatenateGenericAlias) - ): - args = (*args[:i], tuple(args[i]), *args[i + 1:]) - - alen = len(args) - plen = len(params) - if alen != plen: - raise TypeError( - f"Too {'many' if alen > plen else 'few'} arguments for {self};" - f" actual {alen}, expected {plen}" - ) - - subst = dict(zip(self.__parameters__, args)) - # determine new args - new_args = [] - for arg in self.__args__: - if isinstance(arg, type): - new_args.append(arg) - continue - if isinstance(arg, TypeVar): - arg = subst[arg] - if ( - (isinstance(arg, typing._GenericAlias) and _is_unpack(arg)) - or ( - hasattr(_types, "GenericAlias") - and isinstance(arg, _types.GenericAlias) - and getattr(arg, "__unpacked__", False) - ) - ): - raise TypeError(f"{arg} is not valid as type argument") - - elif isinstance(arg, - typing._GenericAlias - if not hasattr(_types, "GenericAlias") else - (typing._GenericAlias, _types.GenericAlias) - ): - subparams = arg.__parameters__ - if subparams: - subargs = tuple(subst[x] for x in subparams) - arg = arg[subargs] - new_args.append(arg) - return self.copy_with(tuple(new_args)) - -# 3.10+ -else: - _ConcatenateGenericAlias = typing._ConcatenateGenericAlias - - # 3.10 - if sys.version_info < (3, 11): - - class _ConcatenateGenericAlias(typing._ConcatenateGenericAlias, _root=True): - # needed for checks in collections.abc.Callable to accept this class - __module__ = "typing" - - def copy_with(self, params): - if isinstance(params[-1], (list, tuple)): - return (*params[:-1], *params[-1]) - if isinstance(params[-1], typing._ConcatenateGenericAlias): - params = (*params[:-1], *params[-1].__args__) - elif not (params[-1] is ... or isinstance(params[-1], ParamSpec)): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - return super(typing._ConcatenateGenericAlias, self).copy_with(params) - - def __getitem__(self, args): - value = super().__getitem__(args) - if isinstance(value, tuple) and any(_is_unpack(t) for t in value): - return tuple(_unpack_args(*(n for n in value))) - return value - - -# 3.9.2 -class _EllipsisDummy: ... - - -# <=3.10 -def _create_concatenate_alias(origin, parameters): - if parameters[-1] is ... and sys.version_info < (3, 9, 2): - # Hack: Arguments must be types, replace it with one. - parameters = (*parameters[:-1], _EllipsisDummy) - if sys.version_info >= (3, 10, 3): - concatenate = _ConcatenateGenericAlias(origin, parameters, - _typevar_types=(TypeVar, ParamSpec), - _paramspec_tvars=True) - else: - concatenate = _ConcatenateGenericAlias(origin, parameters) - if parameters[-1] is not _EllipsisDummy: - return concatenate - # Remove dummy again - concatenate.__args__ = tuple(p if p is not _EllipsisDummy else ... - for p in concatenate.__args__) - if sys.version_info < (3, 10): - # backport needs __args__ adjustment only - return concatenate - concatenate.__parameters__ = tuple(p for p in concatenate.__parameters__ - if p is not _EllipsisDummy) - return concatenate - - -# <=3.10 -@typing._tp_cache -def _concatenate_getitem(self, parameters): - if parameters == (): - raise TypeError("Cannot take a Concatenate of no types.") - if not isinstance(parameters, tuple): - parameters = (parameters,) - if not (parameters[-1] is ... or isinstance(parameters[-1], ParamSpec)): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - msg = "Concatenate[arg, ...]: each arg must be a type." - parameters = (*(typing._type_check(p, msg) for p in parameters[:-1]), - parameters[-1]) - return _create_concatenate_alias(self, parameters) - - -# 3.11+; Concatenate does not accept ellipsis in 3.10 -# Breakpoint: https://github.com/python/cpython/pull/30969 -if sys.version_info >= (3, 11): - Concatenate = typing.Concatenate -# <=3.10 -else: - @_ExtensionsSpecialForm - def Concatenate(self, parameters): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - return _concatenate_getitem(self, parameters) - - -# 3.10+ -if hasattr(typing, 'TypeGuard'): - TypeGuard = typing.TypeGuard -# 3.9 -else: - @_ExtensionsSpecialForm - def TypeGuard(self, parameters): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - -# 3.13+ -if hasattr(typing, 'TypeIs'): - TypeIs = typing.TypeIs -# <=3.12 -else: - @_ExtensionsSpecialForm - def TypeIs(self, parameters): - """Special typing form used to annotate the return type of a user-defined - type narrower function. ``TypeIs`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeIs`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeIs[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeIs`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the intersection of the type inside ``TypeIs`` and the argument's - previously known type. - - For example:: - - def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]: - return hasattr(val, '__await__') - - def f(val: Union[int, Awaitable[int]]) -> int: - if is_awaitable(val): - assert_type(val, Awaitable[int]) - else: - assert_type(val, int) - - ``TypeIs`` also works with type variables. For more information, see - PEP 742 (Narrowing types with TypeIs). - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - -# 3.15+? -if hasattr(typing, 'TypeForm'): - TypeForm = typing.TypeForm -# <=3.14 -else: - class _TypeFormForm(_ExtensionsSpecialForm, _root=True): - # TypeForm(X) is equivalent to X but indicates to the type checker - # that the object is a TypeForm. - def __call__(self, obj, /): - return obj - - @_TypeFormForm - def TypeForm(self, parameters): - """A special form representing the value that results from the evaluation - of a type expression. This value encodes the information supplied in the - type expression, and it represents the type described by that type expression. - - When used in a type expression, TypeForm describes a set of type form objects. - It accepts a single type argument, which must be a valid type expression. - ``TypeForm[T]`` describes the set of all type form objects that represent - the type T or types that are assignable to T. - - Usage: - - def cast[T](typ: TypeForm[T], value: Any) -> T: ... - - reveal_type(cast(int, "x")) # int - - See PEP 747 for more information. - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - - - -if hasattr(typing, "LiteralString"): # 3.11+ - LiteralString = typing.LiteralString -else: - @_SpecialForm - def LiteralString(self, params): - """Represents an arbitrary literal string. - - Example:: - - from typing_extensions import LiteralString - - def query(sql: LiteralString) -> ...: - ... - - query("SELECT * FROM table") # ok - query(f"SELECT * FROM {input()}") # not ok - - See PEP 675 for details. - - """ - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, "Self"): # 3.11+ - Self = typing.Self -else: - @_SpecialForm - def Self(self, params): - """Used to spell the type of "self" in classes. - - Example:: - - from typing import Self - - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self - - """ - - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, "Never"): # 3.11+ - Never = typing.Never -else: - @_SpecialForm - def Never(self, params): - """The bottom type, a type that has no members. - - This can be used to define a function that should never be - called, or a function that never returns:: - - from typing_extensions import Never - - def never_call_me(arg: Never) -> None: - pass - - def int_or_str(arg: int | str) -> None: - never_call_me(arg) # type checker error - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - never_call_me(arg) # ok, arg is of type Never - - """ - - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, 'Required'): # 3.11+ - Required = typing.Required - NotRequired = typing.NotRequired -else: # <=3.10 - @_ExtensionsSpecialForm - def Required(self, parameters): - """A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - @_ExtensionsSpecialForm - def NotRequired(self, parameters): - """A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - -if hasattr(typing, 'ReadOnly'): - ReadOnly = typing.ReadOnly -else: # <=3.12 - @_ExtensionsSpecialForm - def ReadOnly(self, parameters): - """A special typing construct to mark an item of a TypedDict as read-only. - - For example: - - class Movie(TypedDict): - title: ReadOnly[str] - year: int - - def mutate_movie(m: Movie) -> None: - m["year"] = 1992 # allowed - m["title"] = "The Matrix" # typechecker error - - There is no runtime checking for this property. - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - -_UNPACK_DOC = """\ -Type unpack operator. - -The type unpack operator takes the child types from some container type, -such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For -example: - - # For some generic class `Foo`: - Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] - - Ts = TypeVarTuple('Ts') - # Specifies that `Bar` is generic in an arbitrary number of types. - # (Think of `Ts` as a tuple of an arbitrary number of individual - # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the - # `Generic[]`.) - class Bar(Generic[Unpack[Ts]]): ... - Bar[int] # Valid - Bar[int, str] # Also valid - -From Python 3.11, this can also be done using the `*` operator: - - Foo[*tuple[int, str]] - class Bar(Generic[*Ts]): ... - -The operator can also be used along with a `TypedDict` to annotate -`**kwargs` in a function signature. For instance: - - class Movie(TypedDict): - name: str - year: int - - # This function expects two keyword arguments - *name* of type `str` and - # *year* of type `int`. - def foo(**kwargs: Unpack[Movie]): ... - -Note that there is only some runtime checking of this operator. Not -everything the runtime allows may be accepted by static type checkers. - -For more information, see PEP 646 and PEP 692. -""" - - -# PEP 692 changed the repr of Unpack[] -# Breakpoint: https://github.com/python/cpython/pull/104048 -if sys.version_info >= (3, 12): - Unpack = typing.Unpack - - def _is_unpack(obj): - return get_origin(obj) is Unpack - -else: # <=3.11 - class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True): - def __init__(self, getitem): - super().__init__(getitem) - self.__doc__ = _UNPACK_DOC - - class _UnpackAlias(typing._GenericAlias, _root=True): - if sys.version_info < (3, 11): - # needed for compatibility with Generic[Unpack[Ts]] - __class__ = typing.TypeVar - - @property - def __typing_unpacked_tuple_args__(self): - assert self.__origin__ is Unpack - assert len(self.__args__) == 1 - arg, = self.__args__ - if isinstance(arg, (typing._GenericAlias, _types.GenericAlias)): - if arg.__origin__ is not tuple: - raise TypeError("Unpack[...] must be used with a tuple type") - return arg.__args__ - return None - - @property - def __typing_is_unpacked_typevartuple__(self): - assert self.__origin__ is Unpack - assert len(self.__args__) == 1 - return isinstance(self.__args__[0], TypeVarTuple) - - def __getitem__(self, args): - if self.__typing_is_unpacked_typevartuple__: - return args - # Cannot use `super().__getitem__` here because of the `__class__` assignment - # in the class body on Python <=3.11 - # (https://github.com/python/typing_extensions/issues/661) - return typing._GenericAlias.__getitem__(self, args) - - @_UnpackSpecialForm - def Unpack(self, parameters): - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return _UnpackAlias(self, (item,)) - - def _is_unpack(obj): - return isinstance(obj, _UnpackAlias) - - -def _unpack_args(*args): - newargs = [] - for arg in args: - subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) - if subargs is not None and (not (subargs and subargs[-1] is ...)): - newargs.extend(subargs) - else: - newargs.append(arg) - return newargs - - -if sys.version_info >= (3, 15): - from typing import TypeVarTuple - -elif hasattr(typing, "TypeVarTuple"): # 3.11+ - - # Add default parameter - PEP 696 and bound/variance parameters - class TypeVarTuple(metaclass=_TypeVarLikeMeta): - """Type variable tuple.""" - - _backported_typevarlike = typing.TypeVarTuple - - def __new__(cls, name, *, bound=None, - covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - - if _PEP_696_IMPLEMENTED: - # can pass default argument - tvt = typing.TypeVarTuple(name, default=default) - else: - tvt = typing.TypeVarTuple(name) - _set_default(tvt, default) - - tvt.__bound__ = bound - tvt.__covariant__ = bool(covariant) - tvt.__contravariant__ = bool(contravariant) - tvt.__infer_variance__ = bool(infer_variance) - - _set_module(tvt) - - def _typevartuple_prepare_subst(alias, args): - params = alias.__parameters__ - typevartuple_index = params.index(tvt) - for param in params[typevartuple_index + 1:]: - if isinstance(param, TypeVarTuple): - raise TypeError( - f"More than one TypeVarTuple parameter in {alias}" - ) - - alen = len(args) - plen = len(params) - left = typevartuple_index - right = plen - typevartuple_index - 1 - var_tuple_index = None - fillarg = None - for k, arg in enumerate(args): - if not isinstance(arg, type): - subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) - if subargs and len(subargs) == 2 and subargs[-1] is ...: - if var_tuple_index is not None: - raise TypeError( - "More than one unpacked " - "arbitrary-length tuple argument" - ) - var_tuple_index = k - fillarg = subargs[0] - if var_tuple_index is not None: - left = min(left, var_tuple_index) - right = min(right, alen - var_tuple_index - 1) - elif left + right > alen: - raise TypeError(f"Too few arguments for {alias};" - f" actual {alen}, expected at least {plen - 1}") - if left == alen - right and tvt.has_default(): - replacement = _unpack_args(tvt.__default__) - else: - replacement = args[left: alen - right] - - return ( - *args[:left], - *([fillarg] * (typevartuple_index - left)), - replacement, - *([fillarg] * (plen - right - left - typevartuple_index - 1)), - *args[alen - right:], - ) - - tvt.__typing_prepare_subst__ = _typevartuple_prepare_subst - return tvt - - def __init_subclass__(self, *args, **kwds): - raise TypeError("Cannot subclass special typing classes") - -else: # <=3.10 - class TypeVarTuple(_DefaultMixin): - """Type variable tuple. - - Usage:: - - Ts = TypeVarTuple('Ts') - - In the same way that a normal type variable is a stand-in for a single - type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* - type such as ``Tuple[int, str]``. - - Type variable tuples can be used in ``Generic`` declarations. - Consider the following example:: - - class Array(Generic[*Ts]): ... - - The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, - where ``T1`` and ``T2`` are type variables. To use these type variables - as type parameters of ``Array``, we must *unpack* the type variable tuple using - the star operator: ``*Ts``. The signature of ``Array`` then behaves - as if we had simply written ``class Array(Generic[T1, T2]): ...``. - In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows - us to parameterise the class with an *arbitrary* number of type parameters. - - Type variable tuples can be used anywhere a normal ``TypeVar`` can. - This includes class definitions, as shown above, as well as function - signatures and variable annotations:: - - class Array(Generic[*Ts]): - - def __init__(self, shape: Tuple[*Ts]): - self._shape: Tuple[*Ts] = shape - - def get_shape(self) -> Tuple[*Ts]: - return self._shape - - shape = (Height(480), Width(640)) - x: Array[Height, Width] = Array(shape) - y = abs(x) # Inferred type is Array[Height, Width] - z = x + x # ... is Array[Height, Width] - x.get_shape() # ... is tuple[Height, Width] - - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - def __iter__(self): - yield self.__unpacked__ - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - self.__name__ = name - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - self.__infer_variance__ = bool(infer_variance) - self.__bound__ = bound - _DefaultMixin.__init__(self, default) - - # for pickling: - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - self.__unpacked__ = Unpack[self] - - def __repr__(self): - if self.__infer_variance__: - prefix = '' - elif self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - def __init_subclass__(self, *args, **kwds): - if '_root' not in kwds: - raise TypeError("Cannot subclass special typing classes") - - -if hasattr(typing, "reveal_type"): # 3.11+ - reveal_type = typing.reveal_type -else: # <=3.10 - def reveal_type(obj: T, /) -> T: - """Reveal the inferred type of a variable. - - When a static type checker encounters a call to ``reveal_type()``, - it will emit the inferred type of the argument:: - - x: int = 1 - reveal_type(x) - - Running a static type checker (e.g., ``mypy``) on this example - will produce output similar to 'Revealed type is "builtins.int"'. - - At runtime, the function prints the runtime type of the - argument and returns it unchanged. - - """ - print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr) - return obj - - -if hasattr(typing, "_ASSERT_NEVER_REPR_MAX_LENGTH"): # 3.11+ - _ASSERT_NEVER_REPR_MAX_LENGTH = typing._ASSERT_NEVER_REPR_MAX_LENGTH -else: # <=3.10 - _ASSERT_NEVER_REPR_MAX_LENGTH = 100 - - -if hasattr(typing, "assert_never"): # 3.11+ - assert_never = typing.assert_never -else: # <=3.10 - def assert_never(arg: Never, /) -> Never: - """Assert to the type checker that a line of code is unreachable. - - Example:: - - def int_or_str(arg: int | str) -> None: - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - assert_never(arg) - - If a type checker finds that a call to assert_never() is - reachable, it will emit an error. - - At runtime, this throws an exception when called. - - """ - value = repr(arg) - if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH: - value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...' - raise AssertionError(f"Expected code to be unreachable, but got: {value}") - - -# dataclass_transform exists in 3.11 but lacks the frozen_default parameter -# Breakpoint: https://github.com/python/cpython/pull/99958 -if sys.version_info >= (3, 12): # 3.12+ - dataclass_transform = typing.dataclass_transform -else: # <=3.11 - def dataclass_transform( - *, - eq_default: bool = True, - order_default: bool = False, - kw_only_default: bool = False, - frozen_default: bool = False, - field_specifiers: typing.Tuple[ - typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], - ... - ] = (), - **kwargs: typing.Any, - ) -> typing.Callable[[T], T]: - """Decorator that marks a function, class, or metaclass as providing - dataclass-like behavior. - - Example: - - from typing_extensions import dataclass_transform - - _T = TypeVar("_T") - - # Used on a decorator function - @dataclass_transform() - def create_model(cls: type[_T]) -> type[_T]: - ... - return cls - - @create_model - class CustomerModel: - id: int - name: str - - # Used on a base class - @dataclass_transform() - class ModelBase: ... - - class CustomerModel(ModelBase): - id: int - name: str - - # Used on a metaclass - @dataclass_transform() - class ModelMeta(type): ... - - class ModelBase(metaclass=ModelMeta): ... - - class CustomerModel(ModelBase): - id: int - name: str - - Each of the ``CustomerModel`` classes defined in this example will now - behave similarly to a dataclass created with the ``@dataclasses.dataclass`` - decorator. For example, the type checker will synthesize an ``__init__`` - method. - - The arguments to this decorator can be used to customize this behavior: - - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be - True or False if it is omitted by the caller. - - ``order_default`` indicates whether the ``order`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``kw_only_default`` indicates whether the ``kw_only`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``frozen_default`` indicates whether the ``frozen`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``field_specifiers`` specifies a static list of supported classes - or functions that describe fields, similar to ``dataclasses.field()``. - - At runtime, this decorator records its arguments in the - ``__dataclass_transform__`` attribute on the decorated object. - - See PEP 681 for details. - - """ - def decorator(cls_or_fn): - cls_or_fn.__dataclass_transform__ = { - "eq_default": eq_default, - "order_default": order_default, - "kw_only_default": kw_only_default, - "frozen_default": frozen_default, - "field_specifiers": field_specifiers, - "kwargs": kwargs, - } - return cls_or_fn - return decorator - - -if hasattr(typing, "override"): # 3.12+ - override = typing.override -else: # <=3.11 - _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) - - def override(arg: _F, /) -> _F: - """Indicate that a method is intended to override a method in a base class. - - Usage: - - class Base: - def method(self) -> None: - pass - - class Child(Base): - @override - def method(self) -> None: - super().method() - - When this decorator is applied to a method, the type checker will - validate that it overrides a method with the same name on a base class. - This helps prevent bugs that may occur when a base class is changed - without an equivalent change to a child class. - - There is no runtime checking of these properties. The decorator - sets the ``__override__`` attribute to ``True`` on the decorated object - to allow runtime introspection. - - See PEP 698 for details. - - """ - try: - arg.__override__ = True - except (AttributeError, TypeError): - # Skip the attribute silently if it is not writable. - # AttributeError happens if the object has __slots__ or a - # read-only property, TypeError if it's a builtin class. - pass - return arg - - -# Python 3.13.8+ and 3.14.1+ contain a fix for the wrapped __init_subclass__ -# Breakpoint: https://github.com/python/cpython/pull/138210 -if ((3, 13, 8) <= sys.version_info < (3, 14)) or sys.version_info >= (3, 14, 1): - deprecated = warnings.deprecated -else: - _T = typing.TypeVar("_T") - - class deprecated: - """Indicate that a class, function or overload is deprecated. - - When this decorator is applied to an object, the type checker - will generate a diagnostic on usage of the deprecated object. - - Usage: - - @deprecated("Use B instead") - class A: - pass - - @deprecated("Use g instead") - def f(): - pass - - @overload - @deprecated("int support is deprecated") - def g(x: int) -> int: ... - @overload - def g(x: str) -> int: ... - - The warning specified by *category* will be emitted at runtime - on use of deprecated objects. For functions, that happens on calls; - for classes, on instantiation and on creation of subclasses. - If the *category* is ``None``, no warning is emitted at runtime. - The *stacklevel* determines where the - warning is emitted. If it is ``1`` (the default), the warning - is emitted at the direct caller of the deprecated object; if it - is higher, it is emitted further up the stack. - Static type checker behavior is not affected by the *category* - and *stacklevel* arguments. - - The deprecation message passed to the decorator is saved in the - ``__deprecated__`` attribute on the decorated object. - If applied to an overload, the decorator - must be after the ``@overload`` decorator for the attribute to - exist on the overload as returned by ``get_overloads()``. - - See PEP 702 for details. - - """ - def __init__( - self, - message: str, - /, - *, - category: typing.Optional[typing.Type[Warning]] = DeprecationWarning, - stacklevel: int = 1, - ) -> None: - if not isinstance(message, str): - raise TypeError( - "Expected an object of type str for 'message', not " - f"{type(message).__name__!r}" - ) - self.message = message - self.category = category - self.stacklevel = stacklevel - - def __call__(self, arg: _T, /) -> _T: - # Make sure the inner functions created below don't - # retain a reference to self. - msg = self.message - category = self.category - stacklevel = self.stacklevel - if category is None: - arg.__deprecated__ = msg - return arg - elif isinstance(arg, type): - import functools - from types import MethodType - - original_new = arg.__new__ - - @functools.wraps(original_new) - def __new__(cls, /, *args, **kwargs): - if cls is arg: - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - if original_new is not object.__new__: - return original_new(cls, *args, **kwargs) - # Mirrors a similar check in object.__new__. - elif cls.__init__ is object.__init__ and (args or kwargs): - raise TypeError(f"{cls.__name__}() takes no arguments") - else: - return original_new(cls) - - arg.__new__ = staticmethod(__new__) - - if "__init_subclass__" in arg.__dict__: - # __init_subclass__ is directly present on the decorated class. - # Synthesize a wrapper that calls this method directly. - original_init_subclass = arg.__init_subclass__ - # We need slightly different behavior if __init_subclass__ - # is a bound method (likely if it was implemented in Python). - # Otherwise, it likely means it's a builtin such as - # object's implementation of __init_subclass__. - if isinstance(original_init_subclass, MethodType): - original_init_subclass = original_init_subclass.__func__ - - @functools.wraps(original_init_subclass) - def __init_subclass__(*args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return original_init_subclass(*args, **kwargs) - else: - def __init_subclass__(cls, *args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return super(arg, cls).__init_subclass__(*args, **kwargs) - - arg.__init_subclass__ = classmethod(__init_subclass__) - - arg.__deprecated__ = __new__.__deprecated__ = msg - __init_subclass__.__deprecated__ = msg - return arg - elif callable(arg): - import functools - import inspect - - @functools.wraps(arg) - def wrapper(*args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return arg(*args, **kwargs) - - if inspect.iscoroutinefunction(arg): - # Breakpoint: https://github.com/python/cpython/pull/99247 - if sys.version_info >= (3, 12): - wrapper = inspect.markcoroutinefunction(wrapper) - else: - import asyncio.coroutines - - wrapper._is_coroutine = asyncio.coroutines._is_coroutine - - arg.__deprecated__ = wrapper.__deprecated__ = msg - return wrapper - else: - raise TypeError( - "@deprecated decorator with non-None category must be applied to " - f"a class or callable, not {arg!r}" - ) - -# Breakpoint: https://github.com/python/cpython/pull/23702 -if sys.version_info < (3, 10): - def _is_param_expr(arg): - return arg is ... or isinstance( - arg, (tuple, list, ParamSpec, _ConcatenateGenericAlias) - ) -else: - def _is_param_expr(arg): - return arg is ... or isinstance( - arg, - ( - tuple, - list, - ParamSpec, - _ConcatenateGenericAlias, - typing._ConcatenateGenericAlias, - ), - ) - - -# We have to do some monkey patching to deal with the dual nature of -# Unpack/TypeVarTuple: -# - We want Unpack to be a kind of TypeVar so it gets accepted in -# Generic[Unpack[Ts]] -# - We want it to *not* be treated as a TypeVar for the purposes of -# counting generic parameters, so that when we subscript a generic, -# the runtime doesn't try to substitute the Unpack with the subscripted type. -if not hasattr(typing, "TypeVarTuple"): - def _check_generic(cls, parameters, elen=_marker): - """Check correct count for parameters of a generic cls (internal helper). - - This gives a nice error message in case of count mismatch. - """ - # If substituting a single ParamSpec with multiple arguments - # we do not check the count - if (inspect.isclass(cls) and issubclass(cls, typing.Generic) - and len(cls.__parameters__) == 1 - and isinstance(cls.__parameters__[0], ParamSpec) - and parameters - and not _is_param_expr(parameters[0]) - ): - # Generic modifies parameters variable, but here we cannot do this - return - - if not elen: - raise TypeError(f"{cls} is not a generic class") - if elen is _marker: - if not hasattr(cls, "__parameters__") or not cls.__parameters__: - raise TypeError(f"{cls} is not a generic class") - elen = len(cls.__parameters__) - alen = len(parameters) - if alen != elen: - expect_val = elen - if hasattr(cls, "__parameters__"): - parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] - num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) - if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): - return - - # deal with TypeVarLike defaults - # required TypeVarLikes cannot appear after a defaulted one. - if alen < elen: - # since we validate TypeVarLike default in _collect_type_vars - # or _collect_parameters we can safely check parameters[alen] - if ( - getattr(parameters[alen], '__default__', NoDefault) - is not NoDefault - ): - return - - num_default_tv = sum(getattr(p, '__default__', NoDefault) - is not NoDefault for p in parameters) - - elen -= num_default_tv - - expect_val = f"at least {elen}" - - # Breakpoint: https://github.com/python/cpython/pull/27515 - things = "arguments" if sys.version_info >= (3, 10) else "parameters" - raise TypeError(f"Too {'many' if alen > elen else 'few'} {things}" - f" for {cls}; actual {alen}, expected {expect_val}") -else: - # Python 3.11+ - - def _check_generic(cls, parameters, elen): - """Check correct count for parameters of a generic cls (internal helper). - - This gives a nice error message in case of count mismatch. - """ - if not elen: - raise TypeError(f"{cls} is not a generic class") - alen = len(parameters) - if alen != elen: - expect_val = elen - if hasattr(cls, "__parameters__"): - parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] - - # deal with TypeVarLike defaults - # required TypeVarLikes cannot appear after a defaulted one. - if alen < elen: - # since we validate TypeVarLike default in _collect_type_vars - # or _collect_parameters we can safely check parameters[alen] - if ( - getattr(parameters[alen], '__default__', NoDefault) - is not NoDefault - ): - return - - num_default_tv = sum(getattr(p, '__default__', NoDefault) - is not NoDefault for p in parameters) - - elen -= num_default_tv - - expect_val = f"at least {elen}" - - raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments" - f" for {cls}; actual {alen}, expected {expect_val}") - -if not _PEP_696_IMPLEMENTED: - typing._check_generic = _check_generic - - -def _has_generic_or_protocol_as_origin() -> bool: - try: - frame = sys._getframe(2) - # - Catch AttributeError: not all Python implementations have sys._getframe() - # - Catch ValueError: maybe we're called from an unexpected module - # and the call stack isn't deep enough - except (AttributeError, ValueError): - return False # err on the side of leniency - else: - # If we somehow get invoked from outside typing.py, - # also err on the side of leniency - if frame.f_globals.get("__name__") != "typing": - return False - origin = frame.f_locals.get("origin") - # Cannot use "in" because origin may be an object with a buggy __eq__ that - # throws an error. - return origin is typing.Generic or origin is Protocol or origin is typing.Protocol - - -_TYPEVARTUPLE_TYPES = {TypeVarTuple, getattr(typing, "TypeVarTuple", None)} - - -def _is_unpacked_typevartuple(x) -> bool: - if get_origin(x) is not Unpack: - return False - args = get_args(x) - return ( - bool(args) - and len(args) == 1 - and type(args[0]) in _TYPEVARTUPLE_TYPES - ) - - -# Python 3.11+ _collect_type_vars was renamed to _collect_parameters -if hasattr(typing, '_collect_type_vars'): - def _collect_type_vars(types, typevar_types=None): - """Collect all type variable contained in types in order of - first appearance (lexicographic order). For example:: - - _collect_type_vars((T, List[S, T])) == (T, S) - """ - if typevar_types is None: - typevar_types = typing.TypeVar - tvars = [] - - # A required TypeVarLike cannot appear after a TypeVarLike with a default - # if it was a direct call to `Generic[]` or `Protocol[]` - enforce_default_ordering = _has_generic_or_protocol_as_origin() - default_encountered = False - - # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple - type_var_tuple_encountered = False - - for t in types: - if _is_unpacked_typevartuple(t): - type_var_tuple_encountered = True - elif ( - isinstance(t, typevar_types) and not isinstance(t, _UnpackAlias) - and t not in tvars - ): - if enforce_default_ordering: - has_default = getattr(t, '__default__', NoDefault) is not NoDefault - if has_default: - if type_var_tuple_encountered: - raise TypeError('Type parameter with a default' - ' follows TypeVarTuple') - default_encountered = True - elif default_encountered: - raise TypeError(f'Type parameter {t!r} without a default' - ' follows type parameter with a default') - - tvars.append(t) - if _should_collect_from_parameters(t): - tvars.extend([t for t in t.__parameters__ if t not in tvars]) - elif isinstance(t, tuple): - # Collect nested type_vars - # tuple wrapped by _prepare_paramspec_params(cls, params) - for x in t: - for collected in _collect_type_vars([x]): - if collected not in tvars: - tvars.append(collected) - return tuple(tvars) - - typing._collect_type_vars = _collect_type_vars -else: - def _collect_parameters(args): - """Collect all type variables and parameter specifications in args - in order of first appearance (lexicographic order). - - For example:: - - assert _collect_parameters((T, Callable[P, T])) == (T, P) - """ - parameters = [] - - # A required TypeVarLike cannot appear after a TypeVarLike with default - # if it was a direct call to `Generic[]` or `Protocol[]` - enforce_default_ordering = _has_generic_or_protocol_as_origin() - default_encountered = False - - # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple - type_var_tuple_encountered = False - - for t in args: - if isinstance(t, type): - # We don't want __parameters__ descriptor of a bare Python class. - pass - elif isinstance(t, tuple): - # `t` might be a tuple, when `ParamSpec` is substituted with - # `[T, int]`, or `[int, *Ts]`, etc. - for x in t: - for collected in _collect_parameters([x]): - if collected not in parameters: - parameters.append(collected) - elif hasattr(t, '__typing_subst__'): - if t not in parameters: - if enforce_default_ordering: - has_default = ( - getattr(t, '__default__', NoDefault) is not NoDefault - ) - - if type_var_tuple_encountered and has_default: - raise TypeError('Type parameter with a default' - ' follows TypeVarTuple') - - if has_default: - default_encountered = True - elif default_encountered: - raise TypeError(f'Type parameter {t!r} without a default' - ' follows type parameter with a default') - - parameters.append(t) - else: - if _is_unpacked_typevartuple(t): - type_var_tuple_encountered = True - for x in getattr(t, '__parameters__', ()): - if x not in parameters: - parameters.append(x) - - return tuple(parameters) - - if not _PEP_696_IMPLEMENTED: - typing._collect_parameters = _collect_parameters - -# Backport typing.NamedTuple as it exists in Python 3.13. -# In 3.11, the ability to define generic `NamedTuple`s was supported. -# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. -# On 3.12, we added __orig_bases__ to call-based NamedTuples -# On 3.13, we deprecated kwargs-based NamedTuples -# Breakpoint: https://github.com/python/cpython/pull/105609 -if sys.version_info >= (3, 13): - NamedTuple = typing.NamedTuple -else: - def _make_nmtuple(name, types, module, defaults=()): - fields = [n for n, t in types] - annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") - for n, t in types} - nm_tpl = collections.namedtuple(name, fields, - defaults=defaults, module=module) - nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations - return nm_tpl - - _prohibited_namedtuple_fields = typing._prohibited - _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) - - class _NamedTupleMeta(type): - def __new__(cls, typename, bases, ns): - assert _NamedTuple in bases - for base in bases: - if base is not _NamedTuple and base is not typing.Generic: - raise TypeError( - 'can only inherit from a NamedTuple type and Generic') - bases = tuple(tuple if base is _NamedTuple else base for base in bases) - if "__annotations__" in ns: - types = ns["__annotations__"] - elif "__annotate__" in ns: - # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated - types = ns["__annotate__"](1) - else: - types = {} - default_names = [] - for field_name in types: - if field_name in ns: - default_names.append(field_name) - elif default_names: - raise TypeError(f"Non-default namedtuple field {field_name} " - f"cannot follow default field" - f"{'s' if len(default_names) > 1 else ''} " - f"{', '.join(default_names)}") - nm_tpl = _make_nmtuple( - typename, types.items(), - defaults=[ns[n] for n in default_names], - module=ns['__module__'] - ) - nm_tpl.__bases__ = bases - if typing.Generic in bases: - if hasattr(typing, '_generic_class_getitem'): # 3.12+ - nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem) - else: - class_getitem = typing.Generic.__class_getitem__.__func__ - nm_tpl.__class_getitem__ = classmethod(class_getitem) - # update from user namespace without overriding special namedtuple attributes - for key, val in ns.items(): - if key in _prohibited_namedtuple_fields: - raise AttributeError("Cannot overwrite NamedTuple attribute " + key) - elif key not in _special_namedtuple_fields: - if key not in nm_tpl._fields: - setattr(nm_tpl, key, ns[key]) - try: - set_name = type(val).__set_name__ - except AttributeError: - pass - else: - try: - set_name(val, nm_tpl, key) - except BaseException as e: - msg = ( - f"Error calling __set_name__ on {type(val).__name__!r} " - f"instance {key!r} in {typename!r}" - ) - # BaseException.add_note() existed on py311, - # but the __set_name__ machinery didn't start - # using add_note() until py312. - # Making sure exceptions are raised in the same way - # as in "normal" classes seems most important here. - # Breakpoint: https://github.com/python/cpython/pull/95915 - if sys.version_info >= (3, 12): - e.add_note(msg) - raise - else: - raise RuntimeError(msg) from e - - if typing.Generic in bases: - nm_tpl.__init_subclass__() - return nm_tpl - - _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) - - def _namedtuple_mro_entries(bases): - assert NamedTuple in bases - return (_NamedTuple,) - - def NamedTuple(typename, fields=_marker, /, **kwargs): - """Typed version of namedtuple. - - Usage:: - - class Employee(NamedTuple): - name: str - id: int - - This is equivalent to:: - - Employee = collections.namedtuple('Employee', ['name', 'id']) - - The resulting class has an extra __annotations__ attribute, giving a - dict that maps field names to types. (The field names are also in - the _fields attribute, which is part of the namedtuple API.) - An alternative equivalent functional syntax is also accepted:: - - Employee = NamedTuple('Employee', [('name', str), ('id', int)]) - """ - if fields is _marker: - if kwargs: - deprecated_thing = "Creating NamedTuple classes using keyword arguments" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "Use the class-based or functional syntax instead." - ) - else: - deprecated_thing = "Failing to pass a value for the 'fields' parameter" - example = f"`{typename} = NamedTuple({typename!r}, [])`" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "To create a NamedTuple class with 0 fields " - "using the functional syntax, " - "pass an empty list, e.g. " - ) + example + "." - elif fields is None: - if kwargs: - raise TypeError( - "Cannot pass `None` as the 'fields' parameter " - "and also specify fields using keyword arguments" - ) - else: - deprecated_thing = "Passing `None` as the 'fields' parameter" - example = f"`{typename} = NamedTuple({typename!r}, [])`" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "To create a NamedTuple class with 0 fields " - "using the functional syntax, " - "pass an empty list, e.g. " - ) + example + "." - elif kwargs: - raise TypeError("Either list of fields or keywords" - " can be provided to NamedTuple, not both") - if fields is _marker or fields is None: - warnings.warn( - deprecation_msg.format(name=deprecated_thing, remove="3.15"), - DeprecationWarning, - stacklevel=2, - ) - fields = kwargs.items() - nt = _make_nmtuple(typename, fields, module=_caller()) - nt.__orig_bases__ = (NamedTuple,) - return nt - - NamedTuple.__mro_entries__ = _namedtuple_mro_entries - - -if hasattr(collections.abc, "Buffer"): - Buffer = collections.abc.Buffer -else: - class Buffer(abc.ABC): # noqa: B024 - """Base class for classes that implement the buffer protocol. - - The buffer protocol allows Python objects to expose a low-level - memory buffer interface. Before Python 3.12, it is not possible - to implement the buffer protocol in pure Python code, or even - to check whether a class implements the buffer protocol. In - Python 3.12 and higher, the ``__buffer__`` method allows access - to the buffer protocol from Python code, and the - ``collections.abc.Buffer`` ABC allows checking whether a class - implements the buffer protocol. - - To indicate support for the buffer protocol in earlier versions, - inherit from this ABC, either in a stub file or at runtime, - or use ABC registration. This ABC provides no methods, because - there is no Python-accessible methods shared by pre-3.12 buffer - classes. It is useful primarily for static checks. - - """ - - # As a courtesy, register the most common stdlib buffer classes. - Buffer.register(memoryview) - Buffer.register(bytearray) - Buffer.register(bytes) - - -# Backport of types.get_original_bases, available on 3.12+ in CPython -if hasattr(_types, "get_original_bases"): - get_original_bases = _types.get_original_bases -else: - def get_original_bases(cls, /): - """Return the class's "original" bases prior to modification by `__mro_entries__`. - - Examples:: - - from typing import TypeVar, Generic - from typing_extensions import NamedTuple, TypedDict - - T = TypeVar("T") - class Foo(Generic[T]): ... - class Bar(Foo[int], float): ... - class Baz(list[str]): ... - Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) - Spam = TypedDict("Spam", {"a": int, "b": str}) - - assert get_original_bases(Bar) == (Foo[int], float) - assert get_original_bases(Baz) == (list[str],) - assert get_original_bases(Eggs) == (NamedTuple,) - assert get_original_bases(Spam) == (TypedDict,) - assert get_original_bases(int) == (object,) - """ - try: - return cls.__dict__.get("__orig_bases__", cls.__bases__) - except AttributeError: - raise TypeError( - f'Expected an instance of type, not {type(cls).__name__!r}' - ) from None - - -# NewType is a class on Python 3.10+, making it pickleable -# The error message for subclassing instances of NewType was improved on 3.11+ -# Breakpoint: https://github.com/python/cpython/pull/30268 -if sys.version_info >= (3, 11): - NewType = typing.NewType -else: - class NewType: - """NewType creates simple unique types with almost zero - runtime overhead. NewType(name, tp) is considered a subtype of tp - by static type checkers. At runtime, NewType(name, tp) returns - a dummy callable that simply returns its argument. Usage:: - UserId = NewType('UserId', int) - def name_by_id(user_id: UserId) -> str: - ... - UserId('user') # Fails type check - name_by_id(42) # Fails type check - name_by_id(UserId(42)) # OK - num = UserId(5) + 1 # type: int - """ - - def __call__(self, obj, /): - return obj - - def __init__(self, name, tp): - self.__qualname__ = name - if '.' in name: - name = name.rpartition('.')[-1] - self.__name__ = name - self.__supertype__ = tp - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __mro_entries__(self, bases): - # We defined __mro_entries__ to get a better error message - # if a user attempts to subclass a NewType instance. bpo-46170 - supercls_name = self.__name__ - - class Dummy: - def __init_subclass__(cls): - subcls_name = cls.__name__ - raise TypeError( - f"Cannot subclass an instance of NewType. " - f"Perhaps you were looking for: " - f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`" - ) - - return (Dummy,) - - def __repr__(self): - return f'{self.__module__}.{self.__qualname__}' - - def __reduce__(self): - return self.__qualname__ - - # Breakpoint: https://github.com/python/cpython/pull/21515 - if sys.version_info >= (3, 10): - # PEP 604 methods - # It doesn't make sense to have these methods on Python <3.10 - - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - -# Breakpoint: https://github.com/python/cpython/pull/149172 -if sys.version_info >= (3, 15): - TypeAliasType = typing.TypeAliasType -# <=3.14 -else: - # Breakpoint: https://github.com/python/cpython/pull/103764 - if sys.version_info >= (3, 12): - # 3.12-3.14 - def _is_unionable(obj): - """Corresponds to is_unionable() in unionobject.c in CPython.""" - return obj is None or isinstance(obj, ( - type, - _types.GenericAlias, - _types.UnionType, - typing.TypeAliasType, - TypeAliasType, - )) - else: - # <=3.11 - def _is_unionable(obj): - """Corresponds to is_unionable() in unionobject.c in CPython.""" - return obj is None or isinstance(obj, ( - type, - _types.GenericAlias, - _types.UnionType, - TypeAliasType, - )) - - if sys.version_info < (3, 10): - # Copied and pasted from https://github.com/python/cpython/blob/986a4e1b6fcae7fe7a1d0a26aea446107dd58dd2/Objects/genericaliasobject.c#L568-L582, - # so that we emulate the behaviour of `types.GenericAlias` - # on the latest versions of CPython - _ATTRIBUTE_DELEGATION_EXCLUSIONS = frozenset({ - "__class__", - "__bases__", - "__origin__", - "__args__", - "__unpacked__", - "__parameters__", - "__typing_unpacked_tuple_args__", - "__mro_entries__", - "__reduce_ex__", - "__reduce__", - "__copy__", - "__deepcopy__", - }) - - class _TypeAliasGenericAlias(typing._GenericAlias, _root=True): - def __getattr__(self, attr): - if attr in _ATTRIBUTE_DELEGATION_EXCLUSIONS: - return object.__getattr__(self, attr) - return getattr(self.__origin__, attr) - - - class TypeAliasType: - """Create named, parameterized type aliases. - - This provides a backport of the new `type` statement in Python 3.12: - - type ListOrSet[T] = list[T] | set[T] - - is equivalent to: - - T = TypeVar("T") - ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,)) - - The name ListOrSet can then be used as an alias for the type it refers to. - - The type_params argument should contain all the type parameters used - in the value of the type alias. If the alias is not generic, this - argument is omitted. - - Static type checkers should only support type aliases declared using - TypeAliasType that follow these rules: - - - The first argument (the name) must be a string literal. - - The TypeAliasType instance must be immediately assigned to a variable - of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid, - as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)'). - - """ - - def __init__(self, name: str, value, *, type_params=()): - if not isinstance(name, str): - raise TypeError("TypeAliasType name must be a string") - if not isinstance(type_params, tuple): - raise TypeError("type_params must be a tuple") - self.__value__ = value - self.__type_params__ = type_params - - default_value_encountered = False - parameters = [] - for type_param in type_params: - if ( - not isinstance(type_param, (TypeVar, TypeVarTuple, ParamSpec)) - # <=3.11 - # Unpack Backport passes isinstance(type_param, TypeVar) - or _is_unpack(type_param) - ): - raise TypeError(f"Expected a type param, got {type_param!r}") - has_default = ( - getattr(type_param, '__default__', NoDefault) is not NoDefault - ) - if default_value_encountered and not has_default: - raise TypeError(f"non-default type parameter '{type_param!r}'" - " follows default type parameter") - if has_default: - default_value_encountered = True - if isinstance(type_param, TypeVarTuple): - parameters.extend(type_param) - else: - parameters.append(type_param) - self.__parameters__ = tuple(parameters) - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - # Setting this attribute closes the TypeAliasType from further modification - self.__name__ = name - - def __setattr__(self, name: str, value: object, /) -> None: - if hasattr(self, "__name__") and name != "__module__": - self._raise_attribute_error(name) - super().__setattr__(name, value) - - def __delattr__(self, name: str, /) -> Never: - self._raise_attribute_error(name) - - def _raise_attribute_error(self, name: str) -> Never: - # Match the Python 3.12 error messages exactly - if name == "__name__": - raise AttributeError("readonly attribute") - elif name in {"__value__", "__type_params__", "__parameters__"}: - raise AttributeError( - f"attribute '{name}' of 'typing.TypeAliasType' objects " - "is not writable" - ) - else: - raise AttributeError( - f"'typing.TypeAliasType' object has no attribute '{name}'" - ) - - def __repr__(self) -> str: - return self.__name__ - - if sys.version_info < (3, 11): - def _check_single_param(self, param, recursion=0): - # Allow [], [int], [int, str], [int, ...], [int, T] - if param is ...: - return ... - if param is None: - return None - # Note in <= 3.9 _ConcatenateGenericAlias inherits from list - if isinstance(param, list) and recursion == 0: - return [self._check_single_param(arg, recursion+1) - for arg in param] - return typing._type_check( - param, f'Subscripting {self.__name__} requires a type.' - ) - - def _check_parameters(self, parameters): - if sys.version_info < (3, 11): - return tuple( - self._check_single_param(item) - for item in parameters - ) - return tuple(typing._type_check( - item, f'Subscripting {self.__name__} requires a type.' - ) - for item in parameters - ) - - def __getitem__(self, parameters): - if not self.__type_params__: - raise TypeError("Only generic type aliases are subscriptable") - if not isinstance(parameters, tuple): - parameters = (parameters,) - # Using 3.9 here will create problems with Concatenate - if sys.version_info >= (3, 10): - return _types.GenericAlias(self, parameters) - type_vars = _collect_type_vars(parameters) - parameters = self._check_parameters(parameters) - alias = _TypeAliasGenericAlias(self, parameters) - # alias.__parameters__ is not complete if Concatenate is present - # as it is converted to a list from which no parameters are extracted. - if alias.__parameters__ != type_vars: - alias.__parameters__ = type_vars - return alias - - def __reduce__(self): - return self.__name__ - - def __init_subclass__(cls, *args, **kwargs): - raise TypeError( - "type 'typing_extensions.TypeAliasType' is not an acceptable base type" - ) - - # The presence of this method convinces typing._type_check - # that TypeAliasTypes are types. - def __call__(self): - raise TypeError("Type alias is not callable") - - # Breakpoint: https://github.com/python/cpython/pull/21515 - if sys.version_info >= (3, 10): - def __or__(self, right): - # For forward compatibility with 3.12, reject Unions - # that are not accepted by the built-in Union. - if not _is_unionable(right): - return NotImplemented - return typing.Union[self, right] - - def __ror__(self, left): - if not _is_unionable(left): - return NotImplemented - return typing.Union[left, self] - - -if hasattr(typing, "is_protocol"): - is_protocol = typing.is_protocol - get_protocol_members = typing.get_protocol_members -else: - def is_protocol(tp: type, /) -> bool: - """Return True if the given type is a Protocol. - - Example:: - - >>> from typing_extensions import Protocol, is_protocol - >>> class P(Protocol): - ... def a(self) -> str: ... - ... b: int - >>> is_protocol(P) - True - >>> is_protocol(int) - False - """ - return ( - isinstance(tp, type) - and getattr(tp, '_is_protocol', False) - and tp is not Protocol - and tp is not typing.Protocol - ) - - def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]: - """Return the set of members defined in a Protocol. - - Example:: - - >>> from typing_extensions import Protocol, get_protocol_members - >>> class P(Protocol): - ... def a(self) -> str: ... - ... b: int - >>> get_protocol_members(P) == frozenset({'a', 'b'}) - True - - Raise a TypeError for arguments that are not Protocols. - """ - if not is_protocol(tp): - raise TypeError(f'{tp!r} is not a Protocol') - if hasattr(tp, '__protocol_attrs__'): - return frozenset(tp.__protocol_attrs__) - return frozenset(_get_protocol_attrs(tp)) - - -if hasattr(typing, "Doc"): - Doc = typing.Doc -else: - class Doc: - """Define the documentation of a type annotation using ``Annotated``, to be - used in class attributes, function and method parameters, return values, - and variables. - - The value should be a positional-only string literal to allow static tools - like editors and documentation generators to use it. - - This complements docstrings. - - The string value passed is available in the attribute ``documentation``. - - Example:: - - >>> from typing_extensions import Annotated, Doc - >>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ... - """ - def __init__(self, documentation: str, /) -> None: - self.documentation = documentation - - def __repr__(self) -> str: - return f"Doc({self.documentation!r})" - - def __hash__(self) -> int: - return hash(self.documentation) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Doc): - return NotImplemented - return self.documentation == other.documentation - - -_CapsuleType = getattr(_types, "CapsuleType", None) - -if _CapsuleType is None: - try: - import _socket - except ImportError: - pass - else: - _CAPI = getattr(_socket, "CAPI", None) - if _CAPI is not None: - _CapsuleType = type(_CAPI) - -if _CapsuleType is not None: - CapsuleType = _CapsuleType - __all__.append("CapsuleType") - - -if sys.version_info >= (3, 14): - from annotationlib import Format, get_annotations -else: - # Available since Python 3.14.0a3 - # PR: https://github.com/python/cpython/pull/124415 - class Format(enum.IntEnum): - VALUE = 1 - VALUE_WITH_FAKE_GLOBALS = 2 - FORWARDREF = 3 - STRING = 4 - - # Available since Python 3.14.0a1 - # PR: https://github.com/python/cpython/pull/119891 - def get_annotations(obj, *, globals=None, locals=None, eval_str=False, - format=Format.VALUE): - """Compute the annotations dict for an object. - - obj may be a callable, class, or module. - Passing in an object of any other type raises TypeError. - - Returns a dict. get_annotations() returns a new dict every time - it's called; calling it twice on the same object will return two - different but equivalent dicts. - - This is a backport of `inspect.get_annotations`, which has been - in the standard library since Python 3.10. See the standard library - documentation for more: - - https://docs.python.org/3/library/inspect.html#inspect.get_annotations - - This backport adds the *format* argument introduced by PEP 649. The - three formats supported are: - * VALUE: the annotations are returned as-is. This is the default and - it is compatible with the behavior on previous Python versions. - * FORWARDREF: return annotations as-is if possible, but replace any - undefined names with ForwardRef objects. The implementation proposed by - PEP 649 relies on language changes that cannot be backported; the - typing-extensions implementation simply returns the same result as VALUE. - * STRING: return annotations as strings, in a format close to the original - source. Again, this behavior cannot be replicated directly in a backport. - As an approximation, typing-extensions retrieves the annotations under - VALUE semantics and then stringifies them. - - The purpose of this backport is to allow users who would like to use - FORWARDREF or STRING semantics once PEP 649 is implemented, but who also - want to support earlier Python versions, to simply write: - - typing_extensions.get_annotations(obj, format=Format.FORWARDREF) - - """ - format = Format(format) - if format is Format.VALUE_WITH_FAKE_GLOBALS: - raise ValueError( - "The VALUE_WITH_FAKE_GLOBALS format is for internal use only" - ) - - if eval_str and format is not Format.VALUE: - raise ValueError("eval_str=True is only supported with format=Format.VALUE") - - if isinstance(obj, type): - # class - obj_dict = getattr(obj, '__dict__', None) - if obj_dict and hasattr(obj_dict, 'get'): - ann = obj_dict.get('__annotations__', None) - if isinstance(ann, _types.GetSetDescriptorType): - ann = None - else: - ann = None - - obj_globals = None - module_name = getattr(obj, '__module__', None) - if module_name: - module = sys.modules.get(module_name, None) - if module: - obj_globals = getattr(module, '__dict__', None) - obj_locals = dict(vars(obj)) - unwrap = obj - elif isinstance(obj, _types.ModuleType): - # module - ann = getattr(obj, '__annotations__', None) - obj_globals = obj.__dict__ - obj_locals = None - unwrap = None - elif callable(obj): - # this includes types.Function, types.BuiltinFunctionType, - # types.BuiltinMethodType, functools.partial, functools.singledispatch, - # "class funclike" from Lib/test/test_inspect... on and on it goes. - ann = getattr(obj, '__annotations__', None) - obj_globals = getattr(obj, '__globals__', None) - obj_locals = None - unwrap = obj - elif hasattr(obj, '__annotations__'): - ann = obj.__annotations__ - obj_globals = obj_locals = unwrap = None - else: - raise TypeError(f"{obj!r} is not a module, class, or callable.") - - if ann is None: - return {} - - if not isinstance(ann, dict): - raise ValueError(f"{obj!r}.__annotations__ is neither a dict nor None") - - if not ann: - return {} - - if not eval_str: - if format is Format.STRING: - return { - key: value if isinstance(value, str) else typing._type_repr(value) - for key, value in ann.items() - } - return dict(ann) - - if unwrap is not None: - while True: - if hasattr(unwrap, '__wrapped__'): - unwrap = unwrap.__wrapped__ - continue - if isinstance(unwrap, functools.partial): - unwrap = unwrap.func - continue - break - if hasattr(unwrap, "__globals__"): - obj_globals = unwrap.__globals__ - - if globals is None: - globals = obj_globals - if locals is None: - locals = obj_locals or {} - - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - if type_params := getattr(obj, "__type_params__", ()): - locals = {param.__name__: param for param in type_params} | locals - - return_value = {key: - value if not isinstance(value, str) else eval(value, globals, locals) - for key, value in ann.items() } - return return_value - - -if hasattr(typing, "evaluate_forward_ref"): - evaluate_forward_ref = typing.evaluate_forward_ref -else: - # Implements annotationlib.ForwardRef.evaluate - def _eval_with_owner( - forward_ref, *, owner=None, globals=None, locals=None, type_params=None - ): - if forward_ref.__forward_evaluated__: - return forward_ref.__forward_value__ - if getattr(forward_ref, "__cell__", None) is not None: - try: - value = forward_ref.__cell__.cell_contents - except ValueError: - pass - else: - forward_ref.__forward_evaluated__ = True - forward_ref.__forward_value__ = value - return value - if owner is None: - owner = getattr(forward_ref, "__owner__", None) - - if ( - globals is None - and getattr(forward_ref, "__forward_module__", None) is not None - ): - globals = getattr( - sys.modules.get(forward_ref.__forward_module__, None), "__dict__", None - ) - if globals is None: - globals = getattr(forward_ref, "__globals__", None) - if globals is None: - if isinstance(owner, type): - module_name = getattr(owner, "__module__", None) - if module_name: - module = sys.modules.get(module_name, None) - if module: - globals = getattr(module, "__dict__", None) - elif isinstance(owner, _types.ModuleType): - globals = getattr(owner, "__dict__", None) - elif callable(owner): - globals = getattr(owner, "__globals__", None) - - # If we pass None to eval() below, the globals of this module are used. - if globals is None: - globals = {} - - if locals is None: - locals = {} - if isinstance(owner, type): - locals.update(vars(owner)) - - if type_params is None and owner is not None: - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - type_params = getattr(owner, "__type_params__", None) - - # Type parameters exist in their own scope, which is logically - # between the locals and the globals. We simulate this by adding - # them to the globals. - if type_params is not None: - globals = dict(globals) - for param in type_params: - globals[param.__name__] = param - - arg = forward_ref.__forward_arg__ - if arg.isidentifier() and not keyword.iskeyword(arg): - if arg in locals: - value = locals[arg] - elif arg in globals: - value = globals[arg] - elif hasattr(builtins, arg): - return getattr(builtins, arg) - else: - raise NameError(arg) - else: - code = forward_ref.__forward_code__ - value = eval(code, globals, locals) - forward_ref.__forward_evaluated__ = True - forward_ref.__forward_value__ = value - return value - - def evaluate_forward_ref( - forward_ref, - *, - owner=None, - globals=None, - locals=None, - type_params=None, - format=None, - _recursive_guard=frozenset(), - ): - """Evaluate a forward reference as a type hint. - - This is similar to calling the ForwardRef.evaluate() method, - but unlike that method, evaluate_forward_ref() also: - - * Recursively evaluates forward references nested within the type hint. - * Rejects certain objects that are not valid type hints. - * Replaces type hints that evaluate to None with types.NoneType. - * Supports the *FORWARDREF* and *STRING* formats. - - *forward_ref* must be an instance of ForwardRef. *owner*, if given, - should be the object that holds the annotations that the forward reference - derived from, such as a module, class object, or function. It is used to - infer the namespaces to use for looking up names. *globals* and *locals* - can also be explicitly given to provide the global and local namespaces. - *type_params* is a tuple of type parameters that are in scope when - evaluating the forward reference. This parameter must be provided (though - it may be an empty tuple) if *owner* is not given and the forward reference - does not already have an owner set. *format* specifies the format of the - annotation and is a member of the annotationlib.Format enum. - - """ - if format == Format.STRING: - return forward_ref.__forward_arg__ - if forward_ref.__forward_arg__ in _recursive_guard: - return forward_ref - - # Evaluate the forward reference - try: - value = _eval_with_owner( - forward_ref, - owner=owner, - globals=globals, - locals=locals, - type_params=type_params, - ) - except NameError: - if format == Format.FORWARDREF: - return forward_ref - else: - raise - - if isinstance(value, str): - value = ForwardRef(value) - - # Recursively evaluate the type - if isinstance(value, ForwardRef): - if getattr(value, "__forward_module__", True) is not None: - globals = None - return evaluate_forward_ref( - value, - globals=globals, - locals=locals, - type_params=type_params, owner=owner, - _recursive_guard=_recursive_guard, format=format - ) - if sys.version_info < (3, 12, 5) and type_params: - # Make use of type_params - locals = dict(locals) if locals else {} - for tvar in type_params: - if tvar.__name__ not in locals: # lets not overwrite something present - locals[tvar.__name__] = tvar - if sys.version_info < (3, 12, 5): - return typing._eval_type( - value, - globals, - locals, - recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, - ) - else: - return typing._eval_type( - value, - globals, - locals, - type_params, - recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, - ) - - -if sys.version_info >= (3, 14, 0, "beta"): - type_repr = annotationlib.type_repr -else: - def type_repr(value): - """Convert a Python value to a format suitable for use with the STRING format. - - This is intended as a helper for tools that support the STRING format but do - not have access to the code that originally produced the annotations. It uses - repr() for most objects. - - """ - if isinstance(value, (type, _types.FunctionType, _types.BuiltinFunctionType)): - if value.__module__ == "builtins": - return value.__qualname__ - return f"{value.__module__}.{value.__qualname__}" - if value is ...: - return "..." - return repr(value) - - -# Aliases for items that are in typing in all supported versions. -# We use hasattr() checks so this library will continue to import on -# future versions of Python that may remove these names. -_typing_names = [ - "AbstractSet", - "AnyStr", - "BinaryIO", - "Callable", - "Collection", - "Container", - "Dict", - "FrozenSet", - "Hashable", - "IO", - "ItemsView", - "Iterable", - "Iterator", - "KeysView", - "List", - "Mapping", - "MappingView", - "Match", - "MutableMapping", - "MutableSequence", - "MutableSet", - "Optional", - "Pattern", - "Reversible", - "Sequence", - "Set", - "Sized", - "TextIO", - "Tuple", - "Union", - "ValuesView", - "cast", - "no_type_check", - # This is private, but it was defined by typing_extensions for a long time - # and some users rely on it. - "_AnnotatedAlias", -] - -# Breakpoint: https://github.com/python/cpython/pull/133602 -if sys.version_info < (3, 15, 0): - _typing_names.append("no_type_check_decorator") - __all__.append("no_type_check_decorator") - -globals().update( - {name: getattr(typing, name) for name in _typing_names if hasattr(typing, name)} -) -# These are defined unconditionally because they are used in -# typing-extensions itself. -Generic = typing.Generic -ForwardRef = typing.ForwardRef -Annotated = typing.Annotated diff --git a/venv/pyvenv.cfg b/venv/pyvenv.cfg old mode 100755 new mode 100644 index b76f367..83d072d --- a/venv/pyvenv.cfg +++ b/venv/pyvenv.cfg @@ -1,5 +1,5 @@ home = /usr/bin include-system-site-packages = false -version = 3.11.2 -executable = /usr/bin/python3.11 -command = /usr/bin/python3 -m venv /home/marco/Jogo3/app/venv +version = 3.14.4 +executable = /usr/bin/python3.14 +command = /usr/bin/python3 -m venv /home/apps/apps/Jogo3/app/venv