Merge master and fix conflicts, and remove de_json's

This commit is contained in:
Harshil
2026-06-09 21:28:38 -04:00
136 changed files with 8103 additions and 463 deletions
+3
View File
@@ -26,6 +26,9 @@
// Enable automerge globally:
"automerge": true,
// Only upgrade packages if 7 days have passed:
"minimumReleaseAge": "7 days",
// Group package updates together:
"packageRules": [
// Linting dependencies in pyproject.toml in sync with the pre-commit-config hooks:
+2 -2
View File
@@ -31,10 +31,10 @@ jobs:
persist-credentials: false
- name: Install uv
uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
# Install a specific version of uv.
version: "0.10.10"
version: "0.11.16"
# Install 3.13:
python-version: 3.13
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
- name: Upload linkcheck output
# Run also if the previous steps failed
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: linkcheck-output
path: docs/build/html/output.*
+2 -2
View File
@@ -21,13 +21,13 @@ jobs:
with:
persist-credentials: false
- name: Install the latest version of uv
uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- 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@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
with:
sarif_file: results.sarif
category: zizmor
+3 -3
View File
@@ -30,7 +30,7 @@ jobs:
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: python-package-distributions
path: dist/
@@ -60,7 +60,7 @@ jobs:
name: python-package-distributions
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
compute-signatures:
name: Compute SHA1 Sums and Sign with Sigstore
@@ -92,7 +92,7 @@ jobs:
./dist/*.tar.gz
./dist/*.whl
- name: Store the distribution packages and signatures
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: python-package-distributions-and-signatures
path: dist/
+3 -3
View File
@@ -30,7 +30,7 @@ jobs:
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: python-package-distributions
path: dist/
@@ -60,7 +60,7 @@ jobs:
name: python-package-distributions
path: dist/
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
repository-url: https://test.pypi.org/legacy/
@@ -94,7 +94,7 @@ jobs:
./dist/*.tar.gz
./dist/*.whl
- name: Store the distribution packages and signatures
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: python-package-distributions-and-signatures
path: dist/
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
# For adding labels and closing
issues: write
steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
with:
# PRs never get stale
days-before-stale: 3
@@ -18,7 +18,7 @@ jobs:
python-version: 3.12
pyright-version: ~=1.1.367
- name: Check Output
uses: jannekem/run-python-script-action@bbfca66c612a28f3eeca0ae40e1f810265e2ea68 # v1.7
uses: jannekem/run-python-script-action@9d8e2e0878d575fb6073277f38ce3f10ebf4f059 # v1.8
env:
TYPE_COMPLETENESS: ${{ steps.pyright-type-completeness.outputs.base-completeness-score }}
with:
+3 -2
View File
@@ -87,15 +87,16 @@ jobs:
.test_report_optionals_junit.xml
- name: Submit coverage
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
env_vars: OS,PYTHON
name: ${{ matrix.os }}-${{ matrix.python-version }}
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload test results to Codecov
uses: codecov/test-results-action@0fa95f0e1eeaafde2c782583b36b28ad0d8c77d3 # v1.2.1
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
if: ${{ !cancelled() }}
with:
files: .test_report_no_optionals_junit.xml,.test_report_optionals_junit.xml
token: ${{ secrets.CODECOV_TOKEN }}
report_type: test_results
+2 -2
View File
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.15.6'
rev: 'v0.15.15'
hooks:
# Run the linter:
- id: ruff-check
@@ -23,7 +23,7 @@ repos:
- . # this basically does `pip install -e .`
priority: 10
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.19.1
rev: v1.20.2
hooks:
- id: mypy
name: mypy-ptb
+2
View File
@@ -75,10 +75,12 @@ The following wonderful people contributed directly or indirectly to this projec
- `jossalgon <https://github.com/jossalgon>`_
- `JRoot3D <https://github.com/JRoot3D>`_
- `Juan Cuevas <https://github.com/cuevasrja>`
- `karin0 <https://github.com/karin0>`_
- `kenjitagawa <https://github.com/kenjitagawa>`_
- `kennethcheo <https://github.com/kennethcheo>`_
- `Kirill Vasin <https://github.com/vasinkd>`_
- `Kjwon15 <https://github.com/kjwon15>`_
- `Krishna Chaitanya Balusu <https://github.com/Krishnachaitanyakc>`_
- `Li-aung Yip <https://github.com/LiaungYip>`_
- `locobott <https://github.com/locobott>`_
- `Loo Zheng Yuan <https://github.com/loozhengyuan>`_
+2 -2
View File
@@ -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.5-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-10.0-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API version
@@ -77,7 +77,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.5** are natively supported by this library.
All types and methods of the Telegram Bot API **10.0** 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
+5
View File
@@ -0,0 +1,5 @@
bugfixes = "Fixed incorrect isinstance check in class telegram.ext.filters._MergedFilter for or_filter."
[[pull_requests]]
uid = "5125"
author_uids = ["gistrec"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.7"
[[pull_requests]]
uid = "5177"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Migrate from deprecated test-results-action to codecov-action"
[[pull_requests]]
uid = "5183"
author_uids = ["Krishnachaitanyakc"]
closes_threads = ["5158"]
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.8"
[[pull_requests]]
uid = "5184"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
dependencies = "Update dependency cryptography to v46.0.6 [SECURITY]"
[[pull_requests]]
uid = "5185"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
other = "Update codecov/codecov-action action to v5.5.4"
[[pull_requests]]
uid = "5190"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update astral-sh/setup-uv action to v7.6.0"
[[pull_requests]]
uid = "5191"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update dependency astral-sh/uv to v0.11.2"
[[pull_requests]]
uid = "5192"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update dependency mypy to v1.20.0"
[[pull_requests]]
uid = "5193"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update github/codeql-action action to v4.35.1"
[[pull_requests]]
uid = "5194"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,24 @@
features = """
Full Support for Bot API 9.6
.. warning::
- Bot API 9.6 replaces the field ``correct_option_id`` of ``Poll`` with the new field ``correct_option_ids``. The field ``correct_option_id`` is still present in PTB for backward compatibility, but it will be removed in future releases.
- Bot API 9.6 replaces the argument ``correct_option_id`` of ``Bot.send_poll`` with the new argument ``correct_option_ids``. The argument ``correct_option_id`` is still present in PTB for backward compatibility, but it will be removed in future releases.
- Bot API 9.6 introduces a now required argument ``persistent_id`` to ``PollOption``. For backward compatibility, the argument is currently still marked as optional in the signature and its presence is enforced through a runtime check. In future versions, this argument will be made required in the signature as well.
- Bot API 9.6 introduces a now required argument ``option_persistent_ids`` to ``PollAnswer``. For backward compatibility, the argument is currently still marked as optional in the signature and its presence is enforced through a runtime check. In future versions, this argument will be made required in the signature as well.
- Bot API 9.6 introduces a now required argument ``allows_revoting`` to ``Poll``. For backward compatibility, the argument is currently still marked as optional in the signature and its presence is enforced through a runtime check. In future versions, this argument will be made required in the signature as well.
Please make sure to update your code accordingly to avoid potential issues in the future. We recommend using keyword arguments to ensure compatibility with future updates.
"""
pull_requests = [
{ uid = "5196", author_uid = "harshil21" },
{ uid = "5202", author_uid = "ouyooung" },
{ uid = "5197", author_uid = "harshil21" },
]
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.9"
[[pull_requests]]
uid = "5198"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update Mypy to v1.20.1"
[[pull_requests]]
uid = "5199"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
dependencies = "Update dependency cryptography to v46.0.7 [SECURITY]"
[[pull_requests]]
uid = "5203"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.10"
[[pull_requests]]
uid = "5205"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update dependency pytest to v9.0.3 [SECURITY]"
[[pull_requests]]
uid = "5206"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.11"
[[pull_requests]]
uid = "5209"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.12"
[[pull_requests]]
uid = "5217"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update actions/upload-artifact action to v7.0.1"
[[pull_requests]]
uid = "5220"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update dependency astral-sh/uv to v0.11.8"
[[pull_requests]]
uid = "5221"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update github/codeql-action action to v4.35.2"
[[pull_requests]]
uid = "5222"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update Mypy to v1.20.2"
[[pull_requests]]
uid = "5223"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update jannekem/run-python-script-action action to v1.8"
[[pull_requests]]
uid = "5224"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,33 @@
features = """
Full Support for Bot API 10.0
.. warning::
- Bot API 10.0 introduces a now required argument ``members_only`` to ``Poll``. For backward compatibility, the argument is currently still marked as optional in the signature and its presence is enforced through a runtime check. In future versions, this argument will be made required in the signature as well.
Please make sure to update your code accordingly to avoid potential issues in the future. We recommend using keyword arguments to ensure compatibility with future updates.
"""
deprecations = """
* Deprecated passing the ``filename`` parameter positionally to the classes:
* ``InputMediaAnimation``
* ``InputMediaAudio``
* ``InputMediaPhoto``
* ``InputMediaDocument``
* ``InputMediaVideo``
Please pass ``filename`` as a keyword argument instead, as this parameter will become keyword-only in the future.
* Deprecated ``InputPollOption.de_json``. The class ``InputPollOption`` is input only and its ``de_json`` method will be removed in future versions. The Bot API 10.0 ``media`` field of ``InputPollOption`` will not be included for deserialization.
"""
pull_requests = [
{ uid = "5229", author_uid = "aelkheir", closes_threads = ["5228"] },
{ uid = "5230", author_uid = "harshil21" },
{ uid = "5235", author_uid = "harshil21" },
{ uid = "5238", author_uid = "harshil21" },
{ uid = "5232", author_uid = "aelkheir" },
{ uid = "5232", author_uid = ["Poolitzer", "Phil9l", "harshil21", "aelkheir"] },
]
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.13"
[[pull_requests]]
uid = "5233"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
bugfixes = "`Update.effective_user` now checks for `channel_post` and `edited_channel_post`"
[[pull_requests]]
uid = "5237"
author_uids = ["karin0"]
closes_threads = ["5236"]
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.14"
[[pull_requests]]
uid = "5245"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
security = "Disallow packages newer than last 7 days"
[[pull_requests]]
uid = "5247"
author_uids = ["harshil21"]
closes_threads = ["5195"]
@@ -0,0 +1,5 @@
other = "Make instantiation of ``TelegramObject``'s 15% faster"
[[pull_requests]]
uid = "5250"
author_uids = ["harshil21"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.15"
[[pull_requests]]
uid = "5252"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update dependency astral-sh/uv to v0.11.16"
[[pull_requests]]
uid = "5253"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update dependency sphinxcontrib-mermaid to v2.0.2"
[[pull_requests]]
uid = "5254"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update actions/stale action to v10.3.0"
[[pull_requests]]
uid = "5255"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update github/codeql-action action to v4.36.0"
[[pull_requests]]
uid = "5256"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update pypa/gh-action-pypi-publish action to v1.14.0"
[[pull_requests]]
uid = "5257"
author_uids = ["renovate[bot]"]
closes_threads = []
+1
View File
@@ -52,6 +52,7 @@ PRIVATE_BASE_CLASSES = {
"_BaseMedium": "TelegramObject",
"_CredentialsBase": "TelegramObject",
"_ChatBase": "TelegramObject",
"_BaseInputMedia": "TelegramObject",
}
+21
View File
@@ -41,6 +41,8 @@
- Used for sending paid media to channels
* - :meth:`~telegram.Bot.send_photo`
- Used for sending photos
* - :meth:`~telegram.Bot.send_live_photo`
- Used for sending live photos
* - :meth:`~telegram.Bot.send_poll`
- Used for sending polls
* - :meth:`~telegram.Bot.send_sticker`
@@ -80,6 +82,8 @@
- Used for answering the callback query
* - :meth:`~telegram.Bot.answer_inline_query`
- Used for answering the inline query
* - :meth:`~telegram.Bot.answer_guest_query`
- Used for replying to a received guest message
* - :meth:`~telegram.Bot.answer_pre_checkout_query`
- Used for answering a pre checkout query
* - :meth:`~telegram.Bot.answer_shipping_query`
@@ -104,6 +108,10 @@
- Used for stopping the running poll
* - :meth:`~telegram.Bot.set_message_reaction`
- Used for setting reactions on messages
* - :meth:`~telegram.Bot.delete_message_reaction`
- Used for deleting reactions on messages
* - :meth:`~telegram.Bot.delete_all_message_reactions`
- Used for deleting all reactions by a chat or user
.. raw:: html
@@ -167,6 +175,8 @@
- Used for unpinning a message
* - :meth:`~telegram.Bot.unpin_all_chat_messages`
- Used for unpinning all pinned chat messages
* - :meth:`~telegram.Bot.get_user_personal_chat_messages`
- Used for obtaining the personal chat messages of a user
* - :meth:`~telegram.Bot.get_user_profile_audios`
- Used for obtaining user's profile audios
* - :meth:`~telegram.Bot.get_user_profile_photos`
@@ -237,6 +247,10 @@
- Used for obtaining the menu button of a private chat or the default menu button
* - :meth:`~telegram.Bot.set_chat_menu_button`
- Used for setting the menu button of a private chat or the default menu button
* - :meth:`~telegram.Bot.set_managed_bot_access_settings`
- Used for changing the access settings of a managed bot
* - :meth:`~telegram.Bot.get_managed_bot_access_settings`
- Used for obtaining the access settings of a managed bot
* - :meth:`~telegram.Bot.set_my_description`
- Used for setting the description of the bot
* - :meth:`~telegram.Bot.get_my_description`
@@ -496,12 +510,19 @@
- Used for getting information about gifts available for sending
* - :meth:`~telegram.Bot.get_chat_gifts`
- Used for getting information about gifts owned and hosted by a chat
* - :meth:`~telegram.Bot.get_managed_bot_token`
- Used for getting the token of a managed bot
* - :meth:`~telegram.Bot.replace_managed_bot_token`
- Used for replacing the token of a managed bot
* - :meth:`~telegram.Bot.get_me`
- Used for getting basic information about the bot
* - :meth:`~telegram.Bot.get_user_gifts`
- Used for getting information about gifts owned and hosted by a user
* - :meth:`~telegram.Bot.save_prepared_inline_message`
- Used for storing a message to be sent by a user of a Mini App
* - :meth:`~telegram.Bot.save_prepared_keyboard_button`
- Used for saving a keyboard button to be used in a Mini App
.. raw:: html
+18 -1
View File
@@ -8,6 +8,7 @@ Available Types
telegram.animation
telegram.audio
telegram.birthdate
telegram.botaccesssettings
telegram.botcommand
telegram.botcommandscope
telegram.botcommandscopeallchatadministrators
@@ -101,26 +102,37 @@ Available Types
telegram.inputmediaanimation
telegram.inputmediaaudio
telegram.inputmediadocument
telegram.inputmedialivephoto
telegram.inputmedialocation
telegram.inputmediaphoto
telegram.inputmediasticker
telegram.inputmediavenue
telegram.inputmediavideo
telegram.inputpaidmedia
telegram.inputpaidmedialivephoto
telegram.inputpaidmediaphoto
telegram.inputpaidmediavideo
telegram.inputpollmedia
telegram.inputprofilephoto
telegram.inputprofilephotoanimated
telegram.inputprofilephotostatic
telegram.inputpolloption
telegram.inputpolloptionmedia
telegram.inputstorycontent
telegram.inputstorycontentphoto
telegram.inputstorycontentvideo
telegram.keyboardbutton
telegram.keyboardbuttonpolltype
telegram.keyboardbuttonrequestchat
telegram.keyboardbuttonrequestmanagedbot
telegram.keyboardbuttonrequestusers
telegram.linkpreviewoptions
telegram.livephoto
telegram.location
telegram.locationaddress
telegram.loginurl
telegram.managedbotcreated
telegram.managedbotupdated
telegram.maybeinaccessiblemessage
telegram.menubutton
telegram.menubuttoncommands
@@ -143,6 +155,7 @@ Available Types
telegram.ownedgiftunique
telegram.paidmedia
telegram.paidmediainfo
telegram.paidmedialivephoto
telegram.paidmediaphoto
telegram.paidmediapreview
telegram.paidmediapurchased
@@ -151,7 +164,10 @@ Available Types
telegram.photosize
telegram.poll
telegram.pollanswer
telegram.polloption
telegram.pollmedia
telegram.polloptionadded
telegram.polloptiondeleted
telegram.preparedkeyboardbutton
telegram.proximityalerttriggered
telegram.reactioncount
telegram.reactiontype
@@ -161,6 +177,7 @@ Available Types
telegram.replykeyboardmarkup
telegram.replykeyboardremove
telegram.replyparameters
telegram.sentguestmessage
telegram.sentwebappmessage
telegram.shareduser
telegram.story
@@ -0,0 +1,6 @@
BotAccessSettings
=================
.. autoclass:: telegram.BotAccessSettings
:members:
:show-inheritance:
@@ -16,6 +16,7 @@ Handlers
telegram.ext.conversationhandler
telegram.ext.filters
telegram.ext.inlinequeryhandler
telegram.ext.managedbotupdatedhandler
telegram.ext.messagehandler
telegram.ext.messagereactionhandler
telegram.ext.paidmediapurchasedhandler
@@ -0,0 +1,6 @@
ManagedBotUpdatedHandler
========================
.. autoclass:: telegram.ext.ManagedBotUpdatedHandler
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputMediaLivePhoto
===================
.. autoclass:: telegram.InputMediaLivePhoto
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputMediaLocation
==================
.. autoclass:: telegram.InputMediaLocation
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputMediaSticker
=================
.. autoclass:: telegram.InputMediaSticker
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
InputMediaVenue
===============
.. autoclass:: telegram.InputMediaVenue
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputPaidMediaLivePhoto
======================
.. autoclass:: telegram.InputPaidMediaLivePhoto
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
InputPollMedia
==============
.. versionadded:: NEXT.VERSION
.. autoclass:: telegram.InputPollMedia
@@ -0,0 +1,6 @@
InputPollOptionMedia
====================
.. versionadded:: NEXT.VERSION
.. autoclass:: telegram.InputPollOptionMedia
@@ -0,0 +1,6 @@
KeyboardButtonRequestManagedBot
===============================
.. autoclass:: telegram.KeyboardButtonRequestManagedBot
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
LivePhoto
=========
.. autoclass:: telegram.LivePhoto
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
ManagedBotCreated
=================
.. autoclass:: telegram.ManagedBotCreated
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
ManagedBotUpdated
=================
.. autoclass:: telegram.ManagedBotUpdated
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
PaidMediaLivePhoto
==================
.. autoclass:: telegram.PaidMediaLivePhoto
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
PollMedia
=========
.. autoclass:: telegram.PollMedia
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
PollOptionAdded
===============
.. autoclass:: telegram.PollOptionAdded
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
PollOptionDeleted
=================
.. autoclass:: telegram.PollOptionDeleted
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
PreparedKeyboardButton
======================
.. autoclass:: telegram.PreparedKeyboardButton
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
SentGuestMessage
================
.. autoclass:: telegram.SentGuestMessage
:members:
:show-inheritance:
+8 -4
View File
@@ -98,7 +98,7 @@ tests = [
# required for building the wheels for releases
"build",
# For the test suite
"pytest==9.0.2",
"pytest==9.0.3",
# needed because pytest doesn't come with native support for coroutines as tests
"pytest-asyncio==0.21.2",
# xdist runs tests in parallel
@@ -120,7 +120,7 @@ docs = [
"sphinx==9.1.0; python_version >= '3.12'",
"furo==2025.12.19",
"sphinx-paramlinks==0.6.0",
"sphinxcontrib-mermaid==2.0.1",
"sphinxcontrib-mermaid==2.0.2",
"sphinx-copybutton==0.5.2",
"sphinx-inline-tabs==2025.12.21.14",
# Temporary. See #4387
@@ -133,8 +133,8 @@ docs = [
]
linting = [
"prek",
"ruff==0.15.6",
"mypy==1.19.1",
"ruff==0.15.15",
"mypy==1.20.2",
"pylint==4.0.5"
]
all = [{ include-group = "tests" }, { include-group = "docs" }, { include-group = "linting"}]
@@ -153,6 +153,10 @@ exclude = [".venv*", "venv*", ".github", "uv.lock"]
[tool.hatch.build.targets.wheel]
packages = ["src/telegram"]
# uv
[tool.uv]
exclude-newer = "7 days"
# CHANGO
[tool.chango]
sys_path = "changes"
+45 -2
View File
@@ -35,6 +35,7 @@ __all__ = (
"BackgroundTypeWallpaper",
"Birthdate",
"Bot",
"BotAccessSettings",
"BotCommand",
"BotCommandScope",
"BotCommandScopeAllChatAdministrators",
@@ -157,13 +158,20 @@ __all__ = (
"InputMediaAnimation",
"InputMediaAudio",
"InputMediaDocument",
"InputMediaLivePhoto",
"InputMediaLocation",
"InputMediaPhoto",
"InputMediaSticker",
"InputMediaVenue",
"InputMediaVideo",
"InputMessageContent",
"InputPaidMedia",
"InputPaidMediaLivePhoto",
"InputPaidMediaPhoto",
"InputPaidMediaVideo",
"InputPollMedia",
"InputPollOption",
"InputPollOptionMedia",
"InputProfilePhoto",
"InputProfilePhotoAnimated",
"InputProfilePhotoStatic",
@@ -177,12 +185,16 @@ __all__ = (
"KeyboardButton",
"KeyboardButtonPollType",
"KeyboardButtonRequestChat",
"KeyboardButtonRequestManagedBot",
"KeyboardButtonRequestUsers",
"LabeledPrice",
"LinkPreviewOptions",
"LivePhoto",
"Location",
"LocationAddress",
"LoginUrl",
"ManagedBotCreated",
"ManagedBotUpdated",
"MaskPosition",
"MaybeInaccessibleMessage",
"MenuButton",
@@ -207,6 +219,7 @@ __all__ = (
"OwnedGifts",
"PaidMedia",
"PaidMediaInfo",
"PaidMediaLivePhoto",
"PaidMediaPhoto",
"PaidMediaPreview",
"PaidMediaPurchased",
@@ -228,9 +241,13 @@ __all__ = (
"PhotoSize",
"Poll",
"PollAnswer",
"PollMedia",
"PollOption",
"PollOptionAdded",
"PollOptionDeleted",
"PreCheckoutQuery",
"PreparedInlineMessage",
"PreparedKeyboardButton",
"ProximityAlertTriggered",
"ReactionCount",
"ReactionType",
@@ -248,6 +265,7 @@ __all__ = (
"RevenueWithdrawalStateSucceeded",
"SecureData",
"SecureValue",
"SentGuestMessage",
"SentWebAppMessage",
"SharedUser",
"ShippingAddress",
@@ -342,6 +360,7 @@ from telegram._payment.stars.transactionpartner import (
from . import _version, constants, error, helpers, request, warnings
from ._birthdate import Birthdate
from ._bot import Bot
from ._botaccesssettings import BotAccessSettings
from ._botcommand import BotCommand
from ._botcommandscope import (
BotCommandScope,
@@ -429,11 +448,18 @@ from ._files.inputmedia import (
InputMediaAnimation,
InputMediaAudio,
InputMediaDocument,
InputMediaLivePhoto,
InputMediaLocation,
InputMediaPhoto,
InputMediaSticker,
InputMediaVenue,
InputMediaVideo,
InputPaidMedia,
InputPaidMediaLivePhoto,
InputPaidMediaPhoto,
InputPaidMediaVideo,
InputPollMedia,
InputPollOptionMedia,
)
from ._files.inputprofilephoto import (
InputProfilePhoto,
@@ -441,6 +467,7 @@ from ._files.inputprofilephoto import (
InputProfilePhotoStatic,
)
from ._files.inputsticker import InputSticker
from ._files.livephoto import LivePhoto
from ._files.location import Location
from ._files.photosize import PhotoSize
from ._files.sticker import MaskPosition, Sticker, StickerSet
@@ -498,9 +525,14 @@ from ._inline.inputvenuemessagecontent import InputVenueMessageContent
from ._inline.preparedinlinemessage import PreparedInlineMessage
from ._keyboardbutton import KeyboardButton
from ._keyboardbuttonpolltype import KeyboardButtonPollType
from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
from ._keyboardbuttonrequest import (
KeyboardButtonRequestChat,
KeyboardButtonRequestManagedBot,
KeyboardButtonRequestUsers,
)
from ._linkpreviewoptions import LinkPreviewOptions
from ._loginurl import LoginUrl
from ._managedbot import ManagedBotCreated, ManagedBotUpdated
from ._menubutton import MenuButton, MenuButtonCommands, MenuButtonDefault, MenuButtonWebApp
from ._message import InaccessibleMessage, MaybeInaccessibleMessage, Message
from ._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
@@ -518,6 +550,7 @@ from ._ownedgift import OwnedGift, OwnedGiftRegular, OwnedGifts, OwnedGiftUnique
from ._paidmedia import (
PaidMedia,
PaidMediaInfo,
PaidMediaLivePhoto,
PaidMediaPhoto,
PaidMediaPreview,
PaidMediaPurchased,
@@ -564,7 +597,16 @@ from ._payment.stars.revenuewithdrawalstate import (
RevenueWithdrawalStateSucceeded,
)
from ._payment.successfulpayment import SuccessfulPayment
from ._poll import InputPollOption, Poll, PollAnswer, PollOption
from ._poll import (
InputPollOption,
Poll,
PollAnswer,
PollMedia,
PollOption,
PollOptionAdded,
PollOptionDeleted,
)
from ._preparedkeyboardbutton import PreparedKeyboardButton
from ._proximityalerttriggered import ProximityAlertTriggered
from ._reaction import (
ReactionCount,
@@ -576,6 +618,7 @@ from ._reaction import (
from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
from ._replykeyboardmarkup import ReplyKeyboardMarkup
from ._replykeyboardremove import ReplyKeyboardRemove
from ._sentguestmessage import SentGuestMessage
from ._sentwebappmessage import SentWebAppMessage
from ._shared import ChatShared, SharedUser, UsersShared
from ._story import Story
+736 -61
View File
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2026
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Bot Access Settings."""
from collections.abc import Sequence
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
class BotAccessSettings(TelegramObject):
"""
This object describes the access settings of a bot.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`is_access_restricted` and :attr:`added_users` are equal.
.. versionadded:: NEXT.VERSION
Args:
is_access_restricted (:obj:`bool`): :obj:`True`, if only selected users can access the bot.
The bot's owner can always access it.
added_users (Sequence[:class:`telegram.User`], optional): The list of other users who
have access to the bot if the access is restricted.
Attributes:
is_access_restricted (:obj:`bool`): :obj:`True`, if only selected users can access the bot.
The bot's owner can always access it.
added_users (Sequence[:class:`telegram.User`]): Optional. The list of other users who
have access to the bot if the access is restricted.
"""
__slots__ = ("added_users", "is_access_restricted")
def __init__(
self,
is_access_restricted: bool,
added_users: Sequence[User] | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
self.is_access_restricted: bool = is_access_restricted
self.added_users: tuple[User, ...] = parse_sequence_arg(added_users)
self._id_attrs = (self.is_access_restricted, self.added_users)
self._freeze()
+181 -2
View File
@@ -34,6 +34,7 @@ from telegram._utils import enum
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import (
CorrectOptionID,
CorrectOptionIds,
FileInput,
JSONDict,
ODVInput,
@@ -57,12 +58,15 @@ if TYPE_CHECKING:
InputChecklist,
InputMediaAudio,
InputMediaDocument,
InputMediaLivePhoto,
InputMediaPhoto,
InputMediaVideo,
InputPaidMedia,
InputPollMedia,
InputPollOption,
LabeledPrice,
LinkPreviewOptions,
LivePhoto,
Location,
Message,
MessageEntity,
@@ -310,6 +314,7 @@ class _ChatBase(TelegramObject):
async def get_administrators(
self,
return_bots: bool | None = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -333,6 +338,7 @@ class _ChatBase(TelegramObject):
"""
return await self.get_bot().get_chat_administrators(
chat_id=self.id,
return_bots=return_bots,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
@@ -1087,7 +1093,7 @@ class _ChatBase(TelegramObject):
async def send_message_draft(
self,
draft_id: int,
text: str,
text: str | None = None,
message_thread_id: int | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
entities: Sequence["MessageEntity"] | None = None,
@@ -1104,6 +1110,9 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_message_draft`.
.. versionchanged:: NEXT.VERSION
Bot API 10.0 makes the ``text`` argument optional.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -1189,7 +1198,7 @@ class _ChatBase(TelegramObject):
async def send_media_group(
self,
media: Sequence[
"InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo"
"InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo | InputMediaLivePhoto" # noqa: E501 # pylint: disable=line-too-long
],
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
@@ -1348,6 +1357,76 @@ class _ChatBase(TelegramObject):
suggested_post_parameters=suggested_post_parameters,
)
async def send_live_photo(
self,
live_photo: "FileInput | LivePhoto",
photo: "FileInput | PhotoSize",
business_connection_id: str | None = None,
message_thread_id: int | None = None,
direct_messages_topic_id: int | None = None,
caption: str | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence["MessageEntity"] | None = None,
show_caption_above_media: bool | None = None,
has_spoiler: bool | None = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
allow_paid_broadcast: bool | None = None,
message_effect_id: str | None = None,
suggested_post_parameters: "SuggestedPostParameters | None" = None,
reply_parameters: "ReplyParameters | None" = None,
reply_markup: "ReplyMarkup | None" = None,
*,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int | None = None,
filename: str | None = 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: JSONDict | None = None,
) -> "Message":
"""Shortcut for::
await bot.send_live_photo(update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see :meth:`telegram.Bot.send_live_photo`.
.. versionadded:: NEXT.VERSION
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
return await self.get_bot().send_live_photo(
chat_id=self.id,
live_photo=live_photo,
photo=photo,
business_connection_id=business_connection_id,
message_thread_id=message_thread_id,
direct_messages_topic_id=direct_messages_topic_id,
caption=caption,
parse_mode=parse_mode,
caption_entities=caption_entities,
show_caption_above_media=show_caption_above_media,
has_spoiler=has_spoiler,
disable_notification=disable_notification,
protect_content=protect_content,
allow_paid_broadcast=allow_paid_broadcast,
message_effect_id=message_effect_id,
suggested_post_parameters=suggested_post_parameters,
reply_parameters=reply_parameters,
reply_markup=reply_markup,
allow_sending_without_reply=allow_sending_without_reply,
reply_to_message_id=reply_to_message_id,
filename=filename,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def send_contact(
self,
phone_number: str | None = None,
@@ -2296,6 +2375,18 @@ class _ChatBase(TelegramObject):
question_entities: Sequence["MessageEntity"] | None = None,
message_effect_id: str | None = None,
allow_paid_broadcast: bool | None = None,
shuffle_options: bool | None = None,
allows_revoting: bool | None = None,
correct_option_ids: CorrectOptionIds | None = None,
allow_adding_options: bool | None = None,
hide_results_until_closes: bool | None = None,
description: str | None = None,
description_parse_mode: ODVInput[str] | None = None,
description_entities: Sequence["MessageEntity"] | None = None,
members_only: bool | None = None,
country_codes: Sequence[str] | None = None,
explanation_media: "InputPollMedia | None" = None,
media: "InputPollMedia | None" = None,
*,
reply_to_message_id: int | None = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
@@ -2323,6 +2414,9 @@ class _ChatBase(TelegramObject):
type=type, # pylint=pylint,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
correct_option_ids=correct_option_ids,
is_closed=is_closed,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
@@ -2346,6 +2440,15 @@ class _ChatBase(TelegramObject):
business_connection_id=business_connection_id,
question_parse_mode=question_parse_mode,
question_entities=question_entities,
description=description,
description_parse_mode=description_parse_mode,
description_entities=description_entities,
hide_results_until_closes=hide_results_until_closes,
allow_adding_options=allow_adding_options,
members_only=members_only,
country_codes=country_codes,
explanation_media=explanation_media,
media=media,
)
async def send_copy(
@@ -4032,6 +4135,82 @@ class _ChatBase(TelegramObject):
api_kwargs=api_kwargs,
)
async def delete_reaction(
self,
message_id: int,
user_id: int | None = None,
actor_chat_id: int | None = 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: JSONDict | None = None,
) -> bool:
"""
Shortcut for::
await bot.delete_message_reaction(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_message_reaction`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().delete_message_reaction(
chat_id=self.id,
message_id=message_id,
user_id=user_id,
actor_chat_id=actor_chat_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def delete_all_reactions(
self,
user_id: int | None = None,
actor_chat_id: int | None = 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: JSONDict | None = None,
) -> bool:
"""
Shortcut for::
await bot.delete_all_message_reactions(
chat_id=update.effective_chat.id,
*args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_all_message_reactions`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().delete_all_message_reactions(
chat_id=self.id,
user_id=user_id,
actor_chat_id=actor_chat_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
class Chat(_ChatBase):
"""This object represents a chat.
+1 -1
View File
@@ -241,7 +241,7 @@ class ChatFullInfo(_ChatBase):
.. versionadded:: 22.6
paid_message_star_count (:obj:`int`, optional): The number of Telegram Stars a general user
have to pay to send a message to the chat
has to pay to send a message to the chat
.. versionadded:: 22.6
first_profile_audio (:obj:`telegram.Audio`, optional): For private chats, the first audio
+19
View File
@@ -490,8 +490,13 @@ class ChatMemberRestricted(ChatMember):
.. versionadded:: 20.1
can_edit_tag (:obj:`bool`): :obj:`True`, if the user is allowed to edit their own tag.
If omitted, defaults to the value of :attr:`can_pin_messages`.
.. versionadded:: 22.7
can_react_to_messages (:obj:`bool`): :obj:`True`, if the user is allowed to react to
messages.
.. versionadded:: NEXT.VERSION
tag (:obj:`str`, optional): Tag of the member.
.. versionadded:: 22.7
@@ -546,8 +551,13 @@ class ChatMemberRestricted(ChatMember):
.. versionadded:: 20.1
can_edit_tag (:obj:`bool`): :obj:`True`, if the user is allowed to edit their own tag.
If omitted, defaults to the value of :attr:`can_pin_messages`.
.. versionadded:: 22.7
can_react_to_messages (:obj:`bool`): :obj:`True`, if the user is allowed to react to
messages.
.. versionadded:: NEXT.VERSION
tag (:obj:`str`): Optional. Tag of the member.
.. versionadded:: 22.7
@@ -561,6 +571,7 @@ class ChatMemberRestricted(ChatMember):
"can_invite_users",
"can_manage_topics",
"can_pin_messages",
"can_react_to_messages",
"can_send_audios",
"can_send_documents",
"can_send_messages",
@@ -598,10 +609,17 @@ class ChatMemberRestricted(ChatMember):
can_send_voice_notes: bool,
can_edit_tag: bool,
tag: str | None = None,
# tags: NEXT.VERSION
# temporarily optional to make it not breaking
can_react_to_messages: bool | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(status=ChatMember.RESTRICTED, user=user, api_kwargs=api_kwargs)
if can_react_to_messages is None:
raise TypeError("`can_react_to_messages` is required and cannot be None")
with self._unfrozen():
self.is_member: bool = is_member
self.can_change_info: bool = can_change_info
@@ -620,6 +638,7 @@ class ChatMemberRestricted(ChatMember):
self.can_send_video_notes: bool = can_send_video_notes
self.can_send_voice_notes: bool = can_send_voice_notes
self.can_edit_tag: bool = can_edit_tag
self.can_react_to_messages: bool = can_react_to_messages
self.tag: str | None = tag
+2 -2
View File
@@ -64,11 +64,11 @@ class ChatOwnerLeft(TelegramObject):
.. versionadded:: 22.7
Args:
new_owner (:class:`telegram.User`, optional): The user which will be the new owner of the
new_owner (:class:`telegram.User`, optional): The user who will become the new owner of the
chat if the previous owner does not return to the chat
Attributes:
new_owner (:class:`telegram.User`): Optional. The user which will be the new owner of the
new_owner (:class:`telegram.User`): Optional. The user who will become the new owner of the
chat if the previous owner does not return to the chat
"""
+16 -1
View File
@@ -31,7 +31,7 @@ class ChatPermissions(TelegramObject):
:attr:`can_change_info`, :attr:`can_invite_users`, :attr:`can_pin_messages`,
:attr:`can_send_audios`, :attr:`can_send_documents`, :attr:`can_send_photos`,
:attr:`can_send_videos`, :attr:`can_send_video_notes`, :attr:`can_send_voice_notes`,
:attr:`can_manage_topics` and :attr:`can_edit_tag` are equal.
:attr:`can_manage_topics`, :attr:`can_edit_tag`, and :attr:`can_react_to_messages` are equal.
.. versionchanged:: 20.0
:attr:`can_manage_topics` is considered as well when comparing objects of
@@ -45,6 +45,9 @@ class ChatPermissions(TelegramObject):
.. versionchanged:: 22.7
:attr:`can_edit_tag` is considered as well when comparing objects of
this type in terms of equality.
.. versionchanged:: NEXT.VERSION
:attr:`can_react_to_messages` is considered as well when comparing objects of
this type in terms of equality.
Note:
@@ -95,6 +98,10 @@ class ChatPermissions(TelegramObject):
tag.
.. versionadded:: 22.7
can_react_to_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to react
to messages. If omitted, defaults to the value of :attr:`can_send_messages`.
.. versionadded:: NEXT.VERSION
Attributes:
can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text
@@ -140,6 +147,10 @@ class ChatPermissions(TelegramObject):
tag.
.. versionadded:: 22.7
can_react_to_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to react
to messages. If omitted, defaults to the value of :attr:`can_send_messages`.
.. versionadded:: NEXT.VERSION
"""
@@ -150,6 +161,7 @@ class ChatPermissions(TelegramObject):
"can_invite_users",
"can_manage_topics",
"can_pin_messages",
"can_react_to_messages",
"can_send_audios",
"can_send_documents",
"can_send_messages",
@@ -184,6 +196,7 @@ class ChatPermissions(TelegramObject):
can_send_video_notes: bool | None = None,
can_send_voice_notes: bool | None = None,
can_edit_tag: bool | None = None,
can_react_to_messages: bool | None = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -204,6 +217,7 @@ class ChatPermissions(TelegramObject):
self.can_send_video_notes: bool | None = can_send_video_notes
self.can_send_voice_notes: bool | None = can_send_voice_notes
self.can_edit_tag: bool | None = can_edit_tag
self.can_react_to_messages: bool | None = can_react_to_messages
self._id_attrs = (
self.can_send_messages,
@@ -221,6 +235,7 @@ class ChatPermissions(TelegramObject):
self.can_send_video_notes,
self.can_send_voice_notes,
self.can_edit_tag,
self.can_react_to_messages,
)
self._freeze()
+528 -55
View File
@@ -16,7 +16,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/].
"""Base class for Telegram InputMedia Objects."""
"""Base classes for Telegram InputMedia, InputPaidMedia, InputPollMedia
and InputPollOptionMedia Objects."""
import datetime as dtm
from collections.abc import Sequence
@@ -28,6 +29,7 @@ from telegram._files.audio import Audio
from telegram._files.document import Document
from telegram._files.inputfile import InputFile
from telegram._files.photosize import PhotoSize
from telegram._files.sticker import Sticker
from telegram._files.video import Video
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
@@ -37,17 +39,47 @@ from telegram._utils.datetime import get_timedelta_value
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.files import parse_file_input
from telegram._utils.types import JSONDict, ODVInput, TimePeriod
from telegram.constants import InputMediaType
from telegram._utils.warnings import warn
from telegram.constants import BaseInputMediaType
from telegram.warnings import PTBDeprecationWarning
if TYPE_CHECKING:
from telegram._utils.types import FileInput
MediaType: TypeAlias = Animation | Audio | Document | PhotoSize | Video
class InputMedia(TelegramObject):
class _BaseInputMedia(TelegramObject):
"""
Base class for Telegram InputMedia Objects.
Base class for objects representing the various input media types.
Args:
media_type (:obj:`str`): Type of media that the instance represents.
Attributes:
type (:obj:`str`): Type of media that the instance represents.
"""
__slots__ = ("type",)
def __init__(
self,
media_type: str,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
self.type: str = enum.get_member(constants.BaseInputMediaType, media_type, media_type)
class InputMedia(_BaseInputMedia):
"""
This object represents the content of a media message to be sent. It should be one of:
* :class:`telegram.InputMediaAnimation`
* :class:`telegram.InputMediaAudio`
* :class:`telegram.InputMediaDocument`
* :class:`telegram.InputMediaLivePhoto`
* :class:`telegram.InputMediaPhoto`
* :class:`telegram.InputMediaVideo`
.. versionchanged:: 20.0
Added arguments and attributes :attr:`type`, :attr:`media`, :attr:`caption`,
@@ -85,7 +117,7 @@ class InputMedia(TelegramObject):
"""
__slots__ = ("caption", "caption_entities", "media", "parse_mode", "type")
__slots__ = ("caption", "caption_entities", "media", "parse_mode")
def __init__(
self,
@@ -97,14 +129,12 @@ class InputMedia(TelegramObject):
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
self.type: str = enum.get_member(constants.InputMediaType, media_type, media_type)
self.media: str | InputFile = media
self.caption: str | None = caption
self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
self.parse_mode: ODVInput[str] = parse_mode
self._freeze()
super().__init__(media_type=media_type, api_kwargs=api_kwargs)
with self._unfrozen():
self.media: str | InputFile = media
self.caption: str | None = caption
self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
self.parse_mode: ODVInput[str] = parse_mode
@staticmethod
def _parse_thumbnail_input(thumbnail: "FileInput | None") -> str | InputFile | None:
@@ -123,6 +153,7 @@ class InputPaidMedia(TelegramObject):
* :class:`telegram.InputPaidMediaPhoto`
* :class:`telegram.InputPaidMediaVideo`
* :class:`telegram.InputPaidMediaLivePhoto`
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
@@ -142,6 +173,11 @@ class InputPaidMedia(TelegramObject):
""":const:`telegram.constants.InputPaidMediaType.PHOTO`"""
VIDEO: Final[str] = constants.InputPaidMediaType.VIDEO
""":const:`telegram.constants.InputPaidMediaType.VIDEO`"""
LIVE_PHOTO: Final[str] = constants.InputPaidMediaType.LIVE_PHOTO
""":const:`telegram.constants.InputPaidMediaType.LIVE_PHOTO`
.. versionadded:: NEXT.VERSION
"""
__slots__ = ("media", "type")
@@ -300,6 +336,51 @@ class InputPaidMediaVideo(InputPaidMedia):
return get_timedelta_value(self._duration, attribute="duration")
class InputPaidMediaLivePhoto(InputPaidMedia):
"""
The paid media to send is a live photo.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: NEXT.VERSION
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
| :class:`pathlib.Path` | :class:`~telegram.Video`): Video of the live photo to send.
Pass a ``file_id`` to send a file that exists on the Telegram servers (recommended).
|uploadinputnopath| Sending live photos by a URL is currently unsupported. Lastly you
can pass an existing :class:`telegram.Video` object to send.
photo (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
:class:`pathlib.Path` | :class:`~telegram.PhotoSize`): Photo of the live photo to send.
Pass a ``file_id`` to send a file that exists on the Telegram servers (recommended).
|uploadinputnopath| Sending live photos by a URL is currently unsupported.
Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
Attributes:
type (:obj:`str`): Type of the media, always
:tg-const:`telegram.constants.InputPaidMediaType.LIVE_PHOTO`.
media (:obj:`str` | :class:`telegram.InputFile`): Video of the live photo to send.
|fileinputnopath|
photo (:obj:`str` | :class:`telegram.InputFile`): Photo of the live photo to send.
|fileinputnopath|
"""
__slots__ = ("photo",)
def __init__(
self,
media: "FileInput | Video",
photo: "FileInput | PhotoSize",
*,
api_kwargs: JSONDict | None = None,
):
media = parse_file_input(media, tg_type=Video, attach=True, local_mode=True)
photo = parse_file_input(photo, tg_type=PhotoSize, attach=True, local_mode=True)
super().__init__(type=InputPaidMedia.LIVE_PHOTO, media=media, api_kwargs=api_kwargs)
with self._unfrozen():
self.photo: str | InputFile = photo
class InputMediaAnimation(InputMedia):
"""Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
@@ -320,11 +401,12 @@ class InputMediaAnimation(InputMedia):
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
filename (:obj:`str`, optional): Custom file name for the animation, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 13.1
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the animation to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
after entities parsing.
@@ -353,8 +435,17 @@ class InputMediaAnimation(InputMedia):
.. versionadded:: 21.3
Keyword Args:
filename (:obj:`str`, optional): Custom file name for the animation, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.ANIMATION`.
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.ANIMATION`.
media (:obj:`str` | :class:`telegram.InputFile`): Animation to send.
caption (:obj:`str`): Optional. Caption of the animation to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
@@ -403,13 +494,28 @@ class InputMediaAnimation(InputMedia):
height: int | None = None,
duration: TimePeriod | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
filename: str | None = None,
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
thumbnail: "FileInput | None" = None,
show_caption_above_media: bool | None = None,
*,
filename: str | None = None,
api_kwargs: JSONDict | None = None,
):
if filename_depr is not None and filename is not None:
raise ValueError("`filename_depr` and `filename` are mutually exclusive.")
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
stacklevel=2,
)
if isinstance(media, Animation):
width = media.width if width is None else width
height = media.height if height is None else height
@@ -418,10 +524,13 @@ class InputMediaAnimation(InputMedia):
else:
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
effective_filename = filename_depr or filename
media = parse_file_input(
media, filename=effective_filename, attach=True, local_mode=True
)
super().__init__(
InputMediaType.ANIMATION,
BaseInputMediaType.ANIMATION,
media,
caption,
caption_entities,
@@ -453,11 +562,12 @@ class InputMediaPhoto(InputMedia):
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
filename (:obj:`str`, optional): Custom file name for the photo, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 13.1
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional ): Caption of the photo to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
@@ -474,8 +584,17 @@ class InputMediaPhoto(InputMedia):
.. versionadded:: 21.3
Keyword Args:
filename (:obj:`str`, optional): Custom file name for the photo, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.PHOTO`.
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.PHOTO`.
media (:obj:`str` | :class:`telegram.InputFile`): Photo to send.
caption (:obj:`str`): Optional. Caption of the photo to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
@@ -507,17 +626,35 @@ class InputMediaPhoto(InputMedia):
caption: str | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence[MessageEntity] | None = None,
filename: str | None = None,
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
show_caption_above_media: bool | None = None,
*,
filename: str | None = None,
api_kwargs: JSONDict | None = None,
):
if filename_depr is not None and filename is not None:
raise ValueError("`filename_depr` and `filename` are mutually exclusive.")
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
stacklevel=2,
)
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, PhotoSize, filename=filename, attach=True, local_mode=True)
effective_filename = filename_depr or filename
media = parse_file_input(
media, PhotoSize, filename=effective_filename, attach=True, local_mode=True
)
super().__init__(
InputMediaType.PHOTO,
BaseInputMediaType.PHOTO,
media,
caption,
caption_entities,
@@ -553,11 +690,12 @@ class InputMediaVideo(InputMedia):
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
filename (:obj:`str`, optional): Custom file name for the video, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 13.1
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the video to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
@@ -594,8 +732,17 @@ class InputMediaVideo(InputMedia):
.. versionadded:: 21.3
Keyword Args:
filename (:obj:`str`, optional): Custom file name for the video, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.VIDEO`.
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.VIDEO`.
media (:obj:`str` | :class:`telegram.InputFile`): Video file to send.
caption (:obj:`str`): Optional. Caption of the video to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
@@ -656,15 +803,30 @@ class InputMediaVideo(InputMedia):
supports_streaming: bool | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence[MessageEntity] | None = None,
filename: str | None = None,
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
thumbnail: "FileInput | None" = None,
show_caption_above_media: bool | None = None,
cover: "FileInput | None" = None,
start_timestamp: int | None = None,
*,
filename: str | None = None,
api_kwargs: JSONDict | None = None,
):
if filename_depr is not None and filename is not None:
raise ValueError("`filename_depr` and `filename` are mutually exclusive.")
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
stacklevel=2,
)
if isinstance(media, Video):
width = width if width is not None else media.width
height = height if height is not None else media.height
@@ -673,10 +835,13 @@ class InputMediaVideo(InputMedia):
else:
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
effective_filename = filename_depr or filename
media = parse_file_input(
media, filename=effective_filename, attach=True, local_mode=True
)
super().__init__(
InputMediaType.VIDEO,
BaseInputMediaType.VIDEO,
media,
caption,
caption_entities,
@@ -701,6 +866,156 @@ class InputMediaVideo(InputMedia):
return get_timedelta_value(self._duration, attribute="duration")
class InputMediaLocation(_BaseInputMedia):
"""Represents a location to be sent.
.. versionadded:: NEXT.VERSION
Args:
latitude (:obj:`float`): Latitude of the location.
longitude (:obj:`float`): Longitude of the location.
horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location,
measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.LOCATION`.
latitude (:obj:`float`): Latitude of the location.
longitude (:obj:`float`): Longitude of the location.
horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location,
measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
"""
__slots__ = ("horizontal_accuracy", "latitude", "longitude")
def __init__(
self,
latitude: float,
longitude: float,
horizontal_accuracy: float | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(media_type=BaseInputMediaType.LOCATION, api_kwargs=api_kwargs)
with self._unfrozen():
self.latitude: float = latitude
self.longitude: float = longitude
self.horizontal_accuracy: float | None = horizontal_accuracy
class InputMediaVenue(_BaseInputMedia):
"""Represents a venue to be sent.
.. versionadded:: NEXT.VERSION
Args:
latitude (:obj:`float`): Latitude of the location.
longitude (:obj:`float`): Longitude of the location.
title (:obj:`str`): Name of the venue.
address (:obj:`str`): Address of the venue.
foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue.
foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. (For
example, ``arts_entertainment/default``, ``arts_entertainment/aquarium``
or ``food/icecream``).
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/places/web-service/supported_types>`__)
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.VENUE`.
latitude (:obj:`float`): Latitude of the location.
longitude (:obj:`float`): Longitude of the location.
title (:obj:`str`): Name of the venue.
address (:obj:`str`): Address of the venue.
foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue.
foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known. (For
example, ``arts_entertainment/default``, ``arts_entertainment/aquarium``
or ``food/icecream``).
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/places/web-service/supported_types>`__)
"""
__slots__ = (
"address",
"foursquare_id",
"foursquare_type",
"google_place_id",
"google_place_type",
"latitude",
"longitude",
"title",
)
def __init__(
self,
latitude: float,
longitude: float,
title: str,
address: str,
foursquare_id: str | None = None,
foursquare_type: str | None = None,
google_place_id: str | None = None,
google_place_type: str | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(media_type=BaseInputMediaType.VENUE, api_kwargs=api_kwargs)
with self._unfrozen():
self.latitude: float = latitude
self.longitude: float = longitude
self.title: str = title
self.address: str = address
self.foursquare_id: str | None = foursquare_id
self.foursquare_type: str | None = foursquare_type
self.google_place_id: str | None = google_place_id
self.google_place_type: str | None = google_place_type
class InputMediaSticker(_BaseInputMedia):
"""Represents a sticker file to be sent.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: NEXT.VERSION
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
:class:`pathlib.Path` | :class:`telegram.Sticker`): File to send. |fileinputnopath|
Lastly you can pass an existing :class:`telegram.Sticker` object to send.
emoji (:obj:`str`, optional): Emoji associated with the sticker; only for just uploaded
stickers.
Keyword Args:
filename (:obj:`str`, optional): Custom file name for the sticker, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.STICKER`.
media (:obj:`str` | :class:`telegram.InputFile`): Sticker file to send.
emoji (:obj:`str`): Optional. Emoji associated with the sticker; only for just uploaded
stickers.
"""
__slots__ = ("emoji", "media")
def __init__(
self,
media: "FileInput | Sticker",
emoji: str | None = None,
*,
filename: str | None = None,
api_kwargs: JSONDict | None = None,
):
media = parse_file_input(media, Sticker, filename=filename, attach=True, local_mode=True)
super().__init__(media_type=BaseInputMediaType.STICKER, api_kwargs=api_kwargs)
with self._unfrozen():
self.media: str | InputFile = media
self.emoji: str | None = emoji
class InputMediaAudio(InputMedia):
"""Represents an audio file to be treated as music to be sent.
@@ -721,11 +1036,12 @@ class InputMediaAudio(InputMedia):
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
filename (:obj:`str`, optional): Custom file name for the audio, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 13.1
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the audio to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
@@ -748,8 +1064,17 @@ class InputMediaAudio(InputMedia):
.. versionadded:: 20.2
Keyword Args:
filename (:obj:`str`, optional): Custom file name for the audio, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.AUDIO`.
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.AUDIO`.
media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
caption (:obj:`str`): Optional. Caption of the audio to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
@@ -786,11 +1111,26 @@ class InputMediaAudio(InputMedia):
performer: str | None = None,
title: str | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
filename: str | None = None,
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
thumbnail: "FileInput | None" = None,
*,
filename: str | None = None,
api_kwargs: JSONDict | None = None,
):
if filename_depr is not None and filename is not None:
raise ValueError("`filename_depr` and `filename` are mutually exclusive.")
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
stacklevel=2,
)
if isinstance(media, Audio):
duration = duration if duration is not None else media._duration
performer = media.performer if performer is None else performer
@@ -799,10 +1139,13 @@ class InputMediaAudio(InputMedia):
else:
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
effective_filename = filename_depr or filename
media = parse_file_input(
media, filename=effective_filename, attach=True, local_mode=True
)
super().__init__(
InputMediaType.AUDIO,
BaseInputMediaType.AUDIO,
media,
caption,
caption_entities,
@@ -835,11 +1178,12 @@ class InputMediaDocument(InputMedia):
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
filename (:obj:`str`, optional): Custom file name for the document, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: 13.1
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the document to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
@@ -857,8 +1201,17 @@ class InputMediaDocument(InputMedia):
.. versionadded:: 20.2
Keyword Args:
filename (:obj:`str`, optional): Custom file name for the document, when uploading a
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
This parameter is now keyword-only.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.DOCUMENT`.
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.DOCUMENT`.
media (:obj:`str` | :class:`telegram.InputFile`): File to send.
caption (:obj:`str`): Optional. Caption of the document to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
@@ -887,17 +1240,35 @@ class InputMediaDocument(InputMedia):
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_content_type_detection: bool | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
filename: str | None = None,
# tag: deprecated NEXT.VERSION
filename_depr: str | None = None,
# -
thumbnail: "FileInput | None" = None,
*,
filename: str | None = None,
api_kwargs: JSONDict | None = None,
):
if filename_depr is not None and filename is not None:
raise ValueError("`filename_depr` and `filename` are mutually exclusive.")
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
stacklevel=2,
)
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, Document, filename=filename, attach=True, local_mode=True)
effective_filename = filename_depr or filename
media = parse_file_input(
media, Document, filename=effective_filename, attach=True, local_mode=True
)
super().__init__(
InputMediaType.DOCUMENT,
BaseInputMediaType.DOCUMENT,
media,
caption,
caption_entities,
@@ -907,3 +1278,105 @@ class InputMediaDocument(InputMedia):
with self._unfrozen():
self.thumbnail: str | InputFile | None = self._parse_thumbnail_input(thumbnail)
self.disable_content_type_detection: bool | None = disable_content_type_detection
class InputMediaLivePhoto(InputMedia):
"""Represents a live photo to be sent.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: NEXT.VERSION
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
| :class:`pathlib.Path` | :class:`~telegram.Video`): Video of the live photo to send.
Pass a ``file_id`` to send a file that exists on the Telegram servers (recommended).
|uploadinputnopath| Sending live photos by a URL is currently unsupported. Lastly
you can pass an existing :class:`telegram.Video` object to send.
photo (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
| :class:`pathlib.Path` | :class:`~telegram.PhotoSize`): The static photo to send.
Pass a ``file_id`` to send a file that exists on the Telegram servers (recommended).
|uploadinputnopath| Sending live photos by a URL is currently unsupported. Lastly
you can pass an existing :class:`telegram.PhotoSize` object to send.
caption (:obj:`str`, optional): Caption of the live photo to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
parse_mode (:obj:`str`, optional): |parse_mode|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the video needs to be covered
with a spoiler animation.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.BaseInputMediaType.LIVE_PHOTO`.
media (:obj:`str` | :class:`telegram.InputFile`): Video of the live photo to send.
photo (:obj:`str` | :class:`telegram.InputFile`): The static photo to send.
caption (:obj:`str`): Optional. Caption of the live photo to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
after entities parsing.
parse_mode (:obj:`str`): Optional. |parse_mode|
caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the video is covered with a
spoiler animation.
"""
__slots__ = ("has_spoiler", "photo", "show_caption_above_media")
def __init__(
self,
media: "FileInput | Video",
photo: "FileInput | PhotoSize",
caption: str | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence[MessageEntity] | None = None,
show_caption_above_media: bool | None = None,
has_spoiler: bool | None = None,
*,
api_kwargs: JSONDict | None = None,
):
media = parse_file_input(media, tg_type=Video, attach=True, local_mode=True)
photo = parse_file_input(photo, tg_type=PhotoSize, attach=True, local_mode=True)
super().__init__(
BaseInputMediaType.LIVE_PHOTO,
media,
caption,
caption_entities,
parse_mode,
api_kwargs=api_kwargs,
)
with self._unfrozen():
self.photo: str | InputFile = photo
self.show_caption_above_media: bool | None = show_caption_above_media
self.has_spoiler: bool | None = has_spoiler
InputPollMedia: TypeAlias = (
InputMediaAnimation
| InputMediaAudio
| InputMediaDocument
| InputMediaLivePhoto
| InputMediaLocation
| InputMediaPhoto
| InputMediaVenue
| InputMediaVideo
)
"""Type alias for InputPollMedia objects.
versionadded:: NEXT.VERSION
"""
InputPollOptionMedia: TypeAlias = (
InputMediaAnimation
| InputMediaLivePhoto
| InputMediaLocation
| InputMediaPhoto
| InputMediaSticker
| InputMediaVenue
| InputMediaVideo
)
"""Type alias for InputPollOptionMedia objects.
.. versionadded:: NEXT.VERSION
"""
+108
View File
@@ -0,0 +1,108 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2026
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram LivePhoto."""
from collections.abc import Sequence
from typing import TYPE_CHECKING
from telegram._files._basemedium import _BaseMedium
from telegram._files.photosize import PhotoSize
from telegram._utils.argumentparsing import parse_sequence_arg, to_timedelta
from telegram._utils.types import JSONDict, TimePeriod
if TYPE_CHECKING:
import datetime as dtm
class LivePhoto(_BaseMedium):
"""
This object represents a live photo.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`file_unique_id` is equal.
.. versionadded:: NEXT.VERSION
Args:
file_id (:obj:`str`): Identifier for the video file which can be used to download or reuse
the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
width (:obj:`int`): Video width as defined by the sender.
height (:obj:`int`): Video height as defined by the sender.
duration (:obj:`int` | :class:`datetime.timedelta`): Duration of the video
in seconds as defined by the sender.
photo (Sequence[:obj:`telegram.PhotoSize`], optional): Available sizes of the corresponding
static photo.
mime_type (:obj:`str`, optional): MIME type of a file as defined by the sender.
file_size (:obj:`int`, optional): File size in bytes.
Attributes:
file_id (:obj:`str`): Identifier for the video file which can be used to download or reuse
the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
width (:obj:`int`): Video width as defined by the sender.
height (:obj:`int`): Video height as defined by the sender.
duration (:class:`datetime.timedelta`): Duration of the video
in seconds as defined by the sender.
photo (tuple[:obj:`telegram.PhotoSize`]): Optional. Available sizes of the corresponding
static photo.
mime_type (:obj:`str`): Optional. MIME type of a file as defined by the sender.
file_size (:obj:`int`): Optional. File size in bytes.
"""
__slots__ = (
"duration",
"height",
"mime_type",
"photo",
"width",
)
def __init__(
self,
file_id: str,
file_unique_id: str,
width: int,
height: int,
duration: TimePeriod,
photo: Sequence[PhotoSize] | None = None,
mime_type: str | None = None,
file_size: int | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
api_kwargs=api_kwargs,
)
with self._unfrozen():
# Required
self.width: int = width
self.height: int = height
self.duration: dtm.timedelta = to_timedelta(duration)
# Optional
self.photo: Sequence[PhotoSize] | None = parse_sequence_arg(photo)
self.mime_type: str | None = mime_type
+1 -1
View File
@@ -31,7 +31,7 @@ class ForceReply(TelegramObject):
the user (act as if the user has selected the bot's message and tapped 'Reply'). This can be
extremely useful if you want to create user-friendly step-by-step interfaces without having
to sacrifice `privacy mode <https://core.telegram.org/bots/features#privacy-mode>`_. Not
supported in channels and for messages sent on behalf of a Telegram Business account.
supported in channels and for messages sent on behalf of a user account.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`selective` is equal.
+5 -5
View File
@@ -49,8 +49,8 @@ class InputChecklistTask(TelegramObject):
|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.
parse_mode. Currently, only bold, italic, underline, strikethrough, spoiler,
custom_emoji, and date_time entities are allowed.
Attributes:
id (:obj:`int`):
@@ -66,7 +66,7 @@ class InputChecklistTask(TelegramObject):
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.
custom_emoji, and date_time entities are allowed.
"""
@@ -117,7 +117,7 @@ class InputChecklist(TelegramObject):
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.
underline, strikethrough, spoiler, and custom_emoji, and date_time entities are allowed
tasks (Sequence[:class:`telegram.InputChecklistTask`]):
List of
:tg-const:`telegram.constants.InputChecklistLimit.MIN_TASK_NUMBER`\
@@ -139,7 +139,7 @@ class InputChecklist(TelegramObject):
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.
underline, strikethrough, spoiler, and custom_emoji, and date_time entities are allowed
tasks (Sequence[:class:`telegram.InputChecklistTask`]):
List of
:tg-const:`telegram.constants.InputChecklistLimit.MIN_TASK_NUMBER`\
+23 -1
View File
@@ -19,7 +19,11 @@
"""This module contains an object that represents a Telegram KeyboardButton."""
from telegram._keyboardbuttonpolltype import KeyboardButtonPollType
from telegram._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
from telegram._keyboardbuttonrequest import (
KeyboardButtonRequestChat,
KeyboardButtonRequestManagedBot,
KeyboardButtonRequestUsers,
)
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
from telegram._webappinfo import WebAppInfo
@@ -114,6 +118,14 @@ class KeyboardButton(TelegramObject):
Premium subscription.
.. versionadded:: 22.7
request_managed_bot (:obj:`telegram.KeyboardButtonRequestManagedBot`, optional): If
specified, pressing the button will ask the user to create and share a bot that will
be managed by the current bot. Available for bots that enabled management of other bots
in the `@BotFather <https://telegram.me/BotFather>` Mini App. Available in private
chats only.
.. versionadded:: NEXT.VERSION
Attributes:
text (:obj:`str`): Text of the button. If none of the fields other than :attr:`text`,
@@ -161,6 +173,13 @@ class KeyboardButton(TelegramObject):
Premium subscription.
.. versionadded:: 22.7
request_managed_bot (:obj:`telegram.KeyboardButtonRequestManagedBot`): Optional. If
specified, pressing the button will ask the user to create and share a bot that will
be managed by the current bot. Available for bots that enabled management of other bots
in the `@BotFather <https://telegram.me/BotFather>` Mini App. Available in private
chats only.
.. versionadded:: NEXT.VERSION
"""
__slots__ = (
@@ -168,6 +187,7 @@ class KeyboardButton(TelegramObject):
"request_chat",
"request_contact",
"request_location",
"request_managed_bot",
"request_poll",
"request_users",
"style",
@@ -192,6 +212,7 @@ class KeyboardButton(TelegramObject):
request_users: KeyboardButtonRequestUsers | None = None,
style: str | None = None,
icon_custom_emoji_id: str | None = None,
request_managed_bot: KeyboardButtonRequestManagedBot | None = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -208,6 +229,7 @@ class KeyboardButton(TelegramObject):
self.request_chat: KeyboardButtonRequestChat | None = request_chat
self.style: str | None = style
self.icon_custom_emoji_id: str | None = icon_custom_emoji_id
self.request_managed_bot: KeyboardButtonRequestManagedBot | None = request_managed_bot
self._id_attrs = (
self.text,
+50
View File
@@ -248,3 +248,53 @@ class KeyboardButtonRequestChat(TelegramObject):
self._id_attrs = (self.request_id,)
self._freeze()
class KeyboardButtonRequestManagedBot(TelegramObject):
"""
This object defines the parameters for the creation of a managed bot.
Information about the created bot will be shared with the bot using the update
managed_bot and a :obj:`telegram.Message` with the field
:attr:`telegram.Message.managed_bot_created`.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`request_id` is equal.
.. versionadded:: NEXT.VERSION
Args:
request_id (:obj:`int`): Signed 32-bit identifier of the request. Must be unique
within the message.
suggested_name (:obj:`str`, optional): Suggested name for the bot.
suggested_username (:obj:`str`, optional): Suggested username for the bot.
Attributes:
request_id (:obj:`int`): Signed 32-bit identifier of the request. Must be unique
within the message.
suggested_name (:obj:`str`): Optional. Suggested name for the bot.
suggested_username (:obj:`str`): Optional. Suggested username for the bot.
"""
__slots__ = (
"request_id",
"suggested_name",
"suggested_username",
)
def __init__(
self,
request_id: int,
suggested_name: str | None = None,
suggested_username: str | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.request_id: int = request_id
# Optional
self.suggested_name: str | None = suggested_name
self.suggested_username: str | None = suggested_username
self._id_attrs = (self.request_id,)
self._freeze()
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2026
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects that represent managed bots in the Telegram Bot API."""
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.types import (
JSONDict,
)
class ManagedBotCreated(TelegramObject):
"""
This object contains information about the bot that was created to be managed by the current
bot.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`bot` is equal.
.. versionadded:: NEXT.VERSION
Args:
bot (:class:`telegram.User`): Information about the bot. The bot's token can be fetched
using the method :meth:`~telegram.Bot.get_managed_bot_token`.
Attributes:
bot (:class:`telegram.User`): Information about the bot. The bot's token can be fetched
using the method :meth:`~telegram.Bot.get_managed_bot_token`.
"""
__slots__ = ("bot",)
def __init__(
self,
bot: User,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
self.bot: User = bot
self._id_attrs = (self.bot,)
self._freeze()
class ManagedBotUpdated(TelegramObject):
"""
This object contains information about the creation, token update, or owner update of a bot
that is managed by the current bot.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`user` and :attr:`bot` are equal.
.. versionadded:: NEXT.VERSION
Args:
user (:class:`telegram.User`): User that created the bot.
bot (:class:`telegram.User`): Information about the bot. Token of the bot can be fetched
using the method :meth:`~telegram.Bot.get_managed_bot_token`.
Attributes:
user (:class:`telegram.User`): User that created the bot.
bot (:class:`telegram.User`): Information about the bot. Token of the bot can be fetched
using the method :meth:`~telegram.Bot.get_managed_bot_token`.
"""
__slots__ = ("bot", "user")
def __init__(
self,
user: User,
bot: User,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.user: User = user
self.bot: User = bot
self._id_attrs = (
self.user,
self.bot,
)
self._freeze()
+293 -5
View File
@@ -37,6 +37,7 @@ from telegram._files.animation import Animation
from telegram._files.audio import Audio
from telegram._files.contact import Contact
from telegram._files.document import Document
from telegram._files.livephoto import LivePhoto
from telegram._files.location import Location
from telegram._files.photosize import PhotoSize
from telegram._files.sticker import Sticker
@@ -57,6 +58,7 @@ from telegram._gifts import GiftInfo
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inputchecklist import InputChecklist
from telegram._linkpreviewoptions import LinkPreviewOptions
from telegram._managedbot import ManagedBotCreated
from telegram._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
from telegram._messageentity import MessageEntity
from telegram._paidmedia import PaidMediaInfo
@@ -65,7 +67,7 @@ from telegram._passport.passportdata import PassportData
from telegram._payment.invoice import Invoice
from telegram._payment.refundedpayment import RefundedPayment
from telegram._payment.successfulpayment import SuccessfulPayment
from telegram._poll import Poll
from telegram._poll import Poll, PollOptionAdded, PollOptionDeleted
from telegram._proximityalerttriggered import ProximityAlertTriggered
from telegram._reply import ReplyParameters
from telegram._shared import ChatShared, UsersShared
@@ -80,6 +82,7 @@ from telegram._utils.entities import parse_message_entities, parse_message_entit
from telegram._utils.strings import TextEncoding
from telegram._utils.types import (
CorrectOptionID,
CorrectOptionIds,
JSONDict,
MarkdownVersion,
ODVInput,
@@ -107,17 +110,21 @@ if TYPE_CHECKING:
GiveawayCompleted,
GiveawayCreated,
GiveawayWinners,
InlineQueryResult,
InputMedia,
InputMediaAudio,
InputMediaDocument,
InputMediaLivePhoto,
InputMediaPhoto,
InputMediaVideo,
InputPaidMedia,
InputPollMedia,
InputPollOption,
LabeledPrice,
MessageId,
MessageOrigin,
ReactionType,
SentGuestMessage,
SuggestedPostApprovalFailed,
SuggestedPostApproved,
SuggestedPostDeclined,
@@ -690,6 +697,43 @@ class Message(MaybeInaccessibleMessage):
supergroups only
.. versionadded:: 22.7
poll_option_added (:class:`telegram.PollOptionAdded`, optional): Service message:
answer option was added to a poll.
.. versionadded:: NEXT.VERSION
poll_option_deleted (:class:`telegram.PollOptionDeleted`, optional): Service message:
answer option was deleted from a poll.
.. versionadded:: NEXT.VERSION
reply_to_poll_option_id (:obj:`str`, optional): Persistent
identifier of the specific poll option that is being replied to.
.. versionadded:: NEXT.VERSION
managed_bot_created (:class:`telegram.ManagedBotCreated`, optional): Service message: user
created a bot that will be managed by the current bot.
.. versionadded:: NEXT.VERSION
guest_bot_caller_user (:class:`telegram.User`, optional): For a message sent by a guest
bot, this is the user whose original message triggered the bot's response.
.. versionadded:: NEXT.VERSION
guest_bot_caller_chat (:class:`telegram.Chat`, optional): For a message sent by a guest
bot, this is the chat whose original message triggered the bot's response.
.. versionadded:: NEXT.VERSION
guest_query_id (:obj:`str`, optional): The unique identifier for the guest query. Use this
identifier with the method :meth:`telegram.Bot.answer_guest_query` to send a response
message. If non-empty, the message belongs to the chat where the guest bot was
summoned, which may not coincide with other existing bot chats sharing the same
identifier.
.. versionadded:: NEXT.VERSION
live_photo (:class:`telegram.LivePhoto`, optional): Message is a live photo, information
about the live photo. For backward compatibility, when this field is set, the photo
field will also be set.
.. versionadded:: NEXT.VERSION
Attributes:
message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances
@@ -1106,6 +1150,42 @@ class Message(MaybeInaccessibleMessage):
supergroups only
.. versionadded:: 22.7
poll_option_added (:class:`telegram.PollOptionAdded`): Optional. Service message:
answer option was added to a poll.
.. versionadded:: NEXT.VERSION
poll_option_deleted (:class:`telegram.PollOptionDeleted`): Optional. Service message:
answer option was deleted from a poll.
.. versionadded:: NEXT.VERSION
reply_to_poll_option_id (:obj:`str`): Optional. Persistent
identifier of the specific poll option that is being replied to.
.. versionadded:: NEXT.VERSION
managed_bot_created (:class:`telegram.ManagedBotCreated`): Optional. Service message: user
created a bot that will be managed by the current bot.
.. versionadded:: NEXT.VERSION
guest_bot_caller_user (:class:`telegram.User`): Optional. For a message sent by a guest
bot, this is the user whose original message triggered the bot's response.
.. versionadded:: NEXT.VERSION
guest_bot_caller_chat (:class:`telegram.Chat`): Optional. For a message sent by a guest
bot, this is the chat whose original message triggered the bot's response.
.. versionadded:: NEXT.VERSION
guest_query_id (:obj:`str`): Optional. The unique identifier for the guest query. Use this
identifier with the method :meth:`telegram.Bot.answer_guest_query` to send a response
message. If non-empty, the message belongs to the chat where the guest bot was
summoned, which may not coincide with other existing bot chats sharing the same
identifier.
.. versionadded:: NEXT.VERSION
live_photo (:class:`telegram.LivePhoto`): Optional. Message is a live photo, information
about the live photo. For backward compatibility, when this field is set, the photo
field will also be set.
.. versionadded:: NEXT.VERSION
.. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
@@ -1167,6 +1247,9 @@ class Message(MaybeInaccessibleMessage):
"giveaway_created",
"giveaway_winners",
"group_chat_created",
"guest_bot_caller_chat",
"guest_bot_caller_user",
"guest_query_id",
"has_media_spoiler",
"has_protected_content",
"invoice",
@@ -1176,7 +1259,9 @@ class Message(MaybeInaccessibleMessage):
"is_topic_message",
"left_chat_member",
"link_preview_options",
"live_photo",
"location",
"managed_bot_created",
"media_group_id",
"message_auto_delete_timer_changed",
"message_thread_id",
@@ -1192,12 +1277,15 @@ class Message(MaybeInaccessibleMessage):
"photo",
"pinned_message",
"poll",
"poll_option_added",
"poll_option_deleted",
"proximity_alert_triggered",
"quote",
"refunded_payment",
"reply_markup",
"reply_to_checklist_task_id",
"reply_to_message",
"reply_to_poll_option_id",
"reply_to_story",
"sender_boost_count",
"sender_business_bot",
@@ -1338,6 +1426,14 @@ class Message(MaybeInaccessibleMessage):
chat_owner_changed: ChatOwnerChanged | None = None,
chat_owner_left: ChatOwnerLeft | None = None,
sender_tag: str | None = None,
poll_option_added: PollOptionAdded | None = None,
poll_option_deleted: PollOptionDeleted | None = None,
reply_to_poll_option_id: str | None = None,
managed_bot_created: ManagedBotCreated | None = None,
guest_bot_caller_user: User | None = None,
guest_bot_caller_chat: Chat | None = None,
guest_query_id: str | None = None,
live_photo: LivePhoto | None = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -1468,6 +1564,14 @@ class Message(MaybeInaccessibleMessage):
self.chat_owner_changed: ChatOwnerChanged | None = chat_owner_changed
self.chat_owner_left: ChatOwnerLeft | None = chat_owner_left
self.sender_tag: str | None = sender_tag
self.poll_option_added: PollOptionAdded | None = poll_option_added
self.poll_option_deleted: PollOptionDeleted | None = poll_option_deleted
self.reply_to_poll_option_id: str | None = reply_to_poll_option_id
self.managed_bot_created: ManagedBotCreated | None = managed_bot_created
self.guest_bot_caller_user: User | None = guest_bot_caller_user
self.guest_bot_caller_chat: Chat | None = guest_bot_caller_chat
self.guest_query_id: str | None = guest_query_id
self.live_photo: LivePhoto | None = live_photo
self._effective_attachment = DEFAULT_NONE
@@ -1518,6 +1622,7 @@ class Message(MaybeInaccessibleMessage):
| Document
| Game
| Invoice
| LivePhoto
| Location
| PassportData
| Sequence[PhotoSize]
@@ -1542,6 +1647,7 @@ class Message(MaybeInaccessibleMessage):
* :class:`telegram.Animation`
* :class:`telegram.Game`
* :class:`telegram.Invoice`
* :class:`telegram.LivePhoto`
* :class:`telegram.Location`
* :class:`telegram.PassportData`
* list[:class:`telegram.PhotoSize`]
@@ -1930,7 +2036,7 @@ class Message(MaybeInaccessibleMessage):
async def reply_text_draft(
self,
draft_id: int,
text: str,
text: str | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
entities: Sequence["MessageEntity"] | None = None,
message_thread_id: ODVInput[int] = DEFAULT_NONE,
@@ -1957,6 +2063,9 @@ class Message(MaybeInaccessibleMessage):
.. versionadded:: 22.6
.. versionchanged:: NEXT.VERSION
Bot API 10.0 makes the ``text`` argument optional.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -2229,7 +2338,7 @@ class Message(MaybeInaccessibleMessage):
async def reply_media_group(
self,
media: Sequence[
"InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo"
"InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo | InputMediaLivePhoto" # noqa: E501 # pylint: disable=line-too-long
],
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
@@ -2390,6 +2499,87 @@ class Message(MaybeInaccessibleMessage):
suggested_post_parameters=suggested_post_parameters,
)
async def reply_live_photo(
self,
live_photo: "FileInput | LivePhoto",
photo: "FileInput | PhotoSize",
caption: str | None = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "ReplyMarkup | None" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence["MessageEntity"] | None = None,
show_caption_above_media: bool | None = None,
has_spoiler: bool | None = None,
protect_content: ODVInput[bool] = DEFAULT_NONE,
message_thread_id: ODVInput[int] = DEFAULT_NONE,
reply_parameters: "ReplyParameters | None" = None,
message_effect_id: str | None = None,
allow_paid_broadcast: bool | None = None,
suggested_post_parameters: "SuggestedPostParameters | None" = None,
*,
reply_to_message_id: int | None = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
filename: str | None = None,
do_quote: bool | (_ReplyKwargs | None) = 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: JSONDict | None = None,
) -> "Message":
"""Shortcut for::
await bot.send_live_photo(
update.effective_message.chat_id,
message_thread_id=update.effective_message.message_thread_id,
business_connection_id=self.business_connection_id,
direct_messages_topic_id=self.direct_messages_topic.topic_id,
*args,
**kwargs,
)
For the documentation of the arguments, please see :meth:`telegram.Bot.send_live_photo`.
.. versionadded:: NEXT.VERSION
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
)
message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
return await self.get_bot().send_live_photo(
chat_id=chat_id,
live_photo=live_photo,
photo=photo,
caption=caption,
disable_notification=disable_notification,
reply_parameters=effective_reply_parameters,
reply_markup=reply_markup,
parse_mode=parse_mode,
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
has_spoiler=has_spoiler,
show_caption_above_media=show_caption_above_media,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
business_connection_id=self.business_connection_id,
message_effect_id=message_effect_id,
allow_paid_broadcast=allow_paid_broadcast,
direct_messages_topic_id=self._extract_direct_messages_topic_id(),
suggested_post_parameters=suggested_post_parameters,
)
async def reply_audio(
self,
audio: "FileInput | Audio",
@@ -3273,6 +3463,18 @@ class Message(MaybeInaccessibleMessage):
question_entities: Sequence["MessageEntity"] | None = None,
message_effect_id: str | None = None,
allow_paid_broadcast: bool | None = None,
shuffle_options: bool | None = None,
allows_revoting: bool | None = None,
correct_option_ids: CorrectOptionIds | None = None,
allow_adding_options: bool | None = None,
hide_results_until_closes: bool | None = None,
description: str | None = None,
description_parse_mode: ODVInput[str] | None = None,
description_entities: Sequence["MessageEntity"] | None = None,
members_only: bool | None = None,
country_codes: Sequence[str] | None = None,
explanation_media: "InputPollMedia | None" = None,
media: "InputPollMedia | None" = None,
*,
reply_to_message_id: int | None = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
@@ -3322,6 +3524,9 @@ class Message(MaybeInaccessibleMessage):
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
correct_option_ids=correct_option_ids,
is_closed=is_closed,
disable_notification=disable_notification,
reply_parameters=effective_reply_parameters,
@@ -3343,6 +3548,15 @@ class Message(MaybeInaccessibleMessage):
question_entities=question_entities,
message_effect_id=message_effect_id,
allow_paid_broadcast=allow_paid_broadcast,
description=description,
description_parse_mode=description_parse_mode,
description_entities=description_entities,
hide_results_until_closes=hide_results_until_closes,
allow_adding_options=allow_adding_options,
members_only=members_only,
country_codes=country_codes,
explanation_media=explanation_media,
media=media,
)
async def reply_dice(
@@ -3461,7 +3675,7 @@ class Message(MaybeInaccessibleMessage):
)
return await self.get_bot().send_checklist(
business_connection_id=self.business_connection_id,
chat_id=chat_id, # type: ignore[arg-type]
chat_id=chat_id,
checklist=checklist,
disable_notification=disable_notification,
reply_parameters=effective_reply_parameters,
@@ -3573,7 +3787,7 @@ class Message(MaybeInaccessibleMessage):
)
message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
return await self.get_bot().send_game(
chat_id=chat_id, # type: ignore[arg-type]
chat_id=chat_id,
game_short_name=game_short_name,
disable_notification=disable_notification,
reply_parameters=effective_reply_parameters,
@@ -4948,6 +5162,80 @@ class Message(MaybeInaccessibleMessage):
api_kwargs=api_kwargs,
)
async def delete_reaction(
self,
user_id: int | None = None,
actor_chat_id: int | None = 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: JSONDict | None = None,
) -> bool:
"""Shortcut for::
await bot.delete_message_reaction(
chat_id=message.chat_id,
message_id=message.message_id,
*args, **kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_message_reaction`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool` On success, :obj:`True` is returned.
"""
return await self.get_bot().delete_message_reaction(
chat_id=self.chat_id,
message_id=self.message_id,
user_id=user_id,
actor_chat_id=actor_chat_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def answer_guest_query(
self,
result: "InlineQueryResult",
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
) -> "SentGuestMessage":
"""Shortcut for::
await bot.answer_guest_query(
self.guest_query_id,
*args, **kwargs,
)
For the documentation of the arguments, please see :meth:`telegram.Bot.answer_guest_query`.
.. versionadded:: NEXT.VERSION
Returns:
:class:`telegram.SentGuestMessage`: On success, a
:class:`telegram.SentGuestMessage` is returned.
"""
return await self.get_bot().answer_guest_query(
guest_query_id=self.guest_query_id,
result=result,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text from a given :class:`telegram.MessageEntity`.
+38
View File
@@ -23,6 +23,7 @@ from collections.abc import Sequence
from typing import TYPE_CHECKING, ClassVar, Final
from telegram import constants
from telegram._files.livephoto import LivePhoto
from telegram._files.video import Video
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
@@ -65,6 +66,7 @@ class PaidMedia(TelegramObject):
"preview": "PaidMediaPreview",
"photo": "PaidMediaPhoto",
"video": "PaidMediaVideo",
"live_photo": "PaidMediaLivePhoto",
},
)
@@ -74,6 +76,8 @@ class PaidMedia(TelegramObject):
""":const:`telegram.constants.PaidMediaType.PHOTO`"""
VIDEO: Final[str] = constants.PaidMediaType.VIDEO
""":const:`telegram.constants.PaidMediaType.VIDEO`"""
LIVE_PHOTO: Final[str] = constants.PaidMediaType.LIVE_PHOTO
""":const:`telegram.constants.PaidMediaType.LIVE_PHOTO`"""
def __init__(
self,
@@ -214,6 +218,40 @@ class PaidMediaVideo(PaidMedia):
self._id_attrs = (self.type, self.video)
class PaidMediaLivePhoto(PaidMedia):
"""
The paid media is a live photo.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`live_photo` are equal.
.. versionadded:: NEXT.VERSION
Args:
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.LIVE_PHOTO`
live_photo (:class:`telegram.LivePhoto`): The photo.
Attributes:
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.LIVE_PHOTO`
live_photo (:class:`telegram.LivePhoto`): The photo.
"""
__slots__ = ("live_photo",)
def __init__(
self,
live_photo: LivePhoto,
*,
api_kwargs: JSONDict | None = None,
) -> None:
super().__init__(type=PaidMedia.LIVE_PHOTO, api_kwargs=api_kwargs)
with self._unfrozen():
self.live_photo: LivePhoto = live_photo
self._id_attrs = (self.type, self.live_photo)
class PaidMediaInfo(TelegramObject):
"""
Describes the paid media added to a message.
+616 -12
View File
@@ -20,10 +20,19 @@
import datetime as dtm
from collections.abc import Sequence
from typing import Final
from typing import TYPE_CHECKING, Final
from telegram import constants
from telegram._chat import Chat
from telegram._files.animation import Animation
from telegram._files.audio import Audio
from telegram._files.document import Document
from telegram._files.livephoto import LivePhoto
from telegram._files.location import Location
from telegram._files.photosize import PhotoSize
from telegram._files.sticker import Sticker
from telegram._files.venue import Venue
from telegram._files.video import Video
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._user import User
@@ -36,6 +45,110 @@ from telegram._utils.datetime import get_timedelta_value
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.entities import parse_message_entities, parse_message_entity
from telegram._utils.types import JSONDict, ODVInput, TimePeriod
from telegram._utils.warnings import warn
from telegram.warnings import PTBDeprecationWarning
if TYPE_CHECKING:
from telegram._files.inputmedia import InputPollOptionMedia
from telegram._message import MaybeInaccessibleMessage
class PollMedia(TelegramObject):
"""
At most one of the optional fields can be present in any given object.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if all of their attributes are equal.
.. versionadded:: NEXT.VERSION
Args:
animation (:class:`telegram.Animation`, optional): Media is an animation, information about
the animation
audio (:class:`telegram.Audio`, optional): Media is an audio file, information about the
file; currently, can't be received in a poll option
document (:class:`telegram.Document`, optional): Media is a general file, information about
the file; currently, can't be received in a poll option
live_photo (:class:`telegram.LivePhoto`, optional): Media is a live photo, information
about the live photo
location (:class:`telegram.Location`, optional): Media is a shared location, information
about the location
photo (Sequence[:class:`telegram.PhotoSize`], optional): Media is a photo, available sizes
of the photo
sticker (:class:`telegram.Sticker`, optional): Media is a sticker, information about the
sticker; currently, for poll options only
venue (:class:`telegram.Venue`, optional): Media is a venue, information about the venue
video (:class:`telegram.Video`, optional): Media is a video, information about the video
Attributes:
animation (:class:`telegram.Animation`): Optional. Media is an animation, information about
the animation
audio (:class:`telegram.Audio`): Optional. Media is an audio file, information about the
file; currently, can't be received in a poll option
document (:class:`telegram.Document`): Optional. Media is a general file, information about
the file; currently, can't be received in a poll option
live_photo (:class:`telegram.LivePhoto`, optional): Media is a live photo, information
about the live photo
location (:class:`telegram.Location`): Optional. Media is a shared location, information
about the location
photo (tuple[:class:`telegram.PhotoSize`]): Optional. Media is a photo, available sizes
of the photo
sticker (:class:`telegram.Sticker`): Optional. Media is a sticker, information about the
sticker; currently, for poll options only
venue (:class:`telegram.Venue`): Optional. Media is a venue, information about the venue
video (:class:`telegram.Video`): Optional. Media is a video, information about the video
"""
__slots__ = (
"animation",
"audio",
"document",
"live_photo",
"location",
"photo",
"sticker",
"venue",
"video",
)
def __init__(
self,
animation: Animation | None = None,
audio: Audio | None = None,
document: Document | None = None,
live_photo: LivePhoto | None = None,
location: Location | None = None,
photo: Sequence[PhotoSize] | None = None,
sticker: Sticker | None = None,
venue: Venue | None = None,
video: Video | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
self.animation: Animation | None = animation
self.audio: Audio | None = audio
self.document: Document | None = document
self.live_photo: LivePhoto | None = live_photo
self.location: Location | None = location
self.photo: tuple[PhotoSize, ...] = parse_sequence_arg(photo)
self.sticker: Sticker | None = sticker
self.venue: Venue | None = venue
self.video: Video | None = video
self._id_attrs = (
self.animation,
self.audio,
self.document,
self.live_photo,
self.location,
self.photo,
self.sticker,
self.venue,
self.video,
)
self._freeze()
class InputPollOption(TelegramObject):
@@ -58,6 +171,9 @@ class InputPollOption(TelegramObject):
:paramref:`text_parse_mode`.
Currently, only custom emoji entities are allowed.
This list is empty if the text does not contain entities.
media (:class:`telegram.InputPollOptionMedia`, optional): Media added to the poll option.
.. versionadded:: NEXT.VERSION
Attributes:
text (:obj:`str`): Option text,
@@ -70,15 +186,19 @@ class InputPollOption(TelegramObject):
:paramref:`text_parse_mode`.
Currently, only custom emoji entities are allowed.
This list is empty if the text does not contain entities.
media (:class:`telegram.InputPollOptionMedia`): Optional. Media added to the poll option.
.. versionadded:: NEXT.VERSION
"""
__slots__ = ("text", "text_entities", "text_parse_mode")
__slots__ = ("media", "text", "text_entities", "text_parse_mode")
def __init__(
self,
text: str,
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
text_entities: Sequence[MessageEntity] | None = None,
media: "InputPollOptionMedia | None" = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -86,6 +206,7 @@ class InputPollOption(TelegramObject):
self.text: str = text
self.text_parse_mode: ODVInput[str] = text_parse_mode
self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
self.media: InputPollOptionMedia | None = media
self._id_attrs = (self.text,)
@@ -97,9 +218,18 @@ class PollOption(TelegramObject):
This object contains information about one answer option in a poll.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`text` and :attr:`voter_count` are equal.
considered equal, if their :attr:`text`, :attr:`voter_count` and :attr:`persistent_id`
are equal.
.. versionchanged:: NEXT.VERSION
Added attribute :attr:`persistent_id` to equality checks.
Args:
persistent_id (:obj:`str`): Unique identifier of the option, persistent on option addition
and deletion.
.. versionadded:: NEXT.VERSION
text (:obj:`str`): Option text,
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
characters.
@@ -109,8 +239,27 @@ class PollOption(TelegramObject):
poll option texts.
.. versionadded:: 21.2
media (:class:`telegram.PollMedia`, optional): Media added to the poll option.
.. versionadded:: NEXT.VERSION
added_by_user (:class:`telegram.User`, optional): User who added the option;
omitted if the option wasn't added by a user after poll creation.
.. versionadded:: NEXT.VERSION
added_by_chat (:class:`telegram.Chat`, optional): Chat that added the option;
omitted if the option wasn't added by a chat after poll creation.
.. versionadded:: NEXT.VERSION
addition_date (:obj:`datetime.datetime`, optional): Point in time
when the option was added; omitted if the option existed in the original poll.
.. versionadded:: NEXT.VERSION
Attributes:
persistent_id (:obj:`str`): Unique identifier of the option, persistent on option addition
and deletion.
.. versionadded:: NEXT.VERSION
text (:obj:`str`): Option text,
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
characters.
@@ -121,25 +270,64 @@ class PollOption(TelegramObject):
This list is empty if the question does not contain entities.
.. versionadded:: 21.2
media (:class:`telegram.PollMedia`): Optional. Media added to the poll option.
.. versionadded:: NEXT.VERSION
added_by_user (:class:`telegram.User`): Optional. User who added the option;
omitted if the option wasn't added by a user after poll creation.
.. versionadded:: NEXT.VERSION
added_by_chat (:class:`telegram.Chat`): Optional. Chat that added the option;
omitted if the option wasn't added by a chat after poll creation.
.. versionadded:: NEXT.VERSION
addition_date (:obj:`datetime.datetime`): Optional. Point in time
when the option was added; omitted if the option existed in the original poll.
.. versionadded:: NEXT.VERSION
"""
__slots__ = ("text", "text_entities", "voter_count")
__slots__ = (
"added_by_chat",
"added_by_user",
"addition_date",
"media",
"persistent_id",
"text",
"text_entities",
"voter_count",
)
def __init__(
self,
text: str,
voter_count: int,
text_entities: Sequence[MessageEntity] | None = None,
added_by_user: User | None = None,
added_by_chat: Chat | None = None,
addition_date: dtm.datetime | None = None,
media: PollMedia | None = None,
# tags: required in NEXT.VERSION, bot api 9.6
# temporarily optional to avoid breaking changes
persistent_id: str | None = None,
*,
api_kwargs: JSONDict | None = None,
):
if persistent_id is None:
raise TypeError("`persistent_id` is a required argument since Bot API 9.6")
super().__init__(api_kwargs=api_kwargs)
self.text: str = text
self.voter_count: int = voter_count
self.added_by_user: User | None = added_by_user
self.added_by_chat: Chat | None = added_by_chat
self.addition_date: dtm.datetime | None = addition_date
self.persistent_id: str = persistent_id
self.media: PollMedia | None = media
self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
self._id_attrs = (self.text, self.voter_count)
self._id_attrs = (self.text, self.voter_count, self.persistent_id)
self._freeze()
@@ -221,6 +409,10 @@ class PollAnswer(TelegramObject):
.. versionchanged:: 20.0
|sequenceclassargs|
option_persistent_ids (Sequence[:obj:`str`]): Persistent identifiers of the
chosen answer options. May be empty if the vote was retracted.
.. versionadded:: NEXT.VERSION
user (:class:`telegram.User`, optional): The user that changed the answer to the poll,
if the voter isn't anonymous. If the voter is anonymous, this field will contain the
user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility.
@@ -239,6 +431,10 @@ class PollAnswer(TelegramObject):
.. versionchanged:: 20.0
|tupleclassattrs|
option_persistent_ids (tuple[:obj:`str`]): Persistent identifiers of the
chosen answer options. May be empty if the vote was retracted.
.. versionadded:: NEXT.VERSION
user (:class:`telegram.User`): Optional. The user, who changed the answer to the
poll, if the voter isn't anonymous. If the voter is anonymous, this field will contain
the user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility
@@ -249,10 +445,9 @@ class PollAnswer(TelegramObject):
poll, if the voter is anonymous.
.. versionadded:: 20.5
"""
__slots__ = ("option_ids", "poll_id", "user", "voter_chat")
__slots__ = ("option_ids", "option_persistent_ids", "poll_id", "user", "voter_chat")
def __init__(
self,
@@ -260,14 +455,21 @@ class PollAnswer(TelegramObject):
option_ids: Sequence[int],
user: User | None = None,
voter_chat: Chat | None = None,
# tags: required in NEXT.VERSION, bot api 9.6
# temporarily optional to avoid breaking changes
option_persistent_ids: Sequence[str] | None = None,
*,
api_kwargs: JSONDict | None = None,
):
if option_persistent_ids is None:
raise TypeError("`option_persistent_ids` is a required argument since Bot API 9.6")
super().__init__(api_kwargs=api_kwargs)
self.poll_id: str = poll_id
self.voter_chat: Chat | None = voter_chat
self.option_ids: tuple[int, ...] = parse_sequence_arg(option_ids)
self.user: User | None = user
self.option_persistent_ids: tuple[str, ...] = parse_sequence_arg(option_persistent_ids)
self._id_attrs = (
self.poll_id,
@@ -279,6 +481,200 @@ class PollAnswer(TelegramObject):
self._freeze()
class PollOptionAdded(TelegramObject):
"""
Describes a service message about an option added to a poll.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`option_persistent_id`, and :attr:`option_text` are equal.
.. versionadded:: NEXT.VERSION
Args:
option_persistent_id (:obj:`str`): Unique identifier of the added option.
option_text (:obj:`str`): Option text.
poll_message (:class:`telegram.MaybeInaccessibleMessage`, optional): Message
containing the poll to which the option was added, if known.
Note that the Message object in this field will not contain the
:attr:`~telegram.Message.reply_to_message` field even if it itself is a reply.
option_text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special
entities that appear in the :paramref:`option_text`.
Attributes:
option_persistent_id (:obj:`str`): Unique identifier of the added option.
option_text (:obj:`str`): Option text.
poll_message (:class:`telegram.MaybeInaccessibleMessage`): Optional. Message
containing the poll to which the option was added, if known.
Note that the Message object in this field will not contain the
:attr:`~telegram.Message.reply_to_message` field even if it itself is a reply.
option_text_entities (tuple[:class:`telegram.MessageEntity`]): Optional. Special
entities that appear in the :paramref:`option_text`.
"""
__slots__ = ("option_persistent_id", "option_text", "option_text_entities", "poll_message")
def __init__(
self,
option_persistent_id: str,
option_text: str,
poll_message: "MaybeInaccessibleMessage | None" = None,
option_text_entities: Sequence[MessageEntity] | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
self.option_persistent_id: str = option_persistent_id
self.option_text: str = option_text
self.poll_message: MaybeInaccessibleMessage | None = poll_message
self.option_text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(
option_text_entities
)
self._id_attrs = (self.option_persistent_id, self.option_text)
self._freeze()
def parse_option_text_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`option_text`
from a given :class:`telegram.MessageEntity` of :attr:`option_text_entities`.
Note:
This method is present because Telegram calculates the offset and length in
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
(That is, you can't just slice ``Message.text`` with the offset and length.)
Args:
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
be an entity that belongs to :attr:`option_text_entities`.
Returns:
:obj:`str`: The text of the given entity.
"""
return parse_message_entity(self.option_text, entity)
def parse_option_text_entities(
self, types: list[str] | None = None
) -> dict[MessageEntity, str]:
"""
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
It contains entities from this polls option text 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:`option_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.option_text, self.option_text_entities, types)
class PollOptionDeleted(TelegramObject):
"""
Describes a service message about an option deleted from a poll.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`option_persistent_id`, :attr:`option_text` are equal.
.. versionadded:: NEXT.VERSION
Args:
option_persistent_id (:obj:`str`): Unique identifier of the deleted option.
option_text (:obj:`str`): Option text.
poll_message (:class:`telegram.MaybeInaccessibleMessage`, optional): Message
containing the poll to which the option was deleted, if known.
Note that the Message object in this field will not contain the
:attr:`~telegram.Message.reply_to_message` field even if it itself is a reply.
option_text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special
entities that appear in the option_text.
Attributes:
option_persistent_id (:obj:`str`): Unique identifier of the deleted option.
option_text (:obj:`str`): Option text.
poll_message (:class:`telegram.MaybeInaccessibleMessage`): Optional. Message
containing the poll to which the option was deleted, if known.
Note that the Message object in this field will not contain the
:attr:`~telegram.Message.reply_to_message` field even if it itself is a reply.
option_text_entities (tuple[:class:`telegram.MessageEntity`]): Optional. Special
entities that appear in the option_text.
"""
__slots__ = ("option_persistent_id", "option_text", "option_text_entities", "poll_message")
def __init__(
self,
option_persistent_id: str,
option_text: str,
poll_message: "MaybeInaccessibleMessage | None" = None,
option_text_entities: Sequence[MessageEntity] | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
self.option_persistent_id: str = option_persistent_id
self.option_text: str = option_text
self.poll_message: MaybeInaccessibleMessage | None = poll_message
self.option_text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(
option_text_entities
)
self._id_attrs = (self.option_persistent_id, self.option_text)
self._freeze()
def parse_option_text_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`option_text`
from a given :class:`telegram.MessageEntity` of :attr:`option_text_entities`.
Note:
This method is present because Telegram calculates the offset and length in
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
(That is, you can't just slice ``Message.text`` with the offset and length.)
Args:
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
be an entity that belongs to :attr:`option_text_entities`.
Returns:
:obj:`str`: The text of the given entity.
"""
return parse_message_entity(self.option_text, entity)
def parse_option_text_entities(
self, types: list[str] | None = None
) -> dict[MessageEntity, str]:
"""
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
It contains entities from this polls option text 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:`option_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.option_text, self.option_text_entities, types)
class Poll(TelegramObject):
"""
This object contains information about a poll.
@@ -301,9 +697,17 @@ class Poll(TelegramObject):
is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous.
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers.
members_only (:obj:`bool`): :obj:`True`, if voting is limited to users who have been
members of the chat where the poll was originally sent for more than
:tg-const:`telegram.Poll.MIN_MEMBERSHIP_HOURS` hours.
.. versionadded:: NEXT.VERSION
correct_option_id (:obj:`int`, optional): A zero based identifier of the correct answer
option. Available only for closed polls in the quiz mode, which were sent
(not forwarded), by the bot or to a private chat with the bot.
.. deprecated:: NEXT.VERSION
Use :paramref:`correct_option_ids` instead.
explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect
answer or taps on the lamp icon in a quiz-style poll,
0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters.
@@ -316,6 +720,10 @@ class Poll(TelegramObject):
* This attribute is now always a (possibly empty) list and never :obj:`None`.
* |sequenceclassargs|
explanation_media (:class:`telegram.PollMedia`, optional): Media added to the quiz
explanation.
.. versionadded:: NEXT.VERSION
open_period (:obj:`int` | :class:`datetime.timedelta`, optional): Amount of time in seconds
the poll will be active after creation.
@@ -331,6 +739,33 @@ class Poll(TelegramObject):
in poll questions.
.. versionadded:: 21.2
allows_revoting (:obj:`bool`, optional): :obj:`True`, if the poll allows to
change the chosenanswer options.
.. versionadded:: NEXT.VERSION
correct_option_ids (Sequence[:class:`int`], optional): Array of 0-based identifiers of
the correct answer options. Available only for polls in quiz mode which are closed or
were sent (not forwarded) by the bot or to the private chat with the bot.
.. versionadded:: NEXT.VERSION
country_codes (Sequence[:obj:`str`], optional): A list of two-letter ``ISO 3166-1 alpha-2``
country codes indicating the countries from which users can vote in the poll. The
country code ``"FT"`` is used for users with anonymous numbers. If omitted, then users
from any country can participate in the poll.
.. versionadded:: NEXT.VERSION
description (:obj:`str`, optional): Description of the poll;
for polls inside the :class:`~telegram.Message` object only.
.. versionadded:: NEXT.VERSION
description_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special
entities like usernames, URLs, bot commands, etc. that appear in the description
.. versionadded:: NEXT.VERSION
media (:class:`telegram.PollMedia`, optional): Media added to the poll description;
for polls inside the :class:`~telegram.Message` object only.
.. versionadded:: NEXT.VERSION
Attributes:
id (:obj:`str`): Unique poll identifier.
@@ -345,9 +780,11 @@ class Poll(TelegramObject):
is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous.
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers.
correct_option_id (:obj:`int`): Optional. A zero based identifier of the correct answer
option. Available only for closed polls in the quiz mode, which were sent
(not forwarded), by the bot or to a private chat with the bot.
members_only (:obj:`bool`): :obj:`True`, if voting is limited to users who have been
members of the chat where the poll was originally sent for more than
:tg-const:`telegram.Poll.MIN_MEMBERSHIP_HOURS` hours.
.. versionadded:: NEXT.VERSION
explanation (:obj:`str`): Optional. Text that is shown when a user chooses an incorrect
answer or taps on the lamp icon in a quiz-style poll,
0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters.
@@ -360,6 +797,10 @@ class Poll(TelegramObject):
.. versionchanged:: 20.0
This attribute is now always a (possibly empty) list and never :obj:`None`.
explanation_media (:class:`telegram.PollMedia`): Optional. Media added to the quiz
explanation.
.. versionadded:: NEXT.VERSION
open_period (:obj:`int` | :class:`datetime.timedelta`): Optional. Amount of time in seconds
the poll will be active after creation.
@@ -376,19 +817,53 @@ class Poll(TelegramObject):
This list is empty if the question does not contain entities.
.. versionadded:: 21.2
allows_revoting (:obj:`bool`): :obj:`True`, if the poll
allows to change the chosenanswer options
.. versionadded:: NEXT.VERSION
correct_option_ids (tuple[:class:`int`]): Array of 0-based identifiers of the
correct answer options. Available only for polls in quiz mode which are closed or were
sent (not forwarded) by the bot or to the private chat with the bot.
.. versionadded:: NEXT.VERSION
country_codes (tuple[:obj:`str`]): Optional. A list of two-letter ``ISO 3166-1 alpha-2``
country codes indicating the countries from which users can vote in the poll. The
country code ``"FT"`` is used for users with anonymous numbers. If omitted, then users
from any country can participate in the poll.
.. versionadded:: NEXT.VERSION
description (:obj:`str`): Optional. Description of the poll;
for polls inside the Message object only
.. versionadded:: NEXT.VERSION
description_entities (tuple[:class:`telegram.MessageEntity`]): Special
entities like usernames, URLs, bot commands, etc. that appear in the description
.. versionadded:: NEXT.VERSION
media (:class:`telegram.PollMedia`): Optional. Media added to the poll description;
for polls inside the Message object only.
.. versionadded:: NEXT.VERSION
"""
__slots__ = (
"_open_period",
"allows_multiple_answers",
"allows_revoting",
"close_date",
"correct_option_id",
"correct_option_ids",
"country_codes",
"description",
"description_entities",
"explanation",
"explanation_entities",
"explanation_media",
"id",
"is_anonymous",
"is_closed",
"media",
"members_only",
"options",
"question",
"question_entities",
@@ -406,15 +881,35 @@ class Poll(TelegramObject):
is_anonymous: bool,
type: str, # pylint: disable=redefined-builtin
allows_multiple_answers: bool,
# tags: deprecated NEXT.VERSION
# Removed in bot api 9.6:
correct_option_id: int | None = None,
# ---
explanation: str | None = None,
explanation_entities: Sequence[MessageEntity] | None = None,
open_period: TimePeriod | None = None,
close_date: dtm.datetime | None = None,
question_entities: Sequence[MessageEntity] | None = None,
# tags: required in NEXT.VERSION
# temporarily optional to avoid breaking changes
allows_revoting: bool | None = None,
members_only: bool | None = None,
# ---
correct_option_ids: Sequence[int] | None = None,
description: str | None = None,
description_entities: Sequence[MessageEntity] | None = None,
country_codes: Sequence[str] | None = None,
media: PollMedia | None = None,
explanation_media: PollMedia | None = None,
*,
api_kwargs: JSONDict | None = None,
):
if allows_revoting is None:
raise TypeError("`allows_revoting` is a required argument since Bot API 9.6")
if members_only is None:
raise TypeError("`members_only` is a required argument since Bot API 10.0")
super().__init__(api_kwargs=api_kwargs)
self.id: str = id
self.question: str = question
@@ -424,7 +919,27 @@ class Poll(TelegramObject):
self.is_anonymous: bool = is_anonymous
self.type: str = enum.get_member(constants.PollType, type, type)
self.allows_multiple_answers: bool = allows_multiple_answers
self.correct_option_id: int | None = correct_option_id
self.allows_revoting: bool = allows_revoting
self.members_only: bool = members_only
# tag: deprecated NEXT.VERSION
if correct_option_id is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"The parameter `correct_option_id` is deprecated. "
"Use `correct_option_ids` instead.",
),
stacklevel=2,
)
if correct_option_ids is None:
correct_option_ids = [correct_option_id]
self.correct_option_ids: tuple[int, ...] = parse_sequence_arg(correct_option_ids)
self.description: str | None = description
self.description_entities: tuple[MessageEntity, ...] = parse_sequence_arg(
description_entities
)
self.explanation: str | None = explanation
self.explanation_entities: tuple[MessageEntity, ...] = parse_sequence_arg(
explanation_entities
@@ -432,6 +947,9 @@ class Poll(TelegramObject):
self._open_period: dtm.timedelta | None = to_timedelta(open_period)
self.close_date: dtm.datetime | None = close_date
self.question_entities: tuple[MessageEntity, ...] = parse_sequence_arg(question_entities)
self.country_codes: tuple[str, ...] = parse_sequence_arg(country_codes)
self.media: PollMedia | None = media
self.explanation_media: PollMedia | None = explanation_media
self._id_attrs = (self.id,)
@@ -542,6 +1060,82 @@ class Poll(TelegramObject):
"""
return parse_message_entities(self.question, self.question_entities, types)
def parse_description_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`description` from a given :class:`telegram.MessageEntity` of
:attr:`description_entities`.
.. versionadded:: NEXT.VERSION
Note:
This method is present because Telegram calculates the offset and length in
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
(That is, you can't just slice ``Message.text`` with the offset and length.)
Args:
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
be an entity that belongs to :attr:`description_entities`.
Returns:
:obj:`str`: The text of the given entity.
Raises:
RuntimeError: If the poll has no description.
"""
if not self.description:
raise RuntimeError("This Poll has no 'description'.")
return parse_message_entity(self.description, entity)
def parse_description_entities(
self, types: list[str] | None = None
) -> dict[MessageEntity, str]:
"""
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
It contains entities from this polls description filtered by their ``type`` attribute as
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
.. versionadded:: NEXT.VERSION
Note:
This method should always be used instead of the :attr:`description_entities`
attribute, since it calculates the correct substring from the message text based on
UTF-16 codepoints. See :attr:`parse_description_entity` for more info.
Args:
types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
``type`` attribute of an entity is contained in this list, it will be returned.
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
Returns:
dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities
mapped to the text that belongs to them, calculated based on UTF-16 codepoints.
Raises:
RuntimeError: If the poll has no description.
"""
if not self.description:
raise RuntimeError("This Poll has no 'description'.")
return parse_message_entities(self.description, self.description_entities, types)
@property
def correct_option_id(self) -> int | None:
"""A zero based identifier of the correct answer
option. Available only for closed polls in the quiz mode, which were sent
(not forwarded), by the bot or to a private chat with the bot.
.. deprecated:: NEXT.VERSION
Use :attr:`correct_option_ids` instead.
"""
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"The attribute `correct_option_id` is deprecated. "
"Use `correct_option_ids` instead.",
),
stacklevel=2,
)
return self.correct_option_ids[0] if self.correct_option_ids else None
REGULAR: Final[str] = constants.PollType.REGULAR
""":const:`telegram.constants.PollType.REGULAR`"""
QUIZ: Final[str] = constants.PollType.QUIZ
@@ -596,3 +1190,13 @@ class Poll(TelegramObject):
.. versionadded:: 20.0
"""
MAX_DESCRIPTION_CHARACTERS: Final[int] = constants.PollLimit.MAX_DESCRIPTION_CHARACTERS
""":const:`telegram.constants.PollLimit.MAX_DESCRIPTION_CHARACTERS`
.. versionadded:: NEXT.VERSION
"""
MIN_MEMBERSHIP_HOURS: Final[int] = constants.PollLimit.MIN_MEMBERSHIP_HOURS
""":const:`telegram.constants.PollLimit.MIN_MEMBERSHIP_HOURS`
.. versionadded:: NEXT.VERSION
"""
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2026
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram PreparedKeyboardButton."""
from telegram._telegramobject import TelegramObject
from telegram._utils.types import (
JSONDict,
)
class PreparedKeyboardButton(TelegramObject):
"""
Describes a keyboard button to be used by a user of a Mini App.
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:: NEXT.VERSION
Args:
id (:obj:`str`): Unique identifier of the keyboard button.
Attributes:
id (:obj:`str`): Unique identifier of the keyboard button.
"""
__slots__ = ("id",)
def __init__(
self,
id: str, # pylint: disable=redefined-builtin
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
self.id: str = id
self._id_attrs = (self.id,)
self._freeze()
+34 -10
View File
@@ -27,6 +27,7 @@ from telegram._dice import Dice
from telegram._files.animation import Animation
from telegram._files.audio import Audio
from telegram._files.document import Document
from telegram._files.livephoto import LivePhoto
from telegram._files.photosize import PhotoSize
from telegram._files.sticker import Sticker
from telegram._files.venue import Venue
@@ -113,6 +114,10 @@ class ExternalReplyInfo(TelegramObject):
information about the paid media.
.. versionadded:: 21.4
live_photo (:class:`telegram.LivePhoto`, optional): Message is a live photo, information
about the live photo.
.. versionadded:: NEXT.VERSION
Attributes:
origin (:class:`telegram.MessageOrigin`): Origin of the message replied to by the given
@@ -165,6 +170,11 @@ class ExternalReplyInfo(TelegramObject):
information about the paid media.
.. versionadded:: 21.4
live_photo (:class:`telegram.LivePhoto`): Optional. Message is a live photo, information
about the live photo.
.. versionadded:: NEXT.VERSION
"""
__slots__ = (
@@ -181,6 +191,7 @@ class ExternalReplyInfo(TelegramObject):
"has_media_spoiler",
"invoice",
"link_preview_options",
"live_photo",
"location",
"message_id",
"origin",
@@ -222,6 +233,7 @@ class ExternalReplyInfo(TelegramObject):
venue: Venue | None = None,
paid_media: PaidMediaInfo | None = None,
checklist: Checklist | None = None,
live_photo: LivePhoto | None = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -252,6 +264,7 @@ class ExternalReplyInfo(TelegramObject):
self.poll: Poll | None = poll
self.venue: Venue | None = venue
self.paid_media: PaidMediaInfo | None = paid_media
self.live_photo: LivePhoto | None = live_photo
self._id_attrs = (self.origin,)
@@ -275,8 +288,8 @@ class TextQuote(TelegramObject):
units as specified by the sender.
entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that
appear
in the quote. Currently, only bold, italic, underline, strikethrough, spoiler, and
custom_emoji entities are kept in quotes.
in the quote. Currently, only bold, italic, underline, strikethrough, spoiler,
custom_emoji, and date_time entities are kept in quotes.
is_manual (:obj:`bool`, optional): :obj:`True`, if the quote was chosen manually by the
message sender. Otherwise, the quote was added automatically by the server.
@@ -286,8 +299,8 @@ class TextQuote(TelegramObject):
position (:obj:`int`): Approximate quote position in the original message in UTF-16 code
units as specified by the sender.
entities (tuple[:class:`telegram.MessageEntity`]): Optional. Special entities that appear
in the quote. Currently, only bold, italic, underline, strikethrough, spoiler, and
custom_emoji entities are kept in quotes.
in the quote. Currently, only bold, italic, underline, strikethrough, spoiler,
custom_emoji, and date_time entities are kept in quotes.
is_manual (:obj:`bool`): Optional. :obj:`True`, if the quote was chosen manually by the
message sender. Otherwise, the quote was added automatically by the server.
"""
@@ -349,9 +362,9 @@ class ReplyParameters(TelegramObject):
used only for replies in the same chat and forum topic.
quote (:obj:`str`, optional): Quoted part of the message to be replied to; 0-1024
characters after entities parsing. The quote must be an exact substring of the message
to be replied to, including bold, italic, underline, strikethrough, spoiler, and
custom_emoji entities. The message will fail to send if the quote isn't found in the
original message.
to be replied to, including bold, italic, underline, strikethrough, spoiler,
custom_emoji, and date_time entities. The message will fail to send if the quote isn't
found in the original message.
quote_parse_mode (:obj:`str`, optional): Mode for parsing entities in the quote. See
:wiki:`formatting options <Code-snippets#message-formatting-bold-italic-code->` for
more details.
@@ -365,6 +378,10 @@ class ReplyParameters(TelegramObject):
replied to.
.. versionadded:: 22.4
poll_option_id (:obj:`str`, optional): Persistent
identifier of the specific poll option to be replied to.
.. versionadded:: NEXT.VERSION
Attributes:
message_id (:obj:`int`): Identifier of the message that will be replied to in the current
@@ -377,9 +394,9 @@ class ReplyParameters(TelegramObject):
used only for replies in the same chat and forum topic.
quote (:obj:`str`): Optional. Quoted part of the message to be replied to; 0-1024
characters after entities parsing. The quote must be an exact substring of the message
to be replied to, including bold, italic, underline, strikethrough, spoiler, and
custom_emoji entities. The message will fail to send if the quote isn't found in the
original message.
to be replied to, including bold, italic, underline, strikethrough, spoiler,
custom_emoji, and date_time entities. The message will fail to send if the quote isn't
found in the original message.
quote_parse_mode (:obj:`str`): Optional. Mode for parsing entities in the quote. See
:wiki:`formatting options <Code-snippets#message-formatting-bold-italic-code->` for
more details.
@@ -392,6 +409,10 @@ class ReplyParameters(TelegramObject):
replied to.
.. versionadded:: 22.4
poll_option_id (:obj:`str`): Optional. Persistent
identifier of the specific poll option to be replied to.
.. versionadded:: NEXT.VERSION
"""
__slots__ = (
@@ -399,6 +420,7 @@ class ReplyParameters(TelegramObject):
"chat_id",
"checklist_task_id",
"message_id",
"poll_option_id",
"quote",
"quote_entities",
"quote_parse_mode",
@@ -415,6 +437,7 @@ class ReplyParameters(TelegramObject):
quote_entities: Sequence[MessageEntity] | None = None,
quote_position: int | None = None,
checklist_task_id: int | None = None,
poll_option_id: str | None = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -428,6 +451,7 @@ class ReplyParameters(TelegramObject):
self.quote_entities: tuple[MessageEntity, ...] | None = parse_sequence_arg(quote_entities)
self.quote_position: int | None = quote_position
self.checklist_task_id: int | None = checklist_task_id
self.poll_option_id: str | None = poll_option_id
self._id_attrs = (self.message_id,)
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2026
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Sent Guest Message."""
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class SentGuestMessage(TelegramObject):
"""Describes an inline message sent by a guest bot.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`inline_message_id` are equal.
.. versionadded:: NEXT.VERSION
Args:
inline_message_id (:obj:`str`): Identifier of the sent inline message.
Attributes:
inline_message_id (:obj:`str`): Identifier of the sent inline message.
"""
__slots__ = ("inline_message_id",)
def __init__(
self,
inline_message_id: str,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.inline_message_id: str = inline_message_id
self._id_attrs = (self.inline_message_id,)
self._freeze()
+11 -5
View File
@@ -89,10 +89,14 @@ def _make_seq_transform(
inner_fn = _make_seq_transform(inner_args[0], globalns, tg_ns)
if inner_fn is None:
return None
return lambda v, b, _f=inner_fn: [_f(row, b) for row in v] if isinstance(v, list) else v # type: ignore[misc] # pylint: disable=line-too-long
return lambda v, b, _f=inner_fn: ( # type: ignore[misc]
[_f(row, b) for row in v] if isinstance(v, list) else v
)
if isinstance(item_type, type) and issubclass(item_type, TelegramObject):
return lambda v, b, _c=item_type: _c.de_list(v, b) if isinstance(v, list) else v # type: ignore[misc] # pylint: disable=line-too-long
return lambda v, b, _c=item_type: ( # type: ignore[misc]
_c.de_list(v, b) if isinstance(v, list) else v
)
return None
@@ -235,7 +239,7 @@ class TelegramObject:
:exc:`AttributeError`
"""
# protected attributes can always be set for convenient internal use
if key[0] == "_" or not getattr(self, "_frozen", True):
if key[0] == "_" or not self._frozen:
super().__setattr__(key, value)
return
@@ -250,7 +254,7 @@ class TelegramObject:
:exc:`AttributeError`
"""
# protected attributes can always be set for convenient internal use
if key[0] == "_" or not getattr(self, "_frozen", True):
if key[0] == "_" or not self._frozen:
super().__delattr__(key)
return
@@ -603,7 +607,9 @@ class TelegramObject:
# Dispatch to subclass for delegator classes (e.g. TransactionPartner, ChatMember).
if cls.__DE_JSON_DISPATCH__:
dispatch_key, dispatch_mapping = cls.__DE_JSON_DISPATCH__
target_cls: Tele_co = dispatch_mapping.get(data.get(dispatch_key)) # type: ignore[assignment, arg-type] # pylint: disable=line-too-long
target_cls: Tele_co = dispatch_mapping.get( # type: ignore[assignment]
data.get(dispatch_key) # type: ignore[arg-type]
)
if target_cls is not None:
data.pop(dispatch_key)
return target_cls.de_json(data=data, bot=bot)
+83 -34
View File
@@ -28,6 +28,7 @@ from telegram._chatjoinrequest import ChatJoinRequest
from telegram._chatmemberupdated import ChatMemberUpdated
from telegram._choseninlineresult import ChosenInlineResult
from telegram._inline.inlinequery import InlineQuery
from telegram._managedbot import ManagedBotUpdated
from telegram._message import Message
from telegram._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
from telegram._paidmedia import PaidMediaPurchased
@@ -162,6 +163,16 @@ class Update(TelegramObject):
.. versionadded:: 21.6
managed_bot (:class:`telegram.ManagedBotUpdated`, optional): A new bot was created to be
managed by the bot, or token or owner of a managed bot was changed.
.. versionadded:: NEXT.VERSION
guest_message (:class:`telegram.Message`, optional): New guest message. The bot can use
the field :attr:`telegram.Message.guest_query_id` and the method
:meth:`telegram.Bot.answer_guest_query` to send a message in response.
.. versionadded:: NEXT.VERSION
Attributes:
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
@@ -274,6 +285,15 @@ class Update(TelegramObject):
paid media with a non-empty payload sent by the bot in a non-channel chat.
.. versionadded:: 21.6
managed_bot (:class:`telegram.ManagedBotUpdated`): Optional. A new bot was created to be
managed by the bot, or token or owner of a managed bot was changed.
.. versionadded:: NEXT.VERSION
guest_message (:class:`telegram.Message`): Optional. New guest message. The bot can use
the field :attr:`telegram.Message.guest_query_id` and the method
:meth:`telegram.Bot.answerGuestQuery` to send a message in response.
.. versionadded:: NEXT.VERSION
"""
__slots__ = (
@@ -293,7 +313,9 @@ class Update(TelegramObject):
"edited_business_message",
"edited_channel_post",
"edited_message",
"guest_message",
"inline_query",
"managed_bot",
"message",
"message_reaction",
"message_reaction_count",
@@ -402,6 +424,17 @@ class Update(TelegramObject):
.. versionadded:: 21.6
"""
MANAGED_BOT: Final[str] = constants.UpdateType.MANAGED_BOT
""":const:`telegram.constants.UpdateType.MANAGED_BOT`
.. versionadded:: NEXT.VERSION
"""
GUEST_MESSAGE: Final[str] = constants.UpdateType.GUEST_MESSAGE
""":const:`telegram.constants.UpdateType.GUEST_MESSAGE`
.. versionadded:: NEXT.VERSION
"""
ALL_TYPES: Final[list[str]] = list(constants.UpdateType)
"""list[:obj:`str`]: A list of all available update types.
@@ -433,6 +466,8 @@ class Update(TelegramObject):
edited_business_message: Message | None = None,
deleted_business_messages: BusinessMessagesDeleted | None = None,
purchased_paid_media: PaidMediaPurchased | None = None,
managed_bot: ManagedBotUpdated | None = None,
guest_message: Message | None = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -463,6 +498,8 @@ class Update(TelegramObject):
self.edited_business_message: Message | None = edited_business_message
self.deleted_business_messages: BusinessMessagesDeleted | None = deleted_business_messages
self.purchased_paid_media: PaidMediaPurchased | None = purchased_paid_media
self.managed_bot: ManagedBotUpdated | None = managed_bot
self.guest_message: Message | None = guest_message
self._effective_user: User | None = None
self._effective_sender: User | Chat | None = None
@@ -480,8 +517,6 @@ class Update(TelegramObject):
is. If no user is associated with this update, this gives :obj:`None`. This is the case
if any of
* :attr:`channel_post`
* :attr:`edited_channel_post`
* :attr:`poll`
* :attr:`chat_boost`
* :attr:`removed_chat_boost`
@@ -497,6 +532,10 @@ class Update(TelegramObject):
.. versionchanged:: 21.6
This property now also considers :attr:`purchased_paid_media`.
.. versionchanged:: NEXT.VERSION
This property now also considers :attr:`managed_bot`, :attr:`guest_message`,
:attr:`channel_post`, and :attr:`edited_channel_post`.
Example:
* If :attr:`message` is present, this will give
:attr:`telegram.Message.from_user`.
@@ -508,11 +547,20 @@ class Update(TelegramObject):
user = None
if self.message:
user = self.message.from_user
if message := (
self.message
or self.edited_message
or self.business_message
or self.edited_business_message
or self.guest_message
):
user = message.from_user
elif self.edited_message:
user = self.edited_message.from_user
elif self.channel_post:
user = self.channel_post.from_user
elif self.edited_channel_post:
user = self.edited_channel_post.from_user
elif self.inline_query:
user = self.inline_query.from_user
@@ -544,18 +592,15 @@ class Update(TelegramObject):
elif self.message_reaction:
user = self.message_reaction.user
elif self.business_message:
user = self.business_message.from_user
elif self.edited_business_message:
user = self.edited_business_message.from_user
elif self.business_connection:
user = self.business_connection.user
elif self.purchased_paid_media:
user = self.purchased_paid_media.from_user
elif self.managed_bot:
user = self.managed_bot.user
self._effective_user = user
return user
@@ -580,6 +625,9 @@ class Update(TelegramObject):
is present.
.. versionchanged:: NEXT.VERSION
This property now also considers :attr:`guest_message`.
Example:
* If :attr:`message` is present, this will give either
:attr:`telegram.Message.from_user` or :attr:`telegram.Message.sender_chat`.
@@ -602,6 +650,7 @@ class Update(TelegramObject):
or self.edited_channel_post
or self.business_message
or self.edited_business_message
or self.guest_message
):
sender = message.sender_chat
@@ -626,13 +675,16 @@ class Update(TelegramObject):
This is the case, if :attr:`inline_query`,
:attr:`chosen_inline_result`, :attr:`callback_query` from inline messages,
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll`,
:attr:`poll_answer`, :attr:`business_connection`, or :attr:`purchased_paid_media`
is present.
:attr:`poll_answer`, :attr:`business_connection`, :attr:`purchased_paid_media`,
or :attr:`managed_bot` is present.
.. versionchanged:: 21.1
This property now also considers :attr:`business_message`,
:attr:`edited_business_message`, and :attr:`deleted_business_messages`.
.. versionchanged:: NEXT.VERSION
This property now also considers :attr:`guest_message`.
Example:
If :attr:`message` is present, this will give :attr:`telegram.Message.chat`.
@@ -642,21 +694,21 @@ class Update(TelegramObject):
chat = None
if self.message:
chat = self.message.chat
elif self.edited_message:
chat = self.edited_message.chat
if message := (
self.message
or self.edited_message
or self.channel_post
or self.edited_channel_post
or self.business_message
or self.edited_business_message
or self.deleted_business_messages
or self.guest_message
):
chat = message.chat
elif self.callback_query and self.callback_query.message:
chat = self.callback_query.message.chat
elif self.channel_post:
chat = self.channel_post.chat
elif self.edited_channel_post:
chat = self.edited_channel_post.chat
elif self.my_chat_member:
chat = self.my_chat_member.chat
@@ -678,15 +730,6 @@ class Update(TelegramObject):
elif self.message_reaction_count:
chat = self.message_reaction_count.chat
elif self.business_message:
chat = self.business_message.chat
elif self.edited_business_message:
chat = self.edited_business_message.chat
elif self.deleted_business_messages:
chat = self.deleted_business_messages.chat
self._effective_chat = chat
return chat
@@ -703,6 +746,9 @@ class Update(TelegramObject):
This property now also considers :attr:`business_message`, and
:attr:`edited_business_message`.
.. versionchanged:: NEXT.VERSION
This property now also considers :attr:`guest_message`.
Tip:
This property will only ever return objects of type :class:`telegram.Message` or
:obj:`None`, never :class:`telegram.MaybeInaccessibleMessage` or
@@ -751,5 +797,8 @@ class Update(TelegramObject):
elif self.edited_business_message:
message = self.edited_business_message
elif self.guest_message:
message = self.guest_message
self._effective_message = message
return message
+358 -5
View File
@@ -29,6 +29,7 @@ from telegram._telegramobject import TelegramObject
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import (
CorrectOptionID,
CorrectOptionIds,
JSONDict,
ODVInput,
TimePeriod,
@@ -41,17 +42,21 @@ if TYPE_CHECKING:
from telegram import (
Animation,
Audio,
BotAccessSettings,
Contact,
Document,
Gift,
InlineKeyboardMarkup,
InputMediaAudio,
InputMediaDocument,
InputMediaLivePhoto,
InputMediaPhoto,
InputMediaVideo,
InputPollMedia,
InputPollOption,
LabeledPrice,
LinkPreviewOptions,
LivePhoto,
Location,
Message,
MessageEntity,
@@ -107,7 +112,7 @@ class User(TelegramObject):
.. versionadded:: 20.0
can_connect_to_business (:obj:`bool`, optional): :obj:`True`, if the bot can be connected
to a Telegram Business account to receive its messages. Returned only in
to a user account to manage it. Returned only in
:meth:`telegram.Bot.get_me`.
.. versionadded:: 21.1
@@ -124,6 +129,15 @@ class User(TelegramObject):
:meth:`telegram.Bot.get_me`.
.. versionadded:: 22.7
can_manage_bots (:obj:`bool`, optional): :obj:`True`, if other bots can be created to be
controlled by the bot. Returned only in :meth:`telegram.Bot.get_me`.
.. versionadded:: NEXT.VERSION
supports_guest_queries (:obj:`bool`, optional): :obj:`True`, if the bot supports guest
queries from chats it is not a member of. Returned only in
:meth:`telegram.Bot.get_me`.
.. versionadded:: NEXT.VERSION
Attributes:
id (:obj:`int`): Unique identifier for this user or bot.
@@ -164,6 +178,15 @@ class User(TelegramObject):
:meth:`telegram.Bot.get_me`.
.. versionadded:: 22.7
can_manage_bots (:obj:`bool`): Optional. :obj:`True`, if other bots can be created to be
controlled by the bot. Returned only in :meth:`telegram.Bot.get_me`.
.. versionadded:: NEXT.VERSION
supports_guest_queries (:obj:`bool`): Optional. :obj:`True`, if the bot supports guest
queries from chats it is not a member of. Returned only in
:meth:`telegram.Bot.get_me`.
.. versionadded:: NEXT.VERSION
.. |user_chat_id_note| replace:: This shortcuts build on the assumption that :attr:`User.id`
coincides with the :attr:`Chat.id` of the private chat with the user. This has been the
@@ -175,6 +198,7 @@ class User(TelegramObject):
"allows_users_to_create_topics",
"can_connect_to_business",
"can_join_groups",
"can_manage_bots",
"can_read_all_group_messages",
"first_name",
"has_main_web_app",
@@ -184,6 +208,7 @@ class User(TelegramObject):
"is_premium",
"language_code",
"last_name",
"supports_guest_queries",
"supports_inline_queries",
"username",
)
@@ -205,6 +230,8 @@ class User(TelegramObject):
has_main_web_app: bool | None = None,
has_topics_enabled: bool | None = None,
allows_users_to_create_topics: bool | None = None,
can_manage_bots: bool | None = None,
supports_guest_queries: bool | None = None,
*,
api_kwargs: JSONDict | None = None,
):
@@ -226,6 +253,8 @@ class User(TelegramObject):
self.has_main_web_app: bool | None = has_main_web_app
self.has_topics_enabled: bool | None = has_topics_enabled
self.allows_users_to_create_topics: bool | None = allows_users_to_create_topics
self.can_manage_bots: bool | None = can_manage_bots
self.supports_guest_queries: bool | None = supports_guest_queries
self._id_attrs = (self.id,)
@@ -516,7 +545,7 @@ class User(TelegramObject):
async def send_message_draft(
self,
draft_id: int,
text: str,
text: str | None = None,
message_thread_id: int | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
entities: Sequence["MessageEntity"] | None = None,
@@ -538,6 +567,9 @@ class User(TelegramObject):
.. versionadded:: 22.6
.. versionchanged:: NEXT.VERSION
Bot API 10.0 makes the ``text`` argument optional.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -689,10 +721,83 @@ class User(TelegramObject):
suggested_post_parameters=suggested_post_parameters,
)
async def send_live_photo(
self,
live_photo: "FileInput | LivePhoto",
photo: "FileInput | PhotoSize",
business_connection_id: str | None = None,
message_thread_id: int | None = None,
direct_messages_topic_id: int | None = None,
caption: str | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence["MessageEntity"] | None = None,
show_caption_above_media: bool | None = None,
has_spoiler: bool | None = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
allow_paid_broadcast: bool | None = None,
message_effect_id: str | None = None,
suggested_post_parameters: "SuggestedPostParameters | None" = None,
reply_parameters: "ReplyParameters | None" = None,
reply_markup: "ReplyMarkup | None" = None,
*,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int | None = None,
filename: str | None = 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: JSONDict | None = None,
) -> "Message":
"""Shortcut for::
await bot.send_live_photo(update.effective_user.id, *args, **kwargs)
For the documentation of the arguments, please see :meth:`telegram.Bot.send_live_photo`.
.. versionadded:: NEXT.VERSION
Note:
|user_chat_id_note|
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
return await self.get_bot().send_live_photo(
chat_id=self.id,
live_photo=live_photo,
photo=photo,
business_connection_id=business_connection_id,
message_thread_id=message_thread_id,
direct_messages_topic_id=direct_messages_topic_id,
caption=caption,
parse_mode=parse_mode,
caption_entities=caption_entities,
show_caption_above_media=show_caption_above_media,
has_spoiler=has_spoiler,
disable_notification=disable_notification,
protect_content=protect_content,
allow_paid_broadcast=allow_paid_broadcast,
message_effect_id=message_effect_id,
suggested_post_parameters=suggested_post_parameters,
reply_parameters=reply_parameters,
reply_markup=reply_markup,
allow_sending_without_reply=allow_sending_without_reply,
reply_to_message_id=reply_to_message_id,
filename=filename,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def send_media_group(
self,
media: Sequence[
"InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo"
"InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo | InputMediaLivePhoto" # noqa: E501 # pylint: disable=line-too-long
],
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
@@ -1730,6 +1835,18 @@ class User(TelegramObject):
question_entities: Sequence["MessageEntity"] | None = None,
message_effect_id: str | None = None,
allow_paid_broadcast: bool | None = None,
shuffle_options: bool | None = None,
allows_revoting: bool | None = None,
correct_option_ids: CorrectOptionIds | None = None,
allow_adding_options: bool | None = None,
hide_results_until_closes: bool | None = None,
description: str | None = None,
description_parse_mode: ODVInput[str] | None = None,
description_entities: Sequence["MessageEntity"] | None = None,
members_only: bool | None = None,
country_codes: Sequence[str] | None = None,
explanation_media: "InputPollMedia | None" = None,
media: "InputPollMedia | None" = None,
*,
reply_to_message_id: int | None = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
@@ -1760,6 +1877,9 @@ class User(TelegramObject):
type=type, # pylint=pylint,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
correct_option_ids=correct_option_ids,
is_closed=is_closed,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
@@ -1769,6 +1889,8 @@ class User(TelegramObject):
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
message_effect_id=message_effect_id,
allow_paid_broadcast=allow_paid_broadcast,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
open_period=open_period,
@@ -1781,8 +1903,15 @@ class User(TelegramObject):
business_connection_id=business_connection_id,
question_parse_mode=question_parse_mode,
question_entities=question_entities,
message_effect_id=message_effect_id,
allow_paid_broadcast=allow_paid_broadcast,
description=description,
description_parse_mode=description_parse_mode,
description_entities=description_entities,
hide_results_until_closes=hide_results_until_closes,
allow_adding_options=allow_adding_options,
members_only=members_only,
country_codes=country_codes,
explanation_media=explanation_media,
media=media,
)
async def send_gift(
@@ -2712,3 +2841,227 @@ class User(TelegramObject):
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def replace_token(
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: JSONDict | None = None,
) -> str:
"""
Shortcut for::
await bot.replace_managed_bot_token(user_id=update.effective_user.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.replace_managed_bot_token`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`str`: On success, :obj:`str` is returned.
"""
return await self.get_bot().replace_managed_bot_token(
user_id=self.id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def get_managed_bot_access_settings(
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: JSONDict | None = None,
) -> "BotAccessSettings":
"""
Shortcut for::
await bot.get_managed_bot_access_settings(
user_id=update.effective_user.id,
*args, **kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.get_managed_bot_access_settings`.
.. versionadded:: NEXT.VERSION
Returns:
:class:`telegram.BotAccessSettings`: On success, returns the access settings of the bot
managed by the user.
"""
return await self.get_bot().get_managed_bot_access_settings(
user_id=self.id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def set_managed_bot_access_settings(
self,
is_access_restricted: bool,
added_user_ids: Sequence[int] | None = 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: JSONDict | None = None,
) -> bool:
"""
Shortcut for::
await bot.set_managed_bot_access_settings(
user_id=update.effective_user.id,
*args, **kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.set_managed_bot_access_settings`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().set_managed_bot_access_settings(
user_id=self.id,
is_access_restricted=is_access_restricted,
added_user_ids=added_user_ids,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def delete_reaction(
self,
chat_id: int | str,
message_id: int,
actor_chat_id: int | None = 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: JSONDict | None = None,
) -> bool:
"""
Shortcut for::
await bot.delete_message_reaction(
user_id=update.effective_user.id,
*args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_message_reaction`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().delete_message_reaction(
user_id=self.id,
chat_id=chat_id,
message_id=message_id,
actor_chat_id=actor_chat_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def get_personal_chat_messages(
self,
limit: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
) -> tuple["Message", ...]:
"""
Shortcut for::
await bot.get_user_personal_chat_messages(
user_id=update.effective_user.id,
*args, **kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.get_user_personal_chat_messages`.
.. versionadded:: NEXT.VERSION
Returns:
tuple[:class:`telegram.Message`]: On success, a tuple of messages from the personal
channel chat is returned.
"""
return await self.get_bot().get_user_personal_chat_messages(
user_id=self.id,
limit=limit,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def delete_all_reactions(
self,
chat_id: int | str,
actor_chat_id: int | None = 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: JSONDict | None = None,
) -> bool:
"""
Shortcut for::
await bot.delete_all_message_reactions(
user_id=update.effective_user.id,
*args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_all_message_reactions`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().delete_all_message_reactions(
chat_id=chat_id,
user_id=self.id,
actor_chat_id=actor_chat_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
+6 -1
View File
@@ -25,7 +25,7 @@ Warning:
"""
import datetime as dtm
from collections.abc import Callable, Collection
from collections.abc import Callable, Collection, Sequence
from pathlib import Path
from typing import IO, TYPE_CHECKING, Any, Literal, TypeAlias, TypeVar, Union
@@ -93,6 +93,11 @@ HTTPVersion: TypeAlias = Literal["1.1", "2.0", "2"]
CorrectOptionID: TypeAlias = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # pylint: disable=invalid-name
CorrectOptionIds: TypeAlias = Sequence[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]]
"""
.. versionadded:: NEXT.VERSION
"""
MarkdownVersion: TypeAlias = Literal[1, 2]
SocketOpt: TypeAlias = (
+4 -2
View File
@@ -58,7 +58,8 @@ class WebhookInfo(TelegramObject):
connections to the webhook for update delivery.
allowed_updates (Sequence[:obj:`str`], optional): A sequence of update types the bot is
subscribed to. Defaults to all update types, except
:attr:`telegram.Update.chat_member`.
:attr:`~telegram.Update.chat_member`, :attr:`~telegram.Update.message_reaction`,
and :attr:`~telegram.Update.message_reaction_count`.
.. versionchanged:: 20.0
|sequenceclassargs|
@@ -88,7 +89,8 @@ class WebhookInfo(TelegramObject):
connections to the webhook for update delivery.
allowed_updates (tuple[:obj:`str`]): Optional. A tuple of update types the bot is
subscribed to. Defaults to all update types, except
:attr:`telegram.Update.chat_member`.
:attr:`~telegram.Update.chat_member`, :attr:`~telegram.Update.message_reaction`,
and :attr:`~telegram.Update.message_reaction_count`.
.. versionchanged:: 20.0
+153 -5
View File
@@ -45,6 +45,7 @@ __all__ = [
"BackgroundFillType",
"BackgroundTypeLimit",
"BackgroundTypeType",
"BaseInputMediaType",
"BotCommandLimit",
"BotCommandScopeType",
"BotDescriptionLimit",
@@ -87,6 +88,7 @@ __all__ = [
"KeyboardButtonRequestUsersLimit",
"KeyboardButtonStyle",
"LocationLimit",
"ManagedBotAccessLimit",
"MaskPosition",
"MediaGroupLimit",
"MenuButtonType",
@@ -101,6 +103,7 @@ __all__ = [
"OwnedGiftType",
"PaidMediaType",
"ParseMode",
"PersonalChatMessagesLimit",
"PollLimit",
"PollType",
"PollingLimit",
@@ -181,7 +184,7 @@ class _AccentColor(NamedTuple):
#: :data:`telegram.__bot_api_version_info__`.
#:
#: .. versionadded:: 20.0
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=9, minor=5)
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=10, minor=0)
#: :obj:`str`: Telegram Bot API
#: version supported by this version of `python-telegram-bot`. Also available as
#: :data:`telegram.__bot_api_version__`.
@@ -1519,10 +1522,43 @@ class InputChecklistLimit(IntEnum):
"""
class BaseInputMediaType(StringEnum):
"""This enum contains the available types of :class:`telegram.InputMedia`,
:class:`telegram.InputPollMedia` and :class:`telegram.InputPollOptionMedia`. The enum
members of this enumeration are instances of :class:`str` and can be treated as such.
.. versionadded:: NEXT.VERSION
"""
__slots__ = ()
ANIMATION = "animation"
""":obj:`str`: Type of :class:`telegram.InputMediaAnimation`."""
DOCUMENT = "document"
""":obj:`str`: Type of :class:`telegram.InputMediaDocument`."""
AUDIO = "audio"
""":obj:`str`: Type of :class:`telegram.InputMediaAudio`."""
PHOTO = "photo"
""":obj:`str`: Type of :class:`telegram.InputMediaPhoto`."""
VIDEO = "video"
""":obj:`str`: Type of :class:`telegram.InputMediaVideo`."""
LOCATION = "location"
""":obj:`str`: Type of :class:`telegram.InputMediaLocation`."""
STICKER = "sticker"
""":obj:`str`: Type of :class:`telegram.InputMediaSticker`."""
VENUE = "venue"
""":obj:`str`: Type of :class:`telegram.InputMediaVenue`."""
LIVE_PHOTO = "live_photo"
""":obj:`str`: Type of :class:`telegram.InputMediaLivePhoto`."""
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.
.. deprecated:: NEXT.VERSION
Use :class:`telegram.constants.BaseInputMediaType` instead.
.. versionadded:: 20.0
"""
@@ -1538,6 +1574,11 @@ class InputMediaType(StringEnum):
""":obj:`str`: Type of :class:`telegram.InputMediaPhoto`."""
VIDEO = "video"
""":obj:`str`: Type of :class:`telegram.InputMediaVideo`."""
LIVE_PHOTO = "live_photo"
""":obj:`str`: Type of :class:`telegram.InputMediaLivePhoto`.
.. versionadded:: NEXT.VERSION
"""
class InputPaidMediaType(StringEnum):
@@ -1550,9 +1591,14 @@ class InputPaidMediaType(StringEnum):
__slots__ = ()
PHOTO = "photo"
""":obj:`str`: Type of :class:`telegram.InputMediaPhoto`."""
""":obj:`str`: Type of :class:`telegram.InputPaidMediaPhoto`."""
VIDEO = "video"
""":obj:`str`: Type of :class:`telegram.InputMediaVideo`."""
""":obj:`str`: Type of :class:`telegram.InputPaidMediaVideo`."""
LIVE_PHOTO = "live_photo"
""":obj:`str`: Type of :class:`telegram.InputPaidMediaLivePhoto`.
.. versionadded:: NEXT.VERSION
"""
class InputProfilePhotoType(StringEnum):
@@ -1784,6 +1830,8 @@ class LocationLimit(IntEnum):
:meth:`telegram.Bot.edit_message_live_location`
* :paramref:`~telegram.Bot.send_location.horizontal_accuracy` parameter of
:meth:`telegram.Bot.send_location`
* :paramref:`~telegram.InputMediaLocation.horizontal_accuracy` parameter of
:class:`telegram.InputMediaLocation`
"""
MIN_HEADING = 1
@@ -1963,6 +2011,11 @@ class MessageAttachmentType(StringEnum):
""":obj:`str`: Messages with :attr:`telegram.Message.game`."""
INVOICE = "invoice"
""":obj:`str`: Messages with :attr:`telegram.Message.invoice`."""
LIVE_PHOTO = "live_photo"
""":obj:`str`: Messages with :attr:`telegram.Message.live_photo`.
.. versionadded:: NEXT.VERSION
"""
LOCATION = "location"
""":obj:`str`: Messages with :attr:`telegram.Message.location`."""
PAID_MEDIA = "paid_media"
@@ -2345,8 +2398,15 @@ class MessageType(StringEnum):
""":obj:`str`: Messages with :attr:`telegram.Message.invoice`."""
LEFT_CHAT_MEMBER = "left_chat_member"
""":obj:`str`: Messages with :attr:`telegram.Message.left_chat_member`."""
LIVE_PHOTO = "live_photo"
""":obj:`str`: Messages with :attr:`telegram.Message.live_photo`.
.. versionadded:: NEXT.VERSION
"""
LOCATION = "location"
""":obj:`str`: Messages with :attr:`telegram.Message.location`."""
MANAGED_BOT_CREATED = "managed_bot_created"
""":obj:`str`: Messages with :attr:`telegram.Message.managed_bot_created`."""
MESSAGE_AUTO_DELETE_TIMER_CHANGED = "message_auto_delete_timer_changed"
""":obj:`str`: Messages with :attr:`telegram.Message.message_auto_delete_timer_changed`."""
MIGRATE_TO_CHAT_ID = "migrate_to_chat_id"
@@ -2367,6 +2427,16 @@ class MessageType(StringEnum):
.. versionadded:: v22.2
"""
POLL_OPTION_ADDED = "poll_option_added"
""":obj:`str`: Messages with :attr:`telegram.Message.poll_option_added`.
.. versionadded:: NEXT.VERSION
"""
POLL_OPTION_DELETED = "poll_option_deleted"
""":obj:`str`: Messages with :attr:`telegram.Message.poll_option_deleted`.
.. versionadded:: NEXT.VERSION
"""
SUGGESTED_POST_APPROVAL_FAILED = "suggested_post_approval_failed"
""":obj:`str`: Messages with :attr:`telegram.Message.suggested_post_approval_failed`.
@@ -2554,6 +2624,33 @@ class PaidMediaType(StringEnum):
""":obj:`str`: The type of :class:`telegram.PaidMediaVideo`."""
PHOTO = "photo"
""":obj:`str`: The type of :class:`telegram.PaidMediaPhoto`."""
LIVE_PHOTO = "live_photo"
""":obj:`str`: The type of :class:`telegram.PaidMediaLivePhoto`
.. versionadded:: NEXT.VERSION
"""
class PersonalChatMessagesLimit(IntEnum):
"""This enum contains limitations for
:paramref:`telegram.Bot.get_user_personal_chat_messages.limit`.
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
.. versionadded:: NEXT.VERSION
"""
__slots__ = ()
MIN_LIMIT = 1
""":obj:`int`: Minimum value allowed for the
:paramref:`~telegram.Bot.get_user_personal_chat_messages.limit`
parameter of :meth:`telegram.Bot.get_user_personal_chat_messages`.
"""
MAX_LIMIT = 20
""":obj:`int`: Maximum value allowed for the
:paramref:`~telegram.Bot.get_user_personal_chat_messages.limit`
parameter of :meth:`telegram.Bot.get_user_personal_chat_messages`.
"""
class PollingLimit(IntEnum):
@@ -3410,10 +3507,13 @@ class PollLimit(IntEnum):
to the :paramref:`~telegram.Bot.send_poll.options` parameter of
:meth:`telegram.Bot.send_poll`.
"""
MIN_OPTION_NUMBER = 2
MIN_OPTION_NUMBER = 1
""":obj:`int`: Minimum number of strings passed in a :obj:`list`
to the :paramref:`~telegram.Bot.send_poll.options` parameter of
:meth:`telegram.Bot.send_poll`.
.. versionchanged:: NEXT.VERSION
Bot API 10.0 decreased this value from ``2`` to ``1``.
"""
MAX_OPTION_NUMBER = 12
""":obj:`int`: Maximum number of strings passed in a :obj:`list`
@@ -3439,11 +3539,33 @@ class PollLimit(IntEnum):
Also used in the :paramref:`~telegram.Bot.send_poll.close_date` parameter of
:meth:`telegram.Bot.send_poll`.
"""
MAX_OPEN_PERIOD = 600
MAX_OPEN_PERIOD = 2628000
""":obj:`int`: Maximum value allowed for the
:paramref:`~telegram.Bot.send_poll.open_period` parameter of :meth:`telegram.Bot.send_poll`.
Also used in the :paramref:`~telegram.Bot.send_poll.close_date` parameter of
:meth:`telegram.Bot.send_poll`.
.. versionchanged:: NEXT.VERSION
Changed from ``600`` to ``2628000`` since Bot API 9.6.
"""
MAX_DESCRIPTION_CHARACTERS = 1024
""":obj:`int`: Maximum value allowed for the
:paramref:`~telegram.Bot.send_poll.description` parameter of :meth:`telegram.Bot.send_poll`.
.. versionadded:: NEXT.VERSION
"""
MIN_MEMBERSHIP_HOURS = 24
""":obj:`int`: Minimum number of hours a user must have been a member of the chat
before they can vote in a members-only poll.
.. versionadded:: NEXT.VERSION
"""
MAX_COUNTRY_CODES = 12
""":obj:`int`: Maximum number of two-letter ``ISO 3166-1 alpha-2`` country codes passed in a
:obj:`list` to the :paramref:`~telegram.Bot.send_poll.country_codes` parameter of
:meth:`telegram.Bot.send_poll`.
.. versionadded:: NEXT.VERSION
"""
@@ -3594,6 +3716,16 @@ class UpdateType(StringEnum):
.. versionadded:: 21.6
"""
MANAGED_BOT = "managed_bot"
""":obj:`str`: Updates with :attr:`telegram.Update.managed_bot`.
.. versionadded:: NEXT.VERSION
"""
GUEST_MESSAGE = "guest_message"
""":obj:`str`: Updates with :attr:`telegram.Update.guest_message`.
.. versionadded:: NEXT.VERSION
"""
class InvoiceLimit(IntEnum):
@@ -4013,6 +4145,22 @@ class ReactionEmoji(StringEnum):
""":obj:`str`: Pouting face"""
class ManagedBotAccessLimit(IntEnum):
"""This enum contains limitations for :meth:`~telegram.Bot.set_managed_bot_access_settings`.
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
.. versionadded:: NEXT.VERSION
"""
__slots__ = ()
MAX_ALLOWED_USERS = 10
""":obj:`int`: Maximum number of users that can be allowed to access a managed bot in the
:paramref:`~telegram.Bot.set_managed_bot_access_settings.added_user_ids` parameter of
:meth:`~telegram.Bot.set_managed_bot_access_settings`.
"""
class VerifyLimit(IntEnum):
"""This enum contains limitations for :meth:`~telegram.Bot.verify_chat` and
:meth:`~telegram.Bot.verify_user`.
+2
View File
@@ -46,6 +46,7 @@ __all__ = (
"InvalidCallbackData",
"Job",
"JobQueue",
"ManagedBotUpdatedHandler",
"MessageHandler",
"MessageReactionHandler",
"PaidMediaPurchasedHandler",
@@ -88,6 +89,7 @@ from ._handlers.choseninlineresulthandler import ChosenInlineResultHandler
from ._handlers.commandhandler import CommandHandler
from ._handlers.conversationhandler import ConversationHandler
from ._handlers.inlinequeryhandler import InlineQueryHandler
from ._handlers.managedbotupdatedhandler import ManagedBotUpdatedHandler
from ._handlers.messagehandler import MessageHandler
from ._handlers.messagereactionhandler import MessageReactionHandler
from ._handlers.paidmediapurchasedhandler import PaidMediaPurchasedHandler
+313 -5
View File
@@ -38,6 +38,7 @@ from telegram import (
Animation,
Audio,
Bot,
BotAccessSettings,
BotCommand,
BotCommandScope,
BotDescription,
@@ -63,6 +64,7 @@ from telegram import (
InputPaidMedia,
InputPollOption,
InputProfilePhoto,
KeyboardButton,
LinkPreviewOptions,
MaskPosition,
MenuButton,
@@ -72,8 +74,10 @@ from telegram import (
PhotoSize,
Poll,
PreparedInlineMessage,
PreparedKeyboardButton,
ReactionType,
ReplyParameters,
SentGuestMessage,
SentWebAppMessage,
StarAmount,
StarTransactions,
@@ -98,6 +102,7 @@ from telegram._utils.repr import build_repr_with_selected_attrs
from telegram._utils.types import (
BaseUrl,
CorrectOptionID,
CorrectOptionIds,
FileInput,
JSONDict,
ODVInput,
@@ -116,11 +121,14 @@ if TYPE_CHECKING:
InlineQueryResult,
InputMediaAudio,
InputMediaDocument,
InputMediaLivePhoto,
InputMediaPhoto,
InputMediaVideo,
InputPollMedia,
InputSticker,
InputStoryContent,
LabeledPrice,
LivePhoto,
Location,
MessageEntity,
PassportElementError,
@@ -1116,6 +1124,28 @@ class ExtBot(Bot, Generic[RLARGS]):
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def answer_guest_query(
self,
guest_query_id: str,
result: "InlineQueryResult",
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> SentGuestMessage:
return await super().answer_guest_query(
guest_query_id=guest_query_id,
result=result,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def approve_chat_join_request(
self,
chat_id: str | int,
@@ -1841,6 +1871,7 @@ class ExtBot(Bot, Generic[RLARGS]):
async def get_chat_administrators(
self,
chat_id: str | int,
return_bots: bool | None = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -1851,6 +1882,7 @@ class ExtBot(Bot, Generic[RLARGS]):
) -> tuple[ChatMember, ...]:
return await super().get_chat_administrators(
chat_id=chat_id,
return_bots=return_bots,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
@@ -2686,7 +2718,7 @@ class ExtBot(Bot, Generic[RLARGS]):
async def send_checklist(
self,
business_connection_id: str,
chat_id: int,
chat_id: int | str,
checklist: InputChecklist,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
@@ -2724,7 +2756,7 @@ class ExtBot(Bot, Generic[RLARGS]):
async def edit_message_checklist(
self,
business_connection_id: str,
chat_id: int,
chat_id: int | str,
message_id: int,
checklist: InputChecklist,
reply_markup: "InlineKeyboardMarkup | None" = None,
@@ -2855,7 +2887,7 @@ class ExtBot(Bot, Generic[RLARGS]):
async def send_game(
self,
chat_id: int,
chat_id: int | str,
game_short_name: str,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "InlineKeyboardMarkup | None" = None,
@@ -3041,7 +3073,7 @@ class ExtBot(Bot, Generic[RLARGS]):
self,
chat_id: int | str,
media: Sequence[
"InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo"
"InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo | InputMediaLivePhoto" # noqa: E501 # pylint: disable=line-too-long
],
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
@@ -3145,7 +3177,7 @@ class ExtBot(Bot, Generic[RLARGS]):
self,
chat_id: int,
draft_id: int,
text: str,
text: str | None = None,
message_thread_id: int | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
entities: Sequence["MessageEntity"] | None = None,
@@ -3254,6 +3286,18 @@ class ExtBot(Bot, Generic[RLARGS]):
question_entities: Sequence["MessageEntity"] | None = None,
message_effect_id: str | None = None,
allow_paid_broadcast: bool | None = None,
allows_revoting: bool | None = None,
allow_adding_options: bool | None = None,
hide_results_until_closes: bool | None = None,
correct_option_ids: CorrectOptionIds | None = None,
description: str | None = None,
description_parse_mode: ODVInput[str] | None = None,
description_entities: Sequence["MessageEntity"] | None = None,
shuffle_options: bool | None = None,
members_only: bool | None = None,
country_codes: Sequence[str] | None = None,
explanation_media: "InputPollMedia | None" = None,
media: "InputPollMedia | None" = None,
*,
reply_to_message_id: int | None = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
@@ -3295,6 +3339,18 @@ class ExtBot(Bot, Generic[RLARGS]):
question_entities=question_entities,
message_effect_id=message_effect_id,
allow_paid_broadcast=allow_paid_broadcast,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
correct_option_ids=correct_option_ids,
description=description,
description_parse_mode=description_parse_mode,
description_entities=description_entities,
hide_results_until_closes=hide_results_until_closes,
allow_adding_options=allow_adding_options,
members_only=members_only,
country_codes=country_codes,
explanation_media=explanation_media,
media=media,
)
async def send_sticker(
@@ -5013,6 +5069,74 @@ class ExtBot(Bot, Generic[RLARGS]):
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def get_managed_bot_access_settings(
self,
user_id: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> BotAccessSettings:
return await super().get_managed_bot_access_settings(
user_id=user_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def set_managed_bot_access_settings(
self,
user_id: int,
is_access_restricted: bool,
added_user_ids: Sequence[int] | None = 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: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> bool:
return await super().set_managed_bot_access_settings(
user_id=user_id,
is_access_restricted=is_access_restricted,
added_user_ids=added_user_ids,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def get_user_personal_chat_messages(
self,
user_id: int,
limit: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> tuple[Message, ...]:
return await super().get_user_personal_chat_messages(
user_id=user_id,
limit=limit,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def send_paid_media(
self,
chat_id: str | int,
@@ -5511,6 +5635,180 @@ class ExtBot(Bot, Generic[RLARGS]):
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def get_managed_bot_token(
self,
user_id: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> str:
return await super().get_managed_bot_token(
user_id=user_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def replace_managed_bot_token(
self,
user_id: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> str:
return await super().replace_managed_bot_token(
user_id=user_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def save_prepared_keyboard_button(
self,
user_id: int,
button: KeyboardButton,
*,
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: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> PreparedKeyboardButton:
return await super().save_prepared_keyboard_button(
user_id=user_id,
button=button,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def send_live_photo(
self,
chat_id: int | str,
live_photo: "FileInput | LivePhoto",
photo: "FileInput | PhotoSize",
business_connection_id: str | None = None,
message_thread_id: int | None = None,
direct_messages_topic_id: int | None = None,
caption: str | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence["MessageEntity"] | None = None,
show_caption_above_media: bool | None = None,
has_spoiler: bool | None = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
allow_paid_broadcast: bool | None = None,
message_effect_id: str | None = None,
suggested_post_parameters: "SuggestedPostParameters | None" = None,
reply_parameters: "ReplyParameters | None" = None,
reply_markup: "ReplyMarkup | None" = None,
*,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int | None = None,
filename: str | None = 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: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> Message:
return await super().send_live_photo(
chat_id=chat_id,
live_photo=live_photo,
photo=photo,
business_connection_id=business_connection_id,
message_thread_id=message_thread_id,
direct_messages_topic_id=direct_messages_topic_id,
caption=caption,
parse_mode=parse_mode,
caption_entities=caption_entities,
show_caption_above_media=show_caption_above_media,
has_spoiler=has_spoiler,
disable_notification=disable_notification,
protect_content=protect_content,
allow_paid_broadcast=allow_paid_broadcast,
message_effect_id=message_effect_id,
suggested_post_parameters=suggested_post_parameters,
reply_parameters=reply_parameters,
allow_sending_without_reply=allow_sending_without_reply,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup,
filename=filename,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def delete_message_reaction(
self,
chat_id: int | str,
message_id: int,
user_id: int | None = None,
actor_chat_id: int | None = 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: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> bool:
return await super().delete_message_reaction(
chat_id=chat_id,
message_id=message_id,
user_id=user_id,
actor_chat_id=actor_chat_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def delete_all_message_reactions(
self,
chat_id: int | str,
user_id: int | None = None,
actor_chat_id: int | None = 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: JSONDict | None = None,
rate_limit_args: RLARGS | None = None,
) -> bool:
return await super().delete_all_message_reactions(
chat_id=chat_id,
user_id=user_id,
actor_chat_id=actor_chat_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
# updated camelCase aliases
getMe = get_me
sendMessage = send_message
@@ -5565,6 +5863,7 @@ class ExtBot(Bot, Generic[RLARGS]):
answerShippingQuery = answer_shipping_query
answerPreCheckoutQuery = answer_pre_checkout_query
answerWebAppQuery = answer_web_app_query
answerGuestQuery = answer_guest_query
restrictChatMember = restrict_chat_member
promoteChatMember = promote_chat_member
setChatPermissions = set_chat_permissions
@@ -5677,3 +5976,12 @@ class ExtBot(Bot, Generic[RLARGS]):
removeMyProfilePhoto = remove_my_profile_photo
getUserProfileAudios = get_user_profile_audios
setChatMemberTag = set_chat_member_tag
getManagedBotToken = get_managed_bot_token
replaceManagedBotToken = replace_managed_bot_token
savePreparedKeyboardButton = save_prepared_keyboard_button
sendLivePhoto = send_live_photo
getManagedBotAccessSettings = get_managed_bot_access_settings
setManagedBotAccessSettings = set_managed_bot_access_settings
getUserPersonalChatMessages = get_user_personal_chat_messages
deleteMessageReaction = delete_message_reaction
deleteAllMessageReactions = delete_all_message_reactions

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