mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-19 15:45:13 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c062712472 | |||
| 15ae1eac89 | |||
| 1111d342d6 | |||
| e9dd490b2c | |||
| 957345f6d9 | |||
| cedfc99e24 | |||
| 3f5f3a6888 | |||
| ea967b5e71 | |||
| f1d4264f68 | |||
| f55a4c24b6 | |||
| 661045f962 |
@@ -60,7 +60,7 @@ jobs:
|
||||
|
||||
- name: Commit & Push
|
||||
if: steps.check_title.outputs.IS_RELEASE_PR == 'true'
|
||||
uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0
|
||||
uses: stefanzweifel/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 # v6.0.1
|
||||
with:
|
||||
commit_message: "Do chango Release"
|
||||
repository: ./target-repo
|
||||
|
||||
@@ -21,13 +21,13 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
|
||||
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1
|
||||
- name: Run zizmor
|
||||
run: uvx zizmor --persona=pedantic --format sarif . > results.sarif
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: zizmor
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
sha1sum $file > $file.sha1
|
||||
done
|
||||
- name: Sign the dists with Sigstore
|
||||
uses: sigstore/gh-action-sigstore-python@f514d46b907ebcd5bedc05145c03b69c1edd8b46 # v3.0.0
|
||||
uses: sigstore/gh-action-sigstore-python@f7ad0af51a5648d09a20d00370f0a91c3bdf8f84 # v3.0.1
|
||||
with:
|
||||
inputs: >-
|
||||
./dist/*.tar.gz
|
||||
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
sha1sum $file > $file.sha1
|
||||
done
|
||||
- name: Sign the dists with Sigstore
|
||||
uses: sigstore/gh-action-sigstore-python@f514d46b907ebcd5bedc05145c03b69c1edd8b46 # v3.0.0
|
||||
uses: sigstore/gh-action-sigstore-python@f7ad0af51a5648d09a20d00370f0a91c3bdf8f84 # v3.0.1
|
||||
with:
|
||||
inputs: >-
|
||||
./dist/*.tar.gz
|
||||
|
||||
@@ -7,7 +7,7 @@ ci:
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: 'v0.11.9'
|
||||
rev: 'v0.12.2'
|
||||
hooks:
|
||||
- id: ruff
|
||||
name: ruff
|
||||
@@ -25,11 +25,11 @@ repos:
|
||||
- --diff
|
||||
- --check
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 7.2.0
|
||||
rev: 7.3.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: v3.3.6
|
||||
rev: v3.3.7
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^(?!(tests|docs)).*\.py$
|
||||
@@ -41,7 +41,7 @@ repos:
|
||||
- aiolimiter~=1.1,<1.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.15.0
|
||||
rev: v1.16.1
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy-ptb
|
||||
@@ -68,7 +68,7 @@ repos:
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.19.1
|
||||
rev: v3.20.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args:
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@
|
||||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-9.0-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-9.1-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API version
|
||||
|
||||
@@ -81,7 +81,7 @@ After installing_ the library, be sure to check out the section on `working with
|
||||
Telegram API support
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All types and methods of the Telegram Bot API **9.0** are natively supported by this library.
|
||||
All types and methods of the Telegram Bot API **9.1** are natively supported by this library.
|
||||
In addition, Bot API functionality not yet natively included can still be used as described `in our wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Bot-API-Forward-Compatibility>`_.
|
||||
|
||||
Notable Features
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
internal = "Update API Token for Local Testing Bot"
|
||||
|
||||
[[pull_requests]]
|
||||
uid = "4837"
|
||||
author_uid = "Bibo-Joshi"
|
||||
closes_threads = []
|
||||
@@ -0,0 +1,5 @@
|
||||
documentation = "Documentation Improvements. Among others, fix links to source code."
|
||||
[[pull_requests]]
|
||||
uid = "4839"
|
||||
author_uid = "aelkheir"
|
||||
closes_threads = ["4838"]
|
||||
@@ -0,0 +1,5 @@
|
||||
internal = "Bump stefanzweifel/git-auto-commit-action from 5.2.0 to 6.0.1"
|
||||
[[pull_requests]]
|
||||
uid = "4840"
|
||||
author_uid = "dependabot"
|
||||
closes_threads = []
|
||||
@@ -0,0 +1,5 @@
|
||||
internal = "Bump github/codeql-action from 3.28.18 to 3.29.2"
|
||||
[[pull_requests]]
|
||||
uid = "4841"
|
||||
author_uid = "dependabot"
|
||||
closes_threads = []
|
||||
@@ -0,0 +1,5 @@
|
||||
internal = "Bump astral-sh/setup-uv from 5.4.1 to 6.3.1"
|
||||
[[pull_requests]]
|
||||
uid = "4842"
|
||||
author_uid = "dependabot"
|
||||
closes_threads = []
|
||||
@@ -0,0 +1,5 @@
|
||||
internal = "Bump sigstore/gh-action-sigstore-python from 3.0.0 to 3.0.1"
|
||||
[[pull_requests]]
|
||||
uid = "4843"
|
||||
author_uid = "dependabot"
|
||||
closes_threads = []
|
||||
@@ -0,0 +1,18 @@
|
||||
highlights = "Full Support for Bot API 9.1"
|
||||
|
||||
features = """
|
||||
New filters based on Bot API 9.1:
|
||||
|
||||
* ``filters.StatusUpdate.DIRECT_MESSAGE_PRICE_CHANGED`` for ``Message.direct_message_price_changed``
|
||||
* ``filters.StatusUpdate.CHECKLIST_TASKS_ADDED`` for ``Message.checklist_tasks_added``
|
||||
* ``filters.StatusUpdate.CHECKLIST_TASKS_DONE`` for ``Message.checklist_tasks_done``
|
||||
* ``filters.CHECKLIST`` for ``Message.checklist``
|
||||
"""
|
||||
|
||||
pull_requests = [
|
||||
{ uid = "4847", author_uid = "Bibo-Joshi", closes_threads = ["4845"] },
|
||||
{ uid = "4848", author_uid = "Bibo-Joshi" },
|
||||
{ uid = "4849", author_uid = "harshil21" },
|
||||
{ uid = "4851", author_uid = "harshil21" },
|
||||
{ uid = "4857", author_uid = "aelkheir" },
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
breaking = """Remove Functionality Deprecated in API 9.0
|
||||
|
||||
* Remove deprecated argument and attribute ``BusinessConnection.can_reply``.
|
||||
* Remove deprecated argument and attribute ``ChatFullInfo.can_send_gift``
|
||||
* Remove deprecated class ``constants.StarTransactions``. Please instead use :attr:`telegram.constants.Nanostar.VALUE`.
|
||||
* Remove deprecated attributes ``constants.StarTransactionsLimit.NANOSTAR_MIN_AMOUNT`` and ``constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT``. Please instead use :attr:`telegram.constants.NanostarLimit.MIN_AMOUNT` and :attr:`telegram.constants.NanostarLimit.MAX_AMOUNT`.
|
||||
"""
|
||||
[[pull_requests]]
|
||||
uid = "4852"
|
||||
author_uid = "aelkheir"
|
||||
closes_threads = []
|
||||
@@ -0,0 +1,5 @@
|
||||
other= "Make Gender Input Case-Insensitive in ``conversationbot.py``"
|
||||
[[pull_requests]]
|
||||
uid = "4855"
|
||||
author_uid = "fengxiaohu"
|
||||
closes_threads = ["4846"]
|
||||
@@ -0,0 +1,5 @@
|
||||
internal = "Bump `pre-commit` Hooks to Latest Versions"
|
||||
[[pull_requests]]
|
||||
uid = "4858"
|
||||
author_uid = "pre-commit-ci"
|
||||
closes_threads = []
|
||||
@@ -0,0 +1,5 @@
|
||||
other = "Bump Version to v22.3"
|
||||
[[pull_requests]]
|
||||
uid = "4870"
|
||||
author_uid = "Bibo-Joshi"
|
||||
closes_threads = []
|
||||
+1
-1
@@ -80,7 +80,7 @@ class CustomChango(DirectoryChanGo):
|
||||
"""replace "14.5" with version.uid except in the contrib guide
|
||||
then call super
|
||||
"""
|
||||
root = Path(__file__).parent.parent / "telegram"
|
||||
root = Path(__file__).parent.parent / "src"
|
||||
python_files = root.rglob("*.py")
|
||||
pattern = re.compile(r"NEXT\.VERSION")
|
||||
excluded_paths = {root / "docs/source/contribute.rst"}
|
||||
|
||||
@@ -55,6 +55,8 @@ PRIVATE_BASE_CLASSES = {
|
||||
}
|
||||
|
||||
|
||||
# Resolves to the parent directory of `telegram/`, depending on installation setup,
|
||||
# could either be `<absolute_path>/src` or `<absolute_path>/site-packages`
|
||||
FILE_ROOT = Path(inspect.getsourcefile(telegram)).parent.parent.resolve()
|
||||
|
||||
|
||||
@@ -161,7 +163,7 @@ def autodoc_process_docstring(
|
||||
with contextlib.suppress(Exception):
|
||||
source_lines, start_line = inspect.getsourcelines(obj)
|
||||
end_line = start_line + len(source_lines)
|
||||
file = Path(inspect.getsourcefile(obj)).relative_to(FILE_ROOT)
|
||||
file = Path("src") / Path(inspect.getsourcefile(obj)).relative_to(FILE_ROOT)
|
||||
LINE_NUMBERS[name] = (file, start_line, end_line)
|
||||
|
||||
# Since we don't document the `__init__`, we call this manually to have it available for
|
||||
|
||||
@@ -390,6 +390,8 @@
|
||||
- Used to generate an HTTP link for an invoice
|
||||
* - :meth:`~telegram.Bot.edit_user_star_subscription`
|
||||
- Used for editing a user's star subscription
|
||||
* - :meth:`~telegram.Bot.get_my_star_balance`
|
||||
- Used for obtaining the bot's Telegram Stars balance
|
||||
* - :meth:`~telegram.Bot.get_star_transactions`
|
||||
- Used for obtaining the bot's Telegram Stars transactions
|
||||
* - :meth:`~telegram.Bot.refund_star_payment`
|
||||
@@ -447,6 +449,10 @@
|
||||
- Used for transferring owned unique gifts to another user.
|
||||
* - :meth:`~telegram.Bot.transfer_business_account_stars`
|
||||
- Used for transfering Stars from the business account balance to the bot's balance.
|
||||
* - :meth:`~telegram.Bot.send_checklist`
|
||||
- Used for sending a checklist on behalf of the business account.
|
||||
* - :meth:`~telegram.Bot.edit_message_checklist`
|
||||
- Used for editing a checklist on behalf of the business account.
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
@@ -31,6 +31,10 @@ Available Types
|
||||
telegram.chat
|
||||
telegram.chatadministratorrights
|
||||
telegram.chatbackground
|
||||
telegram.checklist
|
||||
telegram.checklisttask
|
||||
telegram.checklisttasksadded
|
||||
telegram.checklisttasksdone
|
||||
telegram.copytextbutton
|
||||
telegram.backgroundtype
|
||||
telegram.backgroundtypefill
|
||||
@@ -66,6 +70,7 @@ Available Types
|
||||
telegram.chatshared
|
||||
telegram.contact
|
||||
telegram.dice
|
||||
telegram.directmessagepricechanged
|
||||
telegram.document
|
||||
telegram.externalreplyinfo
|
||||
telegram.file
|
||||
@@ -85,6 +90,8 @@ Available Types
|
||||
telegram.inaccessiblemessage
|
||||
telegram.inlinekeyboardbutton
|
||||
telegram.inlinekeyboardmarkup
|
||||
telegram.inputchecklist
|
||||
telegram.inputchecklisttask
|
||||
telegram.inputfile
|
||||
telegram.inputmedia
|
||||
telegram.inputmediaanimation
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Checklist
|
||||
=========
|
||||
|
||||
.. autoclass:: telegram.Checklist
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
ChecklistTask
|
||||
=============
|
||||
|
||||
.. autoclass:: telegram.ChecklistTask
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
ChecklistTasksAdded
|
||||
===================
|
||||
|
||||
.. autoclass:: telegram.ChecklistTasksAdded
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
ChecklistTasksDone
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.ChecklistTasksDone
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -5,5 +5,4 @@ telegram.constants Module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:no-undoc-members:
|
||||
:inherited-members: Enum, EnumMeta, str, int, float
|
||||
:exclude-members: __format__, __new__, __repr__, __str__
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
DirectMessagePriceChanged
|
||||
=========================
|
||||
|
||||
.. autoclass:: telegram.DirectMessagePriceChanged
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
InputChecklist
|
||||
==============
|
||||
|
||||
.. autoclass:: telegram.InputChecklist
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
InputChecklistTask
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.InputChecklistTask
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -145,7 +145,9 @@ def main() -> None:
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler("start", start)],
|
||||
states={
|
||||
GENDER: [MessageHandler(filters.Regex("^(Boy|Girl|Other)$"), gender)],
|
||||
# Use case-insensitive regex to accept gender input regardless of letter casing,
|
||||
# e.g., "boy", "BOY", "Girl", etc., will all be matched
|
||||
GENDER: [MessageHandler(filters.Regex("(?i)^(Boy|Girl|Other)$"), gender)],
|
||||
PHOTO: [MessageHandler(filters.PHOTO, photo), CommandHandler("skip", skip_photo)],
|
||||
LOCATION: [
|
||||
MessageHandler(filters.LOCATION, location),
|
||||
|
||||
@@ -82,12 +82,17 @@ __all__ = (
|
||||
"ChatPermissions",
|
||||
"ChatPhoto",
|
||||
"ChatShared",
|
||||
"Checklist",
|
||||
"ChecklistTask",
|
||||
"ChecklistTasksAdded",
|
||||
"ChecklistTasksDone",
|
||||
"ChosenInlineResult",
|
||||
"Contact",
|
||||
"CopyTextButton",
|
||||
"Credentials",
|
||||
"DataCredentials",
|
||||
"Dice",
|
||||
"DirectMessagePriceChanged",
|
||||
"Document",
|
||||
"EncryptedCredentials",
|
||||
"EncryptedPassportElement",
|
||||
@@ -138,6 +143,8 @@ __all__ = (
|
||||
"InlineQueryResultVideo",
|
||||
"InlineQueryResultVoice",
|
||||
"InlineQueryResultsButton",
|
||||
"InputChecklist",
|
||||
"InputChecklistTask",
|
||||
"InputContactMessageContent",
|
||||
"InputFile",
|
||||
"InputInvoiceMessageContent",
|
||||
@@ -302,6 +309,7 @@ __all__ = (
|
||||
"warnings",
|
||||
)
|
||||
|
||||
from telegram._inputchecklist import InputChecklist, InputChecklistTask
|
||||
from telegram._payment.stars.staramount import StarAmount
|
||||
from telegram._payment.stars.startransactions import StarTransaction, StarTransactions
|
||||
from telegram._payment.stars.transactionpartner import (
|
||||
@@ -381,9 +389,11 @@ from ._chatmember import (
|
||||
)
|
||||
from ._chatmemberupdated import ChatMemberUpdated
|
||||
from ._chatpermissions import ChatPermissions
|
||||
from ._checklists import Checklist, ChecklistTask, ChecklistTasksAdded, ChecklistTasksDone
|
||||
from ._choseninlineresult import ChosenInlineResult
|
||||
from ._copytextbutton import CopyTextButton
|
||||
from ._dice import Dice
|
||||
from ._directmessagepricechanged import DirectMessagePriceChanged
|
||||
from ._files._inputstorycontent import (
|
||||
InputStoryContent,
|
||||
InputStoryContentPhoto,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# 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
|
||||
# ruff: noqa: T201, D100, S603, S607
|
||||
# ruff: noqa: T201, D100, S607
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
+174
-1
@@ -78,6 +78,7 @@ from telegram._games.gamehighscore import GameHighScore
|
||||
from telegram._gifts import AcceptedGiftTypes, Gift, Gifts
|
||||
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||
from telegram._inline.preparedinlinemessage import PreparedInlineMessage
|
||||
from telegram._inputchecklist import InputChecklist
|
||||
from telegram._menubutton import MenuButton
|
||||
from telegram._message import Message
|
||||
from telegram._messageid import MessageId
|
||||
@@ -3176,7 +3177,7 @@ class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]):
|
||||
google_place_id (:obj:`str`, optional): Google Places identifier of the venue.
|
||||
google_place_type (:obj:`str`, optional): Google Places type of the venue. (See
|
||||
`supported types \
|
||||
<https://developers.google.com/maps/documentation/places/web-service/supported_types>`_.)
|
||||
<https://developers.google.com/maps/documentation/places/web-service/place-types>`_.)
|
||||
disable_notification (:obj:`bool`, optional): |disable_notification|
|
||||
protect_content (:obj:`bool`, optional): |protect_content|
|
||||
|
||||
@@ -7555,6 +7556,142 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
)
|
||||
return Poll.de_json(result, self)
|
||||
|
||||
async def send_checklist(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
chat_id: int,
|
||||
checklist: InputChecklist,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_effect_id: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = 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,
|
||||
) -> Message:
|
||||
"""
|
||||
Use this method to send a checklist on behalf of a connected business account.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Args:
|
||||
business_connection_id (:obj:`str`):
|
||||
|business_id_str|
|
||||
chat_id (:obj:`int`):
|
||||
Unique identifier for the target chat.
|
||||
checklist (:class:`telegram.InputChecklist`):
|
||||
The checklist to send.
|
||||
disable_notification (:obj:`bool`, optional):
|
||||
|disable_notification|
|
||||
protect_content (:obj:`bool`, optional):
|
||||
|protect_content|
|
||||
message_effect_id (:obj:`str`, optional):
|
||||
|message_effect_id|
|
||||
reply_parameters (:class:`telegram.ReplyParameters`, optional):
|
||||
|reply_parameters|
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional):
|
||||
An object for an inline keyboard
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
|
||||
parameter for
|
||||
reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
|
||||
Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
|
||||
parameter for
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, the sent Message is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
data: JSONDict = {
|
||||
"chat_id": chat_id,
|
||||
"checklist": checklist,
|
||||
}
|
||||
|
||||
return await self._send_message(
|
||||
"sendChecklist",
|
||||
data,
|
||||
disable_notification=disable_notification,
|
||||
reply_markup=reply_markup,
|
||||
protect_content=protect_content,
|
||||
reply_parameters=reply_parameters,
|
||||
message_effect_id=message_effect_id,
|
||||
business_connection_id=business_connection_id,
|
||||
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=api_kwargs,
|
||||
)
|
||||
|
||||
async def edit_message_checklist(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
chat_id: int,
|
||||
message_id: int,
|
||||
checklist: InputChecklist,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = 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:
|
||||
"""
|
||||
Use this method to edit a checklist on behalf of a connected business account.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Args:
|
||||
business_connection_id (:obj:`str`):
|
||||
|business_id_str|
|
||||
chat_id (:obj:`int`):
|
||||
Unique identifier for the target chat.
|
||||
message_id (:obj:`int`):
|
||||
Unique identifier for the target message.
|
||||
checklist (:class:`telegram.InputChecklist`):
|
||||
The new checklist.
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional):
|
||||
An object for the new inline keyboard for the message.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, the sent Message is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
data: JSONDict = {
|
||||
"chat_id": chat_id,
|
||||
"message_id": message_id,
|
||||
"checklist": checklist,
|
||||
}
|
||||
|
||||
return await self._send_message(
|
||||
"editMessageChecklist",
|
||||
data,
|
||||
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=api_kwargs,
|
||||
)
|
||||
|
||||
async def send_dice(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
@@ -11072,6 +11209,36 @@ CHAT_ACTIVITY_TIMEOUT` seconds.
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def get_my_star_balance(
|
||||
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,
|
||||
) -> StarAmount:
|
||||
"""A method to get the current Telegram Stars balance of the bot. Requires no parameters.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Returns:
|
||||
:class:`telegram.StarAmount`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
"""
|
||||
return StarAmount.de_json(
|
||||
await self._post(
|
||||
"getMyStarBalance",
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
)
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
|
||||
"""See :meth:`telegram.TelegramObject.to_dict`."""
|
||||
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
|
||||
@@ -11244,6 +11411,10 @@ CHAT_ACTIVITY_TIMEOUT` seconds.
|
||||
"""Alias for :meth:`send_poll`"""
|
||||
stopPoll = stop_poll
|
||||
"""Alias for :meth:`stop_poll`"""
|
||||
sendChecklist = send_checklist
|
||||
"""Alias for :meth:`send_checklist`"""
|
||||
editMessageChecklist = edit_message_checklist
|
||||
"""Alias for :meth:`edit_message_checklist`"""
|
||||
sendDice = send_dice
|
||||
"""Alias for :meth:`send_dice`"""
|
||||
getMyCommands = get_my_commands
|
||||
@@ -11386,3 +11557,5 @@ CHAT_ACTIVITY_TIMEOUT` seconds.
|
||||
"""Alias for :meth:`remove_chat_verification`"""
|
||||
removeUserVerification = remove_user_verification
|
||||
"""Alias for :meth:`remove_user_verification`"""
|
||||
getMyStarBalance = get_my_star_balance
|
||||
"""Alias for :meth:`get_my_star_balance`"""
|
||||
|
||||
@@ -30,12 +30,6 @@ from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram._utils.warnings_transition import (
|
||||
build_deprecation_warning_message,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
@@ -195,7 +189,10 @@ class BusinessConnection(TelegramObject):
|
||||
|
||||
.. versionadded:: 21.1
|
||||
.. versionchanged:: 22.1
|
||||
Equality comparison now considers :attr:`rights` instead of :attr:`can_reply`.
|
||||
Equality comparison now considers :attr:`rights` instead of ``can_reply``.
|
||||
|
||||
.. versionremoved:: 22.3
|
||||
Removed argument and attribute ``can_reply`` deprecated by API 9.0.
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique identifier of the business connection.
|
||||
@@ -203,11 +200,6 @@ class BusinessConnection(TelegramObject):
|
||||
user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
|
||||
business connection.
|
||||
date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
|
||||
can_reply (:obj:`bool`, optional): True, if the bot can act on behalf of the business
|
||||
account in chats that were active in the last 24 hours.
|
||||
|
||||
.. deprecated:: 22.1
|
||||
Bot API 9.0 deprecated this argument in favor of :paramref:`rights`.
|
||||
is_enabled (:obj:`bool`): True, if the connection is active.
|
||||
rights (:class:`BusinessBotRights`, optional): Rights of the business bot.
|
||||
|
||||
@@ -226,7 +218,6 @@ class BusinessConnection(TelegramObject):
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_can_reply",
|
||||
"date",
|
||||
"id",
|
||||
"is_enabled",
|
||||
@@ -241,37 +232,16 @@ class BusinessConnection(TelegramObject):
|
||||
user: "User",
|
||||
user_chat_id: int,
|
||||
date: dtm.datetime,
|
||||
can_reply: Optional[bool] = None,
|
||||
# temporarily optional to account for changed signature
|
||||
# tags: deprecated 22.1; bot api 9.0
|
||||
is_enabled: Optional[bool] = None,
|
||||
is_enabled: bool,
|
||||
rights: Optional[BusinessBotRights] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
if is_enabled is None:
|
||||
raise TypeError("Missing required argument `is_enabled`")
|
||||
|
||||
if can_reply is not None:
|
||||
warn(
|
||||
PTBDeprecationWarning(
|
||||
version="22.1",
|
||||
message=build_deprecation_warning_message(
|
||||
deprecated_name="can_reply",
|
||||
new_name="rights",
|
||||
bot_api_version="9.0",
|
||||
object_type="parameter",
|
||||
),
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.id: str = id
|
||||
self.user: User = user
|
||||
self.user_chat_id: int = user_chat_id
|
||||
self.date: dtm.datetime = date
|
||||
self._can_reply: Optional[bool] = can_reply
|
||||
self.is_enabled: bool = is_enabled
|
||||
self.rights: Optional[BusinessBotRights] = rights
|
||||
|
||||
@@ -286,22 +256,6 @@ class BusinessConnection(TelegramObject):
|
||||
|
||||
self._freeze()
|
||||
|
||||
@property
|
||||
def can_reply(self) -> Optional[bool]:
|
||||
""":obj:`bool`: Optional. True, if the bot can act on behalf of the business account in
|
||||
chats that were active in the last 24 hours.
|
||||
|
||||
.. deprecated:: 22.1
|
||||
Bot API 9.0 deprecated this argument in favor of :attr:`rights`
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="can_reply",
|
||||
new_attr_name="rights",
|
||||
bot_api_version="9.0",
|
||||
ptb_version="22.1",
|
||||
)
|
||||
return self._can_reply
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BusinessConnection":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
|
||||
@@ -23,6 +23,7 @@ from typing import TYPE_CHECKING, Final, Optional, Union
|
||||
|
||||
from telegram import constants
|
||||
from telegram._files.location import Location
|
||||
from telegram._inputchecklist import InputChecklist
|
||||
from telegram._message import MaybeInaccessibleMessage, Message
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
@@ -345,6 +346,43 @@ class CallbackQuery(TelegramObject):
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def edit_message_checklist(
|
||||
self,
|
||||
checklist: InputChecklist,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = 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,
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for::
|
||||
|
||||
await update.callback_query.message.edit_checklist(*args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Message.edit_checklist`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, the edited Message is returned.
|
||||
|
||||
Raises:
|
||||
:exc:`TypeError` if :attr:`message` is not accessible.
|
||||
|
||||
"""
|
||||
return await self._get_message().edit_checklist(
|
||||
checklist=checklist,
|
||||
reply_markup=reply_markup,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def edit_message_reply_markup(
|
||||
self,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
|
||||
@@ -53,6 +53,7 @@ if TYPE_CHECKING:
|
||||
Document,
|
||||
Gift,
|
||||
InlineKeyboardMarkup,
|
||||
InputChecklist,
|
||||
InputMediaAudio,
|
||||
InputMediaDocument,
|
||||
InputMediaPhoto,
|
||||
@@ -1471,6 +1472,54 @@ class _ChatBase(TelegramObject):
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_checklist(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
checklist: "InputChecklist",
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = 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_checklist(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.send_checklist`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the message posted.
|
||||
|
||||
"""
|
||||
return await self.get_bot().send_checklist(
|
||||
chat_id=self.id,
|
||||
business_connection_id=business_connection_id,
|
||||
checklist=checklist,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
message_effect_id=message_effect_id,
|
||||
reply_parameters=reply_parameters,
|
||||
reply_markup=reply_markup,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def send_dice(
|
||||
self,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
||||
@@ -41,12 +41,6 @@ from telegram._utils.datetime import (
|
||||
get_timedelta_value,
|
||||
)
|
||||
from telegram._utils.types import JSONDict, TimePeriod
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram._utils.warnings_transition import (
|
||||
build_deprecation_warning_message,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, BusinessIntro, BusinessLocation, BusinessOpeningHours, Message
|
||||
@@ -66,6 +60,9 @@ class ChatFullInfo(_ChatBase):
|
||||
object. Previously those were only available because this class inherited from
|
||||
:class:`telegram.Chat`.
|
||||
|
||||
.. versionremoved:: 22.3
|
||||
Removed argument and attribute ``can_send_gift`` deprecated by API 9.0.
|
||||
|
||||
Args:
|
||||
id (:obj:`int`): Unique identifier for this chat.
|
||||
type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`,
|
||||
@@ -226,13 +223,6 @@ class ChatFullInfo(_ChatBase):
|
||||
sent or forwarded to the channel chat. The field is available only for channel chats.
|
||||
|
||||
.. versionadded:: 21.4
|
||||
can_send_gift (:obj:`bool`, optional): :obj:`True`, if gifts can be sent to the chat.
|
||||
|
||||
.. versionadded:: 21.11
|
||||
|
||||
.. deprecated:: 22.1
|
||||
Bot API 9.0 introduced :paramref:`accepted_gift_types`, replacing this argument.
|
||||
Hence, this argument will be removed in future versions.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier for this chat.
|
||||
@@ -403,7 +393,6 @@ class ChatFullInfo(_ChatBase):
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_can_send_gift",
|
||||
"_message_auto_delete_time",
|
||||
"_slow_mode_delay",
|
||||
"accent_color_id",
|
||||
@@ -450,6 +439,7 @@ class ChatFullInfo(_ChatBase):
|
||||
type: str,
|
||||
accent_color_id: int,
|
||||
max_reaction_count: int,
|
||||
accepted_gift_types: AcceptedGiftTypes,
|
||||
title: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
first_name: Optional[str] = None,
|
||||
@@ -490,10 +480,6 @@ class ChatFullInfo(_ChatBase):
|
||||
linked_chat_id: Optional[int] = None,
|
||||
location: Optional[ChatLocation] = None,
|
||||
can_send_paid_media: Optional[bool] = None,
|
||||
# tags: deprecated 22.1; bot api 9.0
|
||||
can_send_gift: Optional[bool] = None,
|
||||
# temporarily optional to account for changed signature
|
||||
accepted_gift_types: Optional[AcceptedGiftTypes] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -507,23 +493,6 @@ class ChatFullInfo(_ChatBase):
|
||||
is_forum=is_forum,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
if accepted_gift_types is None:
|
||||
raise TypeError("`accepted_gift_type` is a required argument since Bot API 9.0")
|
||||
|
||||
if can_send_gift is not None:
|
||||
warn(
|
||||
PTBDeprecationWarning(
|
||||
"22.1",
|
||||
build_deprecation_warning_message(
|
||||
deprecated_name="can_send_gift",
|
||||
new_name="accepted_gift_types",
|
||||
object_type="parameter",
|
||||
bot_api_version="9.0",
|
||||
),
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
# Required and unique to this class-
|
||||
with self._unfrozen():
|
||||
self.max_reaction_count: int = max_reaction_count
|
||||
@@ -575,28 +544,8 @@ class ChatFullInfo(_ChatBase):
|
||||
self.business_location: Optional[BusinessLocation] = business_location
|
||||
self.business_opening_hours: Optional[BusinessOpeningHours] = business_opening_hours
|
||||
self.can_send_paid_media: Optional[bool] = can_send_paid_media
|
||||
self._can_send_gift: Optional[bool] = can_send_gift
|
||||
self.accepted_gift_types: AcceptedGiftTypes = accepted_gift_types
|
||||
|
||||
@property
|
||||
def can_send_gift(self) -> Optional[bool]:
|
||||
"""
|
||||
:obj:`bool`: Optional. :obj:`True`, if gifts can be sent to the chat.
|
||||
|
||||
.. deprecated:: 22.1
|
||||
As Bot API 9.0 replaces this attribute with :attr:`accepted_gift_types`, this attribute
|
||||
will be removed in future versions.
|
||||
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="can_send_gift",
|
||||
new_attr_name="accepted_gift_types",
|
||||
bot_api_version="9.0",
|
||||
ptb_version="22.1",
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._can_send_gift
|
||||
|
||||
@property
|
||||
def slow_mode_delay(self) -> Optional[Union[int, dtm.timedelta]]:
|
||||
return get_timedelta_value(self._slow_mode_delay, attribute="slow_mode_delay")
|
||||
@@ -624,7 +573,7 @@ class ChatFullInfo(_ChatBase):
|
||||
data.get("accepted_gift_types"), AcceptedGiftTypes, bot
|
||||
)
|
||||
|
||||
from telegram import ( # pylint: disable=import-outside-toplevel
|
||||
from telegram import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessOpeningHours,
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an objects related to Telegram checklists."""
|
||||
import datetime as dtm
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._messageentity import MessageEntity
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.entities import parse_message_entities, parse_message_entity
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram.constants import ZERO_DATE
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, Message
|
||||
|
||||
|
||||
class ChecklistTask(TelegramObject):
|
||||
"""
|
||||
Describes a task in a checklist.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if all their :attr:`id` is equal.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Args:
|
||||
id (:obj:`int`): Unique identifier of the task.
|
||||
text (:obj:`str`): Text of the task.
|
||||
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special
|
||||
entities that appear in the task text.
|
||||
completed_by_user (:class:`telegram.User`, optional): User that completed the task; omitted
|
||||
if the task wasn't completed
|
||||
completion_date (:class:`datetime.datetime`, optional): Point in time when
|
||||
the task was completed; :attr:`~telegram.constants.ZERO_DATE` if the task wasn't
|
||||
completed
|
||||
|
||||
|datetime_localization|
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier of the task.
|
||||
text (:obj:`str`): Text of the task.
|
||||
text_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. Special
|
||||
entities that appear in the task text.
|
||||
completed_by_user (:class:`telegram.User`): Optional. User that completed the task; omitted
|
||||
if the task wasn't completed
|
||||
completion_date (:class:`datetime.datetime`): Optional. Point in time when
|
||||
the task was completed; :attr:`~telegram.constants.ZERO_DATE` if the task wasn't
|
||||
completed
|
||||
|
||||
|datetime_localization|
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"completed_by_user",
|
||||
"completion_date",
|
||||
"id",
|
||||
"text",
|
||||
"text_entities",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: int, # pylint: disable=redefined-builtin
|
||||
text: str,
|
||||
text_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
completed_by_user: Optional[User] = None,
|
||||
completion_date: Optional[dtm.datetime] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.id: int = id
|
||||
self.text: str = text
|
||||
self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
|
||||
self.completed_by_user: Optional[User] = completed_by_user
|
||||
self.completion_date: Optional[dtm.datetime] = completion_date
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChecklistTask":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
if (date := data.get("completion_date")) == 0:
|
||||
data["completion_date"] = ZERO_DATE
|
||||
else:
|
||||
data["completion_date"] = from_timestamp(date, tzinfo=loc_tzinfo)
|
||||
|
||||
data["completed_by_user"] = de_json_optional(data.get("completed_by_user"), User, bot)
|
||||
data["text_entities"] = de_list_optional(data.get("text_entities"), MessageEntity, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
def parse_entity(self, entity: MessageEntity) -> str:
|
||||
"""Returns the text in :attr:`text`
|
||||
from a given :class:`telegram.MessageEntity` of :attr:`text_entities`.
|
||||
|
||||
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 ``ChecklistTask.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:`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 checklist task 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.
|
||||
|
||||
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)
|
||||
|
||||
|
||||
class Checklist(TelegramObject):
|
||||
"""
|
||||
Describes a checklist.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if all their :attr:`tasks` are equal.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Args:
|
||||
title (:obj:`str`): Title of the checklist.
|
||||
title_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special
|
||||
entities that appear in the checklist title.
|
||||
tasks (Sequence[:class:`telegram.ChecklistTask`]): List of tasks in the checklist.
|
||||
others_can_add_tasks (:obj:`bool`, optional): :obj:`True` if users other than the creator
|
||||
of the list can add tasks to the list
|
||||
others_can_mark_tasks_as_done (:obj:`bool`, optional): :obj:`True` if users other than the
|
||||
creator of the list can mark tasks as done or not done
|
||||
|
||||
Attributes:
|
||||
title (:obj:`str`): Title of the checklist.
|
||||
title_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. Special
|
||||
entities that appear in the checklist title.
|
||||
tasks (Tuple[:class:`telegram.ChecklistTask`]): List of tasks in the checklist.
|
||||
others_can_add_tasks (:obj:`bool`): Optional. :obj:`True` if users other than the creator
|
||||
of the list can add tasks to the list
|
||||
others_can_mark_tasks_as_done (:obj:`bool`): Optional. :obj:`True` if users other than the
|
||||
creator of the list can mark tasks as done or not done
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"others_can_add_tasks",
|
||||
"others_can_mark_tasks_as_done",
|
||||
"tasks",
|
||||
"title",
|
||||
"title_entities",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
title: str,
|
||||
tasks: Sequence[ChecklistTask],
|
||||
title_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
others_can_add_tasks: Optional[bool] = None,
|
||||
others_can_mark_tasks_as_done: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.title: str = title
|
||||
self.title_entities: tuple[MessageEntity, ...] = parse_sequence_arg(title_entities)
|
||||
self.tasks: tuple[ChecklistTask, ...] = parse_sequence_arg(tasks)
|
||||
self.others_can_add_tasks: Optional[bool] = others_can_add_tasks
|
||||
self.others_can_mark_tasks_as_done: Optional[bool] = others_can_mark_tasks_as_done
|
||||
|
||||
self._id_attrs = (self.tasks,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Checklist":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
data["title_entities"] = de_list_optional(data.get("title_entities"), MessageEntity, bot)
|
||||
data["tasks"] = de_list_optional(data.get("tasks"), ChecklistTask, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
def parse_entity(self, entity: MessageEntity) -> str:
|
||||
"""Returns the text in :attr:`title`
|
||||
from a given :class:`telegram.MessageEntity` of :attr:`title_entities`.
|
||||
|
||||
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 :attr:`title` 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:`title_entities`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The text of the given entity.
|
||||
"""
|
||||
return parse_message_entity(self.title, 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 checklist's title 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:`title_entities`
|
||||
attribute, since it calculates the correct substring from the message text based on
|
||||
UTF-16 codepoints. See :attr:`parse_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.title, self.title_entities, types)
|
||||
|
||||
|
||||
class ChecklistTasksDone(TelegramObject):
|
||||
"""
|
||||
Describes a service message about checklist tasks marked as done or not done.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their :attr:`marked_as_done_task_ids` and
|
||||
:attr:`marked_as_not_done_task_ids` are equal.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Args:
|
||||
checklist_message (:class:`telegram.Message`, optional): Message containing the checklist
|
||||
whose tasks were marked as done or not done. Note that the ~:class:`telegram.Message`
|
||||
object in this field will not contain the :attr:`~telegram.Message.reply_to_message`
|
||||
field even if it itself is a reply.
|
||||
marked_as_done_task_ids (Sequence[:obj:`int`], optional): Identifiers of the tasks that
|
||||
were marked as done
|
||||
marked_as_not_done_task_ids (Sequence[:obj:`int`], optional): Identifiers of the tasks that
|
||||
were marked as not done
|
||||
|
||||
Attributes:
|
||||
checklist_message (:class:`telegram.Message`): Optional. Message containing the checklist
|
||||
whose tasks were marked as done or not done. Note that the ~:class:`telegram.Message`
|
||||
object in this field will not contain the :attr:`~telegram.Message.reply_to_message`
|
||||
field even if it itself is a reply.
|
||||
marked_as_done_task_ids (Tuple[:obj:`int`]): Optional. Identifiers of the tasks that were
|
||||
marked as done
|
||||
marked_as_not_done_task_ids (Tuple[:obj:`int`]): Optional. Identifiers of the tasks that
|
||||
were marked as not done
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"checklist_message",
|
||||
"marked_as_done_task_ids",
|
||||
"marked_as_not_done_task_ids",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
checklist_message: Optional["Message"] = None,
|
||||
marked_as_done_task_ids: Optional[Sequence[int]] = None,
|
||||
marked_as_not_done_task_ids: Optional[Sequence[int]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.checklist_message: Optional[Message] = checklist_message
|
||||
self.marked_as_done_task_ids: tuple[int, ...] = parse_sequence_arg(marked_as_done_task_ids)
|
||||
self.marked_as_not_done_task_ids: tuple[int, ...] = parse_sequence_arg(
|
||||
marked_as_not_done_task_ids
|
||||
)
|
||||
|
||||
self._id_attrs = (self.marked_as_done_task_ids, self.marked_as_not_done_task_ids)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChecklistTasksDone":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
# needs to be imported here to avoid circular import issues
|
||||
from telegram import Message # pylint: disable=import-outside-toplevel # noqa: PLC0415
|
||||
|
||||
data["checklist_message"] = de_json_optional(data.get("checklist_message"), Message, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class ChecklistTasksAdded(TelegramObject):
|
||||
"""
|
||||
Describes a service message about tasks added to a checklist.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their :attr:`tasks` are equal.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Args:
|
||||
checklist_message (:class:`telegram.Message`, optional): Message containing the checklist
|
||||
to which tasks were added. Note that the ~:class:`telegram.Message`
|
||||
object in this field will not contain the :attr:`~telegram.Message.reply_to_message`
|
||||
field even if it itself is a reply.
|
||||
tasks (Sequence[:class:`telegram.ChecklistTask`]): List of tasks added to the checklist
|
||||
|
||||
Attributes:
|
||||
checklist_message (:class:`telegram.Message`): Optional. Message containing the checklist
|
||||
to which tasks were added. Note that the ~:class:`telegram.Message`
|
||||
object in this field will not contain the :attr:`~telegram.Message.reply_to_message`
|
||||
field even if it itself is a reply.
|
||||
tasks (Tuple[:class:`telegram.ChecklistTask`]): List of tasks added to the checklist
|
||||
"""
|
||||
|
||||
__slots__ = ("checklist_message", "tasks")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tasks: Sequence[ChecklistTask],
|
||||
checklist_message: Optional["Message"] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.checklist_message: Optional[Message] = checklist_message
|
||||
self.tasks: tuple[ChecklistTask, ...] = parse_sequence_arg(tasks)
|
||||
|
||||
self._id_attrs = (self.tasks,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChecklistTasksAdded":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
# needs to be imported here to avoid circular import issues
|
||||
from telegram import Message # pylint: disable=import-outside-toplevel # noqa: PLC0415
|
||||
|
||||
data["checklist_message"] = de_json_optional(data.get("checklist_message"), Message, bot)
|
||||
data["tasks"] = ChecklistTask.de_list(data.get("tasks", []), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Direct Message Price."""
|
||||
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class DirectMessagePriceChanged(TelegramObject):
|
||||
"""
|
||||
Describes a service message about a change in the price of direct messages sent to a channel
|
||||
chat.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`are_direct_messages_enabled`, and
|
||||
:attr:`direct_message_star_count` are equal.
|
||||
|
||||
Args:
|
||||
are_direct_messages_enabled (:obj:`bool`):
|
||||
:obj:`True`, if direct messages are enabled for the channel chat; :obj:`False`
|
||||
otherwise.
|
||||
direct_message_star_count (:obj:`int`, optional):
|
||||
The new number of Telegram Stars that must be paid by users for each direct message
|
||||
sent to the channel. Does not apply to users who have been exempted by administrators.
|
||||
Defaults to ``0``.
|
||||
|
||||
Attributes:
|
||||
are_direct_messages_enabled (:obj:`bool`):
|
||||
:obj:`True`, if direct messages are enabled for the channel chat; :obj:`False`
|
||||
otherwise.
|
||||
direct_message_star_count (:obj:`int`):
|
||||
Optional. The new number of Telegram Stars that must be paid by users for each direct
|
||||
message sent to the channel. Does not apply to users who have been exempted by
|
||||
administrators. Defaults to ``0``.
|
||||
"""
|
||||
|
||||
__slots__ = ("are_direct_messages_enabled", "direct_message_star_count")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
are_direct_messages_enabled: bool,
|
||||
direct_message_star_count: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.are_direct_messages_enabled: bool = are_direct_messages_enabled
|
||||
self.direct_message_star_count: Optional[int] = direct_message_star_count
|
||||
|
||||
self._id_attrs = (self.are_direct_messages_enabled, self.direct_message_star_count)
|
||||
|
||||
self._freeze()
|
||||
@@ -371,7 +371,9 @@ class GiveawayCompleted(TelegramObject):
|
||||
data = cls._parse_data(data)
|
||||
|
||||
# Unfortunately, this needs to be here due to cyclic imports
|
||||
from telegram._message import Message # pylint: disable=import-outside-toplevel
|
||||
from telegram._message import ( # noqa: PLC0415 # pylint: disable=import-outside-toplevel
|
||||
Message,
|
||||
)
|
||||
|
||||
data["giveaway_message"] = de_json_optional(data.get("giveaway_message"), Message, bot)
|
||||
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an objects that are related to Telegram input checklists."""
|
||||
from collections.abc import Sequence
|
||||
from typing import Optional
|
||||
|
||||
from telegram._messageentity import MessageEntity
|
||||
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
|
||||
|
||||
|
||||
class InputChecklistTask(TelegramObject):
|
||||
"""
|
||||
Describes a task to add to a checklist.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal if their :attr:`id` is equal.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Args:
|
||||
id (:obj:`int`):
|
||||
Unique identifier of the task; must be positive and unique among all task identifiers
|
||||
currently present in the checklist.
|
||||
text (:obj:`str`):
|
||||
Text of the task;
|
||||
:tg-const:`telegram.constants.InputChecklistLimit.MIN_TEXT_LENGTH`\
|
||||
-:tg-const:`telegram.constants.InputChecklistLimit.MAX_TEXT_LENGTH` characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`, optional):
|
||||
|parse_mode|
|
||||
text_entities (Sequence[:class:`telegram.MessageEntity`], optional):
|
||||
List of special entities that appear in the text, which can be specified instead of
|
||||
parse_mode. Currently, only bold, italic, underline, strikethrough, spoiler, and
|
||||
custom_emoji entities are allowed.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`):
|
||||
Unique identifier of the task; must be positive and unique among all task identifiers
|
||||
currently present in the checklist.
|
||||
text (:obj:`str`):
|
||||
Text of the task;
|
||||
:tg-const:`telegram.constants.InputChecklistLimit.MIN_TEXT_LENGTH`\
|
||||
-:tg-const:`telegram.constants.InputChecklistLimit.MAX_TEXT_LENGTH` characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`):
|
||||
Optional. |parse_mode|
|
||||
text_entities (Sequence[:class:`telegram.MessageEntity`]):
|
||||
Optional. List of special entities that appear in the text, which can be specified
|
||||
instead of parse_mode. Currently, only bold, italic, underline, strikethrough, spoiler,
|
||||
and custom_emoji entities are allowed.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"id",
|
||||
"parse_mode",
|
||||
"text",
|
||||
"text_entities",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: int, # pylint: disable=redefined-builtin
|
||||
text: str,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
text_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.id: int = id
|
||||
self.text: str = text
|
||||
self.parse_mode: ODVInput[str] = parse_mode
|
||||
self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
|
||||
class InputChecklist(TelegramObject):
|
||||
"""
|
||||
Describes a checklist to create.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal if their :attr:`tasks` is equal.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Args:
|
||||
title (:obj:`str`):
|
||||
Title of the checklist;
|
||||
:tg-const:`telegram.constants.InputChecklistLimit.MIN_TITLE_LENGTH`\
|
||||
-:tg-const:`telegram.constants.InputChecklistLimit.MAX_TITLE_LENGTH` characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`, optional):
|
||||
|parse_mode|
|
||||
title_entities (Sequence[:class:`telegram.MessageEntity`], optional):
|
||||
List of special entities that appear in the title, which
|
||||
can be specified instead of :paramref:`parse_mode`. Currently, only bold, italic,
|
||||
underline, strikethrough, spoiler, and custom_emoji entities are allowed.
|
||||
tasks (Sequence[:class:`telegram.InputChecklistTask`]):
|
||||
List of
|
||||
:tg-const:`telegram.constants.InputChecklistLimit.MIN_TASK_NUMBER`\
|
||||
-:tg-const:`telegram.constants.InputChecklistLimit.MAX_TASK_NUMBER` tasks in
|
||||
the checklist.
|
||||
others_can_add_tasks (:obj:`bool`, optional):
|
||||
Pass :obj:`True` if other users can add tasks to the checklist.
|
||||
others_can_mark_tasks_as_done (:obj:`bool`, optional):
|
||||
Pass :obj:`True` if other users can mark tasks as done or not done in the checklist.
|
||||
|
||||
Attributes:
|
||||
title (:obj:`str`):
|
||||
Title of the checklist;
|
||||
:tg-const:`telegram.constants.InputChecklistLimit.MIN_TITLE_LENGTH`\
|
||||
-:tg-const:`telegram.constants.InputChecklistLimit.MAX_TITLE_LENGTH` characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`):
|
||||
Optional. |parse_mode|
|
||||
title_entities (Sequence[:class:`telegram.MessageEntity`]):
|
||||
Optional. List of special entities that appear in the title, which
|
||||
can be specified instead of :paramref:`parse_mode`. Currently, only bold, italic,
|
||||
underline, strikethrough, spoiler, and custom_emoji entities are allowed.
|
||||
tasks (Sequence[:class:`telegram.InputChecklistTask`]):
|
||||
List of
|
||||
:tg-const:`telegram.constants.InputChecklistLimit.MIN_TASK_NUMBER`\
|
||||
-:tg-const:`telegram.constants.InputChecklistLimit.MAX_TASK_NUMBER` tasks in
|
||||
the checklist.
|
||||
others_can_add_tasks (:obj:`bool`):
|
||||
Optional. Pass :obj:`True` if other users can add tasks to the checklist.
|
||||
others_can_mark_tasks_as_done (:obj:`bool`):
|
||||
Optional. Pass :obj:`True` if other users can mark tasks as done or not done in
|
||||
the checklist.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"others_can_add_tasks",
|
||||
"others_can_mark_tasks_as_done",
|
||||
"parse_mode",
|
||||
"tasks",
|
||||
"title",
|
||||
"title_entities",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
title: str,
|
||||
tasks: Sequence[InputChecklistTask],
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
title_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
others_can_add_tasks: Optional[bool] = None,
|
||||
others_can_mark_tasks_as_done: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.title: str = title
|
||||
self.tasks: tuple[InputChecklistTask, ...] = parse_sequence_arg(tasks)
|
||||
self.parse_mode: ODVInput[str] = parse_mode
|
||||
self.title_entities: tuple[MessageEntity, ...] = parse_sequence_arg(title_entities)
|
||||
self.others_can_add_tasks: Optional[bool] = others_can_add_tasks
|
||||
self.others_can_mark_tasks_as_done: Optional[bool] = others_can_mark_tasks_as_done
|
||||
|
||||
self._id_attrs = (self.tasks,)
|
||||
|
||||
self._freeze()
|
||||
+166
-3
@@ -28,7 +28,9 @@ from typing import TYPE_CHECKING, Optional, TypedDict, Union
|
||||
from telegram._chat import Chat
|
||||
from telegram._chatbackground import ChatBackground
|
||||
from telegram._chatboost import ChatBoostAdded
|
||||
from telegram._checklists import Checklist, ChecklistTasksAdded, ChecklistTasksDone
|
||||
from telegram._dice import Dice
|
||||
from telegram._directmessagepricechanged import DirectMessagePriceChanged
|
||||
from telegram._files.animation import Animation
|
||||
from telegram._files.audio import Audio
|
||||
from telegram._files.contact import Contact
|
||||
@@ -51,6 +53,7 @@ from telegram._forumtopic import (
|
||||
from telegram._games.game import Game
|
||||
from telegram._gifts import GiftInfo
|
||||
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from telegram._inputchecklist import InputChecklist
|
||||
from telegram._linkpreviewoptions import LinkPreviewOptions
|
||||
from telegram._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
|
||||
from telegram._messageentity import MessageEntity
|
||||
@@ -524,6 +527,9 @@ class Message(MaybeInaccessibleMessage):
|
||||
by a spoiler animation.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
checklist (:class:`telegram.Checklist`, optional): Message is a checklist
|
||||
|
||||
.. versionadded:: 22.3
|
||||
users_shared (:class:`telegram.UsersShared`, optional): Service message: users were shared
|
||||
with the bot
|
||||
|
||||
@@ -601,6 +607,14 @@ class Message(MaybeInaccessibleMessage):
|
||||
background set.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
checklist_tasks_done (:class:`telegram.ChecklistTasksDone`, optional): Service message:
|
||||
some tasks in a checklist were marked as done or not done
|
||||
|
||||
.. versionadded:: 22.3
|
||||
checklist_tasks_added (:class:`telegram.ChecklistTasksAdded`, optional): Service message:
|
||||
tasks were added to a checklist
|
||||
|
||||
.. versionadded:: 22.3
|
||||
paid_media (:class:`telegram.PaidMediaInfo`, optional): Message contains paid media;
|
||||
information about the paid media.
|
||||
|
||||
@@ -609,6 +623,11 @@ class Message(MaybeInaccessibleMessage):
|
||||
message about a refunded payment, information about the payment.
|
||||
|
||||
.. versionadded:: 21.4
|
||||
direct_message_price_changed (:class:`telegram.DirectMessagePriceChanged`, optional):
|
||||
Service message: the price for paid messages in the corresponding direct messages chat
|
||||
of a channel has changed.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Attributes:
|
||||
message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances
|
||||
@@ -868,6 +887,9 @@ class Message(MaybeInaccessibleMessage):
|
||||
by a spoiler animation.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
checklist (:class:`telegram.Checklist`): Optional. Message is a checklist
|
||||
|
||||
.. versionadded:: 22.3
|
||||
users_shared (:class:`telegram.UsersShared`): Optional. Service message: users were shared
|
||||
with the bot
|
||||
|
||||
@@ -946,6 +968,14 @@ class Message(MaybeInaccessibleMessage):
|
||||
background set
|
||||
|
||||
.. versionadded:: 21.2
|
||||
checklist_tasks_done (:class:`telegram.ChecklistTasksDone`): Optional. Service message:
|
||||
some tasks in a checklist were marked as done or not done
|
||||
|
||||
.. versionadded:: 22.3
|
||||
checklist_tasks_added (:class:`telegram.ChecklistTasksAdded`): Optional. Service message:
|
||||
tasks were added to a checklist
|
||||
|
||||
.. versionadded:: 22.3
|
||||
paid_media (:class:`telegram.PaidMediaInfo`): Optional. Message contains paid media;
|
||||
information about the paid media.
|
||||
|
||||
@@ -954,6 +984,11 @@ class Message(MaybeInaccessibleMessage):
|
||||
message about a refunded payment, information about the payment.
|
||||
|
||||
.. versionadded:: 21.4
|
||||
direct_message_price_changed (:class:`telegram.DirectMessagePriceChanged`):
|
||||
Optional. Service message: the price for paid messages in the corresponding direct
|
||||
messages chat of a channel has changed.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
.. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
|
||||
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
|
||||
@@ -983,10 +1018,14 @@ class Message(MaybeInaccessibleMessage):
|
||||
"channel_chat_created",
|
||||
"chat_background_set",
|
||||
"chat_shared",
|
||||
"checklist",
|
||||
"checklist_tasks_added",
|
||||
"checklist_tasks_done",
|
||||
"connected_website",
|
||||
"contact",
|
||||
"delete_chat_photo",
|
||||
"dice",
|
||||
"direct_message_price_changed",
|
||||
"document",
|
||||
"edit_date",
|
||||
"effect_id",
|
||||
@@ -1152,6 +1191,10 @@ class Message(MaybeInaccessibleMessage):
|
||||
unique_gift: Optional[UniqueGiftInfo] = None,
|
||||
paid_message_price_changed: Optional[PaidMessagePriceChanged] = None,
|
||||
paid_star_count: Optional[int] = None,
|
||||
direct_message_price_changed: Optional[DirectMessagePriceChanged] = None,
|
||||
checklist: Optional[Checklist] = None,
|
||||
checklist_tasks_done: Optional[ChecklistTasksDone] = None,
|
||||
checklist_tasks_added: Optional[ChecklistTasksAdded] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -1233,6 +1276,7 @@ class Message(MaybeInaccessibleMessage):
|
||||
)
|
||||
self.write_access_allowed: Optional[WriteAccessAllowed] = write_access_allowed
|
||||
self.has_media_spoiler: Optional[bool] = has_media_spoiler
|
||||
self.checklist: Optional[Checklist] = checklist
|
||||
self.users_shared: Optional[UsersShared] = users_shared
|
||||
self.chat_shared: Optional[ChatShared] = chat_shared
|
||||
self.story: Optional[Story] = story
|
||||
@@ -1251,6 +1295,8 @@ class Message(MaybeInaccessibleMessage):
|
||||
self.sender_business_bot: Optional[User] = sender_business_bot
|
||||
self.is_from_offline: Optional[bool] = is_from_offline
|
||||
self.chat_background_set: Optional[ChatBackground] = chat_background_set
|
||||
self.checklist_tasks_done: Optional[ChecklistTasksDone] = checklist_tasks_done
|
||||
self.checklist_tasks_added: Optional[ChecklistTasksAdded] = checklist_tasks_added
|
||||
self.effect_id: Optional[str] = effect_id
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
self.paid_media: Optional[PaidMediaInfo] = paid_media
|
||||
@@ -1261,6 +1307,9 @@ class Message(MaybeInaccessibleMessage):
|
||||
paid_message_price_changed
|
||||
)
|
||||
self.paid_star_count: Optional[int] = paid_star_count
|
||||
self.direct_message_price_changed: Optional[DirectMessagePriceChanged] = (
|
||||
direct_message_price_changed
|
||||
)
|
||||
|
||||
self._effective_attachment = DEFAULT_NONE
|
||||
|
||||
@@ -1402,16 +1451,16 @@ class Message(MaybeInaccessibleMessage):
|
||||
)
|
||||
|
||||
# Unfortunately, this needs to be here due to cyclic imports
|
||||
from telegram._giveaway import ( # pylint: disable=import-outside-toplevel
|
||||
from telegram._giveaway import ( # pylint: disable=C0415 # noqa: PLC0415
|
||||
Giveaway,
|
||||
GiveawayCompleted,
|
||||
GiveawayCreated,
|
||||
GiveawayWinners,
|
||||
)
|
||||
from telegram._messageorigin import ( # pylint: disable=import-outside-toplevel
|
||||
from telegram._messageorigin import ( # pylint: disable=C0415 # noqa: PLC0415
|
||||
MessageOrigin,
|
||||
)
|
||||
from telegram._reply import ( # pylint: disable=import-outside-toplevel
|
||||
from telegram._reply import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
|
||||
ExternalReplyInfo,
|
||||
TextQuote,
|
||||
)
|
||||
@@ -1437,6 +1486,16 @@ class Message(MaybeInaccessibleMessage):
|
||||
data["reply_to_story"] = de_json_optional(data.get("reply_to_story"), Story, bot)
|
||||
data["boost_added"] = de_json_optional(data.get("boost_added"), ChatBoostAdded, bot)
|
||||
data["sender_business_bot"] = de_json_optional(data.get("sender_business_bot"), User, bot)
|
||||
data["direct_message_price_changed"] = de_json_optional(
|
||||
data.get("direct_message_price_changed"), DirectMessagePriceChanged, bot
|
||||
)
|
||||
data["checklist"] = de_json_optional(data.get("checklist"), Checklist, bot)
|
||||
data["checklist_tasks_done"] = de_json_optional(
|
||||
data.get("checklist_tasks_done"), ChecklistTasksDone, bot
|
||||
)
|
||||
data["checklist_tasks_added"] = de_json_optional(
|
||||
data.get("checklist_tasks_added"), ChecklistTasksAdded, bot
|
||||
)
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
@@ -3250,6 +3309,63 @@ class Message(MaybeInaccessibleMessage):
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def reply_checklist(
|
||||
self,
|
||||
checklist: InputChecklist,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_effect_id: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_checklist(
|
||||
business_connection_id=self.business_connection_id,
|
||||
chat_id=update.effective_message.chat_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.send_checklist`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Keyword Args:
|
||||
do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the message posted.
|
||||
|
||||
"""
|
||||
chat_id, effective_reply_parameters = await self._parse_quote_arguments(
|
||||
do_quote, reply_to_message_id, reply_parameters, allow_sending_without_reply
|
||||
)
|
||||
return await self.get_bot().send_checklist(
|
||||
business_connection_id=self.business_connection_id,
|
||||
chat_id=chat_id, # type: ignore[arg-type]
|
||||
checklist=checklist,
|
||||
disable_notification=disable_notification,
|
||||
reply_parameters=effective_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,
|
||||
protect_content=protect_content,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_chat_action(
|
||||
self,
|
||||
action: str,
|
||||
@@ -3859,6 +3975,53 @@ class Message(MaybeInaccessibleMessage):
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def edit_checklist(
|
||||
self,
|
||||
checklist: InputChecklist,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = 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.edit_message_checklist(
|
||||
business_connection_id=message.business_connection_id,
|
||||
chat_id=message.chat_id,
|
||||
message_id=message.message_id,
|
||||
*args, **kwargs
|
||||
)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.edit_message_checklist`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Note:
|
||||
You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
|
||||
of methods) or channel posts, if the bot is an admin in that channel. However, this
|
||||
behaviour is undocumented and might be changed by Telegram.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, the edited Message is returned.
|
||||
|
||||
"""
|
||||
return await self.get_bot().edit_message_checklist(
|
||||
business_connection_id=self.business_connection_id,
|
||||
chat_id=self.chat_id,
|
||||
message_id=self.message_id,
|
||||
checklist=checklist,
|
||||
reply_markup=reply_markup,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def edit_media(
|
||||
self,
|
||||
media: "InputMedia",
|
||||
|
||||
@@ -347,13 +347,17 @@ class OwnedGiftUnique(OwnedGift):
|
||||
bot; for gifts received on behalf of business accounts only.
|
||||
sender_user (:class:`telegram.User`, optional): Sender of the gift if it is a known user.
|
||||
send_date (:obj:`datetime.datetime`): Date the gift was sent as :class:`datetime.datetime`.
|
||||
|datetime_localization|.
|
||||
|datetime_localization|
|
||||
is_saved (:obj:`bool`, optional): :obj:`True`, if the gift is displayed on the account's
|
||||
profile page; for gifts received on behalf of business accounts only.
|
||||
can_be_transferred (:obj:`bool`, optional): :obj:`True`, if the gift can be transferred to
|
||||
another owner; for gifts received on behalf of business accounts only.
|
||||
transfer_star_count (:obj:`int`, optional): Number of Telegram Stars that must be paid
|
||||
to transfer the gift; omitted if the bot cannot transfer the gift.
|
||||
next_transfer_date (:obj:`datetime.datetime`, optional): Date when the gift can be
|
||||
transferred. If it's in the past, then the gift can be transferred now.
|
||||
|datetime_localization|
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the owned gift, always :tg-const:`~telegram.OwnedGift.UNIQUE`.
|
||||
@@ -362,19 +366,24 @@ class OwnedGiftUnique(OwnedGift):
|
||||
bot; for gifts received on behalf of business accounts only.
|
||||
sender_user (:class:`telegram.User`): Optional. Sender of the gift if it is a known user.
|
||||
send_date (:obj:`datetime.datetime`): Date the gift was sent as :class:`datetime.datetime`.
|
||||
|datetime_localization|.
|
||||
|datetime_localization|
|
||||
is_saved (:obj:`bool`): Optional. :obj:`True`, if the gift is displayed on the account's
|
||||
profile page; for gifts received on behalf of business accounts only.
|
||||
can_be_transferred (:obj:`bool`): Optional. :obj:`True`, if the gift can be transferred to
|
||||
another owner; for gifts received on behalf of business accounts only.
|
||||
transfer_star_count (:obj:`int`): Optional. Number of Telegram Stars that must be paid
|
||||
to transfer the gift; omitted if the bot cannot transfer the gift.
|
||||
next_transfer_date (:obj:`datetime.datetime`): Optional. Date when the gift can be
|
||||
transferred. If it's in the past, then the gift can be transferred now.
|
||||
|datetime_localization|
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"can_be_transferred",
|
||||
"gift",
|
||||
"is_saved",
|
||||
"next_transfer_date",
|
||||
"owned_gift_id",
|
||||
"send_date",
|
||||
"sender_user",
|
||||
@@ -390,6 +399,7 @@ class OwnedGiftUnique(OwnedGift):
|
||||
is_saved: Optional[bool] = None,
|
||||
can_be_transferred: Optional[bool] = None,
|
||||
transfer_star_count: Optional[int] = None,
|
||||
next_transfer_date: Optional[dtm.datetime] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> None:
|
||||
@@ -403,6 +413,7 @@ class OwnedGiftUnique(OwnedGift):
|
||||
self.is_saved: Optional[bool] = is_saved
|
||||
self.can_be_transferred: Optional[bool] = can_be_transferred
|
||||
self.transfer_star_count: Optional[int] = transfer_star_count
|
||||
self.next_transfer_date: Optional[dtm.datetime] = next_transfer_date
|
||||
|
||||
self._id_attrs = (self.type, self.gift, self.send_date)
|
||||
|
||||
@@ -415,5 +426,8 @@ class OwnedGiftUnique(OwnedGift):
|
||||
data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo)
|
||||
data["sender_user"] = de_json_optional(data.get("sender_user"), User, bot)
|
||||
data["gift"] = de_json_optional(data.get("gift"), UniqueGift, bot)
|
||||
data["next_transfer_date"] = from_timestamp(
|
||||
data.get("next_transfer_date"), tzinfo=loc_tzinfo
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# flake8: noqa: E501
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
|
||||
@@ -416,6 +416,7 @@ class TransactionPartnerUser(TransactionPartner):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transaction_type: str,
|
||||
user: "User",
|
||||
invoice_payload: Optional[str] = None,
|
||||
paid_media: Optional[Sequence[PaidMedia]] = None,
|
||||
@@ -424,17 +425,11 @@ class TransactionPartnerUser(TransactionPartner):
|
||||
gift: Optional[Gift] = None,
|
||||
affiliate: Optional[AffiliateInfo] = None,
|
||||
premium_subscription_duration: Optional[int] = None,
|
||||
# temporarily optional to account for changed signature
|
||||
transaction_type: Optional[str] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> None:
|
||||
super().__init__(type=TransactionPartner.USER, api_kwargs=api_kwargs)
|
||||
|
||||
# tags: deprecated 22.1, bot api 9.0
|
||||
if transaction_type is None:
|
||||
raise TypeError("`transaction_type` is a required argument since Bot API 9.0")
|
||||
|
||||
with self._unfrozen():
|
||||
self.user: User = user
|
||||
self.affiliate: Optional[AffiliateInfo] = affiliate
|
||||
|
||||
@@ -21,6 +21,7 @@ from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
|
||||
from telegram._chat import Chat
|
||||
from telegram._checklists import Checklist
|
||||
from telegram._dice import Dice
|
||||
from telegram._files.animation import Animation
|
||||
from telegram._files.audio import Audio
|
||||
@@ -89,6 +90,9 @@ class ExternalReplyInfo(TelegramObject):
|
||||
the file.
|
||||
has_media_spoiler (:obj:`bool`, optional): :obj:`True`, if the message media is covered by
|
||||
a spoiler animation.
|
||||
checklist (:class:`telegram.Checklist`, optional): Message is a checklist
|
||||
|
||||
.. versionadded:: 22.3
|
||||
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.
|
||||
@@ -138,6 +142,9 @@ class ExternalReplyInfo(TelegramObject):
|
||||
the file.
|
||||
has_media_spoiler (:obj:`bool`): Optional. :obj:`True`, if the message media is covered by
|
||||
a spoiler animation.
|
||||
checklist (:class:`telegram.Checklist`): Optional. Message is a checklist
|
||||
|
||||
.. versionadded:: 22.3
|
||||
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.
|
||||
@@ -164,6 +171,7 @@ class ExternalReplyInfo(TelegramObject):
|
||||
"animation",
|
||||
"audio",
|
||||
"chat",
|
||||
"checklist",
|
||||
"contact",
|
||||
"dice",
|
||||
"document",
|
||||
@@ -213,6 +221,7 @@ class ExternalReplyInfo(TelegramObject):
|
||||
poll: Optional[Poll] = None,
|
||||
venue: Optional[Venue] = None,
|
||||
paid_media: Optional[PaidMediaInfo] = None,
|
||||
checklist: Optional[Checklist] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -232,6 +241,7 @@ class ExternalReplyInfo(TelegramObject):
|
||||
self.video_note: Optional[VideoNote] = video_note
|
||||
self.voice: Optional[Voice] = voice
|
||||
self.has_media_spoiler: Optional[bool] = has_media_spoiler
|
||||
self.checklist: Optional[Checklist] = checklist
|
||||
self.contact: Optional[Contact] = contact
|
||||
self.dice: Optional[Dice] = dice
|
||||
self.game: Optional[Game] = game
|
||||
@@ -278,6 +288,7 @@ class ExternalReplyInfo(TelegramObject):
|
||||
data["poll"] = de_json_optional(data.get("poll"), Poll, bot)
|
||||
data["venue"] = de_json_optional(data.get("venue"), Venue, bot)
|
||||
data["paid_media"] = de_json_optional(data.get("paid_media"), PaidMediaInfo, bot)
|
||||
data["checklist"] = de_json_optional(data.get("checklist"), Checklist, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# 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 related to unique gifs."""
|
||||
import datetime as dtm
|
||||
from typing import TYPE_CHECKING, Final, Optional
|
||||
|
||||
from telegram import constants
|
||||
@@ -25,6 +26,7 @@ from telegram._files.sticker import Sticker
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -340,31 +342,63 @@ class UniqueGiftInfo(TelegramObject):
|
||||
|
||||
Args:
|
||||
gift (:class:`UniqueGift`): Information about the gift.
|
||||
origin (:obj:`str`): Origin of the gift. Currently, either :attr:`UPGRADE`
|
||||
or :attr:`TRANSFER`.
|
||||
origin (:obj:`str`): Origin of the gift. Currently, either :attr:`UPGRADE` for gifts
|
||||
upgraded from regular gifts, :attr:`TRANSFER` for gifts transferred from other users
|
||||
or channels, or :attr:`RESALE` for gifts bought from other users.
|
||||
|
||||
.. versionchanged:: 22.3
|
||||
The :attr:`RESALE` origin was added.
|
||||
owned_gift_id (:obj:`str`, optional) Unique identifier of the received gift for the
|
||||
bot; only present for gifts received on behalf of business accounts.
|
||||
transfer_star_count (:obj:`int`, optional): Number of Telegram Stars that must be paid
|
||||
to transfer the gift; omitted if the bot cannot transfer the gift.
|
||||
last_resale_star_count (:obj:`int`, optional): For gifts bought from other users, the price
|
||||
paid for the gift.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
next_transfer_date (:obj:`datetime.datetime`, optional): Date when the gift can be
|
||||
transferred. If it's in the past, then the gift can be transferred now.
|
||||
|datetime_localization|
|
||||
|
||||
.. versionadded:: 22.3
|
||||
|
||||
Attributes:
|
||||
gift (:class:`UniqueGift`): Information about the gift.
|
||||
origin (:obj:`str`): Origin of the gift. Currently, either :attr:`UPGRADE`
|
||||
or :attr:`TRANSFER`.
|
||||
origin (:obj:`str`): Origin of the gift. Currently, either :attr:`UPGRADE` for gifts
|
||||
upgraded from regular gifts, :attr:`TRANSFER` for gifts transferred from other users
|
||||
or channels, or :attr:`RESALE` for gifts bought from other users.
|
||||
|
||||
.. versionchanged:: 22.3
|
||||
The :attr:`RESALE` origin was added.
|
||||
owned_gift_id (:obj:`str`) Optional. Unique identifier of the received gift for the
|
||||
bot; only present for gifts received on behalf of business accounts.
|
||||
transfer_star_count (:obj:`int`): Optional. Number of Telegram Stars that must be paid
|
||||
to transfer the gift; omitted if the bot cannot transfer the gift.
|
||||
last_resale_star_count (:obj:`int`): Optional. For gifts bought from other users, the price
|
||||
paid for the gift.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
next_transfer_date (:obj:`datetime.datetime`): Optional. Date when the gift can be
|
||||
transferred. If it's in the past, then the gift can be transferred now.
|
||||
|datetime_localization|
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
UPGRADE: Final[str] = constants.UniqueGiftInfoOrigin.UPGRADE
|
||||
""":const:`telegram.constants.UniqueGiftInfoOrigin.UPGRADE`"""
|
||||
TRANSFER: Final[str] = constants.UniqueGiftInfoOrigin.TRANSFER
|
||||
""":const:`telegram.constants.UniqueGiftInfoOrigin.TRANSFER`"""
|
||||
RESALE: Final[str] = constants.UniqueGiftInfoOrigin.RESALE
|
||||
""":const:`telegram.constants.UniqueGiftInfoOrigin.RESALE`
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"gift",
|
||||
"last_resale_star_count",
|
||||
"next_transfer_date",
|
||||
"origin",
|
||||
"owned_gift_id",
|
||||
"transfer_star_count",
|
||||
@@ -376,6 +410,8 @@ class UniqueGiftInfo(TelegramObject):
|
||||
origin: str,
|
||||
owned_gift_id: Optional[str] = None,
|
||||
transfer_star_count: Optional[int] = None,
|
||||
last_resale_star_count: Optional[int] = None,
|
||||
next_transfer_date: Optional[dtm.datetime] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -386,6 +422,8 @@ class UniqueGiftInfo(TelegramObject):
|
||||
# Optional
|
||||
self.owned_gift_id: Optional[str] = owned_gift_id
|
||||
self.transfer_star_count: Optional[int] = transfer_star_count
|
||||
self.last_resale_star_count: Optional[int] = last_resale_star_count
|
||||
self.next_transfer_date: Optional[dtm.datetime] = next_transfer_date
|
||||
|
||||
self._id_attrs = (self.gift, self.origin)
|
||||
|
||||
@@ -396,6 +434,10 @@ class UniqueGiftInfo(TelegramObject):
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
data["gift"] = de_json_optional(data.get("gift"), UniqueGift, bot)
|
||||
data["next_transfer_date"] = from_timestamp(
|
||||
data.get("next_transfer_date"), tzinfo=loc_tzinfo
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -134,7 +134,7 @@ def parse_file_input( # pylint: disable=too-many-return-statements
|
||||
: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
|
||||
from telegram import InputFile # pylint: disable=import-outside-toplevel # noqa: PLC0415
|
||||
|
||||
if isinstance(file_input, str) and file_input.startswith("file://"):
|
||||
if not local_mode:
|
||||
|
||||
@@ -51,6 +51,6 @@ class Version(NamedTuple):
|
||||
|
||||
|
||||
__version_info__: Final[Version] = Version(
|
||||
major=22, minor=2, micro=0, releaselevel="final", serial=0
|
||||
major=22, minor=3, micro=0, releaselevel="final", serial=0
|
||||
)
|
||||
__version__: Final[str] = str(__version_info__)
|
||||
|
||||
+83
-49
@@ -27,6 +27,10 @@ those classes.
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
* Most of the constants in this module are grouped into enums.
|
||||
|
||||
.. versionremoved:: 22.3
|
||||
Removed deprecated class ``StarTransactions``. Please instead use
|
||||
:attr:`telegram.constants.Nanostar.VALUE`.
|
||||
"""
|
||||
# TODO: Remove this when https://github.com/PyCQA/pylint/issues/6887 is resolved.
|
||||
# pylint: disable=invalid-enum-extension,invalid-slots
|
||||
@@ -73,6 +77,7 @@ __all__ = [
|
||||
"InlineQueryResultLimit",
|
||||
"InlineQueryResultType",
|
||||
"InlineQueryResultsButtonLimit",
|
||||
"InputChecklistLimit",
|
||||
"InputMediaType",
|
||||
"InputPaidMediaType",
|
||||
"InputProfilePhotoType",
|
||||
@@ -103,7 +108,6 @@ __all__ = [
|
||||
"ReactionType",
|
||||
"ReplyLimit",
|
||||
"RevenueWithdrawalStateType",
|
||||
"StarTransactions",
|
||||
"StarTransactionsLimit",
|
||||
"StickerFormat",
|
||||
"StickerLimit",
|
||||
@@ -169,7 +173,7 @@ class _AccentColor(NamedTuple):
|
||||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=9, minor=0)
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=9, minor=1)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
@@ -185,6 +189,7 @@ 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`
|
||||
# and :class:`telegram.ChecklistTask`.
|
||||
#:
|
||||
#: .. versionadded:: 20.8
|
||||
ZERO_DATE: Final[dtm.datetime] = dtm.datetime(1970, 1, 1, tzinfo=UTC)
|
||||
@@ -1408,6 +1413,47 @@ class InlineKeyboardMarkupLimit(IntEnum):
|
||||
"""
|
||||
|
||||
|
||||
class InputChecklistLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.InputChecklist`/
|
||||
:class:`telegram.InputChecklistTask`. The enum
|
||||
members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MIN_TITLE_LENGTH = 1
|
||||
""":obj:`int`: Minimum number of characters in a :obj:`str` passed as
|
||||
:paramref:`~telegram.InputChecklist.title` parameter of :class:`telegram.InputChecklist`
|
||||
"""
|
||||
|
||||
MAX_TITLE_LENGTH = 255
|
||||
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as
|
||||
:paramref:`~telegram.InputChecklist.title` parameter of :class:`telegram.InputChecklist`
|
||||
"""
|
||||
|
||||
MIN_TEXT_LENGTH = 1
|
||||
""":obj:`int`: Minimum number of characters in a :obj:`str` passed as
|
||||
:paramref:`~telegram.InputChecklistTask.text` parameter of :class:`telegram.InputChecklistTask`
|
||||
"""
|
||||
|
||||
MAX_TEXT_LENGTH = 100
|
||||
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as
|
||||
:paramref:`~telegram.InputChecklistTask.text` parameter of :class:`telegram.InputChecklistTask`
|
||||
"""
|
||||
|
||||
MIN_TASK_NUMBER = 1
|
||||
""":obj:`int`: Minimum number of tasks passed as :paramref:`~telegram.InputChecklist.tasks`
|
||||
parameter of :class:`telegram.InputChecklist`
|
||||
"""
|
||||
|
||||
MAX_TASK_NUMBER = 30
|
||||
""":obj:`int`: Maximum number of tasks passed as :paramref:`~telegram.InputChecklistTask.tasks`
|
||||
parameter of :class:`telegram.InputChecklistTask`
|
||||
"""
|
||||
|
||||
|
||||
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.
|
||||
@@ -2055,6 +2101,21 @@ class MessageType(StringEnum):
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
CHECKLIST = "checklist"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.checklist`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
CHECKLIST_TASKS_ADDED = "checklist_tasks_added"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.checklist_tasks_added`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
CHECKLIST_TASKS_DONE = "checklist_tasks_done"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.checklist_tasks_done`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
CONNECTED_WEBSITE = "connected_website"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.connected_website`."""
|
||||
CONTACT = "contact"
|
||||
@@ -2063,6 +2124,11 @@ class MessageType(StringEnum):
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.delete_chat_photo`."""
|
||||
DICE = "dice"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.dice`."""
|
||||
DIRECT_MESSAGE_PRICE_CHANGED = "direct_message_price_changed"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.direct_message_price_changed`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
DOCUMENT = "document"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.document`."""
|
||||
EFFECT_ID = "effect_id"
|
||||
@@ -2737,36 +2803,18 @@ class RevenueWithdrawalStateType(StringEnum):
|
||||
""":obj:`str`: A withdrawal failed and the transaction was refunded."""
|
||||
|
||||
|
||||
# tags: deprecated 22.1, bot api 9.0
|
||||
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
|
||||
|
||||
.. deprecated:: 22.1
|
||||
This class will be removed as its only member :attr:`NANOSTAR_VALUE` will be replaced
|
||||
by :attr:`telegram.constants.Nanostar.VALUE`.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
NANOSTAR_VALUE = Nanostar.VALUE
|
||||
""":obj:`float`: The value of one nanostar as used in
|
||||
:attr:`telegram.StarTransaction.nanostar_amount`.
|
||||
|
||||
.. deprecated:: 22.1
|
||||
This member will be replaced by :attr:`telegram.constants.Nanostar.VALUE`.
|
||||
"""
|
||||
|
||||
|
||||
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
|
||||
|
||||
.. versionremoved:: 22.3
|
||||
Removed deprecated attributes ``StarTransactionsLimit.NANOSTAR_MIN_AMOUNT``
|
||||
and ``StarTransactionsLimit.NANOSTAR_MAX_AMOUNT``. Please instead use
|
||||
:attr:`telegram.constants.NanostarLimit.MIN_AMOUNT`
|
||||
and :attr:`telegram.constants.NanostarLimit.MAX_AMOUNT`.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
@@ -2779,28 +2827,6 @@ class StarTransactionsLimit(IntEnum):
|
||||
""":obj:`int`: Maximum value allowed for the
|
||||
:paramref:`~telegram.Bot.get_star_transactions.limit` parameter of
|
||||
:meth:`telegram.Bot.get_star_transactions`."""
|
||||
# tags: deprecated 22.1, bot api 9.0
|
||||
NANOSTAR_MIN_AMOUNT = NanostarLimit.MIN_AMOUNT
|
||||
""":obj:`int`: Minimum value allowed for :paramref:`~telegram.AffiliateInfo.nanostar_amount`
|
||||
parameter of :class:`telegram.AffiliateInfo`.
|
||||
|
||||
.. versionadded:: 21.9
|
||||
|
||||
.. deprecated:: 22.1
|
||||
This member will be replaced by :attr:`telegram.constants.NanostarLimit.MIN_AMOUNT`.
|
||||
"""
|
||||
# tags: deprecated 22.1, bot api 9.0
|
||||
NANOSTAR_MAX_AMOUNT = NanostarLimit.MAX_AMOUNT
|
||||
""":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
|
||||
|
||||
.. deprecated:: 22.1
|
||||
This member will be replaced by :attr:`telegram.constants.NanostarLimit.MAX_AMOUNT`.
|
||||
"""
|
||||
|
||||
|
||||
class StickerFormat(StringEnum):
|
||||
@@ -3152,10 +3178,13 @@ class PollLimit(IntEnum):
|
||||
to the :paramref:`~telegram.Bot.send_poll.options` parameter of
|
||||
:meth:`telegram.Bot.send_poll`.
|
||||
"""
|
||||
MAX_OPTION_NUMBER = 10
|
||||
MAX_OPTION_NUMBER = 12
|
||||
""":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`.
|
||||
|
||||
.. versionchanged:: 22.3
|
||||
This value was changed from ``10`` to ``12`` in accordance to Bot API 9.1.
|
||||
"""
|
||||
MAX_EXPLANATION_LENGTH = 200
|
||||
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as the
|
||||
@@ -3210,6 +3239,11 @@ class UniqueGiftInfoOrigin(StringEnum):
|
||||
""":obj:`str` gift upgraded"""
|
||||
TRANSFER = "transfer"
|
||||
""":obj:`str` gift transfered"""
|
||||
RESALE = "resale"
|
||||
""":obj:`str` gift bought from other users
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
|
||||
class UpdateType(StringEnum):
|
||||
|
||||
@@ -455,7 +455,9 @@ class Application(
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
# Unfortunately this needs to be here due to cyclical imports
|
||||
from telegram.ext import ApplicationBuilder # pylint: disable=import-outside-toplevel
|
||||
from telegram.ext import ( # noqa: PLC0415 # pylint: disable=import-outside-toplevel
|
||||
ApplicationBuilder,
|
||||
)
|
||||
|
||||
return ApplicationBuilder()
|
||||
|
||||
@@ -498,7 +500,7 @@ class Application(
|
||||
|
||||
# Unfortunately due to circular imports this has to be here
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from telegram.ext._handlers.conversationhandler import ConversationHandler
|
||||
from telegram.ext._handlers.conversationhandler import ConversationHandler # noqa: PLC0415
|
||||
|
||||
# Initialize the persistent conversation handlers with the stored states
|
||||
for handler in itertools.chain.from_iterable(self.handlers.values()):
|
||||
@@ -1369,7 +1371,7 @@ class Application(
|
||||
"""
|
||||
# Unfortunately due to circular imports this has to be here
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from telegram.ext._handlers.conversationhandler import ConversationHandler
|
||||
from telegram.ext._handlers.conversationhandler import ConversationHandler # noqa: PLC0415
|
||||
|
||||
if not isinstance(handler, BaseHandler):
|
||||
raise TypeError(f"handler is not an instance of {BaseHandler.__name__}")
|
||||
@@ -1735,7 +1737,7 @@ class Application(
|
||||
|
||||
# Unfortunately due to circular imports this has to be here
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from telegram.ext._handlers.conversationhandler import PendingState
|
||||
from telegram.ext._handlers.conversationhandler import PendingState # noqa: PLC0415
|
||||
|
||||
for name, (key, new_state) in itertools.chain.from_iterable(
|
||||
zip(itertools.repeat(name), states_dict.pop_accessed_write_items())
|
||||
|
||||
@@ -62,6 +62,7 @@ from telegram import (
|
||||
Gifts,
|
||||
InlineKeyboardMarkup,
|
||||
InlineQueryResultsButton,
|
||||
InputChecklist,
|
||||
InputMedia,
|
||||
InputPaidMedia,
|
||||
InputPollOption,
|
||||
@@ -2639,6 +2640,72 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_checklist(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
chat_id: int,
|
||||
checklist: InputChecklist,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_effect_id: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = 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_checklist(
|
||||
business_connection_id=business_connection_id,
|
||||
chat_id=chat_id,
|
||||
checklist=checklist,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
message_effect_id=message_effect_id,
|
||||
reply_parameters=reply_parameters,
|
||||
reply_markup=reply_markup,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
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_checklist(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
chat_id: int,
|
||||
message_id: int,
|
||||
checklist: InputChecklist,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = 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().edit_message_checklist(
|
||||
business_connection_id=business_connection_id,
|
||||
chat_id=chat_id,
|
||||
message_id=message_id,
|
||||
checklist=checklist,
|
||||
reply_markup=reply_markup,
|
||||
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_dice(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
@@ -5057,6 +5124,24 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def get_my_star_balance(
|
||||
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,
|
||||
) -> StarAmount:
|
||||
return await super().get_my_star_balance(
|
||||
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
|
||||
@@ -5139,6 +5224,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
setPassportDataErrors = set_passport_data_errors
|
||||
sendPoll = send_poll
|
||||
stopPoll = stop_poll
|
||||
sendChecklist = send_checklist
|
||||
editMessageChecklist = edit_message_checklist
|
||||
sendDice = send_dice
|
||||
getMyCommands = get_my_commands
|
||||
setMyCommands = set_my_commands
|
||||
@@ -5210,3 +5297,4 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
verifyUser = verify_user
|
||||
removeChatVerification = remove_chat_verification
|
||||
removeUserVerification = remove_user_verification
|
||||
getMyStarBalance = get_my_star_balance
|
||||
|
||||
@@ -298,7 +298,7 @@ class ConversationHandler(BaseHandler[Update, CCT, object]):
|
||||
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
|
||||
from telegram.ext import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
|
||||
PollAnswerHandler,
|
||||
PollHandler,
|
||||
PreCheckoutQueryHandler,
|
||||
|
||||
@@ -46,6 +46,7 @@ __all__ = (
|
||||
"AUDIO",
|
||||
"BOOST_ADDED",
|
||||
"CAPTION",
|
||||
"CHECKLIST",
|
||||
"COMMAND",
|
||||
"CONTACT",
|
||||
"EFFECT_ID",
|
||||
@@ -920,6 +921,20 @@ class ChatType: # A convenience namespace for Chat types.
|
||||
"""Updates from supergroup."""
|
||||
|
||||
|
||||
class _Checklist(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.checklist)
|
||||
|
||||
|
||||
CHECKLIST = _Checklist(name="filters.CHECKLIST")
|
||||
"""Messages that contain :attr:`telegram.Message.checklist`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
|
||||
class Command(MessageFilter):
|
||||
"""
|
||||
Messages with a :attr:`telegram.MessageEntity.BOT_COMMAND`. By default, only allows
|
||||
@@ -1918,7 +1933,10 @@ class StatusUpdate:
|
||||
StatusUpdate.CHAT_BACKGROUND_SET.check_update(update)
|
||||
or StatusUpdate.CHAT_CREATED.check_update(update)
|
||||
or StatusUpdate.CHAT_SHARED.check_update(update)
|
||||
or StatusUpdate.CHECKLIST_TASKS_ADDED.check_update(update)
|
||||
or StatusUpdate.CHECKLIST_TASKS_DONE.check_update(update)
|
||||
or StatusUpdate.CONNECTED_WEBSITE.check_update(update)
|
||||
or StatusUpdate.DIRECT_MESSAGE_PRICE_CHANGED.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)
|
||||
@@ -1988,6 +2006,30 @@ class StatusUpdate:
|
||||
.. versionadded:: 20.1
|
||||
"""
|
||||
|
||||
class _ChecklistTasksAdded(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.checklist_tasks_added)
|
||||
|
||||
CHECKLIST_TASKS_ADDED = _ChecklistTasksAdded(name="filters.StatusUpdate.CHECKLIST_TASKS_ADDED")
|
||||
"""Messages that contain :attr:`telegram.Message.checklist_tasks_added`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
class _ChecklistTasksDone(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.checklist_tasks_done)
|
||||
|
||||
CHECKLIST_TASKS_DONE = _ChecklistTasksDone(name="filters.StatusUpdate.CHECKLIST_TASKS_DONE")
|
||||
"""Messages that contain :attr:`telegram.Message.checklist_tasks_done`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
class _ConnectedWebsite(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
@@ -1997,6 +2039,20 @@ class StatusUpdate:
|
||||
CONNECTED_WEBSITE = _ConnectedWebsite(name="filters.StatusUpdate.CONNECTED_WEBSITE")
|
||||
"""Messages that contain :attr:`telegram.Message.connected_website`."""
|
||||
|
||||
class _DirectMessagePriceChanged(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.direct_message_price_changed)
|
||||
|
||||
DIRECT_MESSAGE_PRICE_CHANGED = _DirectMessagePriceChanged(
|
||||
name="filters.StatusUpdate.DIRECT_MESSAGE_PRICE_CHANGED"
|
||||
)
|
||||
"""Messages that contain :attr:`telegram.Message.direct_message_price_changed`.
|
||||
|
||||
.. versionadded:: 22.3
|
||||
"""
|
||||
|
||||
class _DeleteChatPhoto(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
@@ -2707,7 +2763,7 @@ class User(_ChatUserBaseFilter):
|
||||
|
||||
@user_ids.setter
|
||||
def user_ids(self, user_id: SCT[int]) -> None:
|
||||
self.chat_ids = user_id # type: ignore[assignment]
|
||||
self.chat_ids = user_id
|
||||
|
||||
def add_user_ids(self, user_id: SCT[int]) -> None:
|
||||
"""
|
||||
@@ -2845,7 +2901,7 @@ class ViaBot(_ChatUserBaseFilter):
|
||||
|
||||
@bot_ids.setter
|
||||
def bot_ids(self, bot_id: SCT[int]) -> None:
|
||||
self.chat_ids = bot_id # type: ignore[assignment]
|
||||
self.chat_ids = bot_id
|
||||
|
||||
def add_bot_ids(self, bot_id: SCT[int]) -> None:
|
||||
"""
|
||||
|
||||
@@ -125,7 +125,10 @@ def effective_message_type(entity: Union["Message", "Update"]) -> Optional[str]:
|
||||
|
||||
"""
|
||||
# Importing on file-level yields cyclic Import Errors
|
||||
from telegram import Message, Update # pylint: disable=import-outside-toplevel
|
||||
from telegram import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
|
||||
Message,
|
||||
Update,
|
||||
)
|
||||
|
||||
if isinstance(entity, Message):
|
||||
message = entity
|
||||
|
||||
@@ -322,19 +322,15 @@ class TestTransactionPartnerUserWithoutRequest(TransactionPartnerTestBase):
|
||||
assert json_dict["subscription_period"] == self.subscription_period.total_seconds()
|
||||
assert json_dict["premium_subscription_duration"] == self.premium_subscription_duration
|
||||
|
||||
def test_transaction_type_is_required_argument(self):
|
||||
with pytest.raises(TypeError, match="`transaction_type` is a required argument"):
|
||||
TransactionPartnerUser(user=self.user)
|
||||
|
||||
def test_equality(self, transaction_partner_user):
|
||||
a = transaction_partner_user
|
||||
b = TransactionPartnerUser(
|
||||
user=self.user,
|
||||
transaction_type=self.transaction_type,
|
||||
user=self.user,
|
||||
)
|
||||
c = TransactionPartnerUser(
|
||||
user=User(id=1, is_bot=False, first_name="user", last_name="user"),
|
||||
transaction_type=self.transaction_type,
|
||||
user=User(id=1, is_bot=False, first_name="user", last_name="user"),
|
||||
)
|
||||
d = User(id=1, is_bot=False, first_name="user", last_name="user")
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class TestDatetime:
|
||||
@pytest.mark.skipif(not TEST_WITH_OPT_DEPS, reason="pytz not installed")
|
||||
def test_localize_pytz(self):
|
||||
dt = dtm.datetime(2023, 1, 1, 12, 0, 0)
|
||||
import pytz
|
||||
import pytz # noqa: PLC0415
|
||||
|
||||
tzinfo = pytz.timezone("Europe/Berlin")
|
||||
localized_dt = tg_dtm.localize(dt, tzinfo)
|
||||
|
||||
@@ -30,7 +30,7 @@ from .envvars import GITHUB_ACTIONS
|
||||
# These bots are only able to talk in our test chats, so they are quite useless for other
|
||||
# purposes than testing.
|
||||
FALLBACKS = (
|
||||
"W3sidG9rZW4iOiAiNTc5Njk0NzE0OkFBRnBLOHc2emtrVXJENHhTZVl3RjNNTzhlLTRHcm1jeTdjIiwgInBheW1lbnRfc"
|
||||
"W3sidG9rZW4iOiAiNTc5Njk0NzE0OkFBRmdqXzhmNFVlV1hrb3VVUnpUZThhRUY0UGNFQkRxdlY0IiwgInBheW1lbnRfc"
|
||||
"HJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TmpRME5qWmxOekk1WWpKaSIsICJjaGF0X2lkIjogIjY3NTY2Nj"
|
||||
"IyNCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTMxMDkxMTEzNSIsICJmb3J1bV9ncm91cF9pZCI6ICItMTAwMTgzODA"
|
||||
"wNDU3NyIsICJjaGFubmVsX2lkIjogIkBweXRob250ZWxlZ3JhbWJvdHRlc3RzIiwgIm5hbWUiOiAiUFRCIHRlc3RzIGZh"
|
||||
|
||||
@@ -8,6 +8,7 @@ from telegram import (
|
||||
BotDescription,
|
||||
BotName,
|
||||
BotShortDescription,
|
||||
BusinessBotRights,
|
||||
BusinessConnection,
|
||||
Chat,
|
||||
ChatAdministratorRights,
|
||||
@@ -69,8 +70,8 @@ _PREPARED_DUMMY_OBJECTS: dict[str, object] = {
|
||||
id="123",
|
||||
user_chat_id=123456,
|
||||
date=_DUMMY_DATE,
|
||||
can_reply=True,
|
||||
is_enabled=True,
|
||||
rights=BusinessBotRights(can_reply=True),
|
||||
),
|
||||
"Chat": Chat(id=123456, type="dummy_type"),
|
||||
"ChatAdministratorRights": ChatAdministratorRights.all_rights(),
|
||||
|
||||
@@ -80,7 +80,7 @@ def caller_func():
|
||||
symlink_to(symlink_file, temp_file)
|
||||
|
||||
sys.path.append(tmp_path.as_posix())
|
||||
from caller_link import caller_func
|
||||
from caller_link import caller_func # noqa: PLC0415
|
||||
|
||||
frame = caller_func()
|
||||
assert was_called_by(frame, temp_file)
|
||||
@@ -111,7 +111,7 @@ def outer_func():
|
||||
symlink_to(symlink_file2, temp_file2)
|
||||
|
||||
sys.path.append(tmp_path.as_posix())
|
||||
from outer_link import outer_func
|
||||
from outer_link import outer_func # noqa: PLC0415
|
||||
|
||||
frame = outer_func()
|
||||
assert was_called_by(frame, temp_file2)
|
||||
|
||||
@@ -23,6 +23,7 @@ import pytest
|
||||
|
||||
from telegram import (
|
||||
Bot,
|
||||
BusinessBotRights,
|
||||
BusinessConnection,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
@@ -81,8 +82,8 @@ def business_connection(bot):
|
||||
user_chat_id=1,
|
||||
user=User(1, "name", username="user_a", is_bot=False),
|
||||
date=dtm.datetime.now(tz=UTC),
|
||||
can_reply=True,
|
||||
is_enabled=True,
|
||||
rights=BusinessBotRights(can_reply=True),
|
||||
)
|
||||
bc.set_bot(bot)
|
||||
return bc
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import asyncio
|
||||
import functools
|
||||
import logging
|
||||
from copy import copy
|
||||
from pathlib import Path
|
||||
from warnings import filterwarnings
|
||||
|
||||
@@ -307,8 +308,6 @@ class TestConversationHandler:
|
||||
)
|
||||
|
||||
def test_repr_with_truncation(self):
|
||||
from copy import copy
|
||||
|
||||
states = copy(self.drinking_states)
|
||||
# there are exactly 3 drinking states. adding one more to make sure it's truncated
|
||||
states["extra_to_be_truncated"] = [CommandHandler("foo", self.start)]
|
||||
|
||||
@@ -42,7 +42,7 @@ class TestDefaults:
|
||||
|
||||
@pytest.mark.skipif(not TEST_WITH_OPT_DEPS, reason="pytz not installed")
|
||||
def test_pytz_deprecation(self, recwarn):
|
||||
import pytz
|
||||
import pytz # noqa: PLC0415
|
||||
|
||||
with pytest.warns(PTBDeprecationWarning, match="pytz") as record:
|
||||
Defaults(tzinfo=pytz.timezone("Europe/Berlin"))
|
||||
|
||||
@@ -1116,7 +1116,22 @@ class TestFilters:
|
||||
assert filters.StatusUpdate.PAID_MESSAGE_PRICE_CHANGED.check_update(update)
|
||||
update.message.paid_message_price_changed = None
|
||||
|
||||
def test_filters_forwarded(self, update, message_origin_user):
|
||||
update.message.direct_message_price_changed = "direct_message_price_changed"
|
||||
assert filters.StatusUpdate.ALL.check_update(update)
|
||||
assert filters.StatusUpdate.DIRECT_MESSAGE_PRICE_CHANGED.check_update(update)
|
||||
update.message.direct_message_price_changed = None
|
||||
|
||||
update.message.checklist_tasks_added = "checklist_tasks_added"
|
||||
assert filters.StatusUpdate.ALL.check_update(update)
|
||||
assert filters.StatusUpdate.CHECKLIST_TASKS_ADDED.check_update(update)
|
||||
update.message.checklist_tasks_added = None
|
||||
|
||||
update.message.checklist_tasks_done = "checklist_tasks_done"
|
||||
assert filters.StatusUpdate.ALL.check_update(update)
|
||||
assert filters.StatusUpdate.CHECKLIST_TASKS_DONE.check_update(update)
|
||||
update.message.checklist_tasks_done = None
|
||||
|
||||
def test_filters_forwarded(self, update):
|
||||
assert filters.FORWARDED.check_update(update)
|
||||
update.message.forward_origin = MessageOriginHiddenUser(dtm.datetime.utcnow(), 1)
|
||||
assert filters.FORWARDED.check_update(update)
|
||||
@@ -2792,3 +2807,10 @@ class TestFilters:
|
||||
update.message.sender_boost_count = "test"
|
||||
assert filters.SENDER_BOOST_COUNT.check_update(update)
|
||||
assert str(filters.SENDER_BOOST_COUNT) == "filters.SENDER_BOOST_COUNT"
|
||||
|
||||
def test_filters_checklist(self, update):
|
||||
assert not filters.CHECKLIST.check_update(update)
|
||||
|
||||
update.message.checklist = "test"
|
||||
assert filters.CHECKLIST.check_update(update)
|
||||
assert str(filters.CHECKLIST) == "filters.CHECKLIST"
|
||||
|
||||
@@ -79,6 +79,7 @@ from telegram import (
|
||||
User,
|
||||
WebAppInfo,
|
||||
)
|
||||
from telegram._payment.stars.staramount import StarAmount
|
||||
from telegram._utils.datetime import UTC, from_timestamp, localize, to_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.strings import to_camel_case
|
||||
@@ -2574,6 +2575,17 @@ class TestBotWithoutRequest:
|
||||
|
||||
await offline_bot.remove_chat_verification(1234)
|
||||
|
||||
async def test_get_my_star_balance(self, offline_bot, monkeypatch):
|
||||
sa = StarAmount(1000).to_json()
|
||||
|
||||
async def do_request(url, request_data: RequestData, *args, **kwargs):
|
||||
assert not request_data.parameters
|
||||
return 200, f'{{"ok": true, "result": {sa}}}'.encode()
|
||||
|
||||
monkeypatch.setattr(offline_bot.request, "do_request", do_request)
|
||||
obj = await offline_bot.get_my_star_balance()
|
||||
assert isinstance(obj, StarAmount)
|
||||
|
||||
|
||||
class TestBotWithRequest:
|
||||
"""
|
||||
@@ -4540,3 +4552,8 @@ class TestBotWithRequest:
|
||||
assert edited_link.name == "sub_name_2"
|
||||
assert sub_link.subscription_period == 2592000
|
||||
assert sub_link.subscription_price == 13
|
||||
|
||||
async def test_get_my_star_balance(self, bot):
|
||||
balance = await bot.get_my_star_balance()
|
||||
assert isinstance(balance, StarAmount)
|
||||
assert balance.amount == 0
|
||||
|
||||
@@ -34,7 +34,6 @@ from telegram import (
|
||||
)
|
||||
from telegram._business import BusinessBotRights
|
||||
from telegram._utils.datetime import UTC, to_timestamp
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@@ -101,7 +100,6 @@ def business_connection(business_bot_rights):
|
||||
BusinessTestBase.user,
|
||||
BusinessTestBase.user_chat_id,
|
||||
BusinessTestBase.date,
|
||||
BusinessTestBase.can_reply,
|
||||
BusinessTestBase.is_enabled,
|
||||
rights=business_bot_rights,
|
||||
)
|
||||
@@ -246,7 +244,6 @@ class TestBusinessConnectionWithoutRequest(BusinessTestBase):
|
||||
"user": self.user.to_dict(),
|
||||
"user_chat_id": self.user_chat_id,
|
||||
"date": to_timestamp(self.date),
|
||||
"can_reply": self.can_reply,
|
||||
"is_enabled": self.is_enabled,
|
||||
"rights": business_bot_rights.to_dict(),
|
||||
}
|
||||
@@ -255,7 +252,6 @@ class TestBusinessConnectionWithoutRequest(BusinessTestBase):
|
||||
assert bc.user == self.user
|
||||
assert bc.user_chat_id == self.user_chat_id
|
||||
assert bc.date == self.date
|
||||
assert bc.can_reply == self.can_reply
|
||||
assert bc.is_enabled == self.is_enabled
|
||||
assert bc.rights == business_bot_rights
|
||||
assert bc.api_kwargs == {}
|
||||
@@ -267,7 +263,6 @@ class TestBusinessConnectionWithoutRequest(BusinessTestBase):
|
||||
"user": self.user.to_dict(),
|
||||
"user_chat_id": self.user_chat_id,
|
||||
"date": to_timestamp(self.date),
|
||||
"can_reply": self.can_reply,
|
||||
"is_enabled": self.is_enabled,
|
||||
"rights": business_bot_rights.to_dict(),
|
||||
}
|
||||
@@ -299,7 +294,6 @@ class TestBusinessConnectionWithoutRequest(BusinessTestBase):
|
||||
self.user,
|
||||
self.user_chat_id,
|
||||
self.date,
|
||||
self.can_reply,
|
||||
self.is_enabled,
|
||||
rights=business_bot_rights,
|
||||
)
|
||||
@@ -308,7 +302,6 @@ class TestBusinessConnectionWithoutRequest(BusinessTestBase):
|
||||
self.user,
|
||||
self.user_chat_id,
|
||||
self.date,
|
||||
self.can_reply,
|
||||
self.is_enabled,
|
||||
rights=business_bot_rights,
|
||||
)
|
||||
@@ -317,7 +310,6 @@ class TestBusinessConnectionWithoutRequest(BusinessTestBase):
|
||||
self.user,
|
||||
self.user_chat_id,
|
||||
self.date,
|
||||
self.can_reply,
|
||||
self.is_enabled,
|
||||
rights=business_bot_rights,
|
||||
)
|
||||
@@ -326,7 +318,6 @@ class TestBusinessConnectionWithoutRequest(BusinessTestBase):
|
||||
self.user,
|
||||
self.user_chat_id,
|
||||
self.date,
|
||||
self.can_reply,
|
||||
self.is_enabled,
|
||||
rights=BusinessBotRights(),
|
||||
)
|
||||
@@ -340,32 +331,6 @@ class TestBusinessConnectionWithoutRequest(BusinessTestBase):
|
||||
assert bc1 != bc4
|
||||
assert hash(bc1) != hash(bc4)
|
||||
|
||||
def test_can_reply_argument_property_deprecation(self, business_connection):
|
||||
with pytest.warns(PTBDeprecationWarning, match=r"9\.0.*can\_reply") as record:
|
||||
assert BusinessConnection(
|
||||
id=self.id_,
|
||||
user=self.user,
|
||||
user_chat_id=self.user_chat_id,
|
||||
date=self.date,
|
||||
can_reply=True,
|
||||
is_enabled=self.is_enabled,
|
||||
)
|
||||
|
||||
assert record[0].category == PTBDeprecationWarning
|
||||
assert record[0].filename == __file__, "wrong stacklevel!"
|
||||
|
||||
with pytest.warns(PTBDeprecationWarning, match=r"9\.0.*can\_reply") as record:
|
||||
assert business_connection.can_reply is self.can_reply
|
||||
|
||||
assert record[0].category == PTBDeprecationWarning
|
||||
assert record[0].filename == __file__, "wrong stacklevel!"
|
||||
|
||||
def test_is_enabled_remains_required(self):
|
||||
with pytest.raises(TypeError):
|
||||
BusinessConnection(
|
||||
id=self.id_, user=self.user, user_chat_id=self.user_chat_id, date=self.date
|
||||
)
|
||||
|
||||
|
||||
class TestBusinessMessagesDeleted(BusinessTestBase):
|
||||
def test_slots(self, business_messages_deleted):
|
||||
|
||||
@@ -21,6 +21,7 @@ import datetime as dtm
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
BusinessBotRights,
|
||||
BusinessConnection,
|
||||
Chat,
|
||||
InputProfilePhotoStatic,
|
||||
@@ -35,7 +36,12 @@ from telegram import (
|
||||
from telegram._files._inputstorycontent import InputStoryContentVideo
|
||||
from telegram._files.sticker import Sticker
|
||||
from telegram._gifts import AcceptedGiftTypes, Gift
|
||||
from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton
|
||||
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from telegram._inputchecklist import InputChecklist, InputChecklistTask
|
||||
from telegram._message import Message
|
||||
from telegram._ownedgift import OwnedGiftRegular, OwnedGifts
|
||||
from telegram._reply import ReplyParameters
|
||||
from telegram._utils.datetime import UTC
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram.constants import InputProfilePhotoType, InputStoryContentType
|
||||
@@ -51,10 +57,15 @@ class TestBusinessMethodsWithoutRequest(BusinessMethodsTestBase):
|
||||
user = User(1, "first", False)
|
||||
user_chat_id = 1
|
||||
date = dtm.datetime.utcnow()
|
||||
can_reply = True
|
||||
rights = BusinessBotRights(can_reply=True)
|
||||
is_enabled = True
|
||||
bc = BusinessConnection(
|
||||
self.bci, user, user_chat_id, date, can_reply, is_enabled
|
||||
self.bci,
|
||||
user,
|
||||
user_chat_id,
|
||||
date,
|
||||
is_enabled,
|
||||
rights=rights,
|
||||
).to_json()
|
||||
|
||||
async def do_request(*args, **kwargs):
|
||||
@@ -632,3 +643,149 @@ class TestBusinessMethodsWithoutRequest(BusinessMethodsTestBase):
|
||||
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.delete_story(business_connection_id=self.bci, story_id=story_id)
|
||||
|
||||
async def test_send_checklist_all_args(self, offline_bot, monkeypatch):
|
||||
chat_id = 123
|
||||
checklist = InputChecklist(
|
||||
title="My Checklist",
|
||||
tasks=[InputChecklistTask(1, "Task 1"), InputChecklistTask(2, "Task 2")],
|
||||
)
|
||||
disable_notification = True
|
||||
protect_content = False
|
||||
message_effect_id = 42
|
||||
reply_parameters = ReplyParameters(23, chat_id, allow_sending_without_reply=True)
|
||||
reply_markup = InlineKeyboardMarkup(
|
||||
[[InlineKeyboardButton(text="test", callback_data="test2")]]
|
||||
)
|
||||
json_message = Message(1, dtm.datetime.now(), Chat(1, ""), text="test").to_json()
|
||||
|
||||
async def make_assertions(*args, **kwargs):
|
||||
params = kwargs.get("request_data").parameters
|
||||
assert params.get("business_connection_id") == self.bci
|
||||
assert params.get("chat_id") == chat_id
|
||||
assert params.get("checklist") == checklist.to_dict()
|
||||
assert params.get("disable_notification") is disable_notification
|
||||
assert params.get("protect_content") is protect_content
|
||||
assert params.get("message_effect_id") == message_effect_id
|
||||
assert params.get("reply_parameters") == reply_parameters.to_dict()
|
||||
assert params.get("reply_markup") == reply_markup.to_dict()
|
||||
|
||||
return 200, f'{{"ok": true, "result": {json_message}}}'.encode()
|
||||
|
||||
monkeypatch.setattr(offline_bot.request, "do_request", make_assertions)
|
||||
obj = await offline_bot.send_checklist(
|
||||
business_connection_id=self.bci,
|
||||
chat_id=chat_id,
|
||||
checklist=checklist,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
message_effect_id=message_effect_id,
|
||||
reply_parameters=reply_parameters,
|
||||
reply_markup=reply_markup,
|
||||
)
|
||||
assert isinstance(obj, Message)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"disable_notification": True}], indirect=True)
|
||||
@pytest.mark.parametrize(
|
||||
("passed_value", "expected_value"),
|
||||
[(DEFAULT_NONE, True), (False, False), (None, None)],
|
||||
)
|
||||
async def test_send_checklist_default_disable_notification(
|
||||
self, default_bot, monkeypatch, passed_value, expected_value
|
||||
):
|
||||
async def make_assertion(url, request_data, *args, **kwargs):
|
||||
assert request_data.parameters.get("disable_notification") is expected_value
|
||||
return Message(1, dtm.datetime.now(), Chat(1, ""), text="test").to_dict()
|
||||
|
||||
monkeypatch.setattr(default_bot.request, "post", make_assertion)
|
||||
kwargs = {
|
||||
"business_connection_id": self.bci,
|
||||
"chat_id": 123,
|
||||
"checklist": InputChecklist(
|
||||
title="My Checklist",
|
||||
tasks=[InputChecklistTask(1, "Task 1")],
|
||||
),
|
||||
}
|
||||
if passed_value is not DEFAULT_NONE:
|
||||
kwargs["disable_notification"] = passed_value
|
||||
|
||||
await default_bot.send_checklist(**kwargs)
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
@pytest.mark.parametrize(
|
||||
("passed_value", "expected_value"),
|
||||
[(DEFAULT_NONE, True), (False, False), (None, None)],
|
||||
)
|
||||
async def test_send_checklist_default_protect_content(
|
||||
self, default_bot, monkeypatch, passed_value, expected_value
|
||||
):
|
||||
async def make_assertion(url, request_data, *args, **kwargs):
|
||||
assert request_data.parameters.get("protect_content") is expected_value
|
||||
return Message(1, dtm.datetime.now(), Chat(1, ""), text="test").to_dict()
|
||||
|
||||
monkeypatch.setattr(default_bot.request, "post", make_assertion)
|
||||
kwargs = {
|
||||
"business_connection_id": self.bci,
|
||||
"chat_id": 123,
|
||||
"checklist": InputChecklist(
|
||||
title="My Checklist",
|
||||
tasks=[InputChecklistTask(1, "Task 1")],
|
||||
),
|
||||
}
|
||||
if passed_value is not DEFAULT_NONE:
|
||||
kwargs["protect_content"] = passed_value
|
||||
|
||||
await default_bot.send_checklist(**kwargs)
|
||||
|
||||
async def test_send_checklist_mutually_exclusive_reply_parameters(self, offline_bot):
|
||||
"""Test that reply_to_message_id and allow_sending_without_reply are mutually exclusive
|
||||
with reply_parameters."""
|
||||
with pytest.raises(ValueError, match="`reply_to_message_id` and"):
|
||||
await offline_bot.send_checklist(
|
||||
self.bci,
|
||||
123,
|
||||
InputChecklist(title="My Checklist", tasks=[InputChecklistTask(1, "Task 1")]),
|
||||
reply_to_message_id=1,
|
||||
reply_parameters=True,
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="`allow_sending_without_reply` and"):
|
||||
await offline_bot.send_checklist(
|
||||
self.bci,
|
||||
123,
|
||||
InputChecklist(title="My Checklist", tasks=[InputChecklistTask(1, "Task 1")]),
|
||||
allow_sending_without_reply=True,
|
||||
reply_parameters=True,
|
||||
)
|
||||
|
||||
async def test_edit_message_checklist_all_args(self, offline_bot, monkeypatch):
|
||||
chat_id = 123
|
||||
message_id = 45
|
||||
checklist = InputChecklist(
|
||||
title="My Checklist",
|
||||
tasks=[InputChecklistTask(1, "Task 1"), InputChecklistTask(2, "Task 2")],
|
||||
)
|
||||
reply_markup = InlineKeyboardMarkup(
|
||||
[[InlineKeyboardButton(text="test", callback_data="test2")]]
|
||||
)
|
||||
json_message = Message(1, dtm.datetime.now(), Chat(1, ""), text="test").to_json()
|
||||
|
||||
async def make_assertions(*args, **kwargs):
|
||||
params = kwargs.get("request_data").parameters
|
||||
assert params.get("business_connection_id") == self.bci
|
||||
assert params.get("chat_id") == chat_id
|
||||
assert params.get("message_id") == message_id
|
||||
assert params.get("checklist") == checklist.to_dict()
|
||||
assert params.get("reply_markup") == reply_markup.to_dict()
|
||||
|
||||
return 200, f'{{"ok": true, "result": {json_message}}}'.encode()
|
||||
|
||||
monkeypatch.setattr(offline_bot.request, "do_request", make_assertions)
|
||||
obj = await offline_bot.edit_message_checklist(
|
||||
business_connection_id=self.bci,
|
||||
chat_id=chat_id,
|
||||
message_id=message_id,
|
||||
checklist=checklist,
|
||||
reply_markup=reply_markup,
|
||||
)
|
||||
assert isinstance(obj, Message)
|
||||
|
||||
@@ -21,7 +21,17 @@ import datetime as dtm
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import Audio, Bot, CallbackQuery, Chat, InaccessibleMessage, Message, User
|
||||
from telegram import (
|
||||
Audio,
|
||||
Bot,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
InaccessibleMessage,
|
||||
InputChecklist,
|
||||
InputChecklistTask,
|
||||
Message,
|
||||
User,
|
||||
)
|
||||
from tests.auxil.bot_method_checks import (
|
||||
check_defaults_handling,
|
||||
check_shortcut_call,
|
||||
@@ -230,6 +240,43 @@ class TestCallbackQueryWithoutRequest(CallbackQueryTestBase):
|
||||
assert await callback_query.edit_message_caption(caption="new caption")
|
||||
assert await callback_query.edit_message_caption("new caption")
|
||||
|
||||
async def test_edit_message_checklist(self, monkeypatch, callback_query):
|
||||
checklist = InputChecklist(title="My Checklist", tasks=[InputChecklistTask(1, "Task 1")])
|
||||
|
||||
if isinstance(callback_query.message, InaccessibleMessage):
|
||||
with pytest.raises(TypeError, match="inaccessible message"):
|
||||
await callback_query.edit_message_checklist(checklist)
|
||||
return
|
||||
|
||||
if callback_query.inline_message_id:
|
||||
pytest.skip("Can't edit inline messages")
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
chat_id = kwargs["chat_id"] == callback_query.message.chat_id
|
||||
message_id = kwargs["message_id"] == callback_query.message.message_id
|
||||
caption = kwargs["checklist"] == checklist
|
||||
return chat_id and message_id and caption
|
||||
|
||||
assert check_shortcut_signature(
|
||||
CallbackQuery.edit_message_checklist,
|
||||
Bot.edit_message_checklist,
|
||||
["chat_id", "message_id", "business_connection_id"],
|
||||
[],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
callback_query.edit_message_checklist,
|
||||
callback_query.get_bot(),
|
||||
"edit_message_checklist",
|
||||
shortcut_kwargs=["chat_id", "message_id", "business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(
|
||||
callback_query.edit_message_checklist, callback_query.get_bot()
|
||||
)
|
||||
|
||||
monkeypatch.setattr(callback_query.get_bot(), "edit_message_checklist", make_assertion)
|
||||
assert await callback_query.edit_message_checklist(checklist=checklist)
|
||||
assert await callback_query.edit_message_checklist(checklist)
|
||||
|
||||
async def test_edit_message_reply_markup(self, monkeypatch, callback_query):
|
||||
if isinstance(callback_query.message, InaccessibleMessage):
|
||||
with pytest.raises(TypeError, match="inaccessible message"):
|
||||
|
||||
+26
-1
@@ -20,7 +20,15 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import Bot, Chat, ChatPermissions, ReactionTypeEmoji, User
|
||||
from telegram import (
|
||||
Bot,
|
||||
Chat,
|
||||
ChatPermissions,
|
||||
InputChecklist,
|
||||
InputChecklistTask,
|
||||
ReactionTypeEmoji,
|
||||
User,
|
||||
)
|
||||
from telegram.constants import ChatAction, ChatType, ReactionEmoji
|
||||
from telegram.helpers import escape_markdown
|
||||
from tests.auxil.bot_method_checks import (
|
||||
@@ -579,6 +587,23 @@ class TestChatWithoutRequest(ChatTestBase):
|
||||
monkeypatch.setattr(chat.get_bot(), "send_dice", make_assertion)
|
||||
assert await chat.send_dice(emoji="test_dice")
|
||||
|
||||
async def test_instance_method_send_checklist(self, monkeypatch, chat):
|
||||
checklist = InputChecklist(title="My Checklist", tasks=[InputChecklistTask(1, "Task 1")])
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return (
|
||||
kwargs["chat_id"] == chat.id
|
||||
and kwargs["business_connection_id"] == "123"
|
||||
and kwargs["checklist"] == checklist
|
||||
)
|
||||
|
||||
assert check_shortcut_signature(Chat.send_checklist, Bot.send_checklist, ["chat_id"], [])
|
||||
assert await check_shortcut_call(chat.send_checklist, chat.get_bot(), "send_checklist")
|
||||
assert await check_defaults_handling(chat.send_checklist, chat.get_bot())
|
||||
|
||||
monkeypatch.setattr(chat.get_bot(), "send_checklist", make_assertion)
|
||||
assert await chat.send_checklist("123", checklist)
|
||||
|
||||
async def test_instance_method_send_game(self, monkeypatch, chat):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["chat_id"] == chat.id and kwargs["game_short_name"] == "test_game"
|
||||
|
||||
@@ -145,7 +145,6 @@ class ChatFullInfoTestBase:
|
||||
first_name = "first_name"
|
||||
last_name = "last_name"
|
||||
can_send_paid_media = True
|
||||
can_send_gift = True
|
||||
accepted_gift_types = AcceptedGiftTypes(True, True, True, True)
|
||||
|
||||
|
||||
@@ -166,7 +165,6 @@ class TestChatFullInfoWithoutRequest(ChatFullInfoTestBase):
|
||||
"max_reaction_count": self.max_reaction_count,
|
||||
"username": self.username,
|
||||
"accepted_gift_types": self.accepted_gift_types.to_dict(),
|
||||
"can_send_gift": self.can_send_gift,
|
||||
"sticker_set_name": self.sticker_set_name,
|
||||
"can_set_sticker_set": self.can_set_sticker_set,
|
||||
"permissions": self.permissions.to_dict(),
|
||||
@@ -334,35 +332,6 @@ class TestChatFullInfoWithoutRequest(ChatFullInfoTestBase):
|
||||
|
||||
assert cfi_dict["max_reaction_count"] == cfi.max_reaction_count
|
||||
|
||||
def test_accepted_gift_types_is_required_argument(self):
|
||||
with pytest.raises(TypeError, match="`accepted_gift_type` is a required argument"):
|
||||
ChatFullInfo(
|
||||
id=123,
|
||||
type=Chat.PRIVATE,
|
||||
accent_color_id=1,
|
||||
max_reaction_count=2,
|
||||
can_send_gift=True,
|
||||
)
|
||||
|
||||
def test_can_send_gift_deprecation_warning(self):
|
||||
with pytest.warns(
|
||||
PTBDeprecationWarning,
|
||||
match="'can_send_gift' was replaced by 'accepted_gift_types' in Bot API 9.0",
|
||||
):
|
||||
chat_full_info = ChatFullInfo(
|
||||
id=123,
|
||||
type=Chat.PRIVATE,
|
||||
accent_color_id=1,
|
||||
max_reaction_count=2,
|
||||
accepted_gift_types=self.accepted_gift_types,
|
||||
can_send_gift=self.can_send_gift,
|
||||
)
|
||||
with pytest.warns(
|
||||
PTBDeprecationWarning,
|
||||
match="Bot API 9.0 renamed the attribute 'can_send_gift' to 'accepted_gift_types'",
|
||||
):
|
||||
chat_full_info.can_send_gift
|
||||
|
||||
def test_time_period_properties(self, PTB_TIMEDELTA, chat_full_info):
|
||||
cfi = chat_full_info
|
||||
if PTB_TIMEDELTA:
|
||||
|
||||
@@ -0,0 +1,439 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import datetime as dtm
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
Checklist,
|
||||
ChecklistTask,
|
||||
ChecklistTasksAdded,
|
||||
ChecklistTasksDone,
|
||||
Dice,
|
||||
MessageEntity,
|
||||
User,
|
||||
)
|
||||
from telegram._utils.datetime import UTC, to_timestamp
|
||||
from telegram.constants import ZERO_DATE
|
||||
from tests.auxil.build_messages import make_message
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
class ChecklistTaskTestBase:
|
||||
id = 42
|
||||
text = "here is a text"
|
||||
text_entities = [
|
||||
MessageEntity(type="bold", offset=0, length=4),
|
||||
MessageEntity(type="italic", offset=5, length=2),
|
||||
]
|
||||
completed_by_user = User(id=1, first_name="Test", last_name="User", is_bot=False)
|
||||
completion_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def checklist_task():
|
||||
return ChecklistTask(
|
||||
id=ChecklistTaskTestBase.id,
|
||||
text=ChecklistTaskTestBase.text,
|
||||
text_entities=ChecklistTaskTestBase.text_entities,
|
||||
completed_by_user=ChecklistTaskTestBase.completed_by_user,
|
||||
completion_date=ChecklistTaskTestBase.completion_date,
|
||||
)
|
||||
|
||||
|
||||
class TestChecklistTaskWithoutRequest(ChecklistTaskTestBase):
|
||||
def test_slot_behaviour(self, checklist_task):
|
||||
for attr in checklist_task.__slots__:
|
||||
assert getattr(checklist_task, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(checklist_task)) == len(
|
||||
set(mro_slots(checklist_task))
|
||||
), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, checklist_task):
|
||||
clt_dict = checklist_task.to_dict()
|
||||
assert isinstance(clt_dict, dict)
|
||||
assert clt_dict["id"] == self.id
|
||||
assert clt_dict["text"] == self.text
|
||||
assert clt_dict["text_entities"] == [entity.to_dict() for entity in self.text_entities]
|
||||
assert clt_dict["completed_by_user"] == self.completed_by_user.to_dict()
|
||||
assert clt_dict["completion_date"] == to_timestamp(self.completion_date)
|
||||
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"id": self.id,
|
||||
"text": self.text,
|
||||
"text_entities": [entity.to_dict() for entity in self.text_entities],
|
||||
"completed_by_user": self.completed_by_user.to_dict(),
|
||||
"completion_date": to_timestamp(self.completion_date),
|
||||
}
|
||||
clt = ChecklistTask.de_json(json_dict, offline_bot)
|
||||
assert isinstance(clt, ChecklistTask)
|
||||
assert clt.id == self.id
|
||||
assert clt.text == self.text
|
||||
assert clt.text_entities == tuple(self.text_entities)
|
||||
assert clt.completed_by_user == self.completed_by_user
|
||||
assert clt.completion_date == self.completion_date
|
||||
assert clt.api_kwargs == {}
|
||||
|
||||
def test_de_json_required_fields(self, offline_bot):
|
||||
json_dict = {
|
||||
"id": self.id,
|
||||
"text": self.text,
|
||||
}
|
||||
clt = ChecklistTask.de_json(json_dict, offline_bot)
|
||||
assert isinstance(clt, ChecklistTask)
|
||||
assert clt.id == self.id
|
||||
assert clt.text == self.text
|
||||
assert clt.text_entities == ()
|
||||
assert clt.completed_by_user is None
|
||||
assert clt.completion_date is None
|
||||
assert clt.api_kwargs == {}
|
||||
|
||||
def test_de_json_localization(self, offline_bot, raw_bot, tz_bot):
|
||||
json_dict = {
|
||||
"id": self.id,
|
||||
"text": self.text,
|
||||
"completion_date": to_timestamp(self.completion_date),
|
||||
}
|
||||
clt_bot = ChecklistTask.de_json(json_dict, offline_bot)
|
||||
clt_bot_raw = ChecklistTask.de_json(json_dict, raw_bot)
|
||||
clt_bot_tz = ChecklistTask.de_json(json_dict, tz_bot)
|
||||
|
||||
# comparing utcoffsets because comparing tzinfo objects is not reliable
|
||||
completion_date_offset = clt_bot_tz.completion_date.utcoffset()
|
||||
completion_date_offset_tz = tz_bot.defaults.tzinfo.utcoffset(
|
||||
clt_bot_tz.completion_date.replace(tzinfo=None)
|
||||
)
|
||||
|
||||
assert clt_bot.completion_date.tzinfo == UTC
|
||||
assert clt_bot_raw.completion_date.tzinfo == UTC
|
||||
assert completion_date_offset_tz == completion_date_offset
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("completion_date", "expected"),
|
||||
[
|
||||
(None, None),
|
||||
(0, ZERO_DATE),
|
||||
(1735689600, dtm.datetime(2025, 1, 1, tzinfo=UTC)),
|
||||
],
|
||||
)
|
||||
def test_de_json_completion_date(self, offline_bot, completion_date, expected):
|
||||
json_dict = {
|
||||
"id": self.id,
|
||||
"text": self.text,
|
||||
"completion_date": completion_date,
|
||||
}
|
||||
clt = ChecklistTask.de_json(json_dict, offline_bot)
|
||||
assert isinstance(clt, ChecklistTask)
|
||||
assert clt.completion_date == expected
|
||||
|
||||
def test_parse_entity(self, checklist_task):
|
||||
assert checklist_task.parse_entity(checklist_task.text_entities[0]) == "here"
|
||||
|
||||
def test_parse_entities(self, checklist_task):
|
||||
assert checklist_task.parse_entities(MessageEntity.BOLD) == {
|
||||
checklist_task.text_entities[0]: "here"
|
||||
}
|
||||
assert checklist_task.parse_entities() == {
|
||||
checklist_task.text_entities[0]: "here",
|
||||
checklist_task.text_entities[1]: "is",
|
||||
}
|
||||
|
||||
def test_equality(self, checklist_task):
|
||||
clt1 = checklist_task
|
||||
clt2 = ChecklistTask(
|
||||
id=self.id,
|
||||
text="other text",
|
||||
)
|
||||
clt3 = ChecklistTask(
|
||||
id=self.id + 1,
|
||||
text=self.text,
|
||||
)
|
||||
clt4 = Dice(value=1, emoji="🎲")
|
||||
|
||||
assert clt1 == clt2
|
||||
assert hash(clt1) == hash(clt2)
|
||||
|
||||
assert clt1 != clt3
|
||||
assert hash(clt1) != hash(clt3)
|
||||
|
||||
assert clt1 != clt4
|
||||
assert hash(clt1) != hash(clt4)
|
||||
|
||||
|
||||
class ChecklistTestBase:
|
||||
title = "Checklist Title"
|
||||
title_entities = [
|
||||
MessageEntity(type="bold", offset=0, length=9),
|
||||
MessageEntity(type="italic", offset=10, length=5),
|
||||
]
|
||||
tasks = [
|
||||
ChecklistTask(
|
||||
id=1,
|
||||
text="Task 1",
|
||||
),
|
||||
ChecklistTask(
|
||||
id=2,
|
||||
text="Task 2",
|
||||
),
|
||||
]
|
||||
others_can_add_tasks = True
|
||||
others_can_mark_tasks_as_done = False
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def checklist():
|
||||
return Checklist(
|
||||
title=ChecklistTestBase.title,
|
||||
title_entities=ChecklistTestBase.title_entities,
|
||||
tasks=ChecklistTestBase.tasks,
|
||||
others_can_add_tasks=ChecklistTestBase.others_can_add_tasks,
|
||||
others_can_mark_tasks_as_done=ChecklistTestBase.others_can_mark_tasks_as_done,
|
||||
)
|
||||
|
||||
|
||||
class TestChecklistWithoutRequest(ChecklistTestBase):
|
||||
def test_slot_behaviour(self, checklist):
|
||||
for attr in checklist.__slots__:
|
||||
assert getattr(checklist, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(checklist)) == len(set(mro_slots(checklist))), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, checklist):
|
||||
cl_dict = checklist.to_dict()
|
||||
assert isinstance(cl_dict, dict)
|
||||
assert cl_dict["title"] == self.title
|
||||
assert cl_dict["title_entities"] == [entity.to_dict() for entity in self.title_entities]
|
||||
assert cl_dict["tasks"] == [task.to_dict() for task in self.tasks]
|
||||
assert cl_dict["others_can_add_tasks"] is self.others_can_add_tasks
|
||||
assert cl_dict["others_can_mark_tasks_as_done"] is self.others_can_mark_tasks_as_done
|
||||
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"title": self.title,
|
||||
"title_entities": [entity.to_dict() for entity in self.title_entities],
|
||||
"tasks": [task.to_dict() for task in self.tasks],
|
||||
"others_can_add_tasks": self.others_can_add_tasks,
|
||||
"others_can_mark_tasks_as_done": self.others_can_mark_tasks_as_done,
|
||||
}
|
||||
cl = Checklist.de_json(json_dict, offline_bot)
|
||||
assert isinstance(cl, Checklist)
|
||||
assert cl.title == self.title
|
||||
assert cl.title_entities == tuple(self.title_entities)
|
||||
assert cl.tasks == tuple(self.tasks)
|
||||
assert cl.others_can_add_tasks is self.others_can_add_tasks
|
||||
assert cl.others_can_mark_tasks_as_done is self.others_can_mark_tasks_as_done
|
||||
assert cl.api_kwargs == {}
|
||||
|
||||
def test_de_json_required_fields(self, offline_bot):
|
||||
json_dict = {
|
||||
"title": self.title,
|
||||
"tasks": [task.to_dict() for task in self.tasks],
|
||||
}
|
||||
cl = Checklist.de_json(json_dict, offline_bot)
|
||||
assert isinstance(cl, Checklist)
|
||||
assert cl.title == self.title
|
||||
assert cl.title_entities == ()
|
||||
assert cl.tasks == tuple(self.tasks)
|
||||
assert not cl.others_can_add_tasks
|
||||
assert not cl.others_can_mark_tasks_as_done
|
||||
|
||||
def test_parse_entity(self, checklist):
|
||||
assert checklist.parse_entity(checklist.title_entities[0]) == "Checklist"
|
||||
assert checklist.parse_entity(checklist.title_entities[1]) == "Title"
|
||||
|
||||
def test_parse_entities(self, checklist):
|
||||
assert checklist.parse_entities(MessageEntity.BOLD) == {
|
||||
checklist.title_entities[0]: "Checklist"
|
||||
}
|
||||
assert checklist.parse_entities() == {
|
||||
checklist.title_entities[0]: "Checklist",
|
||||
checklist.title_entities[1]: "Title",
|
||||
}
|
||||
|
||||
def test_equality(self, checklist, checklist_task):
|
||||
cl1 = checklist
|
||||
cl2 = Checklist(
|
||||
title=self.title + " other",
|
||||
tasks=[ChecklistTask(id=1, text="something"), ChecklistTask(id=2, text="something")],
|
||||
)
|
||||
cl3 = Checklist(
|
||||
title=self.title + " other",
|
||||
tasks=[ChecklistTask(id=42, text="Task 2")],
|
||||
)
|
||||
cl4 = checklist_task
|
||||
|
||||
assert cl1 == cl2
|
||||
assert hash(cl1) == hash(cl2)
|
||||
|
||||
assert cl1 != cl3
|
||||
assert hash(cl1) != hash(cl3)
|
||||
|
||||
assert cl1 != cl4
|
||||
assert hash(cl1) != hash(cl4)
|
||||
|
||||
|
||||
class ChecklistTasksDoneTestBase:
|
||||
checklist_message = make_message("Checklist message")
|
||||
marked_as_done_task_ids = [1, 2, 3]
|
||||
marked_as_not_done_task_ids = [4, 5]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def checklist_tasks_done():
|
||||
return ChecklistTasksDone(
|
||||
checklist_message=ChecklistTasksDoneTestBase.checklist_message,
|
||||
marked_as_done_task_ids=ChecklistTasksDoneTestBase.marked_as_done_task_ids,
|
||||
marked_as_not_done_task_ids=ChecklistTasksDoneTestBase.marked_as_not_done_task_ids,
|
||||
)
|
||||
|
||||
|
||||
class TestChecklistTasksDoneWithoutRequest(ChecklistTasksDoneTestBase):
|
||||
def test_slot_behaviour(self, checklist_tasks_done):
|
||||
for attr in checklist_tasks_done.__slots__:
|
||||
assert getattr(checklist_tasks_done, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(checklist_tasks_done)) == len(
|
||||
set(mro_slots(checklist_tasks_done))
|
||||
), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, checklist_tasks_done):
|
||||
cltd_dict = checklist_tasks_done.to_dict()
|
||||
assert isinstance(cltd_dict, dict)
|
||||
assert cltd_dict["checklist_message"] == self.checklist_message.to_dict()
|
||||
assert cltd_dict["marked_as_done_task_ids"] == self.marked_as_done_task_ids
|
||||
assert cltd_dict["marked_as_not_done_task_ids"] == self.marked_as_not_done_task_ids
|
||||
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"checklist_message": self.checklist_message.to_dict(),
|
||||
"marked_as_done_task_ids": self.marked_as_done_task_ids,
|
||||
"marked_as_not_done_task_ids": self.marked_as_not_done_task_ids,
|
||||
}
|
||||
cltd = ChecklistTasksDone.de_json(json_dict, offline_bot)
|
||||
assert isinstance(cltd, ChecklistTasksDone)
|
||||
assert cltd.checklist_message == self.checklist_message
|
||||
assert cltd.marked_as_done_task_ids == tuple(self.marked_as_done_task_ids)
|
||||
assert cltd.marked_as_not_done_task_ids == tuple(self.marked_as_not_done_task_ids)
|
||||
assert cltd.api_kwargs == {}
|
||||
|
||||
def test_de_json_required_fields(self, offline_bot):
|
||||
cltd = ChecklistTasksDone.de_json({}, offline_bot)
|
||||
assert isinstance(cltd, ChecklistTasksDone)
|
||||
assert cltd.checklist_message is None
|
||||
assert cltd.marked_as_done_task_ids == ()
|
||||
assert cltd.marked_as_not_done_task_ids == ()
|
||||
assert cltd.api_kwargs == {}
|
||||
|
||||
def test_equality(self, checklist_tasks_done):
|
||||
cltd1 = checklist_tasks_done
|
||||
cltd2 = ChecklistTasksDone(
|
||||
checklist_message=None,
|
||||
marked_as_done_task_ids=[1, 2, 3],
|
||||
marked_as_not_done_task_ids=[4, 5],
|
||||
)
|
||||
cltd3 = ChecklistTasksDone(
|
||||
checklist_message=make_message("Checklist message"),
|
||||
marked_as_done_task_ids=[1, 2, 3],
|
||||
)
|
||||
cltd4 = make_message("Not a checklist tasks done")
|
||||
|
||||
assert cltd1 == cltd2
|
||||
assert hash(cltd1) == hash(cltd2)
|
||||
|
||||
assert cltd1 != cltd3
|
||||
assert hash(cltd1) != hash(cltd3)
|
||||
|
||||
assert cltd1 != cltd4
|
||||
assert hash(cltd1) != hash(cltd4)
|
||||
|
||||
|
||||
class ChecklistTasksAddedTestBase:
|
||||
checklist_message = make_message("Checklist message")
|
||||
tasks = [
|
||||
ChecklistTask(id=1, text="Task 1"),
|
||||
ChecklistTask(id=2, text="Task 2"),
|
||||
ChecklistTask(id=3, text="Task 3"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def checklist_tasks_added():
|
||||
return ChecklistTasksAdded(
|
||||
checklist_message=ChecklistTasksAddedTestBase.checklist_message,
|
||||
tasks=ChecklistTasksAddedTestBase.tasks,
|
||||
)
|
||||
|
||||
|
||||
class TestChecklistTasksAddedWithoutRequest(ChecklistTasksAddedTestBase):
|
||||
def test_slot_behaviour(self, checklist_tasks_added):
|
||||
for attr in checklist_tasks_added.__slots__:
|
||||
assert getattr(checklist_tasks_added, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(checklist_tasks_added)) == len(
|
||||
set(mro_slots(checklist_tasks_added))
|
||||
), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, checklist_tasks_added):
|
||||
clta_dict = checklist_tasks_added.to_dict()
|
||||
assert isinstance(clta_dict, dict)
|
||||
assert clta_dict["checklist_message"] == self.checklist_message.to_dict()
|
||||
assert clta_dict["tasks"] == [task.to_dict() for task in self.tasks]
|
||||
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"checklist_message": self.checklist_message.to_dict(),
|
||||
"tasks": [task.to_dict() for task in self.tasks],
|
||||
}
|
||||
clta = ChecklistTasksAdded.de_json(json_dict, offline_bot)
|
||||
assert isinstance(clta, ChecklistTasksAdded)
|
||||
assert clta.checklist_message == self.checklist_message
|
||||
assert clta.tasks == tuple(self.tasks)
|
||||
assert clta.api_kwargs == {}
|
||||
|
||||
def test_de_json_required_fields(self, offline_bot):
|
||||
clta = ChecklistTasksAdded.de_json(
|
||||
{"tasks": [task.to_dict() for task in self.tasks]}, offline_bot
|
||||
)
|
||||
assert isinstance(clta, ChecklistTasksAdded)
|
||||
assert clta.checklist_message is None
|
||||
assert clta.tasks == tuple(self.tasks)
|
||||
assert clta.api_kwargs == {}
|
||||
|
||||
def test_equality(self, checklist_tasks_added):
|
||||
clta1 = checklist_tasks_added
|
||||
clta2 = ChecklistTasksAdded(
|
||||
checklist_message=None,
|
||||
tasks=[
|
||||
ChecklistTask(id=1, text="Other Task 1"),
|
||||
ChecklistTask(id=2, text="Other Task 2"),
|
||||
ChecklistTask(id=3, text="Other Task 3"),
|
||||
],
|
||||
)
|
||||
clta3 = ChecklistTasksAdded(
|
||||
checklist_message=make_message("Checklist message"),
|
||||
tasks=[ChecklistTask(id=1, text="Task 1")],
|
||||
)
|
||||
clta4 = make_message("Not a checklist tasks added")
|
||||
|
||||
assert clta1 == clta2
|
||||
assert hash(clta1) == hash(clta2)
|
||||
|
||||
assert clta1 != clta3
|
||||
assert hash(clta1) != hash(clta3)
|
||||
|
||||
assert clta1 != clta4
|
||||
assert hash(clta1) != hash(clta4)
|
||||
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object for testing a Direct Message Price."""
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import DirectMessagePriceChanged, User
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def direct_message_price_changed():
|
||||
return DirectMessagePriceChanged(
|
||||
are_direct_messages_enabled=DirectMessagePriceChangedTestBase.are_direct_messages_enabled,
|
||||
direct_message_star_count=DirectMessagePriceChangedTestBase.direct_message_star_count,
|
||||
)
|
||||
|
||||
|
||||
class DirectMessagePriceChangedTestBase:
|
||||
are_direct_messages_enabled: bool = True
|
||||
direct_message_star_count: int = 100
|
||||
|
||||
|
||||
class TestDirectMessagePriceChangedWithoutRequest(DirectMessagePriceChangedTestBase):
|
||||
def test_slot_behaviour(self, direct_message_price_changed):
|
||||
action = direct_message_price_changed
|
||||
for attr in action.__slots__:
|
||||
assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
|
||||
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict: JSONDict = {
|
||||
"are_direct_messages_enabled": self.are_direct_messages_enabled,
|
||||
"direct_message_star_count": self.direct_message_star_count,
|
||||
}
|
||||
dmpc = DirectMessagePriceChanged.de_json(json_dict, offline_bot)
|
||||
assert dmpc.api_kwargs == {}
|
||||
|
||||
assert dmpc.are_direct_messages_enabled == self.are_direct_messages_enabled
|
||||
assert dmpc.direct_message_star_count == self.direct_message_star_count
|
||||
|
||||
def test_to_dict(self, direct_message_price_changed):
|
||||
dmpc_dict = direct_message_price_changed.to_dict()
|
||||
assert dmpc_dict["are_direct_messages_enabled"] == self.are_direct_messages_enabled
|
||||
assert dmpc_dict["direct_message_star_count"] == self.direct_message_star_count
|
||||
|
||||
def test_equality(self, direct_message_price_changed):
|
||||
dmpc1 = direct_message_price_changed
|
||||
dmpc2 = DirectMessagePriceChanged(
|
||||
are_direct_messages_enabled=self.are_direct_messages_enabled,
|
||||
direct_message_star_count=self.direct_message_star_count,
|
||||
)
|
||||
assert dmpc1 == dmpc2
|
||||
assert hash(dmpc1) == hash(dmpc2)
|
||||
|
||||
dmpc3 = DirectMessagePriceChanged(
|
||||
are_direct_messages_enabled=False,
|
||||
direct_message_star_count=self.direct_message_star_count,
|
||||
)
|
||||
assert dmpc1 != dmpc3
|
||||
assert hash(dmpc1) != hash(dmpc3)
|
||||
|
||||
not_a_dmpc = User(id=1, first_name="wrong", is_bot=False)
|
||||
assert dmpc1 != not_a_dmpc
|
||||
assert hash(dmpc1) != hash(not_a_dmpc)
|
||||
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import Dice, InputChecklist, InputChecklistTask, MessageEntity
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def input_checklist_task():
|
||||
return InputChecklistTask(
|
||||
id=InputChecklistTaskTestBase.id,
|
||||
text=InputChecklistTaskTestBase.text,
|
||||
parse_mode=InputChecklistTaskTestBase.parse_mode,
|
||||
text_entities=InputChecklistTaskTestBase.text_entities,
|
||||
)
|
||||
|
||||
|
||||
class InputChecklistTaskTestBase:
|
||||
id = 1
|
||||
text = "buy food"
|
||||
parse_mode = "MarkdownV2"
|
||||
text_entities = [
|
||||
MessageEntity(type="bold", offset=0, length=3),
|
||||
MessageEntity(type="italic", offset=4, length=4),
|
||||
]
|
||||
|
||||
|
||||
class TestInputChecklistTaskWithoutRequest(InputChecklistTaskTestBase):
|
||||
def test_slot_behaviour(self, input_checklist_task):
|
||||
for attr in input_checklist_task.__slots__:
|
||||
assert getattr(input_checklist_task, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(input_checklist_task)) == len(
|
||||
set(mro_slots(input_checklist_task))
|
||||
), "duplicate slot"
|
||||
|
||||
def test_expected_values(self, input_checklist_task):
|
||||
assert input_checklist_task.id == self.id
|
||||
assert input_checklist_task.text == self.text
|
||||
assert input_checklist_task.parse_mode == self.parse_mode
|
||||
assert input_checklist_task.text_entities == tuple(self.text_entities)
|
||||
|
||||
def test_to_dict(self, input_checklist_task):
|
||||
iclt_dict = input_checklist_task.to_dict()
|
||||
|
||||
assert isinstance(iclt_dict, dict)
|
||||
assert iclt_dict["id"] == self.id
|
||||
assert iclt_dict["text"] == self.text
|
||||
assert iclt_dict["parse_mode"] == self.parse_mode
|
||||
assert iclt_dict["text_entities"] == [entity.to_dict() for entity in self.text_entities]
|
||||
|
||||
# Test that default-value parameter `parse_mode` is handled correctly
|
||||
input_checklist_task = InputChecklistTask(id=1, text="text")
|
||||
iclt_dict = input_checklist_task.to_dict()
|
||||
assert "parse_mode" not in iclt_dict
|
||||
|
||||
def test_equality(self, input_checklist_task):
|
||||
a = input_checklist_task
|
||||
b = InputChecklistTask(id=self.id, text=f"other {self.text}")
|
||||
c = InputChecklistTask(id=self.id + 1, text=self.text)
|
||||
d = Dice(value=1, emoji="🎲")
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def input_checklist():
|
||||
return InputChecklist(
|
||||
title=InputChecklistTestBase.title,
|
||||
tasks=InputChecklistTestBase.tasks,
|
||||
parse_mode=InputChecklistTestBase.parse_mode,
|
||||
title_entities=InputChecklistTestBase.title_entities,
|
||||
others_can_add_tasks=InputChecklistTestBase.others_can_add_tasks,
|
||||
others_can_mark_tasks_as_done=InputChecklistTestBase.others_can_mark_tasks_as_done,
|
||||
)
|
||||
|
||||
|
||||
class InputChecklistTestBase:
|
||||
title = "test list"
|
||||
tasks = [
|
||||
InputChecklistTask(id=1, text="eat"),
|
||||
InputChecklistTask(id=2, text="sleep"),
|
||||
]
|
||||
parse_mode = "MarkdownV2"
|
||||
title_entities = [
|
||||
MessageEntity(type="bold", offset=0, length=4),
|
||||
MessageEntity(type="italic", offset=5, length=4),
|
||||
]
|
||||
others_can_add_tasks = True
|
||||
others_can_mark_tasks_as_done = False
|
||||
|
||||
|
||||
class TestInputChecklistWithoutRequest(InputChecklistTestBase):
|
||||
def test_slot_behaviour(self, input_checklist):
|
||||
for attr in input_checklist.__slots__:
|
||||
assert getattr(input_checklist, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(input_checklist)) == len(
|
||||
set(mro_slots(input_checklist))
|
||||
), "duplicate slot"
|
||||
|
||||
def test_expected_values(self, input_checklist):
|
||||
assert input_checklist.title == self.title
|
||||
assert input_checklist.tasks == tuple(self.tasks)
|
||||
assert input_checklist.parse_mode == self.parse_mode
|
||||
assert input_checklist.title_entities == tuple(self.title_entities)
|
||||
assert input_checklist.others_can_add_tasks == self.others_can_add_tasks
|
||||
assert input_checklist.others_can_mark_tasks_as_done == self.others_can_mark_tasks_as_done
|
||||
|
||||
def test_to_dict(self, input_checklist):
|
||||
icl_dict = input_checklist.to_dict()
|
||||
|
||||
assert isinstance(icl_dict, dict)
|
||||
assert icl_dict["title"] == self.title
|
||||
assert icl_dict["tasks"] == [task.to_dict() for task in self.tasks]
|
||||
assert icl_dict["parse_mode"] == self.parse_mode
|
||||
assert icl_dict["title_entities"] == [entity.to_dict() for entity in self.title_entities]
|
||||
assert icl_dict["others_can_add_tasks"] == self.others_can_add_tasks
|
||||
assert icl_dict["others_can_mark_tasks_as_done"] == self.others_can_mark_tasks_as_done
|
||||
|
||||
# Test that default-value parameter `parse_mode` is handled correctly
|
||||
input_checklist = InputChecklist(title=self.title, tasks=self.tasks)
|
||||
icl_dict = input_checklist.to_dict()
|
||||
assert "parse_mode" not in icl_dict
|
||||
|
||||
def test_equality(self, input_checklist):
|
||||
a = input_checklist
|
||||
b = InputChecklist(
|
||||
title=f"other {self.title}",
|
||||
tasks=[InputChecklistTask(id=1, text="eat"), InputChecklistTask(id=2, text="sleep")],
|
||||
)
|
||||
c = InputChecklist(
|
||||
title=self.title,
|
||||
tasks=[InputChecklistTask(id=9, text="Other Task")],
|
||||
)
|
||||
d = Dice(value=1, emoji="🎲")
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
+101
-9
@@ -31,15 +31,24 @@ from telegram import (
|
||||
ChatBackground,
|
||||
ChatBoostAdded,
|
||||
ChatShared,
|
||||
Checklist,
|
||||
ChecklistTask,
|
||||
ChecklistTasksAdded,
|
||||
ChecklistTasksDone,
|
||||
Contact,
|
||||
Dice,
|
||||
DirectMessagePriceChanged,
|
||||
Document,
|
||||
ExternalReplyInfo,
|
||||
Game,
|
||||
Gift,
|
||||
GiftInfo,
|
||||
Giveaway,
|
||||
GiveawayCompleted,
|
||||
GiveawayCreated,
|
||||
GiveawayWinners,
|
||||
InputChecklist,
|
||||
InputChecklistTask,
|
||||
InputPaidMediaPhoto,
|
||||
Invoice,
|
||||
LinkPreviewOptions,
|
||||
@@ -63,6 +72,12 @@ from telegram import (
|
||||
Story,
|
||||
SuccessfulPayment,
|
||||
TextQuote,
|
||||
UniqueGift,
|
||||
UniqueGiftBackdrop,
|
||||
UniqueGiftBackdropColors,
|
||||
UniqueGiftInfo,
|
||||
UniqueGiftModel,
|
||||
UniqueGiftSymbol,
|
||||
Update,
|
||||
User,
|
||||
UsersShared,
|
||||
@@ -76,15 +91,6 @@ from telegram import (
|
||||
Voice,
|
||||
WebAppData,
|
||||
)
|
||||
from telegram._gifts import Gift, GiftInfo
|
||||
from telegram._uniquegift import (
|
||||
UniqueGift,
|
||||
UniqueGiftBackdrop,
|
||||
UniqueGiftBackdropColors,
|
||||
UniqueGiftInfo,
|
||||
UniqueGiftModel,
|
||||
UniqueGiftSymbol,
|
||||
)
|
||||
from telegram._utils.datetime import UTC
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import ODVInput
|
||||
@@ -331,6 +337,24 @@ def message(bot):
|
||||
{"refunded_payment": RefundedPayment("EUR", 243, "payload", "charge_id", "provider_id")},
|
||||
{"paid_star_count": 291},
|
||||
{"paid_message_price_changed": PaidMessagePriceChanged(291)},
|
||||
{"direct_message_price_changed": DirectMessagePriceChanged(True, 100)},
|
||||
{
|
||||
"checklist": Checklist(
|
||||
"checklist_id",
|
||||
tasks=[ChecklistTask(id=42, text="task 1"), ChecklistTask(id=43, text="task 2")],
|
||||
)
|
||||
},
|
||||
{
|
||||
"checklist_tasks_done": ChecklistTasksDone(
|
||||
marked_as_done_task_ids=[1, 2, 3],
|
||||
marked_as_not_done_task_ids=[4, 5],
|
||||
)
|
||||
},
|
||||
{
|
||||
"checklist_tasks_added": ChecklistTasksAdded(
|
||||
tasks=[ChecklistTask(id=42, text="task 1"), ChecklistTask(id=43, text="task 2")],
|
||||
)
|
||||
},
|
||||
],
|
||||
ids=[
|
||||
"reply",
|
||||
@@ -408,6 +432,10 @@ def message(bot):
|
||||
"refunded_payment",
|
||||
"paid_star_count",
|
||||
"paid_message_price_changed",
|
||||
"direct_message_price_changed",
|
||||
"checklist",
|
||||
"checklist_tasks_done",
|
||||
"checklist_tasks_added",
|
||||
],
|
||||
)
|
||||
def message_params(bot, request):
|
||||
@@ -2196,6 +2224,42 @@ class TestMessageWithoutRequest(MessageTestBase):
|
||||
message, message.reply_dice, "send_dice", [], monkeypatch
|
||||
)
|
||||
|
||||
async def test_reply_checklist(self, monkeypatch, message):
|
||||
checklist = InputChecklist(title="My Checklist", tasks=[InputChecklistTask(1, "Task 1")])
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return (
|
||||
kwargs["chat_id"] == message.chat_id
|
||||
and kwargs["business_connection_id"] == message.business_connection_id
|
||||
and kwargs["checklist"] == checklist
|
||||
and kwargs["disable_notification"] is True
|
||||
)
|
||||
|
||||
assert check_shortcut_signature(
|
||||
Message.reply_checklist,
|
||||
Bot.send_checklist,
|
||||
["chat_id", "business_connection_id", "reply_to_message_id"],
|
||||
["do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
message.reply_checklist,
|
||||
message.get_bot(),
|
||||
"send_checklist",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["chat_id", "business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_checklist, message.get_bot())
|
||||
|
||||
monkeypatch.setattr(message.get_bot(), "send_checklist", make_assertion)
|
||||
assert await message.reply_checklist(checklist, disable_notification=True)
|
||||
await self.check_quote_parsing(
|
||||
message,
|
||||
message.reply_checklist,
|
||||
"send_checklist",
|
||||
[checklist, True],
|
||||
monkeypatch,
|
||||
)
|
||||
|
||||
async def test_reply_action(self, monkeypatch, message: Message):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
id_ = kwargs["chat_id"] == message.chat_id
|
||||
@@ -2531,6 +2595,34 @@ class TestMessageWithoutRequest(MessageTestBase):
|
||||
monkeypatch.setattr(message.get_bot(), "edit_message_caption", make_assertion)
|
||||
assert await message.edit_caption(caption="new caption")
|
||||
|
||||
async def test_edit_checklist(self, monkeypatch, message):
|
||||
checklist = InputChecklist(title="My Checklist", tasks=[InputChecklistTask(1, "Task 1")])
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return (
|
||||
kwargs["business_connection_id"] == message.business_connection_id
|
||||
and kwargs["chat_id"] == message.chat_id
|
||||
and kwargs["message_id"] == message.message_id
|
||||
and kwargs["checklist"] == checklist
|
||||
)
|
||||
|
||||
assert check_shortcut_signature(
|
||||
Message.edit_checklist,
|
||||
Bot.edit_message_checklist,
|
||||
["chat_id", "message_id", "business_connection_id"],
|
||||
[],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
message.edit_checklist,
|
||||
message.get_bot(),
|
||||
"edit_message_checklist",
|
||||
shortcut_kwargs=["chat_id", "message_id", "business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.edit_checklist, message.get_bot())
|
||||
|
||||
monkeypatch.setattr(message.get_bot(), "edit_message_checklist", make_assertion)
|
||||
assert await message.edit_checklist(checklist=checklist)
|
||||
|
||||
async def test_edit_media(self, monkeypatch, message):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
chat_id = kwargs["chat_id"] == message.chat_id
|
||||
|
||||
@@ -158,10 +158,6 @@ PTB_EXTRA_PARAMS = {
|
||||
"InputPaidMedia": {"type", "media"}, # attributes common to all subclasses
|
||||
"InputStoryContent": {"type"}, # attributes common to all subclasses
|
||||
"StoryAreaType": {"type"}, # attributes common to all subclasses
|
||||
# backwards compatibility for api 9.0 changes
|
||||
# tags: deprecated v22.2, bot api 9.0
|
||||
"BusinessConnection": {"can_reply"},
|
||||
"ChatFullInfo": {"can_send_gift"},
|
||||
"InputProfilePhoto": {"type"}, # attributes common to all subclasses
|
||||
}
|
||||
|
||||
@@ -210,11 +206,6 @@ IGNORED_PARAM_REQUIREMENTS = {
|
||||
"send_venue": {"latitude", "longitude", "title", "address"},
|
||||
"send_contact": {"phone_number", "first_name"},
|
||||
# ---->
|
||||
# backwards compatibility for api 9.0 changes
|
||||
# tags: deprecated v22.2, bot api 9.0
|
||||
"BusinessConnection": {"is_enabled"},
|
||||
"ChatFullInfo": {"accepted_gift_types"},
|
||||
"TransactionPartnerUser": {"transaction_type"},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ def is_parameter_required_by_tg(field: str) -> bool:
|
||||
def wrap_with_none(tg_parameter: "TelegramParameter", mapped_type: Any, obj: object) -> type:
|
||||
"""Adds `None` to type annotation if the parameter isn't required. Respects ignored params."""
|
||||
# have to import here to avoid circular imports
|
||||
from tests.test_official.exceptions import ignored_param_requirements
|
||||
from tests.test_official.exceptions import ignored_param_requirements # noqa: PLC0415
|
||||
|
||||
if tg_parameter.param_name in ignored_param_requirements(obj.__name__):
|
||||
return mapped_type | type(None)
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import datetime as dtm
|
||||
from collections.abc import Sequence
|
||||
from copy import deepcopy
|
||||
|
||||
import pytest
|
||||
@@ -96,6 +95,7 @@ class OwnedGiftTestBase:
|
||||
prepaid_upgrade_star_count = 200
|
||||
can_be_transferred = True
|
||||
transfer_star_count = 300
|
||||
next_transfer_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
|
||||
|
||||
|
||||
class TestOwnedGiftWithoutRequest(OwnedGiftTestBase):
|
||||
@@ -139,6 +139,7 @@ class TestOwnedGiftWithoutRequest(OwnedGiftTestBase):
|
||||
"prepaid_upgrade_star_count": self.prepaid_upgrade_star_count,
|
||||
"can_be_transferred": self.can_be_transferred,
|
||||
"transfer_star_count": self.transfer_star_count,
|
||||
"next_transfer_date": to_timestamp(self.next_transfer_date),
|
||||
}
|
||||
og = OwnedGift.de_json(json_dict, offline_bot)
|
||||
|
||||
@@ -292,6 +293,7 @@ def owned_gift_unique():
|
||||
is_saved=TestOwnedGiftUniqueWithoutRequest.is_saved,
|
||||
can_be_transferred=TestOwnedGiftUniqueWithoutRequest.can_be_transferred,
|
||||
transfer_star_count=TestOwnedGiftUniqueWithoutRequest.transfer_star_count,
|
||||
next_transfer_date=TestOwnedGiftUniqueWithoutRequest.next_transfer_date,
|
||||
)
|
||||
|
||||
|
||||
@@ -313,6 +315,7 @@ class TestOwnedGiftUniqueWithoutRequest(OwnedGiftTestBase):
|
||||
"is_saved": self.is_saved,
|
||||
"can_be_transferred": self.can_be_transferred,
|
||||
"transfer_star_count": self.transfer_star_count,
|
||||
"next_transfer_date": to_timestamp(self.next_transfer_date),
|
||||
}
|
||||
ogu = OwnedGiftUnique.de_json(json_dict, offline_bot)
|
||||
assert ogu.gift == self.unique_gift
|
||||
@@ -322,6 +325,7 @@ class TestOwnedGiftUniqueWithoutRequest(OwnedGiftTestBase):
|
||||
assert ogu.is_saved == self.is_saved
|
||||
assert ogu.can_be_transferred == self.can_be_transferred
|
||||
assert ogu.transfer_star_count == self.transfer_star_count
|
||||
assert ogu.next_transfer_date == self.next_transfer_date
|
||||
assert ogu.api_kwargs == {}
|
||||
|
||||
def test_to_dict(self, owned_gift_unique):
|
||||
@@ -335,6 +339,7 @@ class TestOwnedGiftUniqueWithoutRequest(OwnedGiftTestBase):
|
||||
assert json_dict["is_saved"] == self.is_saved
|
||||
assert json_dict["can_be_transferred"] == self.can_be_transferred
|
||||
assert json_dict["transfer_star_count"] == self.transfer_star_count
|
||||
assert json_dict["next_transfer_date"] == to_timestamp(self.next_transfer_date)
|
||||
|
||||
def test_equality(self, owned_gift_unique):
|
||||
a = owned_gift_unique
|
||||
@@ -365,7 +370,7 @@ def owned_gifts(request):
|
||||
class OwnedGiftsTestBase:
|
||||
total_count = 2
|
||||
next_offset = "next_offset_str"
|
||||
gifts: Sequence[OwnedGifts] = [
|
||||
gifts: list[OwnedGift] = [
|
||||
OwnedGiftRegular(
|
||||
gift=Gift(
|
||||
id="id1",
|
||||
|
||||
@@ -24,6 +24,8 @@ import pytest
|
||||
from telegram import (
|
||||
BotCommand,
|
||||
Chat,
|
||||
Checklist,
|
||||
ChecklistTask,
|
||||
ExternalReplyInfo,
|
||||
Giveaway,
|
||||
LinkPreviewOptions,
|
||||
@@ -47,6 +49,7 @@ def external_reply_info():
|
||||
link_preview_options=ExternalReplyInfoTestBase.link_preview_options,
|
||||
giveaway=ExternalReplyInfoTestBase.giveaway,
|
||||
paid_media=ExternalReplyInfoTestBase.paid_media,
|
||||
checklist=ExternalReplyInfoTestBase.checklist,
|
||||
)
|
||||
|
||||
|
||||
@@ -63,6 +66,13 @@ class ExternalReplyInfoTestBase:
|
||||
1,
|
||||
)
|
||||
paid_media = PaidMediaInfo(5, [PaidMediaPreview(10, 10, 10)])
|
||||
checklist = Checklist(
|
||||
title="Checklist Title",
|
||||
tasks=[
|
||||
ChecklistTask(text="Item 1", id=1),
|
||||
ChecklistTask(text="Item 2", id=2),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class TestExternalReplyInfoWithoutRequest(ExternalReplyInfoTestBase):
|
||||
@@ -81,6 +91,7 @@ class TestExternalReplyInfoWithoutRequest(ExternalReplyInfoTestBase):
|
||||
"link_preview_options": self.link_preview_options.to_dict(),
|
||||
"giveaway": self.giveaway.to_dict(),
|
||||
"paid_media": self.paid_media.to_dict(),
|
||||
"checklist": self.checklist.to_dict(),
|
||||
}
|
||||
|
||||
external_reply_info = ExternalReplyInfo.de_json(json_dict, offline_bot)
|
||||
@@ -92,6 +103,7 @@ class TestExternalReplyInfoWithoutRequest(ExternalReplyInfoTestBase):
|
||||
assert external_reply_info.link_preview_options == self.link_preview_options
|
||||
assert external_reply_info.giveaway == self.giveaway
|
||||
assert external_reply_info.paid_media == self.paid_media
|
||||
assert external_reply_info.checklist == self.checklist
|
||||
|
||||
def test_to_dict(self, external_reply_info):
|
||||
ext_reply_info_dict = external_reply_info.to_dict()
|
||||
@@ -103,6 +115,7 @@ class TestExternalReplyInfoWithoutRequest(ExternalReplyInfoTestBase):
|
||||
assert ext_reply_info_dict["link_preview_options"] == self.link_preview_options.to_dict()
|
||||
assert ext_reply_info_dict["giveaway"] == self.giveaway.to_dict()
|
||||
assert ext_reply_info_dict["paid_media"] == self.paid_media.to_dict()
|
||||
assert ext_reply_info_dict["checklist"] == self.checklist.to_dict()
|
||||
|
||||
def test_equality(self, external_reply_info):
|
||||
a = external_reply_info
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import datetime as dtm
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
@@ -29,6 +31,8 @@ from telegram import (
|
||||
UniqueGiftModel,
|
||||
UniqueGiftSymbol,
|
||||
)
|
||||
from telegram._utils.datetime import UTC, to_timestamp
|
||||
from telegram.constants import UniqueGiftInfoOrigin
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@@ -383,6 +387,8 @@ def unique_gift_info():
|
||||
origin=UniqueGiftInfoTestBase.origin,
|
||||
owned_gift_id=UniqueGiftInfoTestBase.owned_gift_id,
|
||||
transfer_star_count=UniqueGiftInfoTestBase.transfer_star_count,
|
||||
last_resale_star_count=UniqueGiftInfoTestBase.last_resale_star_count,
|
||||
next_transfer_date=UniqueGiftInfoTestBase.next_transfer_date,
|
||||
)
|
||||
|
||||
|
||||
@@ -410,6 +416,8 @@ class UniqueGiftInfoTestBase:
|
||||
origin = UniqueGiftInfo.UPGRADE
|
||||
owned_gift_id = "some_id"
|
||||
transfer_star_count = 10
|
||||
last_resale_star_count = 5
|
||||
next_transfer_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
|
||||
|
||||
|
||||
class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
|
||||
@@ -426,6 +434,8 @@ class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
|
||||
"origin": self.origin,
|
||||
"owned_gift_id": self.owned_gift_id,
|
||||
"transfer_star_count": self.transfer_star_count,
|
||||
"last_resale_star_count": self.last_resale_star_count,
|
||||
"next_transfer_date": to_timestamp(self.next_transfer_date),
|
||||
}
|
||||
unique_gift_info = UniqueGiftInfo.de_json(json_dict, offline_bot)
|
||||
assert unique_gift_info.api_kwargs == {}
|
||||
@@ -433,6 +443,32 @@ class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
|
||||
assert unique_gift_info.origin == self.origin
|
||||
assert unique_gift_info.owned_gift_id == self.owned_gift_id
|
||||
assert unique_gift_info.transfer_star_count == self.transfer_star_count
|
||||
assert unique_gift_info.last_resale_star_count == self.last_resale_star_count
|
||||
assert unique_gift_info.next_transfer_date == self.next_transfer_date
|
||||
|
||||
def test_de_json_localization(self, tz_bot, offline_bot, raw_bot):
|
||||
json_dict = {
|
||||
"gift": self.gift.to_dict(),
|
||||
"origin": self.origin,
|
||||
"owned_gift_id": self.owned_gift_id,
|
||||
"transfer_star_count": self.transfer_star_count,
|
||||
"last_resale_star_count": self.last_resale_star_count,
|
||||
"next_transfer_date": to_timestamp(self.next_transfer_date),
|
||||
}
|
||||
|
||||
unique_gift_info_raw = UniqueGiftInfo.de_json(json_dict, raw_bot)
|
||||
unique_gift_info_offline = UniqueGiftInfo.de_json(json_dict, offline_bot)
|
||||
unique_gift_info_tz = UniqueGiftInfo.de_json(json_dict, tz_bot)
|
||||
|
||||
# comparing utcoffsets because comparing timezones is unpredicatable
|
||||
unique_gift_info_tz_offset = unique_gift_info_tz.next_transfer_date.utcoffset()
|
||||
tz_bot_offset = tz_bot.defaults.tzinfo.utcoffset(
|
||||
unique_gift_info_tz.next_transfer_date.replace(tzinfo=None)
|
||||
)
|
||||
|
||||
assert unique_gift_info_raw.next_transfer_date.tzinfo == UTC
|
||||
assert unique_gift_info_offline.next_transfer_date.tzinfo == UTC
|
||||
assert unique_gift_info_tz_offset == tz_bot_offset
|
||||
|
||||
def test_to_dict(self, unique_gift_info):
|
||||
json_dict = unique_gift_info.to_dict()
|
||||
@@ -440,6 +476,12 @@ class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
|
||||
assert json_dict["origin"] == self.origin
|
||||
assert json_dict["owned_gift_id"] == self.owned_gift_id
|
||||
assert json_dict["transfer_star_count"] == self.transfer_star_count
|
||||
assert json_dict["last_resale_star_count"] == self.last_resale_star_count
|
||||
assert json_dict["next_transfer_date"] == to_timestamp(self.next_transfer_date)
|
||||
|
||||
def test_enum_type_conversion(self, unique_gift_info):
|
||||
assert type(unique_gift_info.origin) is UniqueGiftInfoOrigin
|
||||
assert unique_gift_info.origin == UniqueGiftInfoOrigin.UPGRADE
|
||||
|
||||
def test_equality(self, unique_gift_info):
|
||||
a = unique_gift_info
|
||||
|
||||
@@ -23,6 +23,7 @@ from copy import deepcopy
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
BusinessBotRights,
|
||||
BusinessConnection,
|
||||
BusinessMessagesDeleted,
|
||||
CallbackQuery,
|
||||
@@ -129,7 +130,7 @@ business_connection = BusinessConnection(
|
||||
1,
|
||||
from_timestamp(int(time.time())),
|
||||
True,
|
||||
True,
|
||||
rights=BusinessBotRights(can_reply=True),
|
||||
)
|
||||
|
||||
deleted_business_messages = BusinessMessagesDeleted(
|
||||
|
||||
Reference in New Issue
Block a user