mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-21 08:35:28 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fc45a803d | |||
| 512a0b7417 | |||
| 7d952d8707 | |||
| b496fabf62 | |||
| 637b8e260b | |||
| 912fe45d8c | |||
| 805b7bff32 | |||
| f3bd0f1462 | |||
| 5b0e0b5f78 | |||
| c4623c4476 | |||
| ee6e82d7ad | |||
| c34f4811ea | |||
| d768abdd6b | |||
| 2561ffd16b | |||
| 622fdf7fa3 | |||
| 615f1bf20b | |||
| 7a8b1be5a4 | |||
| 3a8ace2e8b | |||
| 169bd47de3 | |||
| a956dcc6a4 | |||
| ee88973fee | |||
| 8f9fc65be0 | |||
| 75d946e4be | |||
| fed8d8875e | |||
| 42b68f1a70 | |||
| 58b8ef4ce4 | |||
| f6d009d3ac | |||
| 153894728c | |||
| 5fa457974d | |||
| 3ec7bb819c | |||
| 040cd2c2fc | |||
| 474f9c9693 | |||
| e18ca0d5e1 | |||
| 7331fff3fc | |||
| 23536ee759 | |||
| 2d8d43f2a5 | |||
| 8a542e22a0 |
@@ -157,7 +157,7 @@ Check-list for PRs
|
||||
This checklist is a non-exhaustive reminder of things that should be done before a PR is merged, both for you as contributor and for the maintainers.
|
||||
Feel free to copy (parts of) the checklist to the PR description to remind you or the maintainers of open points or if you have questions on anything.
|
||||
|
||||
- Added ``.. versionadded:: NEXT.VERSION``, ``.. versionchanged:: NEXT.VERSION`` or ``.. deprecated:: NEXT.VERSION`` to the docstrings for user facing changes (for methods/class descriptions, arguments and attributes)
|
||||
- Added ``.. versionadded:: NEXT.VERSION``, ``.. versionchanged:: NEXT.VERSION``, ``.. deprecated:: NEXT.VERSION`` or ``.. versionremoved:: NEXT.VERSION`` to the docstrings for user facing changes (for methods/class descriptions, arguments and attributes)
|
||||
- Created new or adapted existing unit tests
|
||||
- Documented code changes according to the `CSI standard <https://standards.mousepawmedia.com/en/stable/csi.html>`__
|
||||
- Added myself alphabetically to ``AUTHORS.rst`` (optional)
|
||||
@@ -276,7 +276,7 @@ This gives us the flexibility to re-order arguments and more importantly
|
||||
to add new required arguments. It's also more explicit and easier to read.
|
||||
|
||||
|
||||
.. _`Code of Conduct`: https://www.python.org/psf/conduct/
|
||||
.. _`Code of Conduct`: https://policies.python.org/python.org/code-of-conduct/
|
||||
.. _`issue tracker`: https://github.com/python-telegram-bot/python-telegram-bot/issues
|
||||
.. _`Telegram group`: https://telegram.me/pythontelegrambotgroup
|
||||
.. _`PEP 8 Style Guide`: https://peps.python.org/pep-0008/
|
||||
|
||||
@@ -12,6 +12,8 @@ body:
|
||||
To make it easier for us to help you, please read this [article](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Ask-Right).
|
||||
|
||||
Please mind that there is also a users' [Telegram group](https://t.me/pythontelegrambotgroup) for questions about the library. Questions asked there might be answered quicker than here. Moreover, [GitHub Discussions](https://github.com/python-telegram-bot/python-telegram-bot/discussions) offer a slightly better format to discuss usage questions.
|
||||
|
||||
If you have asked the same question elsewhere (e.g. the [Telegram group](https://t.me/pythontelegrambotgroup) or [StackOverflow](https://stackoverflow.com/questions/tagged/python-telegram-bot)), provide a link to that thread.
|
||||
|
||||
- type: textarea
|
||||
id: issue-faced
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
- name: Fetch Dependabot metadata
|
||||
id: dependabot-metadata
|
||||
uses: dependabot/fetch-metadata@v1.6.0
|
||||
uses: dependabot/fetch-metadata@v2.1.0
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
pull-requests: write # for srvaroa/labeler to add labels in PR
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: srvaroa/labeler@v1.10.0
|
||||
- uses: srvaroa/labeler@v1.10.1
|
||||
# Config file at .github/labeler.yml
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
@@ -6,6 +6,7 @@ on:
|
||||
- tests/**
|
||||
- requirements.txt
|
||||
- requirements-opts.txt
|
||||
- requirements-dev.txt
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
@@ -6,7 +6,7 @@ ci:
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: 'v0.2.1'
|
||||
rev: 'v0.4.3'
|
||||
hooks:
|
||||
- id: ruff
|
||||
name: ruff
|
||||
@@ -17,7 +17,7 @@ repos:
|
||||
- cachetools~=5.3.3
|
||||
- aiolimiter~=1.1.0
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 24.1.1
|
||||
rev: 24.4.2
|
||||
hooks:
|
||||
- id: black
|
||||
args:
|
||||
@@ -28,7 +28,7 @@ repos:
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: v3.0.3
|
||||
rev: v3.1.0
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^(?!(tests|docs)).*\.py$
|
||||
@@ -40,7 +40,7 @@ repos:
|
||||
- aiolimiter~=1.1.0
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.8.0
|
||||
rev: v1.10.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy-ptb
|
||||
@@ -67,7 +67,7 @@ repos:
|
||||
- cachetools~=5.3.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.15.0
|
||||
rev: v3.15.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args:
|
||||
|
||||
@@ -123,6 +123,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Vorobjev Simon <https://github.com/simonvorobjev>`_
|
||||
- `Wagner Macedo <https://github.com/wagnerluis1982>`_
|
||||
- `wjt <https://github.com/wjt>`_
|
||||
- `Wonseok Oh <https://github.com/marinelay>`_
|
||||
- `Yaw Danso <https://github.com/dglitxh>`_
|
||||
- `Yao Kuan <https://github.com/thatguylah>`_
|
||||
- `zeroone2numeral2 <https://github.com/zeroone2numeral2>`_
|
||||
|
||||
+113
@@ -4,6 +4,119 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 21.2
|
||||
============
|
||||
|
||||
*Released 2024-05-20*
|
||||
|
||||
This is the technical changelog for version 21.2. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full Support for Bot API 7.3 (:pr:`4246`, :pr:`4260`, :pr:`4243`, :pr:`4248`, :pr:`4242` closes :issue:`4236`, :pr:`4247` by `aelkheir <https://github.com/aelkheir>`_)
|
||||
- Remove Functionality Deprecated by Bot API 7.2 (:pr:`4245`)
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Add Version to ``PTBDeprecationWarning`` (:pr:`4262` closes :issue:`4261`)
|
||||
- Handle Exceptions in building ``CallbackContext`` (:pr:`4222`)
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Call ``Application.post_stop`` Only if ``Application.stop`` was called (:pr:`4211` closes :issue:`4210`)
|
||||
- Handle ``SystemExit`` raised in Handlers (:pr:`4157` closes :issue:`4155` and :issue:`4156`)
|
||||
- Make ``Birthdate.to_date`` Return a ``datetime.date`` Object (:pr:`4251`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Documentation Improvements (:pr:`4217`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Add New Rules to ``ruff`` Config (:pr:`4250`)
|
||||
- Adapt Test Suite to Changes in Error Messages (:pr:`4238`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``furo`` from 2024.4.27 to 2024.5.6 (:pr:`4252`)
|
||||
- ``pre-commit`` autoupdate (:pr:`4239`)
|
||||
- Bump ``pytest`` from 8.1.1 to 8.2.0 (:pr:`4231`)
|
||||
- Bump ``dependabot/fetch-metadata`` from 2.0.0 to 2.1.0 (:pr:`4228`)
|
||||
- Bump ``pytest-asyncio`` from 0.21.1 to 0.21.2 (:pr:`4232`)
|
||||
- Bump ``pytest-xdist`` from 3.6.0 to 3.6.1 (:pr:`4233`)
|
||||
- Bump ``furo`` from 2024.1.29 to 2024.4.27 (:pr:`4230`)
|
||||
- Bump ``srvaroa/labeler`` from 1.10.0 to 1.10.1 (:pr:`4227`)
|
||||
- Bump ``pytest`` from 7.4.4 to 8.1.1 (:pr:`4218`)
|
||||
- Bump ``sphinx`` from 7.2.6 to 7.3.7 (:pr:`4215`)
|
||||
- Bump ``pytest-xdist`` from 3.5.0 to 3.6.0 (:pr:`4215`)
|
||||
|
||||
Version 21.1.1
|
||||
==============
|
||||
|
||||
*Released 2024-04-15*
|
||||
|
||||
This is the technical changelog for version 21.1.1. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`__.
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Fix Bug With Parameter ``message_thread_id`` of ``Message.reply_*`` (:pr:`4207` closes :issue:`4205`)
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- Remove Deprecation Warning in ``JobQueue.run_daily`` (:pr:`4206` by `@Konano <https://github.com/Konano>`__)
|
||||
- Fix Annotation of ``EncryptedCredentials.decrypted_secret`` (:pr:`4199` by `@marinelay <https://github.com/marinelay>`__ closes :issue:`4198`)
|
||||
|
||||
|
||||
Version 21.1
|
||||
==============
|
||||
|
||||
*Released 2024-04-12*
|
||||
|
||||
This is the technical changelog for version 21.1. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`__.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- API 7.2 (:pr:`4180` closes :issue:`4179` and :issue:`4181`, :issue:`4181`)
|
||||
- Make ``ChatAdministratorRights/ChatMemberAdministrator.can_*_stories`` Required (API 7.1) (:pr:`4192`)
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- Refactor Debug logging in ``Bot`` to Improve Type Hinting (:pr:`4151` closes :issue:`4010`)
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Make ``Message.reply_*`` Reply in the Same Topic by Default (:pr:`4170` by `@aelkheir <https://github.com/aelkheir>`__ closes :issue:`4139`)
|
||||
- Accept Socket Objects for Webhooks (:pr:`4161` closes :issue:`4078`)
|
||||
- Add ``Update.effective_sender`` (:pr:`4168` by `@aelkheir <https://github.com/aelkheir>`__ closes :issue:`4085`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Documentation Improvements (:pr:`4171`, :pr:`4158` by `@teslaedison <https://github.com/teslaedison>`__)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Temporarily Mark Tests with ``get_sticker_set`` as XFAIL due to API 7.2 Update (:pr:`4190`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- ``pre-commit`` autoupdate (:pr:`4184`)
|
||||
- Bump ``dependabot/fetch-metadata`` from 1.6.0 to 2.0.0 (:pr:`4185`)
|
||||
|
||||
|
||||
Version 21.0.1
|
||||
==============
|
||||
|
||||
|
||||
+3
-3
@@ -14,9 +14,9 @@
|
||||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.1-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.3-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
:alt: Supported Bot API version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-telegram-bot
|
||||
:target: https://pypistats.org/packages/python-telegram-bot
|
||||
@@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **7.1** are supported.
|
||||
All types and methods of the Telegram Bot API **7.3** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
||||
+3
-3
@@ -14,9 +14,9 @@
|
||||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.1-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.3-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
:alt: Supported Bot API version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-telegram-bot-raw
|
||||
:target: https://pypistats.org/packages/python-telegram-bot-raw
|
||||
@@ -85,7 +85,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **7.1** are supported.
|
||||
All types and methods of the Telegram Bot API **7.3** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
sphinx==7.2.6
|
||||
furo==2024.1.29
|
||||
sphinx==7.3.7
|
||||
furo==2024.5.6
|
||||
furo-sphinx-search @ git+https://github.com/harshil21/furo-sphinx-search@v0.2.0.1
|
||||
sphinx-paramlinks==0.6.0
|
||||
sphinxcontrib-mermaid==0.9.2
|
||||
|
||||
+5
-9
@@ -20,9 +20,9 @@ author = "Leandro Toledo"
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = "21.0.1" # telegram.__version__[:3]
|
||||
version = "21.2" # telegram.__version__[:3]
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = "21.0.1" # telegram.__version__
|
||||
release = "21.2" # telegram.__version__
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
needs_sphinx = "6.1.3"
|
||||
@@ -67,7 +67,9 @@ source_suffix = ".rst"
|
||||
master_doc = "index"
|
||||
|
||||
# Global substitutions
|
||||
rst_prolog = (Path.cwd() / "../substitutions/global.rst").read_text(encoding="utf-8")
|
||||
rst_prolog = ""
|
||||
for file in Path.cwd().glob("../substitutions/*.rst"):
|
||||
rst_prolog += "\n" + file.read_text(encoding="utf-8")
|
||||
|
||||
# -- Extension settings ------------------------------------------------
|
||||
napoleon_use_admonition_for_examples = True
|
||||
@@ -140,12 +142,6 @@ html_theme_options = {
|
||||
"admonition-title-font-size": "0.95rem",
|
||||
"admonition-font-size": "0.92rem",
|
||||
},
|
||||
"announcement": (
|
||||
"PTB has undergone significant changes in v20. Please read the documentation "
|
||||
"carefully and also check out the transition guide in the "
|
||||
'<a href="https://github.com/python-telegram-bot/python-telegram-bot/wiki/'
|
||||
'Transition-guide-to-Version-20.0">wiki</a>.'
|
||||
),
|
||||
"footer_icons": [
|
||||
{
|
||||
# Telegram channel logo
|
||||
|
||||
@@ -113,6 +113,10 @@
|
||||
:align: left
|
||||
:widths: 1 4
|
||||
|
||||
* - :meth:`~telegram.Bot.approve_chat_join_request`
|
||||
- Used for approving a chat join request
|
||||
* - :meth:`~telegram.Bot.decline_chat_join_request`
|
||||
- Used for declining a chat join request
|
||||
* - :meth:`~telegram.Bot.ban_chat_member`
|
||||
- Used for banning a member from the chat
|
||||
* - :meth:`~telegram.Bot.unban_chat_member`
|
||||
@@ -137,10 +141,6 @@
|
||||
- Used for editing a non-primary invite link
|
||||
* - :meth:`~telegram.Bot.revoke_chat_invite_link`
|
||||
- Used for revoking an invite link created by the bot
|
||||
* - :meth:`~telegram.Bot.approve_chat_join_request`
|
||||
- Used for approving a chat join request
|
||||
* - :meth:`~telegram.Bot.decline_chat_join_request`
|
||||
- Used for declining a chat join request
|
||||
* - :meth:`~telegram.Bot.set_chat_photo`
|
||||
- Used for setting a photo to a chat
|
||||
* - :meth:`~telegram.Bot.delete_chat_photo`
|
||||
@@ -155,6 +155,8 @@
|
||||
- Used for unpinning a message
|
||||
* - :meth:`~telegram.Bot.unpin_all_chat_messages`
|
||||
- Used for unpinning all pinned chat messages
|
||||
* - :meth:`~telegram.Bot.get_business_connection`
|
||||
- Used for getting information about the business account.
|
||||
* - :meth:`~telegram.Bot.get_user_profile_photos`
|
||||
- Used for obtaining user's profile pictures
|
||||
* - :meth:`~telegram.Bot.get_chat`
|
||||
@@ -237,6 +239,8 @@
|
||||
- Used for setting a sticker set of a chat
|
||||
* - :meth:`~telegram.Bot.delete_chat_sticker_set`
|
||||
- Used for deleting the set sticker set of a chat
|
||||
* - :meth:`~telegram.Bot.replace_sticker_in_set`
|
||||
- Used for replacing a sticker in a set
|
||||
* - :meth:`~telegram.Bot.set_sticker_position_in_set`
|
||||
- Used for moving a sticker's position in the set
|
||||
* - :meth:`~telegram.Bot.set_sticker_set_title`
|
||||
|
||||
@@ -6,6 +6,7 @@ Available Types
|
||||
|
||||
telegram.animation
|
||||
telegram.audio
|
||||
telegram.birthdate
|
||||
telegram.botcommand
|
||||
telegram.botcommandscope
|
||||
telegram.botcommandscopeallchatadministrators
|
||||
@@ -18,9 +19,25 @@ Available Types
|
||||
telegram.botdescription
|
||||
telegram.botname
|
||||
telegram.botshortdescription
|
||||
telegram.businessconnection
|
||||
telegram.businessintro
|
||||
telegram.businesslocation
|
||||
telegram.businessopeninghours
|
||||
telegram.businessopeninghoursinterval
|
||||
telegram.businessmessagesdeleted
|
||||
telegram.callbackquery
|
||||
telegram.chat
|
||||
telegram.chatadministratorrights
|
||||
telegram.chatbackground
|
||||
telegram.backgroundtype
|
||||
telegram.backgroundtypefill
|
||||
telegram.backgroundtypewallpaper
|
||||
telegram.backgroundtypepattern
|
||||
telegram.backgroundtypechattheme
|
||||
telegram.backgroundfill
|
||||
telegram.backgroundfillsolid
|
||||
telegram.backgroundfillgradient
|
||||
telegram.backgroundfillfreeformgradient
|
||||
telegram.chatboost
|
||||
telegram.chatboostadded
|
||||
telegram.chatboostremoved
|
||||
@@ -29,6 +46,7 @@ Available Types
|
||||
telegram.chatboostsourcegiveaway
|
||||
telegram.chatboostsourcepremium
|
||||
telegram.chatboostupdated
|
||||
telegram.chatfullinfo
|
||||
telegram.chatinvitelink
|
||||
telegram.chatjoinrequest
|
||||
telegram.chatlocation
|
||||
@@ -70,6 +88,7 @@ Available Types
|
||||
telegram.inputmediadocument
|
||||
telegram.inputmediaphoto
|
||||
telegram.inputmediavideo
|
||||
telegram.inputpolloption
|
||||
telegram.inputsticker
|
||||
telegram.keyboardbutton
|
||||
telegram.keyboardbuttonpolltype
|
||||
@@ -107,6 +126,7 @@ Available Types
|
||||
telegram.replykeyboardremove
|
||||
telegram.replyparameters
|
||||
telegram.sentwebappmessage
|
||||
telegram.shareduser
|
||||
telegram.story
|
||||
telegram.switchinlinequerychosenchat
|
||||
telegram.telegramobject
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundFill
|
||||
==============
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundFill
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundFillFreeformGradient
|
||||
==============================
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundFillFreeformGradient
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundFillGradient
|
||||
======================
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundFillGradient
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundFillSolid
|
||||
===================
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundFillSolid
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundType
|
||||
==============
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundType
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundTypeChatTheme
|
||||
=======================
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundTypeChatTheme
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundTypeFill
|
||||
==================
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundTypeFill
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundTypePattern
|
||||
=====================
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundTypePattern
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
BackgroundTypeWallpaper
|
||||
=======================
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.BackgroundTypeWallpaper
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,7 @@
|
||||
Birthdate
|
||||
=========
|
||||
|
||||
.. autoclass:: telegram.Birthdate
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
BusinessConnection
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.BusinessConnection
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BusinessIntro
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.BusinessIntro
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BusinessLocation
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.BusinessLocation
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BusinessMessagesDeleted
|
||||
=======================
|
||||
|
||||
.. autoclass:: telegram.BusinessMessagesDeleted
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BusinessOpeningHours
|
||||
====================
|
||||
|
||||
.. autoclass:: telegram.BusinessOpeningHours
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BusinessOpeningHoursInterval
|
||||
============================
|
||||
|
||||
.. autoclass:: telegram.BusinessOpeningHoursInterval
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,8 @@
|
||||
ChatBackground
|
||||
==============
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. autoclass:: telegram.ChatBackground
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
ChatFullInfo
|
||||
============
|
||||
|
||||
.. autoclass:: telegram.ChatFullInfo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BusinessConnectionHandler
|
||||
=========================
|
||||
|
||||
.. autoclass:: telegram.ext.BusinessConnectionHandler
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BusinessMessagesDeletedHandler
|
||||
==============================
|
||||
|
||||
.. autoclass:: telegram.ext.BusinessMessagesDeletedHandler
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -5,6 +5,8 @@ Handlers
|
||||
:titlesonly:
|
||||
|
||||
telegram.ext.basehandler
|
||||
telegram.ext.businessconnectionhandler
|
||||
telegram.ext.businessmessagesdeletedhandler
|
||||
telegram.ext.callbackqueryhandler
|
||||
telegram.ext.chatboosthandler
|
||||
telegram.ext.chatjoinrequesthandler
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
InputPollOption
|
||||
===============
|
||||
|
||||
.. autoclass:: telegram.InputPollOption
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,7 @@
|
||||
SharedUser
|
||||
==========
|
||||
|
||||
.. autoclass:: telegram.SharedUser
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.. |app_run_shutdown| replace:: The app will shut down when :exc:`KeyboardInterrupt` or :exc:`SystemExit` is raised. This also works from within handlers, error handlers and jobs. However, using :meth:`~telegram.ext.Application.stop_running` will give a somewhat cleaner shutdown behavior than manually raising those exceptions. On unix, the app will also shut down on receiving the signals specified by
|
||||
@@ -79,3 +79,5 @@
|
||||
.. |do_quote| replace:: If set to :obj:`True`, the replied message is quoted. For a dict, it must be the output of :meth:`~telegram.Message.build_reply_arguments` to specify exact ``reply_parameters``. If ``reply_to_message_id`` or ``reply_parameters`` are passed, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats.
|
||||
|
||||
.. |non_optional_story_argument| replace:: As of this version, this argument is now required. In accordance with our `stability policy <https://docs.python-telegram-bot.org/en/stable/stability_policy.html>`__, the signature will be kept as optional for now, though they are mandatory and an error will be raised if you don't pass it.
|
||||
|
||||
.. |business_id_str| replace:: Unique identifier of the business connection on behalf of which the message will be sent.
|
||||
|
||||
+6
-4
@@ -20,13 +20,15 @@ explicit-preview-rules = true
|
||||
ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915", "PERF203"]
|
||||
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
|
||||
"G", "ISC", "PT", "ASYNC", "TCH", "SLOT", "PERF", "PYI", "FLY", "AIR", "RUF022",
|
||||
"RUF023", "Q", "INP",]
|
||||
"RUF023", "Q", "INP", "W", "YTT", "DTZ", "ARG"]
|
||||
# Add "FURB" after it's out of preview
|
||||
# Add "A (flake8-builtins)" after we drop pylint
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/*.py" = ["B018"]
|
||||
"tests/**.py" = ["RUF012", "ASYNC101"]
|
||||
"docs/**.py" = ["INP001"]
|
||||
"tests/**.py" = ["RUF012", "ASYNC101", "DTZ", "ARG"]
|
||||
"docs/**.py" = ["INP001", "ARG"]
|
||||
"examples/**.py" = ["ARG"]
|
||||
|
||||
# PYLINT:
|
||||
[tool.pylint."messages control"]
|
||||
@@ -48,7 +50,7 @@ exclude-protected = ["_unfrozen"]
|
||||
# PYTEST:
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
addopts = "--no-success-flaky-report -rsxX"
|
||||
addopts = "--no-success-flaky-report -rX"
|
||||
filterwarnings = [
|
||||
"error",
|
||||
"ignore::DeprecationWarning",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
pre-commit # needed for pre-commit hooks in the git commit command
|
||||
|
||||
# For the test suite
|
||||
pytest==7.4.4
|
||||
pytest-asyncio==0.21.1 # needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-xdist==3.5.0 # xdist runs tests in parallel
|
||||
pytest==8.2.0
|
||||
pytest-asyncio==0.21.2 # needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-xdist==3.6.1 # xdist runs tests in parallel
|
||||
flaky # Used for flaky tests (flaky decorator)
|
||||
beautifulsoup4 # used in test_official for parsing tg docs
|
||||
|
||||
|
||||
+44
-2
@@ -22,6 +22,16 @@ __author__ = "devs@python-telegram-bot.org"
|
||||
__all__ = (
|
||||
"Animation",
|
||||
"Audio",
|
||||
"BackgroundFill",
|
||||
"BackgroundFillFreeformGradient",
|
||||
"BackgroundFillGradient",
|
||||
"BackgroundFillSolid",
|
||||
"BackgroundType",
|
||||
"BackgroundTypeChatTheme",
|
||||
"BackgroundTypeFill",
|
||||
"BackgroundTypePattern",
|
||||
"BackgroundTypeWallpaper",
|
||||
"Birthdate",
|
||||
"Bot",
|
||||
"BotCommand",
|
||||
"BotCommandScope",
|
||||
@@ -35,10 +45,17 @@ __all__ = (
|
||||
"BotDescription",
|
||||
"BotName",
|
||||
"BotShortDescription",
|
||||
"BusinessConnection",
|
||||
"BusinessIntro",
|
||||
"BusinessLocation",
|
||||
"BusinessMessagesDeleted",
|
||||
"BusinessOpeningHours",
|
||||
"BusinessOpeningHoursInterval",
|
||||
"CallbackGame",
|
||||
"CallbackQuery",
|
||||
"Chat",
|
||||
"ChatAdministratorRights",
|
||||
"ChatBackground",
|
||||
"ChatBoost",
|
||||
"ChatBoostAdded",
|
||||
"ChatBoostRemoved",
|
||||
@@ -47,6 +64,7 @@ __all__ = (
|
||||
"ChatBoostSourceGiveaway",
|
||||
"ChatBoostSourcePremium",
|
||||
"ChatBoostUpdated",
|
||||
"ChatFullInfo",
|
||||
"ChatInviteLink",
|
||||
"ChatJoinRequest",
|
||||
"ChatLocation",
|
||||
@@ -124,6 +142,7 @@ __all__ = (
|
||||
"InputMediaPhoto",
|
||||
"InputMediaVideo",
|
||||
"InputMessageContent",
|
||||
"InputPollOption",
|
||||
"InputSticker",
|
||||
"InputTextMessageContent",
|
||||
"InputVenueMessageContent",
|
||||
@@ -184,6 +203,7 @@ __all__ = (
|
||||
"SecureData",
|
||||
"SecureValue",
|
||||
"SentWebAppMessage",
|
||||
"SharedUser",
|
||||
"ShippingAddress",
|
||||
"ShippingOption",
|
||||
"ShippingQuery",
|
||||
@@ -224,6 +244,7 @@ __all__ = (
|
||||
|
||||
|
||||
from . import _version, constants, error, helpers, request, warnings
|
||||
from ._birthdate import Birthdate
|
||||
from ._bot import Bot
|
||||
from ._botcommand import BotCommand
|
||||
from ._botcommandscope import (
|
||||
@@ -238,9 +259,29 @@ from ._botcommandscope import (
|
||||
)
|
||||
from ._botdescription import BotDescription, BotShortDescription
|
||||
from ._botname import BotName
|
||||
from ._business import (
|
||||
BusinessConnection,
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessMessagesDeleted,
|
||||
BusinessOpeningHours,
|
||||
BusinessOpeningHoursInterval,
|
||||
)
|
||||
from ._callbackquery import CallbackQuery
|
||||
from ._chat import Chat
|
||||
from ._chatadministratorrights import ChatAdministratorRights
|
||||
from ._chatbackground import (
|
||||
BackgroundFill,
|
||||
BackgroundFillFreeformGradient,
|
||||
BackgroundFillGradient,
|
||||
BackgroundFillSolid,
|
||||
BackgroundType,
|
||||
BackgroundTypeChatTheme,
|
||||
BackgroundTypeFill,
|
||||
BackgroundTypePattern,
|
||||
BackgroundTypeWallpaper,
|
||||
ChatBackground,
|
||||
)
|
||||
from ._chatboost import (
|
||||
ChatBoost,
|
||||
ChatBoostAdded,
|
||||
@@ -252,6 +293,7 @@ from ._chatboost import (
|
||||
ChatBoostUpdated,
|
||||
UserChatBoosts,
|
||||
)
|
||||
from ._chatfullinfo import ChatFullInfo
|
||||
from ._chatinvitelink import ChatInviteLink
|
||||
from ._chatjoinrequest import ChatJoinRequest
|
||||
from ._chatlocation import ChatLocation
|
||||
@@ -386,14 +428,14 @@ from ._payment.shippingaddress import ShippingAddress
|
||||
from ._payment.shippingoption import ShippingOption
|
||||
from ._payment.shippingquery import ShippingQuery
|
||||
from ._payment.successfulpayment import SuccessfulPayment
|
||||
from ._poll import Poll, PollAnswer, PollOption
|
||||
from ._poll import InputPollOption, Poll, PollAnswer, PollOption
|
||||
from ._proximityalerttriggered import ProximityAlertTriggered
|
||||
from ._reaction import ReactionCount, ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji
|
||||
from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
|
||||
from ._replykeyboardmarkup import ReplyKeyboardMarkup
|
||||
from ._replykeyboardremove import ReplyKeyboardRemove
|
||||
from ._sentwebappmessage import SentWebAppMessage
|
||||
from ._shared import ChatShared, UsersShared
|
||||
from ._shared import ChatShared, SharedUser, UsersShared
|
||||
from ._story import Story
|
||||
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||
from ._telegramobject import TelegramObject
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# 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 Birthday."""
|
||||
from datetime import date
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class Birthdate(TelegramObject):
|
||||
"""
|
||||
This object describes the birthdate of a user.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`day`, and :attr:`month` are equal.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
day (:obj:`int`): Day of the user's birth; 1-31.
|
||||
month (:obj:`int`): Month of the user's birth; 1-12.
|
||||
year (:obj:`int`, optional): Year of the user's birth.
|
||||
|
||||
Attributes:
|
||||
day (:obj:`int`): Day of the user's birth; 1-31.
|
||||
month (:obj:`int`): Month of the user's birth; 1-12.
|
||||
year (:obj:`int`): Optional. Year of the user's birth.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("day", "month", "year")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
day: int,
|
||||
month: int,
|
||||
year: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
# Required
|
||||
self.day: int = day
|
||||
self.month: int = month
|
||||
# Optional
|
||||
self.year: Optional[int] = year
|
||||
|
||||
self._id_attrs = (
|
||||
self.day,
|
||||
self.month,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
|
||||
def to_date(self, year: Optional[int] = None) -> date:
|
||||
"""Return the birthdate as a date object.
|
||||
|
||||
.. versionchanged:: 21.2
|
||||
Now returns a :obj:`datetime.date` object instead of a :obj:`datetime.datetime` object,
|
||||
as was originally intended.
|
||||
|
||||
Args:
|
||||
year (:obj:`int`, optional): The year to use. Required, if the :attr:`year` was not
|
||||
present.
|
||||
|
||||
Returns:
|
||||
:obj:`datetime.date`: The birthdate as a date object.
|
||||
"""
|
||||
if self.year is None and year is None:
|
||||
raise ValueError(
|
||||
"The `year` argument is required if the `year` attribute was not present."
|
||||
)
|
||||
|
||||
return date(year or self.year, self.month, self.day) # type: ignore[arg-type]
|
||||
+281
-176
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,445 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=redefined-builtin
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/]
|
||||
"""This module contains the Telegram Business related classes."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
|
||||
from telegram._chat import Chat
|
||||
from telegram._files.location import Location
|
||||
from telegram._files.sticker import Sticker
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class BusinessConnection(TelegramObject):
|
||||
"""
|
||||
Describes the connection of the bot with a business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal if their :attr:`id`, :attr:`user`, :attr:`user_chat_id`, :attr:`date`,
|
||||
:attr:`can_reply`, and :attr:`is_enabled` are equal.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique identifier of the business connection.
|
||||
user (:class:`telegram.User`): Business account user that created the business connection.
|
||||
user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
|
||||
business connection.
|
||||
date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
|
||||
can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in
|
||||
chats that were active in the last 24 hours.
|
||||
is_enabled (:obj:`bool`): True, if the connection is active.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique identifier of the business connection.
|
||||
user (:class:`telegram.User`): Business account user that created the business connection.
|
||||
user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
|
||||
business connection.
|
||||
date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
|
||||
can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in
|
||||
chats that were active in the last 24 hours.
|
||||
is_enabled (:obj:`bool`): True, if the connection is active.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"can_reply",
|
||||
"date",
|
||||
"id",
|
||||
"is_enabled",
|
||||
"user",
|
||||
"user_chat_id",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
user: "User",
|
||||
user_chat_id: int,
|
||||
date: datetime,
|
||||
can_reply: bool,
|
||||
is_enabled: bool,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.id: str = id
|
||||
self.user: User = user
|
||||
self.user_chat_id: int = user_chat_id
|
||||
self.date: datetime = date
|
||||
self.can_reply: bool = can_reply
|
||||
self.is_enabled: bool = is_enabled
|
||||
|
||||
self._id_attrs = (
|
||||
self.id,
|
||||
self.user,
|
||||
self.user_chat_id,
|
||||
self.date,
|
||||
self.can_reply,
|
||||
self.is_enabled,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessConnection"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
|
||||
data["user"] = User.de_json(data.get("user"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BusinessMessagesDeleted(TelegramObject):
|
||||
"""
|
||||
This object is received when messages are deleted from a connected business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal if their :attr:`business_connection_id`, :attr:`message_ids`, and
|
||||
:attr:`chat` are equal.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
business_connection_id (:obj:`str`): Unique identifier of the business connection.
|
||||
chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot
|
||||
may not have access to the chat or the corresponding user.
|
||||
message_ids (Sequence[:obj:`int`]): A list of identifiers of the deleted messages in the
|
||||
chat of the business account.
|
||||
|
||||
Attributes:
|
||||
business_connection_id (:obj:`str`): Unique identifier of the business connection.
|
||||
chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot
|
||||
may not have access to the chat or the corresponding user.
|
||||
message_ids (Tuple[:obj:`int`]): A list of identifiers of the deleted messages in the
|
||||
chat of the business account.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"business_connection_id",
|
||||
"chat",
|
||||
"message_ids",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
chat: Chat,
|
||||
message_ids: Sequence[int],
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.business_connection_id: str = business_connection_id
|
||||
self.chat: Chat = chat
|
||||
self.message_ids: Tuple[int, ...] = parse_sequence_arg(message_ids)
|
||||
|
||||
self._id_attrs = (
|
||||
self.business_connection_id,
|
||||
self.chat,
|
||||
self.message_ids,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessMessagesDeleted"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BusinessIntro(TelegramObject):
|
||||
"""
|
||||
This object contains information about the start page settings of a Telegram Business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`title`, :attr:`message` and :attr:`sticker` are equal.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
title (:obj:`str`, optional): Title text of the business intro.
|
||||
message (:obj:`str`, optional): Message text of the business intro.
|
||||
sticker (:class:`telegram.Sticker`, optional): Sticker of the business intro.
|
||||
|
||||
Attributes:
|
||||
title (:obj:`str`): Optional. Title text of the business intro.
|
||||
message (:obj:`str`): Optional. Message text of the business intro.
|
||||
sticker (:class:`telegram.Sticker`): Optional. Sticker of the business intro.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"message",
|
||||
"sticker",
|
||||
"title",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
title: Optional[str] = None,
|
||||
message: Optional[str] = None,
|
||||
sticker: Optional[Sticker] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.title: Optional[str] = title
|
||||
self.message: Optional[str] = message
|
||||
self.sticker: Optional[Sticker] = sticker
|
||||
|
||||
self._id_attrs = (self.title, self.message, self.sticker)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessIntro"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BusinessLocation(TelegramObject):
|
||||
"""
|
||||
This object contains information about the location of a Telegram Business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`address` is equal.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
address (:obj:`str`): Address of the business.
|
||||
location (:class:`telegram.Location`, optional): Location of the business.
|
||||
|
||||
Attributes:
|
||||
address (:obj:`str`): Address of the business.
|
||||
location (:class:`telegram.Location`): Optional. Location of the business.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"address",
|
||||
"location",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: str,
|
||||
location: Optional[Location] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.address: str = address
|
||||
self.location: Optional[Location] = location
|
||||
|
||||
self._id_attrs = (self.address,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessLocation"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["location"] = Location.de_json(data.get("location"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BusinessOpeningHoursInterval(TelegramObject):
|
||||
"""
|
||||
This object describes an interval of time during which a business is open.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`opening_minute` and :attr:`closing_minute` are equal.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Examples:
|
||||
A day has (24 * 60 =) 1440 minutes, a week has (7 * 1440 =) 10080 minutes.
|
||||
Starting the the minute's sequence from Monday, example values of
|
||||
:attr:`opening_minute`, :attr:`closing_minute` will map to the following day times:
|
||||
|
||||
* Monday - 8am to 8:30pm:
|
||||
- ``opening_minute = 480`` :guilabel:`8 * 60`
|
||||
- ``closing_minute = 1230`` :guilabel:`20 * 60 + 30`
|
||||
* Tuesday - 24 hours:
|
||||
- ``opening_minute = 1440`` :guilabel:`24 * 60`
|
||||
- ``closing_minute = 2879`` :guilabel:`2 * 24 * 60 - 1`
|
||||
* Sunday - 12am - 11:58pm:
|
||||
- ``opening_minute = 8640`` :guilabel:`6 * 24 * 60`
|
||||
- ``closing_minute = 10078`` :guilabel:`7 * 24 * 60 - 2`
|
||||
|
||||
Args:
|
||||
opening_minute (:obj:`int`): The minute's sequence number in a week, starting on Monday,
|
||||
marking the start of the time interval during which the business is open;
|
||||
0 - 7 * 24 * 60.
|
||||
closing_minute (:obj:`int`): The minute's
|
||||
sequence number in a week, starting on Monday, marking the end of the time interval
|
||||
during which the business is open; 0 - 8 * 24 * 60
|
||||
|
||||
Attributes:
|
||||
opening_minute (:obj:`int`): The minute's sequence number in a week, starting on Monday,
|
||||
marking the start of the time interval during which the business is open;
|
||||
0 - 7 * 24 * 60.
|
||||
closing_minute (:obj:`int`): The minute's
|
||||
sequence number in a week, starting on Monday, marking the end of the time interval
|
||||
during which the business is open; 0 - 8 * 24 * 60
|
||||
"""
|
||||
|
||||
__slots__ = ("_closing_time", "_opening_time", "closing_minute", "opening_minute")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
opening_minute: int,
|
||||
closing_minute: int,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.opening_minute: int = opening_minute
|
||||
self.closing_minute: int = closing_minute
|
||||
|
||||
self._opening_time: Optional[Tuple[int, int, int]] = None
|
||||
self._closing_time: Optional[Tuple[int, int, int]] = None
|
||||
|
||||
self._id_attrs = (self.opening_minute, self.closing_minute)
|
||||
|
||||
self._freeze()
|
||||
|
||||
def _parse_minute(self, minute: int) -> Tuple[int, int, int]:
|
||||
return (minute // 1440, minute % 1440 // 60, minute % 1440 % 60)
|
||||
|
||||
@property
|
||||
def opening_time(self) -> Tuple[int, int, int]:
|
||||
"""Convenience attribute. A :obj:`tuple` parsed from :attr:`opening_minute`. It contains
|
||||
the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`,
|
||||
:attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute`
|
||||
|
||||
Returns:
|
||||
Tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
|
||||
"""
|
||||
if self._opening_time is None:
|
||||
self._opening_time = self._parse_minute(self.opening_minute)
|
||||
return self._opening_time
|
||||
|
||||
@property
|
||||
def closing_time(self) -> Tuple[int, int, int]:
|
||||
"""Convenience attribute. A :obj:`tuple` parsed from :attr:`closing_minute`. It contains
|
||||
the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`,
|
||||
:attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute`
|
||||
|
||||
Returns:
|
||||
Tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
|
||||
"""
|
||||
if self._closing_time is None:
|
||||
self._closing_time = self._parse_minute(self.closing_minute)
|
||||
return self._closing_time
|
||||
|
||||
|
||||
class BusinessOpeningHours(TelegramObject):
|
||||
"""
|
||||
This object describes the opening hours of a business.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`time_zone_name` and :attr:`opening_hours` are equal.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
time_zone_name (:obj:`str`): Unique name of the time zone for which the opening
|
||||
hours are defined.
|
||||
opening_hours (Sequence[:class:`telegram.BusinessOpeningHoursInterval`]): List of
|
||||
time intervals describing business opening hours.
|
||||
|
||||
Attributes:
|
||||
time_zone_name (:obj:`str`): Unique name of the time zone for which the opening
|
||||
hours are defined.
|
||||
opening_hours (Sequence[:class:`telegram.BusinessOpeningHoursInterval`]): List of
|
||||
time intervals describing business opening hours.
|
||||
"""
|
||||
|
||||
__slots__ = ("opening_hours", "time_zone_name")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
time_zone_name: str,
|
||||
opening_hours: Sequence[BusinessOpeningHoursInterval],
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.time_zone_name: str = time_zone_name
|
||||
self.opening_hours: Sequence[BusinessOpeningHoursInterval] = parse_sequence_arg(
|
||||
opening_hours
|
||||
)
|
||||
|
||||
self._id_attrs = (self.time_zone_name, self.opening_hours)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessOpeningHours"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["opening_hours"] = BusinessOpeningHoursInterval.de_list(
|
||||
data.get("opening_hours"), bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
@@ -461,6 +461,7 @@ class CallbackQuery(TelegramObject):
|
||||
horizontal_accuracy: Optional[float] = None,
|
||||
heading: Optional[int] = None,
|
||||
proximity_alert_radius: Optional[int] = None,
|
||||
live_period: Optional[int] = None,
|
||||
*,
|
||||
location: Optional[Location] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -509,6 +510,7 @@ class CallbackQuery(TelegramObject):
|
||||
horizontal_accuracy=horizontal_accuracy,
|
||||
heading=heading,
|
||||
proximity_alert_radius=proximity_alert_radius,
|
||||
live_period=live_period,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
@@ -525,6 +527,7 @@ class CallbackQuery(TelegramObject):
|
||||
horizontal_accuracy=horizontal_accuracy,
|
||||
heading=heading,
|
||||
proximity_alert_radius=proximity_alert_radius,
|
||||
live_period=live_period,
|
||||
)
|
||||
|
||||
async def stop_message_live_location(
|
||||
|
||||
+471
-11
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,11 @@ class ChatAdministratorRights(TelegramObject):
|
||||
:attr:`can_post_stories`, :attr:`can_edit_stories`, and :attr:`can_delete_stories` are
|
||||
considered as well when comparing objects of this type in terms of equality.
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
As of this version, :attr:`can_post_stories`, :attr:`can_edit_stories`,
|
||||
and :attr:`can_delete_stories` is now required. Thus, the order of arguments had to be
|
||||
changed.
|
||||
|
||||
Args:
|
||||
is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden.
|
||||
can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event
|
||||
@@ -75,8 +80,9 @@ class ChatAdministratorRights(TelegramObject):
|
||||
.. versionadded:: 20.6
|
||||
.. versionchanged:: 21.0
|
||||
|non_optional_story_argument|
|
||||
can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit
|
||||
stories posted by other users.
|
||||
can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted
|
||||
by other users, post stories to the chat page, pin chat stories, and access the chat's
|
||||
story archive
|
||||
|
||||
.. versionadded:: 20.6
|
||||
.. versionchanged:: 21.0
|
||||
@@ -123,8 +129,9 @@ class ChatAdministratorRights(TelegramObject):
|
||||
.. versionadded:: 20.6
|
||||
.. versionchanged:: 21.0
|
||||
|non_optional_story_argument|
|
||||
can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit
|
||||
stories posted by other users.
|
||||
can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted
|
||||
by other users, post stories to the chat page, pin chat stories, and access the chat's
|
||||
story archive
|
||||
|
||||
.. versionadded:: 20.6
|
||||
.. versionchanged:: 21.0
|
||||
@@ -169,13 +176,13 @@ class ChatAdministratorRights(TelegramObject):
|
||||
can_promote_members: bool,
|
||||
can_change_info: bool,
|
||||
can_invite_users: bool,
|
||||
can_post_stories: bool,
|
||||
can_edit_stories: bool,
|
||||
can_delete_stories: bool,
|
||||
can_post_messages: Optional[bool] = None,
|
||||
can_edit_messages: Optional[bool] = None,
|
||||
can_pin_messages: Optional[bool] = None,
|
||||
can_manage_topics: Optional[bool] = None,
|
||||
can_post_stories: Optional[bool] = None,
|
||||
can_edit_stories: Optional[bool] = None,
|
||||
can_delete_stories: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> None:
|
||||
@@ -189,12 +196,6 @@ class ChatAdministratorRights(TelegramObject):
|
||||
self.can_promote_members: bool = can_promote_members
|
||||
self.can_change_info: bool = can_change_info
|
||||
self.can_invite_users: bool = can_invite_users
|
||||
# Not actually optionals but because of backwards compatability we pretend they are
|
||||
if can_post_stories is None or can_edit_stories is None or can_delete_stories is None:
|
||||
raise TypeError(
|
||||
"As of v21.0 can_post_stories, can_edit_stories and can_delete_stories"
|
||||
" must be set in order to create this object."
|
||||
)
|
||||
self.can_post_stories: bool = can_post_stories
|
||||
self.can_edit_stories: bool = can_edit_stories
|
||||
self.can_delete_stories: bool = can_delete_stories
|
||||
|
||||
@@ -0,0 +1,540 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains objects related to chat backgrounds."""
|
||||
from typing import TYPE_CHECKING, Dict, Final, Optional, Sequence, Tuple, Type
|
||||
|
||||
from telegram import constants
|
||||
from telegram._files.document import Document
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class BackgroundFill(TelegramObject):
|
||||
"""Base class for Telegram BackgroundFill Objects. It can be one of:
|
||||
|
||||
* :class:`telegram.BackgroundFillSolid`
|
||||
* :class:`telegram.BackgroundFillGradient`
|
||||
* :class:`telegram.BackgroundFillFreeformGradient`
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`type` is equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): Type of the background fill. Can be one of:
|
||||
:attr:`~telegram.BackgroundFill.SOLID`, :attr:`~telegram.BackgroundFill.GRADIENT`
|
||||
or :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background fill. Can be one of:
|
||||
:attr:`~telegram.BackgroundFill.SOLID`, :attr:`~telegram.BackgroundFill.GRADIENT`
|
||||
or :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`.
|
||||
"""
|
||||
|
||||
__slots__ = ("type",)
|
||||
|
||||
SOLID: Final[constants.BackgroundFillType] = constants.BackgroundFillType.SOLID
|
||||
""":const:`telegram.constants.BackgroundFillType.SOLID`"""
|
||||
GRADIENT: Final[constants.BackgroundFillType] = constants.BackgroundFillType.GRADIENT
|
||||
""":const:`telegram.constants.BackgroundFillType.GRADIENT`"""
|
||||
FREEFORM_GRADIENT: Final[constants.BackgroundFillType] = (
|
||||
constants.BackgroundFillType.FREEFORM_GRADIENT
|
||||
)
|
||||
""":const:`telegram.constants.BackgroundFillType.FREEFORM_GRADIENT`"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: str, # pylint: disable=redefined-builtin
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required by all subclasses
|
||||
self.type: str = enum.get_member(constants.BackgroundFillType, type, type)
|
||||
|
||||
self._id_attrs = (self.type,)
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BackgroundFill"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: Dict[str, Type[BackgroundFill]] = {
|
||||
cls.SOLID: BackgroundFillSolid,
|
||||
cls.GRADIENT: BackgroundFillGradient,
|
||||
cls.FREEFORM_GRADIENT: BackgroundFillFreeformGradient,
|
||||
}
|
||||
|
||||
if cls is BackgroundFill and data.get("type") in _class_mapping:
|
||||
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BackgroundFillSolid(BackgroundFill):
|
||||
"""
|
||||
The background is filled using the selected color.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`color` is equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
color (:obj:`int`): The color of the background fill in the `RGB24` format.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background fill. Always
|
||||
:attr:`~telegram.BackgroundFill.SOLID`.
|
||||
color (:obj:`int`): The color of the background fill in the `RGB24` format.
|
||||
"""
|
||||
|
||||
__slots__ = ("color",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
color: int,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(type=self.SOLID, api_kwargs=api_kwargs)
|
||||
|
||||
with self._unfrozen():
|
||||
self.color: int = color
|
||||
|
||||
self._id_attrs = (self.color,)
|
||||
|
||||
|
||||
class BackgroundFillGradient(BackgroundFill):
|
||||
"""
|
||||
The background is a gradient fill.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`top_color`, :attr:`bottom_color`
|
||||
and :attr:`rotation_angle` are equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
top_color (:obj:`int`): Top color of the gradient in the `RGB24` format.
|
||||
bottom_color (:obj:`int`): Bottom color of the gradient in the `RGB24` format.
|
||||
rotation_angle (:obj:`int`): Clockwise rotation angle of the background
|
||||
fill in degrees;
|
||||
0-:tg-const:`telegram.constants.BackgroundFillLimit.MAX_ROTATION_ANGLE`.
|
||||
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background fill. Always
|
||||
:attr:`~telegram.BackgroundFill.GRADIENT`.
|
||||
top_color (:obj:`int`): Top color of the gradient in the `RGB24` format.
|
||||
bottom_color (:obj:`int`): Bottom color of the gradient in the `RGB24` format.
|
||||
rotation_angle (:obj:`int`): Clockwise rotation angle of the background
|
||||
fill in degrees;
|
||||
0-:tg-const:`telegram.constants.BackgroundFillLimit.MAX_ROTATION_ANGLE`.
|
||||
"""
|
||||
|
||||
__slots__ = ("bottom_color", "rotation_angle", "top_color")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
top_color: int,
|
||||
bottom_color: int,
|
||||
rotation_angle: int,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(type=self.GRADIENT, api_kwargs=api_kwargs)
|
||||
|
||||
with self._unfrozen():
|
||||
self.top_color: int = top_color
|
||||
self.bottom_color: int = bottom_color
|
||||
self.rotation_angle: int = rotation_angle
|
||||
|
||||
self._id_attrs = (self.top_color, self.bottom_color, self.rotation_angle)
|
||||
|
||||
|
||||
class BackgroundFillFreeformGradient(BackgroundFill):
|
||||
"""
|
||||
The background is a freeform gradient that rotates after every message in the chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`colors` is equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
colors (Sequence[:obj:`int`]): A list of the 3 or 4 base colors that are used to
|
||||
generate the freeform gradient in the `RGB24` format
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background fill. Always
|
||||
:attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`.
|
||||
colors (Sequence[:obj:`int`]): A list of the 3 or 4 base colors that are used to
|
||||
generate the freeform gradient in the `RGB24` format
|
||||
"""
|
||||
|
||||
__slots__ = ("colors",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
colors: Sequence[int],
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(type=self.FREEFORM_GRADIENT, api_kwargs=api_kwargs)
|
||||
|
||||
with self._unfrozen():
|
||||
self.colors: Tuple[int, ...] = parse_sequence_arg(colors)
|
||||
|
||||
self._id_attrs = (self.colors,)
|
||||
|
||||
|
||||
class BackgroundType(TelegramObject):
|
||||
"""Base class for Telegram BackgroundType Objects. It can be one of:
|
||||
|
||||
* :class:`telegram.BackgroundTypeFill`
|
||||
* :class:`telegram.BackgroundTypeWallpaper`
|
||||
* :class:`telegram.BackgroundTypePattern`
|
||||
* :class:`telegram.BackgroundTypeChatTheme`.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`type` is equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): Type of the background. Can be one of:
|
||||
:attr:`~telegram.BackgroundType.FILL`, :attr:`~telegram.BackgroundType.WALLPAPER`
|
||||
:attr:`~telegram.BackgroundType.PATTERN` or
|
||||
:attr:`~telegram.BackgroundType.CHAT_THEME`.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background. Can be one of:
|
||||
:attr:`~telegram.BackgroundType.FILL`, :attr:`~telegram.BackgroundType.WALLPAPER`
|
||||
:attr:`~telegram.BackgroundType.PATTERN` or
|
||||
:attr:`~telegram.BackgroundType.CHAT_THEME`.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("type",)
|
||||
|
||||
FILL: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.FILL
|
||||
""":const:`telegram.constants.BackgroundTypeType.FILL`"""
|
||||
WALLPAPER: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.WALLPAPER
|
||||
""":const:`telegram.constants.BackgroundTypeType.WALLPAPER`"""
|
||||
PATTERN: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.PATTERN
|
||||
""":const:`telegram.constants.BackgroundTypeType.PATTERN`"""
|
||||
CHAT_THEME: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.CHAT_THEME
|
||||
""":const:`telegram.constants.BackgroundTypeType.CHAT_THEME`"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: str, # pylint: disable=redefined-builtin
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required by all subclasses
|
||||
self.type: str = enum.get_member(constants.BackgroundTypeType, type, type)
|
||||
|
||||
self._id_attrs = (self.type,)
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BackgroundType"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: Dict[str, Type[BackgroundType]] = {
|
||||
cls.FILL: BackgroundTypeFill,
|
||||
cls.WALLPAPER: BackgroundTypeWallpaper,
|
||||
cls.PATTERN: BackgroundTypePattern,
|
||||
cls.CHAT_THEME: BackgroundTypeChatTheme,
|
||||
}
|
||||
|
||||
if cls is BackgroundType and data.get("type") in _class_mapping:
|
||||
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
|
||||
|
||||
if "fill" in data:
|
||||
data["fill"] = BackgroundFill.de_json(data.get("fill"), bot)
|
||||
|
||||
if "document" in data:
|
||||
data["document"] = Document.de_json(data.get("document"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BackgroundTypeFill(BackgroundType):
|
||||
"""
|
||||
The background is automatically filled based on the selected colors.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`fill` and :attr:`dark_theme_dimming` are equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
fill (:obj:`telegram.BackgroundFill`): The background fill.
|
||||
dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
|
||||
percentage;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background. Always
|
||||
:attr:`~telegram.BackgroundType.FILL`.
|
||||
fill (:obj:`telegram.BackgroundFill`): The background fill.
|
||||
dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
|
||||
percentage;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
|
||||
"""
|
||||
|
||||
__slots__ = ("dark_theme_dimming", "fill")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
fill: BackgroundFill,
|
||||
dark_theme_dimming: int,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(type=self.FILL, api_kwargs=api_kwargs)
|
||||
|
||||
with self._unfrozen():
|
||||
self.fill: BackgroundFill = fill
|
||||
self.dark_theme_dimming: int = dark_theme_dimming
|
||||
|
||||
self._id_attrs = (self.fill, self.dark_theme_dimming)
|
||||
|
||||
|
||||
class BackgroundTypeWallpaper(BackgroundType):
|
||||
"""
|
||||
The background is a wallpaper in the `JPEG` format.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`document` and :attr:`dark_theme_dimming` are equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
document (:obj:`telegram.Document`): Document with the wallpaper
|
||||
dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
|
||||
percentage;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
|
||||
is_blurred (:obj:`bool`, optional): :obj:`True`, if the wallpaper is downscaled to fit
|
||||
in a 450x450 square and then box-blurred with radius 12
|
||||
is_moving (:obj:`bool`, optional): :obj:`True`, if the background moves slightly
|
||||
when the device is tilted
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background. Always
|
||||
:attr:`~telegram.BackgroundType.WALLPAPER`.
|
||||
document (:obj:`telegram.Document`): Document with the wallpaper
|
||||
dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
|
||||
percentage;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
|
||||
is_blurred (:obj:`bool`): Optional. :obj:`True`, if the wallpaper is downscaled to fit
|
||||
in a 450x450 square and then box-blurred with radius 12
|
||||
is_moving (:obj:`bool`): Optional. :obj:`True`, if the background moves slightly
|
||||
when the device is tilted
|
||||
"""
|
||||
|
||||
__slots__ = ("dark_theme_dimming", "document", "is_blurred", "is_moving")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
document: Document,
|
||||
dark_theme_dimming: int,
|
||||
is_blurred: Optional[bool] = None,
|
||||
is_moving: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(type=self.WALLPAPER, api_kwargs=api_kwargs)
|
||||
|
||||
with self._unfrozen():
|
||||
# Required
|
||||
self.document: Document = document
|
||||
self.dark_theme_dimming: int = dark_theme_dimming
|
||||
# Optionals
|
||||
self.is_blurred: Optional[bool] = is_blurred
|
||||
self.is_moving: Optional[bool] = is_moving
|
||||
|
||||
self._id_attrs = (self.document, self.dark_theme_dimming)
|
||||
|
||||
|
||||
class BackgroundTypePattern(BackgroundType):
|
||||
"""
|
||||
The background is a `PNG` or `TGV` (gzipped subset of `SVG` with `MIME` type
|
||||
`"application/x-tgwallpattern"`) pattern to be combined with the background fill
|
||||
chosen by the user.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`document` and :attr:`fill` and :attr:`intensity` are equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
document (:obj:`telegram.Document`): Document with the pattern.
|
||||
fill (:obj:`telegram.BackgroundFill`): The background fill that is combined with
|
||||
the pattern.
|
||||
intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled
|
||||
background;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_INTENSITY`.
|
||||
is_inverted (:obj:`int`, optional): :obj:`True`, if the background fill must be applied
|
||||
only to the pattern itself. All other pixels are black in this case. For dark
|
||||
themes only.
|
||||
is_moving (:obj:`bool`, optional): :obj:`True`, if the background moves slightly
|
||||
when the device is tilted.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background. Always
|
||||
:attr:`~telegram.BackgroundType.PATTERN`.
|
||||
document (:obj:`telegram.Document`): Document with the pattern.
|
||||
fill (:obj:`telegram.BackgroundFill`): The background fill that is combined with
|
||||
the pattern.
|
||||
intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled
|
||||
background;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_INTENSITY`.
|
||||
is_inverted (:obj:`int`): Optional. :obj:`True`, if the background fill must be applied
|
||||
only to the pattern itself. All other pixels are black in this case. For dark
|
||||
themes only.
|
||||
is_moving (:obj:`bool`): Optional. :obj:`True`, if the background moves slightly
|
||||
when the device is tilted.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"document",
|
||||
"fill",
|
||||
"intensity",
|
||||
"is_inverted",
|
||||
"is_moving",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
document: Document,
|
||||
fill: BackgroundFill,
|
||||
intensity: int,
|
||||
is_inverted: Optional[bool] = None,
|
||||
is_moving: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(type=self.PATTERN, api_kwargs=api_kwargs)
|
||||
|
||||
with self._unfrozen():
|
||||
# Required
|
||||
self.document: Document = document
|
||||
self.fill: BackgroundFill = fill
|
||||
self.intensity: int = intensity
|
||||
# Optionals
|
||||
self.is_inverted: Optional[bool] = is_inverted
|
||||
self.is_moving: Optional[bool] = is_moving
|
||||
|
||||
self._id_attrs = (self.document, self.fill, self.intensity)
|
||||
|
||||
|
||||
class BackgroundTypeChatTheme(BackgroundType):
|
||||
"""
|
||||
The background is taken directly from a built-in chat theme.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`theme_name` is equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
theme_name (:obj:`str`): Name of the chat theme, which is usually an emoji.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background. Always
|
||||
:attr:`~telegram.BackgroundType.CHAT_THEME`.
|
||||
theme_name (:obj:`str`): Name of the chat theme, which is usually an emoji.
|
||||
"""
|
||||
|
||||
__slots__ = ("theme_name",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
theme_name: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(type=self.CHAT_THEME, api_kwargs=api_kwargs)
|
||||
|
||||
with self._unfrozen():
|
||||
self.theme_name: str = theme_name
|
||||
|
||||
self._id_attrs = (self.theme_name,)
|
||||
|
||||
|
||||
class ChatBackground(TelegramObject):
|
||||
"""
|
||||
This object represents a chat background.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`type` is equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
type (:obj:`telegram.BackgroundType`): Type of the background.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`telegram.BackgroundType`): Type of the background.
|
||||
"""
|
||||
|
||||
__slots__ = ("type",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: BackgroundType, # pylint: disable=redefined-builtin
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.type: BackgroundType = type
|
||||
|
||||
self._id_attrs = (self.type,)
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatBackground"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["type"] = BackgroundType.de_json(data.get("type"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=redefined-builtin
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# 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 ChatFullInfo."""
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional, Sequence
|
||||
|
||||
from telegram._birthdate import Birthdate
|
||||
from telegram._chat import Chat
|
||||
from telegram._chatlocation import ChatLocation
|
||||
from telegram._chatpermissions import ChatPermissions
|
||||
from telegram._files.chatphoto import ChatPhoto
|
||||
from telegram._reaction import ReactionType
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import BusinessIntro, BusinessLocation, BusinessOpeningHours, Message
|
||||
|
||||
|
||||
class ChatFullInfo(Chat):
|
||||
"""
|
||||
This object contains full information about a chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.Chat.id` is equal.
|
||||
|
||||
Caution:
|
||||
This class is a subclass of :class:`telegram.Chat` and inherits all attributes and methods
|
||||
for backwards compatibility. In the future, this class will *NOT* inherit from
|
||||
:class:`telegram.Chat`.
|
||||
|
||||
.. seealso::
|
||||
All arguments and attributes can be found in :class:`telegram.Chat`.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a
|
||||
message in the chat.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Attributes:
|
||||
max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a
|
||||
message in the chat.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ("max_reaction_count",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: int,
|
||||
type: str,
|
||||
accent_color_id: int, # API 7.3 made this argument required
|
||||
max_reaction_count: int, # NEW arg in api 7.3 and is required
|
||||
title: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
first_name: Optional[str] = None,
|
||||
last_name: Optional[str] = None,
|
||||
is_forum: Optional[bool] = None,
|
||||
photo: Optional[ChatPhoto] = None,
|
||||
active_usernames: Optional[Sequence[str]] = None,
|
||||
birthdate: Optional[Birthdate] = None,
|
||||
business_intro: Optional["BusinessIntro"] = None,
|
||||
business_location: Optional["BusinessLocation"] = None,
|
||||
business_opening_hours: Optional["BusinessOpeningHours"] = None,
|
||||
personal_chat: Optional["Chat"] = None,
|
||||
available_reactions: Optional[Sequence[ReactionType]] = None,
|
||||
background_custom_emoji_id: Optional[str] = None,
|
||||
profile_accent_color_id: Optional[int] = None,
|
||||
profile_background_custom_emoji_id: Optional[str] = None,
|
||||
emoji_status_custom_emoji_id: Optional[str] = None,
|
||||
emoji_status_expiration_date: Optional[datetime] = None,
|
||||
bio: Optional[str] = None,
|
||||
has_private_forwards: Optional[bool] = None,
|
||||
has_restricted_voice_and_video_messages: Optional[bool] = None,
|
||||
join_to_send_messages: Optional[bool] = None,
|
||||
join_by_request: Optional[bool] = None,
|
||||
description: Optional[str] = None,
|
||||
invite_link: Optional[str] = None,
|
||||
pinned_message: Optional["Message"] = None,
|
||||
permissions: Optional[ChatPermissions] = None,
|
||||
slow_mode_delay: Optional[int] = None,
|
||||
unrestrict_boost_count: Optional[int] = None,
|
||||
message_auto_delete_time: Optional[int] = None,
|
||||
has_aggressive_anti_spam_enabled: Optional[bool] = None,
|
||||
has_hidden_members: Optional[bool] = None,
|
||||
has_protected_content: Optional[bool] = None,
|
||||
has_visible_history: Optional[bool] = None,
|
||||
sticker_set_name: Optional[str] = None,
|
||||
can_set_sticker_set: Optional[bool] = None,
|
||||
custom_emoji_sticker_set_name: Optional[str] = None,
|
||||
linked_chat_id: Optional[int] = None,
|
||||
location: Optional[ChatLocation] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(
|
||||
id=id,
|
||||
type=type,
|
||||
title=title,
|
||||
username=username,
|
||||
first_name=first_name,
|
||||
last_name=last_name,
|
||||
photo=photo,
|
||||
description=description,
|
||||
invite_link=invite_link,
|
||||
pinned_message=pinned_message,
|
||||
permissions=permissions,
|
||||
sticker_set_name=sticker_set_name,
|
||||
can_set_sticker_set=can_set_sticker_set,
|
||||
slow_mode_delay=slow_mode_delay,
|
||||
bio=bio,
|
||||
linked_chat_id=linked_chat_id,
|
||||
location=location,
|
||||
message_auto_delete_time=message_auto_delete_time,
|
||||
has_private_forwards=has_private_forwards,
|
||||
has_protected_content=has_protected_content,
|
||||
join_to_send_messages=join_to_send_messages,
|
||||
join_by_request=join_by_request,
|
||||
has_restricted_voice_and_video_messages=has_restricted_voice_and_video_messages,
|
||||
is_forum=is_forum,
|
||||
active_usernames=active_usernames,
|
||||
emoji_status_custom_emoji_id=emoji_status_custom_emoji_id,
|
||||
emoji_status_expiration_date=emoji_status_expiration_date,
|
||||
has_aggressive_anti_spam_enabled=has_aggressive_anti_spam_enabled,
|
||||
has_hidden_members=has_hidden_members,
|
||||
available_reactions=available_reactions,
|
||||
accent_color_id=accent_color_id,
|
||||
background_custom_emoji_id=background_custom_emoji_id,
|
||||
profile_accent_color_id=profile_accent_color_id,
|
||||
profile_background_custom_emoji_id=profile_background_custom_emoji_id,
|
||||
has_visible_history=has_visible_history,
|
||||
unrestrict_boost_count=unrestrict_boost_count,
|
||||
custom_emoji_sticker_set_name=custom_emoji_sticker_set_name,
|
||||
birthdate=birthdate,
|
||||
personal_chat=personal_chat,
|
||||
business_intro=business_intro,
|
||||
business_location=business_location,
|
||||
business_opening_hours=business_opening_hours,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
# Required and unique to this class-
|
||||
with self._unfrozen():
|
||||
self.max_reaction_count: int = max_reaction_count
|
||||
|
||||
self._freeze()
|
||||
+14
-13
@@ -191,6 +191,11 @@ class ChatMemberAdministrator(ChatMember):
|
||||
* The argument :paramref:`can_manage_topics` was added, which changes the position of the
|
||||
optional argument :paramref:`custom_title`.
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
As of this version, :attr:`can_post_stories`, :attr:`can_edit_stories`,
|
||||
and :attr:`can_delete_stories` is now required. Thus, the order of arguments had to be
|
||||
changed.
|
||||
|
||||
Args:
|
||||
user (:class:`telegram.User`): Information about the user.
|
||||
can_be_edited (:obj:`bool`): :obj:`True`, if the bot
|
||||
@@ -230,8 +235,9 @@ class ChatMemberAdministrator(ChatMember):
|
||||
.. versionadded:: 20.6
|
||||
.. versionchanged:: 21.0
|
||||
|non_optional_story_argument|
|
||||
can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit
|
||||
stories posted by other users.
|
||||
can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted
|
||||
by other users, post stories to the chat page, pin chat stories, and access the chat's
|
||||
story archive
|
||||
|
||||
.. versionadded:: 20.6
|
||||
.. versionchanged:: 21.0
|
||||
@@ -289,8 +295,9 @@ class ChatMemberAdministrator(ChatMember):
|
||||
.. versionadded:: 20.6
|
||||
.. versionchanged:: 21.0
|
||||
|non_optional_story_argument|
|
||||
can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit
|
||||
stories posted by other users.
|
||||
can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted
|
||||
by other users, post stories to the chat page, pin chat stories, and access the chat's
|
||||
story archive
|
||||
|
||||
.. versionadded:: 20.6
|
||||
.. versionchanged:: 21.0
|
||||
@@ -340,14 +347,14 @@ class ChatMemberAdministrator(ChatMember):
|
||||
can_promote_members: bool,
|
||||
can_change_info: bool,
|
||||
can_invite_users: bool,
|
||||
can_post_stories: bool,
|
||||
can_edit_stories: bool,
|
||||
can_delete_stories: bool,
|
||||
can_post_messages: Optional[bool] = None,
|
||||
can_edit_messages: Optional[bool] = None,
|
||||
can_pin_messages: Optional[bool] = None,
|
||||
can_manage_topics: Optional[bool] = None,
|
||||
custom_title: Optional[str] = None,
|
||||
can_post_stories: Optional[bool] = None,
|
||||
can_edit_stories: Optional[bool] = None,
|
||||
can_delete_stories: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -362,12 +369,6 @@ class ChatMemberAdministrator(ChatMember):
|
||||
self.can_promote_members: bool = can_promote_members
|
||||
self.can_change_info: bool = can_change_info
|
||||
self.can_invite_users: bool = can_invite_users
|
||||
# Not actually optionals but because of backwards compatability we pretend they are
|
||||
if can_post_stories is None or can_edit_stories is None or can_delete_stories is None:
|
||||
raise TypeError(
|
||||
"As of 21.0 can_post_stories, can_edit_stories and can_delete_stories "
|
||||
"must be set in order to create this object."
|
||||
)
|
||||
self.can_post_stories: bool = can_post_stories
|
||||
self.can_edit_stories: bool = can_edit_stories
|
||||
self.can_delete_stories: bool = can_delete_stories
|
||||
|
||||
@@ -63,6 +63,11 @@ class ChatMemberUpdated(TelegramObject):
|
||||
chat via a chat folder invite link
|
||||
|
||||
.. versionadded:: 20.3
|
||||
via_join_request (:obj:`bool`, optional): :obj:`True`, if the user joined the chat after
|
||||
sending a direct join request without using an invite link and being approved by
|
||||
an administrator
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Attributes:
|
||||
chat (:class:`telegram.Chat`): Chat the user belongs to.
|
||||
@@ -80,6 +85,11 @@ class ChatMemberUpdated(TelegramObject):
|
||||
chat via a chat folder invite link
|
||||
|
||||
.. versionadded:: 20.3
|
||||
via_join_request (:obj:`bool`): Optional. :obj:`True`, if the user joined the chat after
|
||||
sending a direct join request without using an invite link and being approved
|
||||
by an administrator
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
"""
|
||||
|
||||
@@ -91,6 +101,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
"new_chat_member",
|
||||
"old_chat_member",
|
||||
"via_chat_folder_invite_link",
|
||||
"via_join_request",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -102,6 +113,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
new_chat_member: ChatMember,
|
||||
invite_link: Optional[ChatInviteLink] = None,
|
||||
via_chat_folder_invite_link: Optional[bool] = None,
|
||||
via_join_request: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -116,6 +128,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
|
||||
# Optionals
|
||||
self.invite_link: Optional[ChatInviteLink] = invite_link
|
||||
self.via_join_request: Optional[bool] = via_join_request
|
||||
|
||||
self._id_attrs = (
|
||||
self.chat,
|
||||
|
||||
@@ -36,6 +36,10 @@ class InputSticker(TelegramObject):
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
As of Bot API 7.2, the new argument :paramref:`format` is a required argument, and thus the
|
||||
order of the arguments has changed.
|
||||
|
||||
Args:
|
||||
sticker (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path`): The
|
||||
added sticker. |uploadinputnopath| Animated and video stickers can't be uploaded via
|
||||
@@ -52,6 +56,13 @@ class InputSticker(TelegramObject):
|
||||
:tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For
|
||||
":tg-const:`telegram.constants.StickerType.REGULAR`" and
|
||||
":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
|
||||
format (:obj:`str`): Format of the added sticker, must be one of
|
||||
:tg-const:`telegram.constants.StickerFormat.STATIC` for a
|
||||
``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM
|
||||
video.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Attributes:
|
||||
sticker (:obj:`str` | :class:`telegram.InputFile`): The added sticker.
|
||||
@@ -67,15 +78,23 @@ class InputSticker(TelegramObject):
|
||||
:tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For
|
||||
":tg-const:`telegram.constants.StickerType.REGULAR`" and
|
||||
":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
|
||||
":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
|
||||
format (:obj:`str`): Format of the added sticker, must be one of
|
||||
:tg-const:`telegram.constants.StickerFormat.STATIC` for a
|
||||
``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM
|
||||
video.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
|
||||
__slots__ = ("emoji_list", "keywords", "mask_position", "sticker")
|
||||
__slots__ = ("emoji_list", "format", "keywords", "mask_position", "sticker")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sticker: FileInput,
|
||||
emoji_list: Sequence[str],
|
||||
format: str, # pylint: disable=redefined-builtin
|
||||
mask_position: Optional[MaskPosition] = None,
|
||||
keywords: Optional[Sequence[str]] = None,
|
||||
*,
|
||||
@@ -91,6 +110,7 @@ class InputSticker(TelegramObject):
|
||||
attach=True,
|
||||
)
|
||||
self.emoji_list: Tuple[str, ...] = parse_sequence_arg(emoji_list)
|
||||
self.format: str = format
|
||||
self.mask_position: Optional[MaskPosition] = mask_position
|
||||
self.keywords: Tuple[str, ...] = parse_sequence_arg(keywords)
|
||||
|
||||
|
||||
@@ -227,16 +227,20 @@ class StickerSet(TelegramObject):
|
||||
.. versionchanged:: 20.0
|
||||
The parameter ``contains_masks`` has been removed. Use :paramref:`sticker_type` instead.
|
||||
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
The parameters ``is_video`` and ``is_animated`` are deprecated and now made optional. Thus,
|
||||
the order of the arguments had to be changed.
|
||||
|
||||
.. versionchanged:: 20.5
|
||||
|removed_thumb_note|
|
||||
|
||||
.. versionremoved:: 21.2
|
||||
Removed the deprecated arguments and attributes ``is_animated`` and ``is_video``.
|
||||
|
||||
Args:
|
||||
name (:obj:`str`): Sticker set name.
|
||||
title (:obj:`str`): Sticker set title.
|
||||
is_animated (:obj:`bool`): :obj:`True`, if the sticker set contains animated stickers.
|
||||
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
|
||||
|
||||
.. versionadded:: 13.11
|
||||
stickers (Sequence[:class:`telegram.Sticker`]): List of all set stickers.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
@@ -255,10 +259,6 @@ class StickerSet(TelegramObject):
|
||||
Attributes:
|
||||
name (:obj:`str`): Sticker set name.
|
||||
title (:obj:`str`): Sticker set title.
|
||||
is_animated (:obj:`bool`): :obj:`True`, if the sticker set contains animated stickers.
|
||||
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
|
||||
|
||||
.. versionadded:: 13.11
|
||||
stickers (Tuple[:class:`telegram.Sticker`]): List of all set stickers.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
@@ -276,8 +276,6 @@ class StickerSet(TelegramObject):
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"is_animated",
|
||||
"is_video",
|
||||
"name",
|
||||
"sticker_type",
|
||||
"stickers",
|
||||
@@ -289,9 +287,7 @@ class StickerSet(TelegramObject):
|
||||
self,
|
||||
name: str,
|
||||
title: str,
|
||||
is_animated: bool,
|
||||
stickers: Sequence[Sticker],
|
||||
is_video: bool,
|
||||
sticker_type: str,
|
||||
thumbnail: Optional[PhotoSize] = None,
|
||||
*,
|
||||
@@ -300,12 +296,9 @@ class StickerSet(TelegramObject):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.name: str = name
|
||||
self.title: str = title
|
||||
self.is_animated: bool = is_animated
|
||||
self.is_video: bool = is_video
|
||||
self.stickers: Tuple[Sticker, ...] = parse_sequence_arg(stickers)
|
||||
self.sticker_type: str = sticker_type
|
||||
# Optional
|
||||
|
||||
self.thumbnail: Optional[PhotoSize] = thumbnail
|
||||
self._id_attrs = (self.name,)
|
||||
|
||||
@@ -323,7 +316,7 @@ class StickerSet(TelegramObject):
|
||||
api_kwargs = {}
|
||||
# These are deprecated fields that TG still returns for backwards compatibility
|
||||
# Let's filter them out to speed up the de-json process
|
||||
for deprecated_field in ("contains_masks", "thumb"):
|
||||
for deprecated_field in ("contains_masks", "thumb", "is_animated", "is_video"):
|
||||
if deprecated_field in data:
|
||||
api_kwargs[deprecated_field] = data.pop(deprecated_field)
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ class ForceReply(TelegramObject):
|
||||
Upon receiving a message with this object, Telegram clients will display a reply interface to
|
||||
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.
|
||||
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.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`selective` is equal.
|
||||
|
||||
@@ -91,6 +91,7 @@ class InlineKeyboardButton(TelegramObject):
|
||||
to the bot when button is pressed, UTF-8
|
||||
:tg-const:`telegram.InlineKeyboardButton.MIN_CALLBACK_DATA`-
|
||||
:tg-const:`telegram.InlineKeyboardButton.MAX_CALLBACK_DATA` bytes.
|
||||
Not supported for messages sent on behalf of a Telegram Business account.
|
||||
If the bot instance allows arbitrary callback data, anything can be passed.
|
||||
|
||||
Tip:
|
||||
@@ -102,25 +103,25 @@ class InlineKeyboardButton(TelegramObject):
|
||||
<https://core.telegram.org/bots/webapps>`_ that will be launched when the user presses
|
||||
the button. The Web App will be able to send an arbitrary message on behalf of the user
|
||||
using the method :meth:`~telegram.Bot.answer_web_app_query`. Available only in
|
||||
private chats between a user and the bot.
|
||||
private chats between a user and the bot. Not supported for messages sent on behalf of
|
||||
a Telegram Business account.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
switch_inline_query (:obj:`str`, optional): If set, pressing the button will prompt the
|
||||
user to select one of their chats, open that chat and insert the bot's username and the
|
||||
specified inline query in the input field. Can be empty, in which case just the bot's
|
||||
username will be inserted. This offers an easy way for users to start using your bot
|
||||
in inline mode when they are currently in a private chat with it. Especially useful
|
||||
when combined with ``switch_pm*`` actions - in this case the user will be automatically
|
||||
returned to the chat they switched from, skipping the chat selection screen.
|
||||
switch_inline_query (:obj:`str`, optional): If set, pressing the button will insert the
|
||||
bot's username and the specified inline query in the current chat's input field. May be
|
||||
empty, in which case only the bot's username will be inserted.
|
||||
|
||||
This offers a quick way for the user to open your bot in inline mode in the same chat -
|
||||
good for selecting something from multiple options. Not supported in channels and for
|
||||
messages sent on behalf of a Telegram Business account.
|
||||
|
||||
Tip:
|
||||
This is similar to the new parameter :paramref:`switch_inline_query_chosen_chat`,
|
||||
but gives no control over which chats can be selected.
|
||||
switch_inline_query_current_chat (:obj:`str`, optional): If set, pressing the button will
|
||||
insert the bot's username and the specified inline query in the current chat's input
|
||||
field. Can be empty, in which case only the bot's username will be inserted. This
|
||||
offers a quick way for the user to open your bot in inline mode in the same chat - good
|
||||
for selecting something from multiple options.
|
||||
prompt the user to select one of their chats of the specified type, open that chat and
|
||||
insert the bot's username and the specified inline query in the input field. Not
|
||||
supported for messages sent on behalf of a Telegram Business account.
|
||||
callback_game (:class:`telegram.CallbackGame`, optional): Description of the game that will
|
||||
be launched when the user presses the button. This type of button **must** always be
|
||||
the **first** button in the first row.
|
||||
@@ -130,7 +131,8 @@ class InlineKeyboardButton(TelegramObject):
|
||||
switch_inline_query_chosen_chat (:obj:`telegram.SwitchInlineQueryChosenChat`, optional):
|
||||
If set, pressing the button will prompt the user to select one of their chats of the
|
||||
specified type, open that chat and insert the bot's username and the specified inline
|
||||
query in the input field.
|
||||
query in the input field. Not supported for messages sent on behalf of a Telegram
|
||||
Business account.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
@@ -159,29 +161,30 @@ class InlineKeyboardButton(TelegramObject):
|
||||
to the bot when button is pressed, UTF-8
|
||||
:tg-const:`telegram.InlineKeyboardButton.MIN_CALLBACK_DATA`-
|
||||
:tg-const:`telegram.InlineKeyboardButton.MAX_CALLBACK_DATA` bytes.
|
||||
Not supported for messages sent on behalf of a Telegram Business account.
|
||||
web_app (:obj:`telegram.WebAppInfo`): Optional. Description of the `Web App
|
||||
<https://core.telegram.org/bots/webapps>`_ that will be launched when the user presses
|
||||
the button. The Web App will be able to send an arbitrary message on behalf of the user
|
||||
using the method :meth:`~telegram.Bot.answer_web_app_query`. Available only in
|
||||
private chats between a user and the bot.
|
||||
private chats between a user and the bot. Not supported for messages sent on behalf of
|
||||
a Telegram Business account.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
switch_inline_query (:obj:`str`): Optional. If set, pressing the button will prompt the
|
||||
user to select one of their chats, open that chat and insert the bot's username and the
|
||||
specified inline query in the input field. Can be empty, in which case just the bot's
|
||||
username will be inserted. This offers an easy way for users to start using your bot
|
||||
in inline mode when they are currently in a private chat with it. Especially useful
|
||||
when combined with ``switch_pm*`` actions - in this case the user will be automatically
|
||||
returned to the chat they switched from, skipping the chat selection screen.
|
||||
switch_inline_query (:obj:`str`): Optional. If set, pressing the button will insert the
|
||||
bot's username and the specified inline query in the current chat's input field. May be
|
||||
empty, in which case only the bot's username will be inserted.
|
||||
|
||||
This offers a quick way for the user to open your bot in inline mode in the same chat -
|
||||
good for selecting something from multiple options. Not supported in channels and for
|
||||
messages sent on behalf of a Telegram Business account.
|
||||
|
||||
Tip:
|
||||
This is similar to the new parameter :paramref:`switch_inline_query_chosen_chat`,
|
||||
but gives no control over which chats can be selected.
|
||||
switch_inline_query_current_chat (:obj:`str`): Optional. If set, pressing the button will
|
||||
insert the bot's username and the specified inline query in the current chat's input
|
||||
field. Can be empty, in which case only the bot's username will be inserted. This
|
||||
offers a quick way for the user to open your bot in inline mode in the same chat - good
|
||||
for selecting something from multiple options.
|
||||
prompt the user to select one of their chats of the specified type, open that chat and
|
||||
insert the bot's username and the specified inline query in the input field. Not
|
||||
supported for messages sent on behalf of a Telegram Business account.
|
||||
callback_game (:class:`telegram.CallbackGame`): Optional. Description of the game that will
|
||||
be launched when the user presses the button. This type of button **must** always be
|
||||
the **first** button in the first row.
|
||||
@@ -191,7 +194,8 @@ class InlineKeyboardButton(TelegramObject):
|
||||
switch_inline_query_chosen_chat (:obj:`telegram.SwitchInlineQueryChosenChat`): Optional.
|
||||
If set, pressing the button will prompt the user to select one of their chats of the
|
||||
specified type, open that chat and insert the bot's username and the specified inline
|
||||
query in the input field.
|
||||
query in the input field. Not supported for messages sent on behalf of a Telegram
|
||||
Business account.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
|
||||
@@ -89,7 +89,9 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||
live_period (:obj:`int`): Optional. Period in seconds for which the location will be
|
||||
updated, should be between
|
||||
:tg-const:`telegram.InlineQueryResultLocation.MIN_LIVE_PERIOD` and
|
||||
:tg-const:`telegram.InlineQueryResultLocation.MAX_LIVE_PERIOD`.
|
||||
:tg-const:`telegram.InlineQueryResultLocation.MAX_LIVE_PERIOD` or
|
||||
:tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` for live
|
||||
locations that can be edited indefinitely.
|
||||
heading (:obj:`int`): Optional. For live locations, a direction in which the user is
|
||||
moving, in degrees. Must be between
|
||||
:tg-const:`telegram.InlineQueryResultLocation.MIN_HEADING` and
|
||||
|
||||
@@ -42,7 +42,9 @@ class InputLocationMessageContent(InputMessageContent):
|
||||
live_period (:obj:`int`, optional): Period in seconds for which the location will be
|
||||
updated, should be between
|
||||
:tg-const:`telegram.InputLocationMessageContent.MIN_LIVE_PERIOD` and
|
||||
:tg-const:`telegram.InputLocationMessageContent.MAX_LIVE_PERIOD`.
|
||||
:tg-const:`telegram.InputLocationMessageContent.MAX_LIVE_PERIOD` or
|
||||
:tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` for live
|
||||
locations that can be edited indefinitely.
|
||||
heading (:obj:`int`, optional): For live locations, a direction in which the user is
|
||||
moving, in degrees. Must be between
|
||||
:tg-const:`telegram.InputLocationMessageContent.MIN_HEADING` and
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains two objects to request chats/users."""
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._chatadministratorrights import ChatAdministratorRights
|
||||
@@ -56,6 +57,16 @@ class KeyboardButtonRequestUsers(TelegramObject):
|
||||
.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
request_name (:obj:`bool`, optional): Pass :obj:`True` to request the users' first and last
|
||||
name.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
request_username (:obj:`bool`, optional): Pass :obj:`True` to request the users' username.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
request_photo (:obj:`bool`, optional): Pass :obj:`True` to request the users' photo.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Attributes:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
@@ -71,11 +82,25 @@ class KeyboardButtonRequestUsers(TelegramObject):
|
||||
.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
request_name (:obj:`bool`): Optional. Pass :obj:`True` to request the users' first and last
|
||||
name.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
request_username (:obj:`bool`): Optional. Pass :obj:`True` to request the users' username.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
request_photo (:obj:`bool`): Optional. Pass :obj:`True` to request the users' photo.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"max_quantity",
|
||||
"request_id",
|
||||
"request_name",
|
||||
"request_photo",
|
||||
"request_username",
|
||||
"user_is_bot",
|
||||
"user_is_premium",
|
||||
)
|
||||
@@ -86,6 +111,9 @@ class KeyboardButtonRequestUsers(TelegramObject):
|
||||
user_is_bot: Optional[bool] = None,
|
||||
user_is_premium: Optional[bool] = None,
|
||||
max_quantity: Optional[int] = None,
|
||||
request_name: Optional[bool] = None,
|
||||
request_username: Optional[bool] = None,
|
||||
request_photo: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -97,6 +125,9 @@ class KeyboardButtonRequestUsers(TelegramObject):
|
||||
self.user_is_bot: Optional[bool] = user_is_bot
|
||||
self.user_is_premium: Optional[bool] = user_is_premium
|
||||
self.max_quantity: Optional[int] = max_quantity
|
||||
self.request_name: Optional[bool] = request_name
|
||||
self.request_username: Optional[bool] = request_username
|
||||
self.request_photo: Optional[bool] = request_photo
|
||||
|
||||
self._id_attrs = (self.request_id,)
|
||||
|
||||
@@ -138,6 +169,15 @@ class KeyboardButtonRequestChat(TelegramObject):
|
||||
applied.
|
||||
bot_is_member (:obj:`bool`, optional): Pass :obj:`True` to request a chat with the bot
|
||||
as a member. Otherwise, no additional restrictions are applied.
|
||||
request_title (:obj:`bool`, optional): Pass :obj:`True` to request the chat's title.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
request_username (:obj:`bool`, optional): Pass :obj:`True` to request the chat's username.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
request_photo (:obj:`bool`, optional): Pass :obj:`True` to request the chat's photo.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
Attributes:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
chat_is_channel (:obj:`bool`): Pass :obj:`True` to request a channel chat, pass
|
||||
@@ -145,7 +185,7 @@ class KeyboardButtonRequestChat(TelegramObject):
|
||||
chat_is_forum (:obj:`bool`): Optional. Pass :obj:`True` to request a forum supergroup, pass
|
||||
:obj:`False` to request a non-forum chat. If not specified, no additional
|
||||
restrictions are applied.
|
||||
chat_has_username (:obj:`bool`, optional): Pass :obj:`True` to request a supergroup or a
|
||||
chat_has_username (:obj:`bool`): Optional. Pass :obj:`True` to request a supergroup or a
|
||||
channel with a username, pass :obj:`False` to request a chat without a username. If
|
||||
not specified, no additional restrictions are applied.
|
||||
chat_is_created (:obj:`bool`) Optional. Pass :obj:`True` to request a chat owned by the
|
||||
@@ -159,6 +199,15 @@ class KeyboardButtonRequestChat(TelegramObject):
|
||||
applied.
|
||||
bot_is_member (:obj:`bool`) Optional. Pass :obj:`True` to request a chat with the bot
|
||||
as a member. Otherwise, no additional restrictions are applied.
|
||||
request_title (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's title.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
request_username (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's username.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
request_photo (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's photo.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
@@ -169,6 +218,9 @@ class KeyboardButtonRequestChat(TelegramObject):
|
||||
"chat_is_created",
|
||||
"chat_is_forum",
|
||||
"request_id",
|
||||
"request_photo",
|
||||
"request_title",
|
||||
"request_username",
|
||||
"user_administrator_rights",
|
||||
)
|
||||
|
||||
@@ -182,6 +234,9 @@ class KeyboardButtonRequestChat(TelegramObject):
|
||||
user_administrator_rights: Optional[ChatAdministratorRights] = None,
|
||||
bot_administrator_rights: Optional[ChatAdministratorRights] = None,
|
||||
bot_is_member: Optional[bool] = None,
|
||||
request_title: Optional[bool] = None,
|
||||
request_username: Optional[bool] = None,
|
||||
request_photo: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -199,6 +254,9 @@ class KeyboardButtonRequestChat(TelegramObject):
|
||||
)
|
||||
self.bot_administrator_rights: Optional[ChatAdministratorRights] = bot_administrator_rights
|
||||
self.bot_is_member: Optional[bool] = bot_is_member
|
||||
self.request_title: Optional[bool] = request_title
|
||||
self.request_username: Optional[bool] = request_username
|
||||
self.request_photo: Optional[bool] = request_photo
|
||||
|
||||
self._id_attrs = (self.request_id,)
|
||||
|
||||
|
||||
+367
-68
File diff suppressed because it is too large
Load Diff
@@ -153,15 +153,15 @@ class EncryptedCredentials(TelegramObject):
|
||||
|
||||
self._id_attrs = (self.data, self.hash, self.secret)
|
||||
|
||||
self._decrypted_secret: Optional[str] = None
|
||||
self._decrypted_secret: Optional[bytes] = None
|
||||
self._decrypted_data: Optional[Credentials] = None
|
||||
|
||||
self._freeze()
|
||||
|
||||
@property
|
||||
def decrypted_secret(self) -> str:
|
||||
def decrypted_secret(self) -> bytes:
|
||||
"""
|
||||
:obj:`str`: Lazily decrypt and return secret.
|
||||
:obj:`bytes`: Lazily decrypt and return secret.
|
||||
|
||||
Raises:
|
||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
||||
|
||||
@@ -60,8 +60,8 @@ class EncryptedPassportElement(TelegramObject):
|
||||
email (:obj:`str`, optional): User's verified email address; available only for "email"
|
||||
type.
|
||||
files (Sequence[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted
|
||||
files with documents provided by the user; available only for "utility_bill",
|
||||
"bank_statement", "rental_agreement", "passport_registration" and
|
||||
files with documents provided by the user; available only for "utility_bill",
|
||||
"bank_statement", "rental_agreement", "passport_registration" and
|
||||
"temporary_registration" types.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
@@ -74,12 +74,12 @@ class EncryptedPassportElement(TelegramObject):
|
||||
reverse side of the document, provided by the user; Available only for
|
||||
"driver_license" and "identity_card".
|
||||
selfie (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
|
||||
selfie of the user holding a document, provided by the user; available if requested for
|
||||
selfie of the user holding a document, provided by the user; available if requested for
|
||||
"passport", "driver_license", "identity_card" and "internal_passport".
|
||||
translation (Sequence[:class:`telegram.PassportFile`], optional): Array of
|
||||
encrypted/decrypted files with translated versions of documents provided by the user;
|
||||
available if requested requested for "passport", "driver_license", "identity_card",
|
||||
"internal_passport", "utility_bill", "bank_statement", "rental_agreement",
|
||||
encrypted/decrypted files with translated versions of documents provided by the user;
|
||||
available if requested requested for "passport", "driver_license", "identity_card",
|
||||
"internal_passport", "utility_bill", "bank_statement", "rental_agreement",
|
||||
"passport_registration" and "temporary_registration" types.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
@@ -101,8 +101,8 @@ class EncryptedPassportElement(TelegramObject):
|
||||
email (:obj:`str`): Optional. User's verified email address; available only for "email"
|
||||
type.
|
||||
files (Tuple[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted
|
||||
files with documents provided by the user; available only for "utility_bill",
|
||||
"bank_statement", "rental_agreement", "passport_registration" and
|
||||
files with documents provided by the user; available only for "utility_bill",
|
||||
"bank_statement", "rental_agreement", "passport_registration" and
|
||||
"temporary_registration" types.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
@@ -157,7 +157,10 @@ class EncryptedPassportElement(TelegramObject):
|
||||
reverse_side: Optional[PassportFile] = None,
|
||||
selfie: Optional[PassportFile] = None,
|
||||
translation: Optional[Sequence[PassportFile]] = None,
|
||||
credentials: Optional["Credentials"] = None, # pylint: disable=unused-argument
|
||||
# TODO: Remove the credentials argument in 22.0 or later
|
||||
credentials: Optional[ # pylint: disable=unused-argument # noqa: ARG002
|
||||
"Credentials"
|
||||
] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
||||
@@ -210,9 +210,11 @@ class PassportElementErrorFiles(PassportElementError):
|
||||
This attribute will return a tuple instead of a list in future major versions.
|
||||
"""
|
||||
warn(
|
||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
||||
" versions.",
|
||||
PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.6",
|
||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
||||
" versions.",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_hashes
|
||||
@@ -427,10 +429,12 @@ class PassportElementErrorTranslationFiles(PassportElementError):
|
||||
This attribute will return a tuple instead of a list in future major versions.
|
||||
"""
|
||||
warn(
|
||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
||||
" versions. See the stability policy:"
|
||||
" https://docs.python-telegram-bot.org/en/stable/stability_policy.html",
|
||||
PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.6",
|
||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
||||
" versions. See the stability policy:"
|
||||
" https://docs.python-telegram-bot.org/en/stable/stability_policy.html",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_hashes
|
||||
|
||||
@@ -107,9 +107,11 @@ class PassportFile(TelegramObject):
|
||||
This attribute will return a datetime instead of a integer in future major versions.
|
||||
"""
|
||||
warn(
|
||||
"The attribute `file_date` will return a datetime instead of an integer in future"
|
||||
" major versions.",
|
||||
PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.6",
|
||||
"The attribute `file_date` will return a datetime instead of an integer in future"
|
||||
" major versions.",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_date
|
||||
@@ -203,5 +205,6 @@ class PassportFile(TelegramObject):
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
file.set_credentials(self._credentials)
|
||||
if self._credentials:
|
||||
file.set_credentials(self._credentials)
|
||||
return file
|
||||
|
||||
+219
-17
@@ -28,12 +28,80 @@ from telegram._user import User
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.entities import parse_message_entities, parse_message_entity
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class InputPollOption(TelegramObject):
|
||||
"""
|
||||
This object contains information about one answer option in a poll to send.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`text` is equal.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
text (:obj:`str`): Option text,
|
||||
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
|
||||
characters.
|
||||
text_parse_mode (:obj:`str`, optional): |parse_mode|
|
||||
Currently, only custom emoji entities are allowed.
|
||||
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities
|
||||
that appear in the option :paramref:`text`. It can be specified instead of
|
||||
:paramref:`text_parse_mode`.
|
||||
Currently, only custom emoji entities are allowed.
|
||||
This list is empty if the text does not contain entities.
|
||||
|
||||
Attributes:
|
||||
text (:obj:`str`): Option text,
|
||||
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
|
||||
characters.
|
||||
text_parse_mode (:obj:`str`): Optional. |parse_mode|
|
||||
Currently, only custom emoji entities are allowed.
|
||||
text_entities (Sequence[:class:`telegram.MessageEntity`]): Special entities
|
||||
that appear in the option :paramref:`text`. It can be specified instead of
|
||||
:paramref:`text_parse_mode`.
|
||||
Currently, only custom emoji entities are allowed.
|
||||
This list is empty if the text does not contain entities.
|
||||
"""
|
||||
|
||||
__slots__ = ("text", "text_entities", "text_parse_mode")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
text_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.text: str = text
|
||||
self.text_parse_mode: ODVInput[str] = text_parse_mode
|
||||
self.text_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
|
||||
|
||||
self._id_attrs = (self.text,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["InputPollOption"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class PollOption(TelegramObject):
|
||||
"""
|
||||
This object contains information about one answer option in a poll.
|
||||
@@ -46,26 +114,101 @@ class PollOption(TelegramObject):
|
||||
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
|
||||
characters.
|
||||
voter_count (:obj:`int`): Number of users that voted for this option.
|
||||
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities
|
||||
that appear in the option text. Currently, only custom emoji entities are allowed in
|
||||
poll option texts.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Attributes:
|
||||
text (:obj:`str`): Option text,
|
||||
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
|
||||
characters.
|
||||
voter_count (:obj:`int`): Number of users that voted for this option.
|
||||
text_entities (Tuple[:class:`telegram.MessageEntity`]): Special entities
|
||||
that appear in the option text. Currently, only custom emoji entities are allowed in
|
||||
poll option texts.
|
||||
This list is empty if the question does not contain entities.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("text", "voter_count")
|
||||
__slots__ = ("text", "text_entities", "voter_count")
|
||||
|
||||
def __init__(self, text: str, voter_count: int, *, api_kwargs: Optional[JSONDict] = None):
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
voter_count: int,
|
||||
text_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.text: str = text
|
||||
self.voter_count: int = voter_count
|
||||
self.text_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
|
||||
|
||||
self._id_attrs = (self.text, self.voter_count)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["PollOption"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
def parse_entity(self, entity: MessageEntity) -> str:
|
||||
"""Returns the text in :attr:`text`
|
||||
from a given :class:`telegram.MessageEntity` of :attr:`text_entities`.
|
||||
|
||||
Note:
|
||||
This method is present because Telegram calculates the offset and length in
|
||||
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
|
||||
(That is, you can't just slice ``Message.text`` with the offset and length.)
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
|
||||
be an entity that belongs to :attr:`text_entities`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The text of the given entity.
|
||||
"""
|
||||
return parse_message_entity(self.text, entity)
|
||||
|
||||
def parse_entities(self, types: Optional[List[str]] = None) -> Dict[MessageEntity, str]:
|
||||
"""
|
||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
||||
It contains entities from this polls question filtered by their ``type`` attribute as
|
||||
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
|
||||
|
||||
Note:
|
||||
This method should always be used instead of the :attr:`text_entities`
|
||||
attribute, since it calculates the correct substring from the message text based on
|
||||
UTF-16 codepoints. See :attr:`parse_entity` for more info.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
types (List[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
|
||||
``type`` attribute of an entity is contained in this list, it will be returned.
|
||||
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
|
||||
|
||||
Returns:
|
||||
Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
||||
the text that belongs to them, calculated based on UTF-16 codepoints.
|
||||
"""
|
||||
return parse_message_entities(self.text, self.text_entities, types)
|
||||
|
||||
MIN_LENGTH: Final[int] = constants.PollLimit.MIN_OPTION_LENGTH
|
||||
""":const:`telegram.constants.PollLimit.MIN_OPTION_LENGTH`
|
||||
|
||||
@@ -215,6 +358,11 @@ class Poll(TelegramObject):
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
question_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities
|
||||
that appear in the :attr:`question`. Currently, only custom emoji entities are allowed
|
||||
in poll questions.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique poll identifier.
|
||||
@@ -251,6 +399,12 @@ class Poll(TelegramObject):
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
question_entities (Tuple[:class:`telegram.MessageEntity`]): Special entities
|
||||
that appear in the :attr:`question`. Currently, only custom emoji entities are allowed
|
||||
in poll questions.
|
||||
This list is empty if the question does not contain entities.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
"""
|
||||
|
||||
@@ -266,6 +420,7 @@ class Poll(TelegramObject):
|
||||
"open_period",
|
||||
"options",
|
||||
"question",
|
||||
"question_entities",
|
||||
"total_voter_count",
|
||||
"type",
|
||||
)
|
||||
@@ -285,6 +440,7 @@ class Poll(TelegramObject):
|
||||
explanation_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
open_period: Optional[int] = None,
|
||||
close_date: Optional[datetime.datetime] = None,
|
||||
question_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -304,6 +460,7 @@ class Poll(TelegramObject):
|
||||
)
|
||||
self.open_period: Optional[int] = open_period
|
||||
self.close_date: Optional[datetime.datetime] = close_date
|
||||
self.question_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(question_entities)
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
@@ -323,11 +480,13 @@ class Poll(TelegramObject):
|
||||
data["options"] = [PollOption.de_json(option, bot) for option in data["options"]]
|
||||
data["explanation_entities"] = MessageEntity.de_list(data.get("explanation_entities"), bot)
|
||||
data["close_date"] = from_timestamp(data.get("close_date"), tzinfo=loc_tzinfo)
|
||||
data["question_entities"] = MessageEntity.de_list(data.get("question_entities"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
def parse_explanation_entity(self, entity: MessageEntity) -> str:
|
||||
"""Returns the text from a given :class:`telegram.MessageEntity`.
|
||||
"""Returns the text in :attr:`explanation` from a given :class:`telegram.MessageEntity` of
|
||||
:attr:`explanation_entities`.
|
||||
|
||||
Note:
|
||||
This method is present because Telegram calculates the offset and length in
|
||||
@@ -336,7 +495,7 @@ class Poll(TelegramObject):
|
||||
|
||||
Args:
|
||||
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
|
||||
be an entity that belongs to this message.
|
||||
be an entity that belongs to :attr:`explanation_entities`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The text of the given entity.
|
||||
@@ -348,10 +507,7 @@ class Poll(TelegramObject):
|
||||
if not self.explanation:
|
||||
raise RuntimeError("This Poll has no 'explanation'.")
|
||||
|
||||
entity_text = self.explanation.encode("utf-16-le")
|
||||
entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
|
||||
|
||||
return entity_text.decode("utf-16-le")
|
||||
return parse_message_entity(self.explanation, entity)
|
||||
|
||||
def parse_explanation_entities(
|
||||
self, types: Optional[List[str]] = None
|
||||
@@ -375,15 +531,61 @@ class Poll(TelegramObject):
|
||||
Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
||||
the text that belongs to them, calculated based on UTF-16 codepoints.
|
||||
|
||||
"""
|
||||
if types is None:
|
||||
types = MessageEntity.ALL_TYPES
|
||||
Raises:
|
||||
RuntimeError: If the poll has no explanation.
|
||||
|
||||
return {
|
||||
entity: self.parse_explanation_entity(entity)
|
||||
for entity in self.explanation_entities
|
||||
if entity.type in types
|
||||
}
|
||||
"""
|
||||
if not self.explanation:
|
||||
raise RuntimeError("This Poll has no 'explanation'.")
|
||||
|
||||
return parse_message_entities(self.explanation, self.explanation_entities, types)
|
||||
|
||||
def parse_question_entity(self, entity: MessageEntity) -> str:
|
||||
"""Returns the text in :attr:`question` from a given :class:`telegram.MessageEntity` of
|
||||
:attr:`question_entities`.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Note:
|
||||
This method is present because Telegram calculates the offset and length in
|
||||
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
|
||||
(That is, you can't just slice ``Message.text`` with the offset and length.)
|
||||
|
||||
Args:
|
||||
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
|
||||
be an entity that belongs to :attr:`question_entities`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The text of the given entity.
|
||||
"""
|
||||
return parse_message_entity(self.question, entity)
|
||||
|
||||
def parse_question_entities(
|
||||
self, types: Optional[List[str]] = None
|
||||
) -> Dict[MessageEntity, str]:
|
||||
"""
|
||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
||||
It contains entities from this polls question filtered by their ``type`` attribute as
|
||||
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Note:
|
||||
This method should always be used instead of the :attr:`question_entities`
|
||||
attribute, since it calculates the correct substring from the message text based on
|
||||
UTF-16 codepoints. See :attr:`parse_question_entity` for more info.
|
||||
|
||||
Args:
|
||||
types (List[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
|
||||
``type`` attribute of an entity is contained in this list, it will be returned.
|
||||
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
|
||||
|
||||
Returns:
|
||||
Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
||||
the text that belongs to them, calculated based on UTF-16 codepoints.
|
||||
|
||||
"""
|
||||
return parse_message_entities(self.question, self.question_entities, types)
|
||||
|
||||
REGULAR: Final[str] = constants.PollType.REGULAR
|
||||
""":const:`telegram.constants.PollType.REGULAR`"""
|
||||
|
||||
@@ -355,6 +355,7 @@ class ReplyParameters(TelegramObject):
|
||||
chat, or in the chat :paramref:`chat_id` if it is specified.
|
||||
chat_id (:obj:`int` | :obj:`str`, optional): If the message to be replied to is from a
|
||||
different chat, |chat_id_channel|
|
||||
Not supported for messages sent on behalf of a business account.
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| Can be
|
||||
used only for replies in the same chat and forum topic.
|
||||
quote (:obj:`str`, optional): Quoted part of the message to be replied to; 0-1024
|
||||
@@ -376,6 +377,7 @@ class ReplyParameters(TelegramObject):
|
||||
chat, or in the chat :paramref:`chat_id` if it is specified.
|
||||
chat_id (:obj:`int` | :obj:`str`): Optional. If the message to be replied to is from a
|
||||
different chat, |chat_id_channel|
|
||||
Not supported for messages sent on behalf of a business account.
|
||||
allow_sending_without_reply (:obj:`bool`): Optional. |allow_sending_without_reply| Can be
|
||||
used only for replies in the same chat and forum topic.
|
||||
quote (:obj:`str`): Optional. Quoted part of the message to be replied to; 0-1024
|
||||
|
||||
@@ -28,7 +28,8 @@ from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class ReplyKeyboardMarkup(TelegramObject):
|
||||
"""This object represents a custom keyboard with reply options.
|
||||
"""This object represents a custom keyboard with reply options. Not supported in channels and
|
||||
for messages sent on behalf of a Telegram Business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their size of :attr:`keyboard` and all the buttons are equal.
|
||||
|
||||
@@ -29,6 +29,7 @@ class ReplyKeyboardRemove(TelegramObject):
|
||||
keyboard and display the default letter-keyboard. By default, custom keyboards are displayed
|
||||
until a new keyboard is sent by a bot. An exception is made for one-time keyboards that are
|
||||
hidden immediately after the user presses a button (see :class:`telegram.ReplyKeyboardMarkup`).
|
||||
Not supported in channels and for messages sent on behalf of a Telegram Business account.
|
||||
|
||||
Note:
|
||||
User will not be able to summon this keyboard; if you want to hide the keyboard from
|
||||
|
||||
+166
-20
@@ -17,11 +17,16 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains two objects used for request chats/users service messages."""
|
||||
from typing import Optional, Sequence, Tuple
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram._bot import Bot
|
||||
|
||||
|
||||
class UsersShared(TelegramObject):
|
||||
"""
|
||||
@@ -29,48 +34,72 @@ class UsersShared(TelegramObject):
|
||||
using a :class:`telegram.KeyboardButtonRequestUsers` button.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`request_id` and :attr:`user_ids` are equal.
|
||||
considered equal, if their :attr:`request_id` and :attr:`users` are equal.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
Bot API 7.0 replaces ``UserShared`` with this class. The only difference is that now
|
||||
the :attr:`user_ids` is a sequence instead of a single integer.
|
||||
the ``user_ids`` is a sequence instead of a single integer.
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
The argument :attr:`users` is now considered for the equality comparison instead of
|
||||
``user_ids``.
|
||||
|
||||
.. versionremoved:: 21.2
|
||||
Removed the deprecated argument and attribute ``user_ids``.
|
||||
|
||||
Args:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
user_ids (Sequence[:obj:`int`]): Identifiers of the shared users. These numbers may have
|
||||
more than 32 significant bits and some programming languages may have difficulty/silent
|
||||
defects in interpreting them. But they have at most 52 significant bits, so 64-bit
|
||||
integers or double-precision float types are safe for storing these identifiers. The
|
||||
bot may not have access to the users and could be unable to use these identifiers,
|
||||
unless the users are already known to the bot by some other means.
|
||||
users (Sequence[:class:`telegram.SharedUser`]): Information about users shared with the
|
||||
bot.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
.. versionchanged:: 21.2
|
||||
This argument is now required.
|
||||
|
||||
Attributes:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
user_ids (Tuple[:obj:`int`]): Identifiers of the shared users. These numbers may have
|
||||
more than 32 significant bits and some programming languages may have difficulty/silent
|
||||
defects in interpreting them. But they have at most 52 significant bits, so 64-bit
|
||||
integers or double-precision float types are safe for storing these identifiers. The
|
||||
bot may not have access to the users and could be unable to use these identifiers,
|
||||
unless the users are already known to the bot by some other means.
|
||||
users (Tuple[:class:`telegram.SharedUser`]): Information about users shared with the
|
||||
bot.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
|
||||
__slots__ = ("request_id", "user_ids")
|
||||
__slots__ = ("request_id", "users")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
request_id: int,
|
||||
user_ids: Sequence[int],
|
||||
users: Sequence["SharedUser"],
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.request_id: int = request_id
|
||||
self.user_ids: Tuple[int, ...] = tuple(user_ids)
|
||||
self.users: Tuple[SharedUser, ...] = parse_sequence_arg(users)
|
||||
|
||||
self._id_attrs = (self.request_id, self.user_ids)
|
||||
self._id_attrs = (self.request_id, self.users)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["UsersShared"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["users"] = SharedUser.de_list(data.get("users"), bot)
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
# Let's filter it out to speed up the de-json process
|
||||
if user_ids := data.get("user_ids"):
|
||||
api_kwargs = {"user_ids": user_ids}
|
||||
|
||||
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
|
||||
|
||||
|
||||
class ChatShared(TelegramObject):
|
||||
"""
|
||||
@@ -88,6 +117,17 @@ class ChatShared(TelegramObject):
|
||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
||||
it. But it is smaller than 52 bits, so a signed 64-bit integer or double-precision
|
||||
float type are safe for storing this identifier.
|
||||
title (:obj:`str`, optional): Title of the chat, if the title was requested by the bot.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
username (:obj:`str`, optional): Username of the chat, if the username was requested by
|
||||
the bot and available.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
photo (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the chat photo,
|
||||
if the photo was requested by the bot
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Attributes:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
@@ -95,21 +135,127 @@ class ChatShared(TelegramObject):
|
||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
||||
it. But it is smaller than 52 bits, so a signed 64-bit integer or double-precision
|
||||
float type are safe for storing this identifier.
|
||||
title (:obj:`str`): Optional. Title of the chat, if the title was requested by the bot.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
username (:obj:`str`): Optional. Username of the chat, if the username was requested by
|
||||
the bot and available.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
photo (Tuple[:class:`telegram.PhotoSize`]): Optional. Available sizes of the chat photo,
|
||||
if the photo was requested by the bot
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
|
||||
__slots__ = ("chat_id", "request_id")
|
||||
__slots__ = ("chat_id", "photo", "request_id", "title", "username")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
request_id: int,
|
||||
chat_id: int,
|
||||
title: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
photo: Optional[Sequence[PhotoSize]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.request_id: int = request_id
|
||||
self.chat_id: int = chat_id
|
||||
self.title: Optional[str] = title
|
||||
self.username: Optional[str] = username
|
||||
self.photo: Optional[Tuple[PhotoSize, ...]] = parse_sequence_arg(photo)
|
||||
|
||||
self._id_attrs = (self.request_id, self.chat_id)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatShared"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class SharedUser(TelegramObject):
|
||||
"""
|
||||
This object contains information about a user that was shared with the bot using a
|
||||
:class:`telegram.KeyboardButtonRequestUsers` button.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`user_id` is equal.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
user_id (:obj:`int`): Identifier of the shared user. This number may have 32 significant
|
||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
||||
it. But it has atmost 52 significant bits, so 64-bit integers or double-precision
|
||||
float types are safe for storing these identifiers. The bot may not have access to the
|
||||
user and could be unable to use this identifier, unless the user is already known to
|
||||
the bot by some other means.
|
||||
first_name (:obj:`str`, optional): First name of the user, if the name was requested by the
|
||||
bot.
|
||||
last_name (:obj:`str`, optional): Last name of the user, if the name was requested by the
|
||||
bot.
|
||||
username (:obj:`str`, optional): Username of the user, if the username was requested by the
|
||||
bot.
|
||||
photo (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the chat photo,
|
||||
if the photo was requested by the bot.
|
||||
|
||||
Attributes:
|
||||
user_id (:obj:`int`): Identifier of the shared user. This number may have 32 significant
|
||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
||||
it. But it has atmost 52 significant bits, so 64-bit integers or double-precision
|
||||
float types are safe for storing these identifiers. The bot may not have access to the
|
||||
user and could be unable to use this identifier, unless the user is already known to
|
||||
the bot by some other means.
|
||||
first_name (:obj:`str`): Optional. First name of the user, if the name was requested by the
|
||||
bot.
|
||||
last_name (:obj:`str`): Optional. Last name of the user, if the name was requested by the
|
||||
bot.
|
||||
username (:obj:`str`): Optional. Username of the user, if the username was requested by the
|
||||
bot.
|
||||
photo (Tuple[:class:`telegram.PhotoSize`]): Available sizes of the chat photo, if
|
||||
the photo was requested by the bot. This list is empty if the photo was not requsted.
|
||||
"""
|
||||
|
||||
__slots__ = ("first_name", "last_name", "photo", "user_id", "username")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
user_id: int,
|
||||
first_name: Optional[str] = None,
|
||||
last_name: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
photo: Optional[Sequence[PhotoSize]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.user_id: int = user_id
|
||||
self.first_name: Optional[str] = first_name
|
||||
self.last_name: Optional[str] = last_name
|
||||
self.username: Optional[str] = username
|
||||
self.photo: Optional[Tuple[PhotoSize, ...]] = parse_sequence_arg(photo)
|
||||
|
||||
self._id_attrs = (self.user_id,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["SharedUser"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+182
-3
@@ -18,9 +18,10 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Update."""
|
||||
|
||||
from typing import TYPE_CHECKING, Final, List, Optional
|
||||
from typing import TYPE_CHECKING, Final, List, Optional, Union
|
||||
|
||||
from telegram import constants
|
||||
from telegram._business import BusinessConnection, BusinessMessagesDeleted
|
||||
from telegram._callbackquery import CallbackQuery
|
||||
from telegram._chatboost import ChatBoostRemoved, ChatBoostUpdated
|
||||
from telegram._chatjoinrequest import ChatJoinRequest
|
||||
@@ -134,6 +135,28 @@ class Update(TelegramObject):
|
||||
|
||||
.. versionadded:: 20.8
|
||||
|
||||
business_connection (:class:`telegram.BusinessConnection`, optional): The bot was connected
|
||||
to or disconnected from a business account, or a user edited an existing connection
|
||||
with the bot.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
business_message (:class:`telegram.Message`, optional): New message from a connected
|
||||
business account.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
edited_business_message (:class:`telegram.Message`, optional): New version of a message
|
||||
from a connected business account.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
deleted_business_messages (:class:`telegram.BusinessMessagesDeleted`, optional): Messages
|
||||
were deleted from a connected business account.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
|
||||
Attributes:
|
||||
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
|
||||
certain positive number and increase sequentially. This ID becomes especially handy if
|
||||
@@ -219,18 +242,44 @@ class Update(TelegramObject):
|
||||
with delay up to a few minutes.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
|
||||
business_connection (:class:`telegram.BusinessConnection`): Optional. The bot was connected
|
||||
to or disconnected from a business account, or a user edited an existing connection
|
||||
with the bot.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
business_message (:class:`telegram.Message`): Optional. New message from a connected
|
||||
business account.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
edited_business_message (:class:`telegram.Message`): Optional. New version of a message
|
||||
from a connected business account.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
deleted_business_messages (:class:`telegram.BusinessMessagesDeleted`): Optional. Messages
|
||||
were deleted from a connected business account.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_effective_chat",
|
||||
"_effective_message",
|
||||
"_effective_sender",
|
||||
"_effective_user",
|
||||
"business_connection",
|
||||
"business_message",
|
||||
"callback_query",
|
||||
"channel_post",
|
||||
"chat_boost",
|
||||
"chat_join_request",
|
||||
"chat_member",
|
||||
"chosen_inline_result",
|
||||
"deleted_business_messages",
|
||||
"edited_business_message",
|
||||
"edited_channel_post",
|
||||
"edited_message",
|
||||
"inline_query",
|
||||
@@ -318,6 +367,22 @@ class Update(TelegramObject):
|
||||
""":const:`telegram.constants.UpdateType.MESSAGE_REACTION_COUNT`
|
||||
|
||||
.. versionadded:: 20.8"""
|
||||
BUSINESS_CONNECTION: Final[str] = constants.UpdateType.BUSINESS_CONNECTION
|
||||
""":const:`telegram.constants.UpdateType.BUSINESS_CONNECTION`
|
||||
|
||||
.. versionadded:: 21.1"""
|
||||
BUSINESS_MESSAGE: Final[str] = constants.UpdateType.BUSINESS_MESSAGE
|
||||
""":const:`telegram.constants.UpdateType.BUSINESS_MESSAGE`
|
||||
|
||||
.. versionadded:: 21.1"""
|
||||
EDITED_BUSINESS_MESSAGE: Final[str] = constants.UpdateType.EDITED_BUSINESS_MESSAGE
|
||||
""":const:`telegram.constants.UpdateType.EDITED_BUSINESS_MESSAGE`
|
||||
|
||||
.. versionadded:: 21.1"""
|
||||
DELETED_BUSINESS_MESSAGES: Final[str] = constants.UpdateType.DELETED_BUSINESS_MESSAGES
|
||||
""":const:`telegram.constants.UpdateType.DELETED_BUSINESS_MESSAGES`
|
||||
|
||||
.. versionadded:: 21.1"""
|
||||
ALL_TYPES: Final[List[str]] = list(constants.UpdateType)
|
||||
"""List[:obj:`str`]: A list of all available update types.
|
||||
|
||||
@@ -344,6 +409,10 @@ class Update(TelegramObject):
|
||||
removed_chat_boost: Optional[ChatBoostRemoved] = None,
|
||||
message_reaction: Optional[MessageReactionUpdated] = None,
|
||||
message_reaction_count: Optional[MessageReactionCountUpdated] = None,
|
||||
business_connection: Optional[BusinessConnection] = None,
|
||||
business_message: Optional[Message] = None,
|
||||
edited_business_message: Optional[Message] = None,
|
||||
deleted_business_messages: Optional[BusinessMessagesDeleted] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -369,8 +438,15 @@ class Update(TelegramObject):
|
||||
self.removed_chat_boost: Optional[ChatBoostRemoved] = removed_chat_boost
|
||||
self.message_reaction: Optional[MessageReactionUpdated] = message_reaction
|
||||
self.message_reaction_count: Optional[MessageReactionCountUpdated] = message_reaction_count
|
||||
self.business_connection: Optional[BusinessConnection] = business_connection
|
||||
self.business_message: Optional[Message] = business_message
|
||||
self.edited_business_message: Optional[Message] = edited_business_message
|
||||
self.deleted_business_messages: Optional[BusinessMessagesDeleted] = (
|
||||
deleted_business_messages
|
||||
)
|
||||
|
||||
self._effective_user: Optional[User] = None
|
||||
self._effective_sender: Optional[Union["User", "Chat"]] = None
|
||||
self._effective_chat: Optional[Chat] = None
|
||||
self._effective_message: Optional[Message] = None
|
||||
|
||||
@@ -391,9 +467,14 @@ class Update(TelegramObject):
|
||||
* :attr:`chat_boost`
|
||||
* :attr:`removed_chat_boost`
|
||||
* :attr:`message_reaction_count`
|
||||
* :attr:`deleted_business_messages`
|
||||
|
||||
is present.
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
This property now also considers :attr:`business_connection`, :attr:`business_message`
|
||||
and :attr:`edited_business_message`.
|
||||
|
||||
Example:
|
||||
* If :attr:`message` is present, this will give
|
||||
:attr:`telegram.Message.from_user`.
|
||||
@@ -441,9 +522,76 @@ 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
|
||||
|
||||
self._effective_user = user
|
||||
return user
|
||||
|
||||
@property
|
||||
def effective_sender(self) -> Optional[Union["User", "Chat"]]:
|
||||
"""
|
||||
:class:`telegram.User` or :class:`telegram.Chat`: The user or chat that sent this update,
|
||||
no matter what kind of update this is.
|
||||
|
||||
Note:
|
||||
* Depending on the type of update and the user's 'Remain anonymous' setting, this
|
||||
could either be :class:`telegram.User`, :class:`telegram.Chat` or :obj:`None`.
|
||||
|
||||
If no user whatsoever is associated with this update, this gives :obj:`None`. This
|
||||
is the case if any of
|
||||
|
||||
* :attr:`poll`
|
||||
* :attr:`chat_boost`
|
||||
* :attr:`removed_chat_boost`
|
||||
* :attr:`message_reaction_count`
|
||||
* :attr:`deleted_business_messages`
|
||||
|
||||
is present.
|
||||
|
||||
Example:
|
||||
* If :attr:`message` is present, this will give either
|
||||
:attr:`telegram.Message.from_user` or :attr:`telegram.Message.sender_chat`.
|
||||
* If :attr:`poll_answer` is present, this will give either
|
||||
:attr:`telegram.PollAnswer.user` or :attr:`telegram.PollAnswer.voter_chat`.
|
||||
* If :attr:`channel_post` is present, this will give
|
||||
:attr:`telegram.Message.sender_chat`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
if self._effective_sender:
|
||||
return self._effective_sender
|
||||
|
||||
sender: Optional[Union["User", "Chat"]] = None
|
||||
|
||||
if message := (
|
||||
self.message
|
||||
or self.edited_message
|
||||
or self.channel_post
|
||||
or self.edited_channel_post
|
||||
or self.business_message
|
||||
or self.edited_business_message
|
||||
):
|
||||
sender = message.sender_chat
|
||||
|
||||
elif self.poll_answer:
|
||||
sender = self.poll_answer.voter_chat
|
||||
|
||||
elif self.message_reaction:
|
||||
sender = self.message_reaction.actor_chat
|
||||
|
||||
if sender is None:
|
||||
sender = self.effective_user
|
||||
|
||||
self._effective_sender = sender
|
||||
return sender
|
||||
|
||||
@property
|
||||
def effective_chat(self) -> Optional["Chat"]:
|
||||
"""
|
||||
@@ -452,8 +600,12 @@ class Update(TelegramObject):
|
||||
If no chat is associated with this update, this gives :obj:`None`.
|
||||
This is the case, if :attr:`inline_query`,
|
||||
:attr:`chosen_inline_result`, :attr:`callback_query` from inline messages,
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll` or
|
||||
:attr:`poll_answer` is present.
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll`,
|
||||
:attr:`poll_answer`, or :attr:`business_connection` is present.
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
This property now also considers :attr:`business_message`,
|
||||
:attr:`edited_business_message`, and :attr:`deleted_business_messages`.
|
||||
|
||||
Example:
|
||||
If :attr:`message` is present, this will give :attr:`telegram.Message.chat`.
|
||||
@@ -500,6 +652,15 @@ 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
|
||||
|
||||
@@ -512,6 +673,10 @@ class Update(TelegramObject):
|
||||
:attr:`callback_query` (i.e. :attr:`telegram.CallbackQuery.message`) or :obj:`None`, if
|
||||
none of those are present.
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
This property now also considers :attr:`business_message`, and
|
||||
:attr:`edited_business_message`.
|
||||
|
||||
Tip:
|
||||
This property will only ever return objects of type :class:`telegram.Message` or
|
||||
:obj:`None`, never :class:`telegram.MaybeInaccessibleMessage` or
|
||||
@@ -554,6 +719,12 @@ class Update(TelegramObject):
|
||||
elif self.edited_channel_post:
|
||||
message = self.edited_channel_post
|
||||
|
||||
elif self.business_message:
|
||||
message = self.business_message
|
||||
|
||||
elif self.edited_business_message:
|
||||
message = self.edited_business_message
|
||||
|
||||
self._effective_message = message
|
||||
return message
|
||||
|
||||
@@ -589,5 +760,13 @@ class Update(TelegramObject):
|
||||
data["message_reaction_count"] = MessageReactionCountUpdated.de_json(
|
||||
data.get("message_reaction_count"), bot
|
||||
)
|
||||
data["business_connection"] = BusinessConnection.de_json(
|
||||
data.get("business_connection"), bot
|
||||
)
|
||||
data["business_message"] = Message.de_json(data.get("business_message"), bot)
|
||||
data["edited_business_message"] = Message.de_json(data.get("edited_business_message"), bot)
|
||||
data["deleted_business_messages"] = BusinessMessagesDeleted.de_json(
|
||||
data.get("deleted_business_messages"), bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+57
-4
@@ -40,6 +40,7 @@ if TYPE_CHECKING:
|
||||
InputMediaDocument,
|
||||
InputMediaPhoto,
|
||||
InputMediaVideo,
|
||||
InputPollOption,
|
||||
LabeledPrice,
|
||||
LinkPreviewOptions,
|
||||
Location,
|
||||
@@ -78,11 +79,11 @@ class User(TelegramObject):
|
||||
username (:obj:`str`, optional): User's or bot's username.
|
||||
language_code (:obj:`str`, optional): IETF language tag of the user's language.
|
||||
can_join_groups (:obj:`str`, optional): :obj:`True`, if the bot can be invited to groups.
|
||||
Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
Returned only in :meth:`telegram.Bot.get_me`.
|
||||
can_read_all_group_messages (:obj:`str`, optional): :obj:`True`, if privacy mode is
|
||||
disabled for the bot. Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
disabled for the bot. Returned only in :meth:`telegram.Bot.get_me`.
|
||||
supports_inline_queries (:obj:`str`, optional): :obj:`True`, if the bot supports inline
|
||||
queries. Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
queries. Returned only in :meth:`telegram.Bot.get_me`.
|
||||
|
||||
is_premium (:obj:`bool`, optional): :obj:`True`, if this user is a Telegram Premium user.
|
||||
|
||||
@@ -91,6 +92,12 @@ class User(TelegramObject):
|
||||
the bot to the attachment menu.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
can_connect_to_business (:obj:`bool`, optional): :obj:`True`, if the bot can be connected
|
||||
to a Telegram Business account to receive its messages. Returned only in
|
||||
:meth:`telegram.Bot.get_me`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier for this user or bot.
|
||||
is_bot (:obj:`bool`): :obj:`True`, if this user is a bot.
|
||||
@@ -112,6 +119,11 @@ class User(TelegramObject):
|
||||
the bot to the attachment menu.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
can_connect_to_business (:obj:`bool`): Optional. :obj:`True`, if the bot can be connected
|
||||
to a Telegram Business account to receive its messages. Returned only in
|
||||
:meth:`telegram.Bot.get_me`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
.. |user_chat_id_note| replace:: This shortcuts build on the assumption that :attr:`User.id`
|
||||
coincides with the :attr:`Chat.id` of the private chat with the user. This has been the
|
||||
case so far, but Telegram does not guarantee that this stays this way.
|
||||
@@ -119,6 +131,7 @@ class User(TelegramObject):
|
||||
|
||||
__slots__ = (
|
||||
"added_to_attachment_menu",
|
||||
"can_connect_to_business",
|
||||
"can_join_groups",
|
||||
"can_read_all_group_messages",
|
||||
"first_name",
|
||||
@@ -144,6 +157,7 @@ class User(TelegramObject):
|
||||
supports_inline_queries: Optional[bool] = None,
|
||||
is_premium: Optional[bool] = None,
|
||||
added_to_attachment_menu: Optional[bool] = None,
|
||||
can_connect_to_business: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -161,6 +175,7 @@ class User(TelegramObject):
|
||||
self.supports_inline_queries: Optional[bool] = supports_inline_queries
|
||||
self.is_premium: Optional[bool] = is_premium
|
||||
self.added_to_attachment_menu: Optional[bool] = added_to_attachment_menu
|
||||
self.can_connect_to_business: Optional[bool] = can_connect_to_business
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
@@ -393,6 +408,7 @@ class User(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
disable_web_page_preview: Optional[bool] = None,
|
||||
@@ -435,6 +451,7 @@ class User(TelegramObject):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def delete_message(
|
||||
@@ -513,6 +530,7 @@ class User(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -556,6 +574,7 @@ class User(TelegramObject):
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_media_group(
|
||||
@@ -567,6 +586,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -610,6 +630,7 @@ class User(TelegramObject):
|
||||
caption=caption,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_audio(
|
||||
@@ -627,6 +648,7 @@ class User(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -673,12 +695,14 @@ class User(TelegramObject):
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
self,
|
||||
action: str,
|
||||
message_thread_id: Optional[int] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -708,6 +732,7 @@ class User(TelegramObject):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
send_action = send_chat_action
|
||||
@@ -724,6 +749,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -766,6 +792,7 @@ class User(TelegramObject):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_dice(
|
||||
@@ -776,6 +803,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -813,6 +841,7 @@ class User(TelegramObject):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
@@ -828,6 +857,7 @@ class User(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -872,6 +902,7 @@ class User(TelegramObject):
|
||||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_game(
|
||||
@@ -882,6 +913,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -919,6 +951,7 @@ class User(TelegramObject):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_invoice(
|
||||
@@ -1031,6 +1064,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1075,6 +1109,7 @@ class User(TelegramObject):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_animation(
|
||||
@@ -1093,6 +1128,7 @@ class User(TelegramObject):
|
||||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1140,6 +1176,7 @@ class User(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
@@ -1151,6 +1188,7 @@ class User(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1189,6 +1227,7 @@ class User(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
@@ -1208,6 +1247,7 @@ class User(TelegramObject):
|
||||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1256,6 +1296,7 @@ class User(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_venue(
|
||||
@@ -1273,6 +1314,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1319,6 +1361,7 @@ class User(TelegramObject):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_video_note(
|
||||
@@ -1332,6 +1375,7 @@ class User(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1374,6 +1418,7 @@ class User(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
@@ -1388,6 +1433,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1431,12 +1477,13 @@ class User(TelegramObject):
|
||||
filename=filename,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_poll(
|
||||
self,
|
||||
question: str,
|
||||
options: Sequence[str],
|
||||
options: Sequence[Union[str, "InputPollOption"]],
|
||||
is_anonymous: Optional[bool] = None,
|
||||
type: Optional[str] = None,
|
||||
allows_multiple_answers: Optional[bool] = None,
|
||||
@@ -1452,6 +1499,9 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
question_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
question_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1500,6 +1550,9 @@ class User(TelegramObject):
|
||||
explanation_entities=explanation_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
question_parse_mode=question_parse_mode,
|
||||
question_entities=question_entities,
|
||||
)
|
||||
|
||||
async def send_copy(
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains auxiliary functionality for parsing MessageEntity objects.
|
||||
|
||||
Warning:
|
||||
Contents of this module are intended to be used internally by the library and *not* by the
|
||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
||||
the changelog.
|
||||
"""
|
||||
from typing import Dict, Optional, Sequence
|
||||
|
||||
from telegram._messageentity import MessageEntity
|
||||
|
||||
|
||||
def parse_message_entity(text: str, entity: MessageEntity) -> str:
|
||||
"""Returns the text from a given :class:`telegram.MessageEntity`.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`): The text to extract the entity from.
|
||||
entity (:class:`telegram.MessageEntity`): The entity to extract the text from.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The text of the given entity.
|
||||
"""
|
||||
entity_text = text.encode("utf-16-le")
|
||||
entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
|
||||
|
||||
return entity_text.decode("utf-16-le")
|
||||
|
||||
|
||||
def parse_message_entities(
|
||||
text: str, entities: Sequence[MessageEntity], types: Optional[Sequence[str]] = None
|
||||
) -> Dict[MessageEntity, str]:
|
||||
"""
|
||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
||||
It contains entities filtered by their ``type`` attribute as
|
||||
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`): The text to extract the entity from.
|
||||
entities (List[:class:`telegram.MessageEntity`]): The entities to extract the text from.
|
||||
types (List[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
|
||||
``type`` attribute of an entity is contained in this list, it will be returned.
|
||||
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
|
||||
|
||||
Returns:
|
||||
Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
||||
the text that belongs to them, calculated based on UTF-16 codepoints.
|
||||
"""
|
||||
if types is None:
|
||||
types = MessageEntity.ALL_TYPES
|
||||
|
||||
return {
|
||||
entity: parse_message_entity(text, entity) for entity in entities if entity.type in types
|
||||
}
|
||||
@@ -60,7 +60,7 @@ class StringEnum(str, _enum.Enum):
|
||||
|
||||
|
||||
# Apply the __repr__ modification and __str__ fix to IntEnum
|
||||
class IntEnum(_enum.IntEnum):
|
||||
class IntEnum(_enum.IntEnum): # pylint: disable=invalid-slots
|
||||
"""Helper class for int enums where ``str(member)`` prints the value, but ``repr(member)``
|
||||
gives ``EnumName.MEMBER_NAME``.
|
||||
"""
|
||||
|
||||
@@ -26,19 +26,28 @@ Warning:
|
||||
the changelog.
|
||||
"""
|
||||
import warnings
|
||||
from typing import Type
|
||||
from typing import Type, Union
|
||||
|
||||
from telegram.warnings import PTBUserWarning
|
||||
|
||||
|
||||
def warn(message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0) -> None:
|
||||
def warn(
|
||||
message: Union[str, PTBUserWarning],
|
||||
category: Type[Warning] = PTBUserWarning,
|
||||
stacklevel: int = 0,
|
||||
) -> None:
|
||||
"""
|
||||
Helper function used as a shortcut for warning with default values.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
Args:
|
||||
message (:obj:`str`): Specify the warnings message to pass to ``warnings.warn()``.
|
||||
message (:obj:`str` | :obj:`PTBUserWarning`): Specify the warnings message to pass to
|
||||
``warnings.warn()``.
|
||||
|
||||
.. versionchanged:: 21.2
|
||||
Now also accepts a :obj:`PTBUserWarning` instance.
|
||||
|
||||
category (:obj:`Type[Warning]`, optional): Specify the Warning class to pass to
|
||||
``warnings.warn()``. Defaults to :class:`telegram.warnings.PTBUserWarning`.
|
||||
stacklevel (:obj:`int`, optional): Specify the stacklevel to pass to ``warnings.warn()``.
|
||||
|
||||
@@ -23,10 +23,10 @@ inside warnings.py.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
from typing import Any, Callable, Type
|
||||
from typing import Any, Callable, Type, Union
|
||||
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
from telegram.warnings import PTBDeprecationWarning, PTBUserWarning
|
||||
|
||||
|
||||
def build_deprecation_warning_message(
|
||||
@@ -54,8 +54,9 @@ def warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg_name: str,
|
||||
new_arg_name: str,
|
||||
bot_api_version: str,
|
||||
ptb_version: str,
|
||||
stacklevel: int = 2,
|
||||
warn_callback: Callable[[str, Type[Warning], int], None] = warn,
|
||||
warn_callback: Callable[[Union[str, PTBUserWarning], Type[Warning], int], None] = warn,
|
||||
) -> Any:
|
||||
"""A helper function for the transition in API when argument is renamed.
|
||||
|
||||
@@ -80,10 +81,12 @@ def warn_about_deprecated_arg_return_new_arg(
|
||||
|
||||
if deprecated_arg:
|
||||
warn_callback(
|
||||
f"Bot API {bot_api_version} renamed the argument '{deprecated_arg_name}' to "
|
||||
f"'{new_arg_name}'.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel + 1,
|
||||
PTBDeprecationWarning(
|
||||
ptb_version,
|
||||
f"Bot API {bot_api_version} renamed the argument '{deprecated_arg_name}' to "
|
||||
f"'{new_arg_name}'.",
|
||||
),
|
||||
stacklevel=stacklevel + 1, # type: ignore[call-arg]
|
||||
)
|
||||
return deprecated_arg
|
||||
|
||||
@@ -94,6 +97,7 @@ def warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name: str,
|
||||
new_attr_name: str,
|
||||
bot_api_version: str,
|
||||
ptb_version: str,
|
||||
stacklevel: int = 2,
|
||||
) -> None:
|
||||
"""A helper function for the transition in API when attribute is renamed. Call from properties.
|
||||
@@ -101,8 +105,10 @@ def warn_about_deprecated_attr_in_property(
|
||||
The properties replace deprecated attributes in classes and issue these deprecation warnings.
|
||||
"""
|
||||
warn(
|
||||
f"Bot API {bot_api_version} renamed the attribute '{deprecated_attr_name}' to "
|
||||
f"'{new_attr_name}'.",
|
||||
PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
ptb_version,
|
||||
f"Bot API {bot_api_version} renamed the attribute '{deprecated_attr_name}' to "
|
||||
f"'{new_attr_name}'.",
|
||||
),
|
||||
stacklevel=stacklevel + 1,
|
||||
)
|
||||
|
||||
@@ -51,7 +51,7 @@ class Version(NamedTuple):
|
||||
|
||||
|
||||
__version_info__: Final[Version] = Version(
|
||||
major=21, minor=0, micro=1, releaselevel="final", serial=0
|
||||
major=21, minor=2, micro=0, releaselevel="final", serial=0
|
||||
)
|
||||
__version__: Final[str] = str(__version_info__)
|
||||
|
||||
|
||||
+141
-4
@@ -29,7 +29,7 @@ those classes.
|
||||
* Most of the constants in this module are grouped into enums.
|
||||
"""
|
||||
# TODO: Remove this when https://github.com/PyCQA/pylint/issues/6887 is resolved.
|
||||
# pylint: disable=invalid-enum-extension
|
||||
# pylint: disable=invalid-enum-extension,invalid-slots
|
||||
|
||||
__all__ = [
|
||||
"BOT_API_VERSION",
|
||||
@@ -37,6 +37,10 @@ __all__ = [
|
||||
"SUPPORTED_WEBHOOK_PORTS",
|
||||
"ZERO_DATE",
|
||||
"AccentColor",
|
||||
"BackgroundFillLimit",
|
||||
"BackgroundFillType",
|
||||
"BackgroundTypeLimit",
|
||||
"BackgroundTypeType",
|
||||
"BotCommandLimit",
|
||||
"BotCommandScopeType",
|
||||
"BotDescriptionLimit",
|
||||
@@ -142,7 +146,7 @@ class _AccentColor(NamedTuple):
|
||||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=1)
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=3)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
@@ -822,6 +826,46 @@ class ChatLimit(IntEnum):
|
||||
"""
|
||||
|
||||
|
||||
class BackgroundTypeLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.BackgroundTypeFill`,
|
||||
:class:`telegram.BackgroundTypeWallpaper` and :class:`telegram.BackgroundTypePattern`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MAX_DIMMING = 100
|
||||
""":obj:`int`: Maximum value allowed for:
|
||||
|
||||
* :paramref:`~telegram.BackgroundTypeFill.dark_theme_dimming` parameter of
|
||||
:class:`telegram.BackgroundTypeFill`
|
||||
* :paramref:`~telegram.BackgroundTypeWallpaper.dark_theme_dimming` parameter of
|
||||
:class:`telegram.BackgroundTypeWallpaper`
|
||||
"""
|
||||
MAX_INTENSITY = 100
|
||||
""":obj:`int`: Maximum value allowed for :paramref:`~telegram.BackgroundTypePattern.intensity`
|
||||
parameter of :class:`telegram.BackgroundTypePattern`
|
||||
"""
|
||||
|
||||
|
||||
class BackgroundFillLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.BackgroundFillGradient`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MAX_ROTATION_ANGLE = 359
|
||||
""":obj:`int`: Maximum value allowed for:
|
||||
:paramref:`~telegram.BackgroundFillGradient.rotation_angle` parameter of
|
||||
:class:`telegram.BackgroundFillGradient`
|
||||
"""
|
||||
|
||||
|
||||
class ChatMemberStatus(StringEnum):
|
||||
"""This enum contains the available states for :class:`telegram.ChatMember`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
@@ -1427,6 +1471,21 @@ class LocationLimit(IntEnum):
|
||||
:meth:`telegram.Bot.send_location`
|
||||
"""
|
||||
|
||||
LIVE_PERIOD_FOREVER = int(hex(0x7FFFFFFF), 16)
|
||||
""":obj:`int`: Value for live locations that can be edited indefinitely. Passed in:
|
||||
|
||||
* :paramref:`~telegram.InlineQueryResultLocation.live_period` parameter of
|
||||
:class:`telegram.InlineQueryResultLocation`
|
||||
* :paramref:`~telegram.InputLocationMessageContent.live_period` parameter of
|
||||
:class:`telegram.InputLocationMessageContent`
|
||||
* :paramref:`~telegram.Bot.edit_message_live_location.live_period` parameter of
|
||||
:meth:`telegram.Bot.edit_message_live_location`
|
||||
* :paramref:`~telegram.Bot.send_location.live_period` parameter of
|
||||
:meth:`telegram.Bot.send_location`
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
MIN_PROXIMITY_ALERT_RADIUS = 1
|
||||
""":obj:`int`: Minimum value allowed for:
|
||||
|
||||
@@ -1690,8 +1749,12 @@ class MessageOriginType(StringEnum):
|
||||
|
||||
|
||||
class MessageType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.Message`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
"""This enum contains the available types of :class:`telegram.Message`. Here, a "type" means
|
||||
a kind of message that is visually distinct from other kinds of messages in the Telegram app.
|
||||
In particular, auxiliary attributes that can be present for multiple types of messages are
|
||||
not considered in this enumeration.
|
||||
|
||||
The enum members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
@@ -1710,6 +1773,11 @@ class MessageType(StringEnum):
|
||||
|
||||
.. versionadded:: 21.0
|
||||
"""
|
||||
BUSINESS_CONNECTION_ID = "business_connection_id"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.business_connection_id`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
CHANNEL_CHAT_CREATED = "channel_chat_created"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.channel_chat_created`."""
|
||||
CHAT_SHARED = "chat_shared"
|
||||
@@ -1717,6 +1785,11 @@ class MessageType(StringEnum):
|
||||
|
||||
.. versionadded:: 20.8
|
||||
"""
|
||||
CHAT_BACKGROUND_SET = "chat_background_set"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.chat_background_set`.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
CONNECTED_WEBSITE = "connected_website"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.connected_website`."""
|
||||
CONTACT = "contact"
|
||||
@@ -1817,6 +1890,11 @@ class MessageType(StringEnum):
|
||||
|
||||
.. versionadded:: 21.0
|
||||
"""
|
||||
SENDER_BUSINESS_BOT = "sender_business_bot"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.sender_business_bot`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
STICKER = "sticker"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.sticker`."""
|
||||
STORY = "story"
|
||||
@@ -2312,6 +2390,9 @@ class StickerSetLimit(IntEnum):
|
||||
MAX_ANIMATED_STICKERS = 50
|
||||
""":obj:`int`: Maximum number of stickers allowed in an animated or video sticker set, as given
|
||||
in :meth:`telegram.Bot.add_sticker_to_set`.
|
||||
|
||||
.. deprecated:: 21.1
|
||||
The animated sticker limit is now 120, the same as :attr:`MAX_STATIC_STICKERS`.
|
||||
"""
|
||||
MAX_STATIC_STICKERS = 120
|
||||
""":obj:`int`: Maximum number of stickers allowed in a static sticker set, as given in
|
||||
@@ -2504,6 +2585,26 @@ class UpdateType(StringEnum):
|
||||
|
||||
.. versionadded:: 20.8
|
||||
"""
|
||||
BUSINESS_CONNECTION = "business_connection"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.business_connection`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
BUSINESS_MESSAGE = "business_message"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.business_message`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
EDITED_BUSINESS_MESSAGE = "edited_business_message"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.edited_business_message`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
DELETED_BUSINESS_MESSAGES = "deleted_business_messages"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.deleted_business_messages`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
|
||||
|
||||
class InvoiceLimit(IntEnum):
|
||||
@@ -2841,3 +2942,39 @@ class ReactionEmoji(StringEnum):
|
||||
""":obj:`str`: Woman Shrugging"""
|
||||
POUTING_FACE = "😡"
|
||||
""":obj:`str`: Pouting face"""
|
||||
|
||||
|
||||
class BackgroundTypeType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.BackgroundType`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
FILL = "fill"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with fill background."""
|
||||
WALLPAPER = "wallpaper"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with wallpaper background."""
|
||||
PATTERN = "pattern"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with pattern background."""
|
||||
CHAT_THEME = "chat_theme"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with chat_theme background."""
|
||||
|
||||
|
||||
class BackgroundFillType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.BackgroundFill`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
SOLID = "solid"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with solid fill."""
|
||||
GRADIENT = "gradient"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with gradient fill."""
|
||||
FREEFORM_GRADIENT = "freeform_gradient"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with freeform_gradient fill."""
|
||||
|
||||
@@ -27,6 +27,8 @@ __all__ = (
|
||||
"BasePersistence",
|
||||
"BaseRateLimiter",
|
||||
"BaseUpdateProcessor",
|
||||
"BusinessConnectionHandler",
|
||||
"BusinessMessagesDeletedHandler",
|
||||
"CallbackContext",
|
||||
"CallbackDataCache",
|
||||
"CallbackQueryHandler",
|
||||
@@ -75,6 +77,8 @@ from ._defaults import Defaults
|
||||
from ._dictpersistence import DictPersistence
|
||||
from ._extbot import ExtBot
|
||||
from ._handlers.basehandler import BaseHandler
|
||||
from ._handlers.businessconnectionhandler import BusinessConnectionHandler
|
||||
from ._handlers.businessmessagesdeletedhandler import BusinessMessagesDeletedHandler
|
||||
from ._handlers.callbackqueryhandler import CallbackQueryHandler
|
||||
from ._handlers.chatboosthandler import ChatBoostHandler
|
||||
from ._handlers.chatjoinrequesthandler import ChatJoinRequestHandler
|
||||
|
||||
@@ -208,7 +208,7 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
||||
callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, List[JSONDict]]]],
|
||||
args: Any,
|
||||
kwargs: Dict[str, Any],
|
||||
endpoint: str,
|
||||
endpoint: str, # noqa: ARG002
|
||||
data: Dict[str, Any],
|
||||
rate_limit_args: Optional[int],
|
||||
) -> Union[bool, JSONDict, List[JSONDict]]:
|
||||
|
||||
+159
-86
@@ -75,6 +75,8 @@ from telegram.ext._utils.types import BD, BT, CCT, CD, JQ, RT, UD, ConversationK
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from socket import socket
|
||||
|
||||
from telegram import Message
|
||||
from telegram.ext import ConversationHandler, JobQueue
|
||||
from telegram.ext._applicationbuilder import InitApplicationBuilder
|
||||
@@ -363,6 +365,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
self.__update_persistence_event = asyncio.Event()
|
||||
self.__update_persistence_lock = asyncio.Lock()
|
||||
self.__create_task_tasks: Set[asyncio.Task] = set() # Used for awaiting tasks upon exit
|
||||
self.__stop_running_marker = asyncio.Event()
|
||||
|
||||
async def __aenter__(self: _AppType) -> _AppType: # noqa: PYI019
|
||||
"""|async_context_manager| :meth:`initializes <initialize>` the App.
|
||||
@@ -514,6 +517,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
await self._add_ch_to_persistence(handler)
|
||||
|
||||
self._initialized = True
|
||||
self.__stop_running_marker.clear()
|
||||
|
||||
async def _add_ch_to_persistence(self, handler: "ConversationHandler") -> None:
|
||||
self._conversation_handler_conversations.update(
|
||||
@@ -668,14 +672,26 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
raise RuntimeError("This Application is not running!")
|
||||
|
||||
self._running = False
|
||||
self.__stop_running_marker.clear()
|
||||
_LOGGER.info("Application is stopping. This might take a moment.")
|
||||
|
||||
# Stop listening for new updates and handle all pending ones
|
||||
await self.update_queue.put(_STOP_SIGNAL)
|
||||
_LOGGER.debug("Waiting for update_queue to join")
|
||||
await self.update_queue.join()
|
||||
if self.__update_fetcher_task:
|
||||
await self.__update_fetcher_task
|
||||
if self.__update_fetcher_task.done():
|
||||
try:
|
||||
self.__update_fetcher_task.result()
|
||||
except BaseException as exc:
|
||||
_LOGGER.critical(
|
||||
"Fetching updates was aborted due to %r. Suppressing "
|
||||
"exception to ensure graceful shutdown.",
|
||||
exc,
|
||||
exc_info=True,
|
||||
)
|
||||
else:
|
||||
await self.update_queue.put(_STOP_SIGNAL)
|
||||
_LOGGER.debug("Waiting for update_queue to join")
|
||||
await self.update_queue.join()
|
||||
await self.__update_fetcher_task
|
||||
_LOGGER.debug("Application stopped fetching of updates.")
|
||||
|
||||
if self._job_queue:
|
||||
@@ -701,17 +717,36 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
shutdown of the application, i.e. the methods listed in :attr:`run_polling` and
|
||||
:attr:`run_webhook` will still be executed.
|
||||
|
||||
This method can also be called within :meth:`post_init`. This allows for a graceful,
|
||||
early shutdown of the application if some condition is met (e.g., a database connection
|
||||
could not be established).
|
||||
|
||||
Note:
|
||||
If the application is not running, this method does nothing.
|
||||
If the application is not running and this method is not called within
|
||||
:meth:`post_init`, this method does nothing.
|
||||
|
||||
Warning:
|
||||
This method is designed to for use in combination with :meth:`run_polling` or
|
||||
:meth:`run_webhook`. Using this method in combination with a custom logic for starting
|
||||
and stopping the application is not guaranteed to work as expected. Use at your own
|
||||
risk.
|
||||
|
||||
.. versionadded:: 20.5
|
||||
|
||||
.. versionchanged:: 21.2
|
||||
Added support for calling within :meth:`post_init`.
|
||||
"""
|
||||
if self.running:
|
||||
# This works because `__run` is using `loop.run_forever()`. If that changes, this
|
||||
# method needs to be adapted.
|
||||
asyncio.get_running_loop().stop()
|
||||
else:
|
||||
_LOGGER.debug("Application is not running, stop_running() does nothing.")
|
||||
self.__stop_running_marker.set()
|
||||
if not self._initialized:
|
||||
_LOGGER.debug(
|
||||
"Application is not running and not initialized. `stop_running()` likely has "
|
||||
"no effect."
|
||||
)
|
||||
|
||||
def run_polling(
|
||||
self,
|
||||
@@ -731,9 +766,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
polling updates from Telegram using :meth:`telegram.ext.Updater.start_polling` and
|
||||
a graceful shutdown of the app on exit.
|
||||
|
||||
The app will shut down when :exc:`KeyboardInterrupt` or :exc:`SystemExit` is raised.
|
||||
On unix, the app will also shut down on receiving the signals specified by
|
||||
:paramref:`stop_signals`.
|
||||
|app_run_shutdown| :paramref:`stop_signals`.
|
||||
|
||||
The order of execution by :meth:`run_polling` is roughly as follows:
|
||||
|
||||
@@ -824,9 +857,11 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
|
||||
if (read_timeout, write_timeout, connect_timeout, pool_timeout) != ((DEFAULT_NONE,) * 4):
|
||||
warn(
|
||||
"Setting timeouts via `Application.run_polling` is deprecated. "
|
||||
"Please use `ApplicationBuilder.get_updates_*_timeout` instead.",
|
||||
PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.6",
|
||||
"Setting timeouts via `Application.run_polling` is deprecated. "
|
||||
"Please use `ApplicationBuilder.get_updates_*_timeout` instead.",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
@@ -866,15 +901,13 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
close_loop: bool = True,
|
||||
stop_signals: ODVInput[Sequence[int]] = DEFAULT_NONE,
|
||||
secret_token: Optional[str] = None,
|
||||
unix: Optional[Union[str, Path]] = None,
|
||||
unix: Optional[Union[str, Path, "socket"]] = None,
|
||||
) -> None:
|
||||
"""Convenience method that takes care of initializing and starting the app,
|
||||
listening for updates from Telegram using :meth:`telegram.ext.Updater.start_webhook` and
|
||||
a graceful shutdown of the app on exit.
|
||||
|
||||
The app will shut down when :exc:`KeyboardInterrupt` or :exc:`SystemExit` is raised.
|
||||
On unix, the app will also shut down on receiving the signals specified by
|
||||
:paramref:`stop_signals`.
|
||||
|app_run_shutdown| :paramref:`stop_signals`.
|
||||
|
||||
If :paramref:`cert`
|
||||
and :paramref:`key` are not provided, the webhook will be started directly on
|
||||
@@ -959,8 +992,17 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
header isn't set or it is set to a wrong token.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
unix (:class:`pathlib.Path` | :obj:`str`, optional): Path to the unix socket file. Path
|
||||
does not need to exist, in which case the file will be created.
|
||||
unix (:class:`pathlib.Path` | :obj:`str` | :class:`socket.socket`, optional): Can be
|
||||
either:
|
||||
|
||||
* the path to the unix socket file as :class:`pathlib.Path` or :obj:`str`. This
|
||||
will be passed to `tornado.netutil.bind_unix_socket <https://www.tornadoweb.org/
|
||||
en/stable/netutil.html#tornado.netutil.bind_unix_socket>`_ to create the socket.
|
||||
If the Path does not exist, the file will be created.
|
||||
|
||||
* or the socket itself. This option allows you to e.g. restrict the permissions of
|
||||
the socket for improved security. Note that you need to pass the correct family,
|
||||
type and socket options yourself.
|
||||
|
||||
Caution:
|
||||
This parameter is a replacement for the default TCP bind. Therefore, it is
|
||||
@@ -969,6 +1011,8 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
appropriate :paramref:`webhook_url`.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
.. versionchanged:: 21.1
|
||||
Added support to pass a socket instance itself.
|
||||
"""
|
||||
if not self.updater:
|
||||
raise RuntimeError(
|
||||
@@ -1025,25 +1069,28 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
loop.run_until_complete(self.initialize())
|
||||
if self.post_init:
|
||||
loop.run_until_complete(self.post_init(self))
|
||||
if self.__stop_running_marker.is_set():
|
||||
_LOGGER.info("Application received stop signal via `stop_running`. Shutting down.")
|
||||
return
|
||||
loop.run_until_complete(updater_coroutine) # one of updater.start_webhook/polling
|
||||
loop.run_until_complete(self.start())
|
||||
loop.run_forever()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
_LOGGER.debug("Application received stop signal. Shutting down.")
|
||||
except Exception as exc:
|
||||
# In case the coroutine wasn't awaited, we don't need to bother the user with a warning
|
||||
updater_coroutine.close()
|
||||
raise exc
|
||||
finally:
|
||||
# We arrive here either by catching the exceptions above or if the loop gets stopped
|
||||
# In case the coroutine wasn't awaited, we don't need to bother the user with a warning
|
||||
updater_coroutine.close()
|
||||
|
||||
try:
|
||||
# Mypy doesn't know that we already check if updater is None
|
||||
if self.updater.running: # type: ignore[union-attr]
|
||||
loop.run_until_complete(self.updater.stop()) # type: ignore[union-attr]
|
||||
if self.running:
|
||||
loop.run_until_complete(self.stop())
|
||||
if self.post_stop:
|
||||
loop.run_until_complete(self.post_stop(self))
|
||||
# post_stop should be called only if stop was called!
|
||||
if self.post_stop:
|
||||
loop.run_until_complete(self.post_stop(self))
|
||||
loop.run_until_complete(self.shutdown())
|
||||
if self.post_shutdown:
|
||||
loop.run_until_complete(self.post_shutdown(self))
|
||||
@@ -1138,9 +1185,11 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
# Generator-based coroutines are not supported in Python 3.12+
|
||||
if sys.version_info < (3, 12) and isinstance(coroutine, Generator):
|
||||
warn(
|
||||
"Generator-based coroutines are deprecated in create_task and will not work"
|
||||
" in Python 3.12+",
|
||||
category=PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.4",
|
||||
"Generator-based coroutines are deprecated in create_task and will not"
|
||||
" work in Python 3.12+",
|
||||
),
|
||||
)
|
||||
return await asyncio.create_task(coroutine)
|
||||
# If user uses generator in python 3.12+, Exception will happen and we cannot do
|
||||
@@ -1172,45 +1221,44 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
finally:
|
||||
self._mark_for_persistence_update(update=update)
|
||||
|
||||
async def _update_fetcher(self) -> None:
|
||||
async def __update_fetcher(self) -> None:
|
||||
# Continuously fetch updates from the queue. Exit only once the signal object is found.
|
||||
while True:
|
||||
try:
|
||||
update = await self.update_queue.get()
|
||||
update = await self.update_queue.get()
|
||||
|
||||
if update is _STOP_SIGNAL:
|
||||
_LOGGER.debug("Dropping pending updates")
|
||||
while not self.update_queue.empty():
|
||||
self.update_queue.task_done()
|
||||
if update is _STOP_SIGNAL:
|
||||
# For the _STOP_SIGNAL
|
||||
self.update_queue.task_done()
|
||||
return
|
||||
|
||||
# For the _STOP_SIGNAL
|
||||
self.update_queue.task_done()
|
||||
return
|
||||
_LOGGER.debug("Processing update %s", update)
|
||||
|
||||
_LOGGER.debug("Processing update %s", update)
|
||||
|
||||
if self._update_processor.max_concurrent_updates > 1:
|
||||
# We don't await the below because it has to be run concurrently
|
||||
self.create_task(
|
||||
self.__process_update_wrapper(update),
|
||||
update=update,
|
||||
name=f"Application:{self.bot.id}:process_concurrent_update",
|
||||
)
|
||||
else:
|
||||
await self.__process_update_wrapper(update)
|
||||
|
||||
except asyncio.CancelledError:
|
||||
# This may happen if the application is manually run via application.start() and
|
||||
# then a KeyboardInterrupt is sent. We must prevent this loop to die since
|
||||
# application.stop() will wait for it's clean shutdown.
|
||||
_LOGGER.warning(
|
||||
"Fetching updates got a asyncio.CancelledError. Ignoring as this task may only"
|
||||
"be closed via `Application.stop`."
|
||||
if self._update_processor.max_concurrent_updates > 1:
|
||||
# We don't await the below because it has to be run concurrently
|
||||
self.create_task(
|
||||
self.__process_update_wrapper(update),
|
||||
update=update,
|
||||
name=f"Application:{self.bot.id}:process_concurrent_update",
|
||||
)
|
||||
else:
|
||||
await self.__process_update_wrapper(update)
|
||||
|
||||
async def _update_fetcher(self) -> None:
|
||||
try:
|
||||
await self.__update_fetcher()
|
||||
finally:
|
||||
while not self.update_queue.empty():
|
||||
_LOGGER.debug("Dropping pending update: %s", self.update_queue.get_nowait())
|
||||
with contextlib.suppress(ValueError):
|
||||
# Since we're shutting down here, it's not too bad if we call task_done
|
||||
# on an empty queue
|
||||
self.update_queue.task_done()
|
||||
|
||||
async def __process_update_wrapper(self, update: object) -> None:
|
||||
await self._update_processor.process_update(update, self.process_update(update))
|
||||
self.update_queue.task_done()
|
||||
try:
|
||||
await self._update_processor.process_update(update, self.process_update(update))
|
||||
finally:
|
||||
self.update_queue.task_done()
|
||||
|
||||
async def process_update(self, update: object) -> None:
|
||||
"""Processes a single update and marks the update to be updated by the persistence later.
|
||||
@@ -1239,30 +1287,43 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
try:
|
||||
for handler in handlers:
|
||||
check = handler.check_update(update) # Should the handler handle this update?
|
||||
if not (check is None or check is False): # if yes,
|
||||
if not context: # build a context if not already built
|
||||
context = self.context_types.context.from_update(update, self)
|
||||
await context.refresh_data()
|
||||
coroutine: Coroutine = handler.handle_update(update, self, check, context)
|
||||
if check is None or check is False:
|
||||
continue
|
||||
|
||||
if not handler.block or ( # if handler is running with block=False,
|
||||
handler.block is DEFAULT_TRUE
|
||||
and isinstance(self.bot, ExtBot)
|
||||
and self.bot.defaults
|
||||
and not self.bot.defaults.block
|
||||
):
|
||||
self.create_task(
|
||||
coroutine,
|
||||
update=update,
|
||||
name=(
|
||||
f"Application:{self.bot.id}:process_update_non_blocking"
|
||||
f":{handler}"
|
||||
if not context: # build a context if not already built
|
||||
try:
|
||||
context = self.context_types.context.from_update(update, self)
|
||||
except Exception as exc:
|
||||
_LOGGER.critical(
|
||||
(
|
||||
"Error while building CallbackContext for update %s. "
|
||||
"Update will not be processed."
|
||||
),
|
||||
update,
|
||||
exc_info=exc,
|
||||
)
|
||||
else:
|
||||
any_blocking = True
|
||||
await coroutine
|
||||
break # Only a max of 1 handler per group is handled
|
||||
return
|
||||
await context.refresh_data()
|
||||
coroutine: Coroutine = handler.handle_update(update, self, check, context)
|
||||
|
||||
if not handler.block or ( # if handler is running with block=False,
|
||||
handler.block is DEFAULT_TRUE
|
||||
and isinstance(self.bot, ExtBot)
|
||||
and self.bot.defaults
|
||||
and not self.bot.defaults.block
|
||||
):
|
||||
self.create_task(
|
||||
coroutine,
|
||||
update=update,
|
||||
name=(
|
||||
f"Application:{self.bot.id}:process_update_non_blocking"
|
||||
f":{handler}"
|
||||
),
|
||||
)
|
||||
else:
|
||||
any_blocking = True
|
||||
await coroutine
|
||||
break # Only a max of 1 handler per group is handled
|
||||
|
||||
# Stop processing with any other handler.
|
||||
except ApplicationHandlerStop:
|
||||
@@ -1796,13 +1857,25 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
callback,
|
||||
block,
|
||||
) in self.error_handlers.items():
|
||||
context = self.context_types.context.from_error(
|
||||
update=update,
|
||||
error=error,
|
||||
application=self,
|
||||
job=job,
|
||||
coroutine=coroutine,
|
||||
)
|
||||
try:
|
||||
context = self.context_types.context.from_error(
|
||||
update=update,
|
||||
error=error,
|
||||
application=self,
|
||||
job=job,
|
||||
coroutine=coroutine,
|
||||
)
|
||||
except Exception as exc:
|
||||
_LOGGER.critical(
|
||||
(
|
||||
"Error while building CallbackContext for exception %s. "
|
||||
"Exception will not be processed by error handlers."
|
||||
),
|
||||
error,
|
||||
exc_info=exc,
|
||||
)
|
||||
return False
|
||||
|
||||
if not block or ( # If error handler has `block=False`, create a Task to run cb
|
||||
block is DEFAULT_TRUE
|
||||
and isinstance(self.bot, ExtBot)
|
||||
|
||||
@@ -528,9 +528,11 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
"""
|
||||
warn(
|
||||
"`ApplicationBuilder.proxy_url` is deprecated since version "
|
||||
"20.7. Use `ApplicationBuilder.proxy` instead.",
|
||||
PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.7",
|
||||
"`ApplicationBuilder.proxy_url` is deprecated. Use `ApplicationBuilder.proxy` "
|
||||
"instead.",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.proxy(proxy_url)
|
||||
@@ -760,9 +762,11 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
"""
|
||||
warn(
|
||||
"`ApplicationBuilder.get_updates_proxy_url` is deprecated since version "
|
||||
"20.7. Use `ApplicationBuilder.get_updates_proxy` instead.",
|
||||
PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.7",
|
||||
"`ApplicationBuilder.get_updates_proxy_url` is deprecated. Use "
|
||||
"`ApplicationBuilder.get_updates_proxy` instead.",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.get_updates_proxy(get_updates_proxy_url)
|
||||
@@ -1334,7 +1338,13 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
|
||||
Tip:
|
||||
This can be used for custom stop logic that requires to await coroutines, e.g.
|
||||
sending message to a chat before shutting down the bot
|
||||
sending message to a chat before shutting down the bot.
|
||||
|
||||
Hint:
|
||||
The callback will be called only, if :meth:`Application.stop` was indeed called
|
||||
successfully. For example, if the application is stopped early by calling
|
||||
:meth:`Application.stop_running` within :meth:`post_init`, then the set callback will
|
||||
*not* be called.
|
||||
|
||||
Example:
|
||||
.. code::
|
||||
|
||||
@@ -163,7 +163,7 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||
return self._update_interval
|
||||
|
||||
@update_interval.setter
|
||||
def update_interval(self, value: object) -> NoReturn:
|
||||
def update_interval(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to update_interval after initialization."
|
||||
)
|
||||
|
||||
@@ -165,7 +165,7 @@ class SimpleUpdateProcessor(BaseUpdateProcessor):
|
||||
|
||||
async def do_process_update(
|
||||
self,
|
||||
update: object,
|
||||
update: object, # noqa: ARG002
|
||||
coroutine: "Awaitable[Any]",
|
||||
) -> None:
|
||||
"""Immediately awaits the coroutine, i.e. does not apply any additional processing.
|
||||
|
||||
@@ -165,7 +165,7 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
return self.application.bot_data
|
||||
|
||||
@bot_data.setter
|
||||
def bot_data(self, value: object) -> NoReturn:
|
||||
def bot_data(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
f"You can not assign a new value to bot_data, see {_STORING_DATA_WIKI}"
|
||||
)
|
||||
@@ -192,7 +192,7 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
return None
|
||||
|
||||
@chat_data.setter
|
||||
def chat_data(self, value: object) -> NoReturn:
|
||||
def chat_data(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
f"You can not assign a new value to chat_data, see {_STORING_DATA_WIKI}"
|
||||
)
|
||||
@@ -214,7 +214,7 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
return None
|
||||
|
||||
@user_data.setter
|
||||
def user_data(self, value: object) -> NoReturn:
|
||||
def user_data(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
f"You can not assign a new value to user_data, see {_STORING_DATA_WIKI}"
|
||||
)
|
||||
|
||||
+54
-20
@@ -156,9 +156,11 @@ class Defaults:
|
||||
raise ValueError("`quote` and `do_quote` are mutually exclusive")
|
||||
if disable_web_page_preview is not None:
|
||||
warn(
|
||||
"`Defaults.disable_web_page_preview` is deprecated. Use "
|
||||
"`Defaults.link_preview_options` instead.",
|
||||
category=PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.8",
|
||||
"`Defaults.disable_web_page_preview` is deprecated. Use "
|
||||
"`Defaults.link_preview_options` instead.",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
self._link_preview_options: Optional[LinkPreviewOptions] = LinkPreviewOptions(
|
||||
@@ -169,8 +171,9 @@ class Defaults:
|
||||
|
||||
if quote is not None:
|
||||
warn(
|
||||
"`Defaults.quote` is deprecated. Use `Defaults.do_quote` instead.",
|
||||
category=PTBDeprecationWarning,
|
||||
PTBDeprecationWarning(
|
||||
"20.8", "`Defaults.quote` is deprecated. Use `Defaults.do_quote` instead."
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
self._do_quote: Optional[bool] = quote
|
||||
@@ -179,13 +182,14 @@ class Defaults:
|
||||
# Gather all defaults that actually have a default value
|
||||
self._api_defaults = {}
|
||||
for kwarg in (
|
||||
"parse_mode",
|
||||
"explanation_parse_mode",
|
||||
"disable_notification",
|
||||
"allow_sending_without_reply",
|
||||
"protect_content",
|
||||
"link_preview_options",
|
||||
"disable_notification",
|
||||
"do_quote",
|
||||
"explanation_parse_mode",
|
||||
"link_preview_options",
|
||||
"parse_mode",
|
||||
"protect_content",
|
||||
"question_parse_mode",
|
||||
):
|
||||
value = getattr(self, kwarg)
|
||||
if value is not None:
|
||||
@@ -235,7 +239,7 @@ class Defaults:
|
||||
return self._parse_mode
|
||||
|
||||
@parse_mode.setter
|
||||
def parse_mode(self, value: object) -> NoReturn:
|
||||
def parse_mode(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to parse_mode after initialization.")
|
||||
|
||||
@property
|
||||
@@ -246,7 +250,7 @@ class Defaults:
|
||||
return self._parse_mode
|
||||
|
||||
@explanation_parse_mode.setter
|
||||
def explanation_parse_mode(self, value: object) -> NoReturn:
|
||||
def explanation_parse_mode(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to explanation_parse_mode after initialization."
|
||||
)
|
||||
@@ -259,11 +263,41 @@ class Defaults:
|
||||
return self._parse_mode
|
||||
|
||||
@quote_parse_mode.setter
|
||||
def quote_parse_mode(self, value: object) -> NoReturn:
|
||||
def quote_parse_mode(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to quote_parse_mode after initialization."
|
||||
)
|
||||
|
||||
@property
|
||||
def text_parse_mode(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. Alias for :attr:`parse_mode`, used for
|
||||
the corresponding parameter of :class:`telegram.InputPollOption`.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
return self._parse_mode
|
||||
|
||||
@text_parse_mode.setter
|
||||
def text_parse_mode(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to text_parse_mode after initialization."
|
||||
)
|
||||
|
||||
@property
|
||||
def question_parse_mode(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. Alias for :attr:`parse_mode`, used for
|
||||
the corresponding parameter of :meth:`telegram.Bot.send_poll`.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
return self._parse_mode
|
||||
|
||||
@question_parse_mode.setter
|
||||
def question_parse_mode(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to question_parse_mode after initialization."
|
||||
)
|
||||
|
||||
@property
|
||||
def disable_notification(self) -> Optional[bool]:
|
||||
""":obj:`bool`: Optional. Sends the message silently. Users will
|
||||
@@ -272,7 +306,7 @@ class Defaults:
|
||||
return self._disable_notification
|
||||
|
||||
@disable_notification.setter
|
||||
def disable_notification(self, value: object) -> NoReturn:
|
||||
def disable_notification(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to disable_notification after initialization."
|
||||
)
|
||||
@@ -289,7 +323,7 @@ class Defaults:
|
||||
return self._link_preview_options.is_disabled if self._link_preview_options else None
|
||||
|
||||
@disable_web_page_preview.setter
|
||||
def disable_web_page_preview(self, value: object) -> NoReturn:
|
||||
def disable_web_page_preview(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to disable_web_page_preview after initialization."
|
||||
)
|
||||
@@ -302,7 +336,7 @@ class Defaults:
|
||||
return self._allow_sending_without_reply
|
||||
|
||||
@allow_sending_without_reply.setter
|
||||
def allow_sending_without_reply(self, value: object) -> NoReturn:
|
||||
def allow_sending_without_reply(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to allow_sending_without_reply after initialization."
|
||||
)
|
||||
@@ -318,7 +352,7 @@ class Defaults:
|
||||
return self._do_quote if self._do_quote is not None else None
|
||||
|
||||
@quote.setter
|
||||
def quote(self, value: object) -> NoReturn:
|
||||
def quote(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to quote after initialization.")
|
||||
|
||||
@property
|
||||
@@ -329,7 +363,7 @@ class Defaults:
|
||||
return self._tzinfo
|
||||
|
||||
@tzinfo.setter
|
||||
def tzinfo(self, value: object) -> NoReturn:
|
||||
def tzinfo(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to tzinfo after initialization.")
|
||||
|
||||
@property
|
||||
@@ -341,7 +375,7 @@ class Defaults:
|
||||
return self._block
|
||||
|
||||
@block.setter
|
||||
def block(self, value: object) -> NoReturn:
|
||||
def block(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to block after initialization.")
|
||||
|
||||
@property
|
||||
@@ -354,7 +388,7 @@ class Defaults:
|
||||
return self._protect_content
|
||||
|
||||
@protect_content.setter
|
||||
def protect_content(self, value: object) -> NoReturn:
|
||||
def protect_content(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can't assign a new value to protect_content after initialization."
|
||||
)
|
||||
|
||||
+125
-10
@@ -48,9 +48,10 @@ from telegram import (
|
||||
BotDescription,
|
||||
BotName,
|
||||
BotShortDescription,
|
||||
BusinessConnection,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
ChatAdministratorRights,
|
||||
ChatFullInfo,
|
||||
ChatInviteLink,
|
||||
ChatMember,
|
||||
ChatPermissions,
|
||||
@@ -63,6 +64,7 @@ from telegram import (
|
||||
InlineKeyboardMarkup,
|
||||
InlineQueryResultsButton,
|
||||
InputMedia,
|
||||
InputPollOption,
|
||||
LinkPreviewOptions,
|
||||
Location,
|
||||
MaskPosition,
|
||||
@@ -112,7 +114,8 @@ if TYPE_CHECKING:
|
||||
)
|
||||
from telegram.ext import BaseRateLimiter, Defaults
|
||||
|
||||
HandledTypes = TypeVar("HandledTypes", bound=Union[Message, CallbackQuery, Chat])
|
||||
HandledTypes = TypeVar("HandledTypes", bound=Union[Message, CallbackQuery, ChatFullInfo])
|
||||
KT = TypeVar("KT", bound=ReplyMarkup)
|
||||
|
||||
|
||||
class ExtBot(Bot, Generic[RLARGS]):
|
||||
@@ -260,7 +263,10 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
@classmethod
|
||||
def _warn(
|
||||
cls, message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0
|
||||
cls,
|
||||
message: Union[str, PTBUserWarning],
|
||||
category: Type[Warning] = PTBUserWarning,
|
||||
stacklevel: int = 0,
|
||||
) -> None:
|
||||
"""We override this method to add one more level to the stacklevel, so that the warning
|
||||
points to the user's code, not to the PTB code.
|
||||
@@ -434,6 +440,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
# 3) set the correct parse_mode for all InputMedia objects
|
||||
# 4) handle the LinkPreviewOptions case (see below)
|
||||
# 5) handle the ReplyParameters case (see below)
|
||||
# 6) handle text_parse_mode in InputPollOption
|
||||
for key, val in data.items():
|
||||
# 1)
|
||||
if isinstance(val, DefaultValue):
|
||||
@@ -485,11 +492,29 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
data[key] = new_value
|
||||
|
||||
def _replace_keyboard(self, reply_markup: Optional[ReplyMarkup]) -> Optional[ReplyMarkup]:
|
||||
# 6)
|
||||
elif isinstance(val, Sequence) and all(
|
||||
isinstance(obj, InputPollOption) for obj in val
|
||||
):
|
||||
new_val = []
|
||||
for option in val:
|
||||
if not isinstance(option.text_parse_mode, DefaultValue):
|
||||
new_val.append(option)
|
||||
else:
|
||||
new_option = copy(option)
|
||||
with new_option._unfrozen():
|
||||
new_option.text_parse_mode = self.defaults.text_parse_mode
|
||||
new_val.append(new_option)
|
||||
data[key] = new_val
|
||||
|
||||
def _replace_keyboard(self, reply_markup: Optional[KT]) -> Optional[KT]:
|
||||
# If the reply_markup is an inline keyboard and we allow arbitrary callback data, let the
|
||||
# CallbackDataCache build a new keyboard with the data replaced. Otherwise return the input
|
||||
if isinstance(reply_markup, InlineKeyboardMarkup) and self.callback_data_cache is not None:
|
||||
return self.callback_data_cache.process_keyboard(reply_markup)
|
||||
# for some reason mypy doesn't understand that IKB is a subtype of Optional[KT]
|
||||
return self.callback_data_cache.process_keyboard( # type: ignore[return-value]
|
||||
reply_markup
|
||||
)
|
||||
|
||||
return reply_markup
|
||||
|
||||
@@ -549,7 +574,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
self.callback_data_cache.process_message(message=obj)
|
||||
return obj # type: ignore[return-value]
|
||||
|
||||
if isinstance(obj, Chat) and obj.pinned_message:
|
||||
if isinstance(obj, ChatFullInfo) and obj.pinned_message:
|
||||
self.callback_data_cache.process_message(obj.pinned_message)
|
||||
|
||||
return obj
|
||||
@@ -567,6 +592,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -597,6 +623,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
if isinstance(result, Message):
|
||||
self._insert_callback_data(result)
|
||||
@@ -846,7 +873,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
rate_limit_args: Optional[RLARGS] = None,
|
||||
) -> Chat:
|
||||
) -> ChatFullInfo:
|
||||
# We override this method to call self._insert_callback_data
|
||||
result = await super().get_chat(
|
||||
chat_id=chat_id,
|
||||
@@ -1178,7 +1205,6 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
name: str,
|
||||
title: str,
|
||||
stickers: Sequence["InputSticker"],
|
||||
sticker_format: str,
|
||||
sticker_type: Optional[str] = None,
|
||||
needs_repainting: Optional[bool] = None,
|
||||
*,
|
||||
@@ -1194,7 +1220,6 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
name=name,
|
||||
title=title,
|
||||
stickers=stickers,
|
||||
sticker_format=sticker_format,
|
||||
sticker_type=sticker_type,
|
||||
needs_repainting=needs_repainting,
|
||||
read_timeout=read_timeout,
|
||||
@@ -1515,6 +1540,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
horizontal_accuracy: Optional[float] = None,
|
||||
heading: Optional[int] = None,
|
||||
proximity_alert_radius: Optional[int] = None,
|
||||
live_period: Optional[int] = None,
|
||||
*,
|
||||
location: Optional[Location] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1534,6 +1560,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
horizontal_accuracy=horizontal_accuracy,
|
||||
heading=heading,
|
||||
proximity_alert_radius=proximity_alert_radius,
|
||||
live_period=live_period,
|
||||
location=location,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -2351,6 +2378,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2384,6 +2412,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
business_connection_id=business_connection_id,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
@@ -2404,6 +2433,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2420,6 +2450,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
audio=audio,
|
||||
duration=duration,
|
||||
performer=performer,
|
||||
business_connection_id=business_connection_id,
|
||||
title=title,
|
||||
caption=caption,
|
||||
disable_notification=disable_notification,
|
||||
@@ -2445,6 +2476,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
chat_id: Union[str, int],
|
||||
action: str,
|
||||
message_thread_id: Optional[int] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2455,6 +2487,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
) -> bool:
|
||||
return await super().send_chat_action(
|
||||
chat_id=chat_id,
|
||||
business_connection_id=business_connection_id,
|
||||
action=action,
|
||||
message_thread_id=message_thread_id,
|
||||
read_timeout=read_timeout,
|
||||
@@ -2476,6 +2509,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2505,6 +2539,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
business_connection_id=business_connection_id,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
@@ -2517,6 +2552,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2530,6 +2566,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
return await super().send_dice(
|
||||
chat_id=chat_id,
|
||||
disable_notification=disable_notification,
|
||||
business_connection_id=business_connection_id,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
reply_markup=reply_markup,
|
||||
emoji=emoji,
|
||||
@@ -2558,6 +2595,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2581,6 +2619,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
business_connection_id=business_connection_id,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
reply_parameters=reply_parameters,
|
||||
@@ -2601,6 +2640,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2617,6 +2657,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
disable_notification=disable_notification,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
reply_markup=reply_markup,
|
||||
business_connection_id=business_connection_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
@@ -2718,6 +2759,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2748,6 +2790,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
business_connection_id=business_connection_id,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
@@ -2762,6 +2805,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2790,6 +2834,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
caption=caption,
|
||||
business_connection_id=business_connection_id,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
)
|
||||
@@ -2806,6 +2851,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
message_thread_id: Optional[int] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
disable_web_page_preview: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -2824,6 +2870,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
entities=entities,
|
||||
disable_web_page_preview=disable_web_page_preview,
|
||||
disable_notification=disable_notification,
|
||||
business_connection_id=business_connection_id,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
@@ -2851,6 +2898,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
message_thread_id: Optional[int] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2877,6 +2925,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
has_spoiler=has_spoiler,
|
||||
reply_parameters=reply_parameters,
|
||||
filename=filename,
|
||||
business_connection_id=business_connection_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
@@ -2888,7 +2937,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
question: str,
|
||||
options: Sequence[str],
|
||||
options: Sequence[Union[str, "InputPollOption"]],
|
||||
is_anonymous: Optional[bool] = None,
|
||||
type: Optional[str] = None, # pylint: disable=redefined-builtin
|
||||
allows_multiple_answers: Optional[bool] = None,
|
||||
@@ -2904,6 +2953,9 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
question_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
question_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2932,6 +2984,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
close_date=close_date,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
explanation_entities=explanation_entities,
|
||||
business_connection_id=business_connection_id,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
reply_parameters=reply_parameters,
|
||||
@@ -2940,6 +2993,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
question_parse_mode=question_parse_mode,
|
||||
question_entities=question_entities,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
@@ -2952,6 +3007,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
message_thread_id: Optional[int] = None,
|
||||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2968,6 +3024,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
disable_notification=disable_notification,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
reply_markup=reply_markup,
|
||||
business_connection_id=business_connection_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
@@ -2996,6 +3053,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -3022,6 +3080,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
google_place_type=google_place_type,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
business_connection_id=business_connection_id,
|
||||
message_thread_id=message_thread_id,
|
||||
reply_parameters=reply_parameters,
|
||||
venue=venue,
|
||||
@@ -3050,6 +3109,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -3077,6 +3137,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
filename=filename,
|
||||
@@ -3100,6 +3161,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -3130,6 +3192,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
@@ -3145,6 +3208,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -3176,6 +3240,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def set_chat_administrator_custom_title(
|
||||
@@ -3462,6 +3527,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
self,
|
||||
name: str,
|
||||
user_id: int,
|
||||
format: str, # pylint: disable=redefined-builtin
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3475,6 +3541,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
name=name,
|
||||
user_id=user_id,
|
||||
thumbnail=thumbnail,
|
||||
format=format,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
@@ -3998,6 +4065,52 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def get_business_connection(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
rate_limit_args: Optional[RLARGS] = None,
|
||||
) -> BusinessConnection:
|
||||
return await super().get_business_connection(
|
||||
business_connection_id=business_connection_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def replace_sticker_in_set(
|
||||
self,
|
||||
user_id: int,
|
||||
name: str,
|
||||
old_sticker: str,
|
||||
sticker: "InputSticker",
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
rate_limit_args: Optional[RLARGS] = None,
|
||||
) -> bool:
|
||||
return await super().replace_sticker_in_set(
|
||||
user_id=user_id,
|
||||
name=name,
|
||||
old_sticker=old_sticker,
|
||||
sticker=sticker,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
# updated camelCase aliases
|
||||
getMe = get_me
|
||||
sendMessage = send_message
|
||||
@@ -4117,3 +4230,5 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages
|
||||
getUserChatBoosts = get_user_chat_boosts
|
||||
setMessageReaction = set_message_reaction
|
||||
getBusinessConnection = get_business_connection
|
||||
replaceStickerInSet = replace_sticker_in_set
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the BusinessConnectionHandler class."""
|
||||
from typing import Optional, TypeVar
|
||||
|
||||
from telegram import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE
|
||||
from telegram._utils.types import SCT, DVType
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils._update_parsing import parse_chat_id, parse_username
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class BusinessConnectionHandler(BaseHandler[Update, CCT]):
|
||||
"""Handler class to handle Telegram
|
||||
:attr:`Business Connections <telegram.Update.business_connection>`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
callback (:term:`coroutine function`): The callback function for this handler. Will be
|
||||
called when :meth:`check_update` has determined that an update should be processed by
|
||||
this handler. Callback signature::
|
||||
|
||||
async def callback(update: Update, context: CallbackContext)
|
||||
user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only
|
||||
those which are from the specified user ID(s).
|
||||
|
||||
username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only
|
||||
those which are from the specified username(s).
|
||||
|
||||
block (:obj:`bool`, optional): Determines whether the return value of the callback should
|
||||
be awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`.
|
||||
|
||||
.. seealso:: :wiki:`Concurrency`
|
||||
Attributes:
|
||||
callback (:term:`coroutine function`): The callback function for this handler.
|
||||
block (:obj:`bool`): Determines whether the return value of the callback should be
|
||||
awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_user_ids",
|
||||
"_usernames",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
user_id: Optional[SCT[int]] = None,
|
||||
username: Optional[SCT[str]] = None,
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
):
|
||||
super().__init__(callback, block=block)
|
||||
|
||||
self._user_ids = parse_chat_id(user_id)
|
||||
self._usernames = parse_username(username)
|
||||
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handler's :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if isinstance(update, Update) and update.business_connection:
|
||||
if not self._user_ids and not self._usernames:
|
||||
return True
|
||||
if update.business_connection.user.id in self._user_ids:
|
||||
return True
|
||||
return update.business_connection.user.username in self._usernames
|
||||
return False
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the BusinessMessagesDeletedHandler class."""
|
||||
from typing import Optional, TypeVar
|
||||
|
||||
from telegram import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE
|
||||
from telegram._utils.types import SCT, DVType
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils._update_parsing import parse_chat_id, parse_username
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class BusinessMessagesDeletedHandler(BaseHandler[Update, CCT]):
|
||||
"""Handler class to handle
|
||||
:attr:`deleted Telegram Business messages <telegram.Update.deleted_business_messages>`.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
Args:
|
||||
callback (:term:`coroutine function`): The callback function for this handler. Will be
|
||||
called when :meth:`check_update` has determined that an update should be processed by
|
||||
this handler. Callback signature::
|
||||
|
||||
async def callback(update: Update, context: CallbackContext)
|
||||
chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only
|
||||
those which are from the specified chat ID(s).
|
||||
|
||||
username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only
|
||||
those which are from the specified username(s).
|
||||
|
||||
block (:obj:`bool`, optional): Determines whether the return value of the callback should
|
||||
be awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`.
|
||||
|
||||
.. seealso:: :wiki:`Concurrency`
|
||||
Attributes:
|
||||
callback (:term:`coroutine function`): The callback function for this handler.
|
||||
block (:obj:`bool`): Determines whether the return value of the callback should be
|
||||
awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_chat_ids",
|
||||
"_usernames",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
chat_id: Optional[SCT[int]] = None,
|
||||
username: Optional[SCT[str]] = None,
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
):
|
||||
super().__init__(callback, block=block)
|
||||
|
||||
self._chat_ids = parse_chat_id(chat_id)
|
||||
self._usernames = parse_username(username)
|
||||
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handler's :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if isinstance(update, Update) and update.deleted_business_messages:
|
||||
if not self._chat_ids and not self._usernames:
|
||||
return True
|
||||
if update.deleted_business_messages.chat.id in self._chat_ids:
|
||||
return True
|
||||
return update.deleted_business_messages.chat.username in self._usernames
|
||||
return False
|
||||
@@ -159,8 +159,8 @@ class CallbackQueryHandler(BaseHandler[Update, CCT]):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: CCT,
|
||||
update: Update,
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]",
|
||||
update: Update, # noqa: ARG002
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002
|
||||
check_result: Union[bool, Match[str]],
|
||||
) -> None:
|
||||
"""Add the result of ``re.match(pattern, update.callback_query.data)`` to
|
||||
|
||||
@@ -107,7 +107,5 @@ class ChatJoinRequestHandler(BaseHandler[Update, CCT]):
|
||||
return True
|
||||
if update.chat_join_request.chat.id in self._chat_ids:
|
||||
return True
|
||||
if update.chat_join_request.from_user.username in self._usernames:
|
||||
return True
|
||||
return False
|
||||
return update.chat_join_request.from_user.username in self._usernames
|
||||
return False
|
||||
|
||||
@@ -109,8 +109,8 @@ class ChosenInlineResultHandler(BaseHandler[Update, CCT]):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: CCT,
|
||||
update: Update,
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]",
|
||||
update: Update, # noqa: ARG002
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002
|
||||
check_result: Union[bool, Match[str]],
|
||||
) -> None:
|
||||
"""This function adds the matched regex pattern result to
|
||||
|
||||
@@ -152,15 +152,12 @@ class CommandHandler(BaseHandler[Update, CCT]):
|
||||
Returns:
|
||||
:obj:`bool`: Whether the args are valid for this handler.
|
||||
"""
|
||||
# pylint: disable=too-many-boolean-expressions
|
||||
if (
|
||||
return bool(
|
||||
(self.has_args is None)
|
||||
or (self.has_args is True and args)
|
||||
or (self.has_args is False and not args)
|
||||
or (isinstance(self.has_args, int) and len(args) == self.has_args)
|
||||
):
|
||||
return True
|
||||
return False
|
||||
)
|
||||
|
||||
def check_update(
|
||||
self, update: object
|
||||
@@ -207,8 +204,8 @@ class CommandHandler(BaseHandler[Update, CCT]):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: CCT,
|
||||
update: Update,
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]",
|
||||
update: Update, # noqa: ARG002
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]],
|
||||
) -> None:
|
||||
"""Add text after the command to :attr:`CallbackContext.args` as list, split on single
|
||||
|
||||
@@ -473,7 +473,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._entry_points
|
||||
|
||||
@entry_points.setter
|
||||
def entry_points(self, value: object) -> NoReturn:
|
||||
def entry_points(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to entry_points after initialization."
|
||||
)
|
||||
@@ -487,7 +487,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._states
|
||||
|
||||
@states.setter
|
||||
def states(self, value: object) -> NoReturn:
|
||||
def states(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to states after initialization.")
|
||||
|
||||
@property
|
||||
@@ -499,7 +499,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._fallbacks
|
||||
|
||||
@fallbacks.setter
|
||||
def fallbacks(self, value: object) -> NoReturn:
|
||||
def fallbacks(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to fallbacks after initialization.")
|
||||
|
||||
@property
|
||||
@@ -508,7 +508,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._allow_reentry
|
||||
|
||||
@allow_reentry.setter
|
||||
def allow_reentry(self, value: object) -> NoReturn:
|
||||
def allow_reentry(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to allow_reentry after initialization."
|
||||
)
|
||||
@@ -519,7 +519,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._per_user
|
||||
|
||||
@per_user.setter
|
||||
def per_user(self, value: object) -> NoReturn:
|
||||
def per_user(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to per_user after initialization.")
|
||||
|
||||
@property
|
||||
@@ -528,7 +528,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._per_chat
|
||||
|
||||
@per_chat.setter
|
||||
def per_chat(self, value: object) -> NoReturn:
|
||||
def per_chat(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to per_chat after initialization.")
|
||||
|
||||
@property
|
||||
@@ -537,7 +537,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._per_message
|
||||
|
||||
@per_message.setter
|
||||
def per_message(self, value: object) -> NoReturn:
|
||||
def per_message(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to per_message after initialization.")
|
||||
|
||||
@property
|
||||
@@ -551,7 +551,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._conversation_timeout
|
||||
|
||||
@conversation_timeout.setter
|
||||
def conversation_timeout(self, value: object) -> NoReturn:
|
||||
def conversation_timeout(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to conversation_timeout after initialization."
|
||||
)
|
||||
@@ -562,7 +562,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value: object) -> NoReturn:
|
||||
def name(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to name after initialization.")
|
||||
|
||||
@property
|
||||
@@ -574,7 +574,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._persistent
|
||||
|
||||
@persistent.setter
|
||||
def persistent(self, value: object) -> NoReturn:
|
||||
def persistent(self, _: object) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to persistent after initialization.")
|
||||
|
||||
@property
|
||||
@@ -586,7 +586,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self._map_to_parent
|
||||
|
||||
@map_to_parent.setter
|
||||
def map_to_parent(self, value: object) -> NoReturn:
|
||||
def map_to_parent(self, _: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to map_to_parent after initialization."
|
||||
)
|
||||
|
||||
@@ -130,8 +130,8 @@ class InlineQueryHandler(BaseHandler[Update, CCT]):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: CCT,
|
||||
update: Update,
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]",
|
||||
update: Update, # noqa: ARG002
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002
|
||||
check_result: Optional[Union[bool, Match[str]]],
|
||||
) -> None:
|
||||
"""Add the result of ``re.match(pattern, update.inline_query.query)`` to
|
||||
|
||||
@@ -102,8 +102,8 @@ class MessageHandler(BaseHandler[Update, CCT]):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: CCT,
|
||||
update: Update,
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]",
|
||||
update: Update, # noqa: ARG002
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002
|
||||
check_result: Optional[Union[bool, Dict[str, object]]],
|
||||
) -> None:
|
||||
"""Adds possible output of data filters to the :class:`CallbackContext`."""
|
||||
|
||||
@@ -171,8 +171,8 @@ class PrefixHandler(BaseHandler[Update, CCT]):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: CCT,
|
||||
update: Update,
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]",
|
||||
update: Update, # noqa: ARG002
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]],
|
||||
) -> None:
|
||||
"""Add text after the command to :attr:`CallbackContext.args` as list, split on single
|
||||
|
||||
@@ -49,7 +49,7 @@ class StringCommandHandler(BaseHandler[str, CCT]):
|
||||
called when :meth:`check_update` has determined that an update should be processed by
|
||||
this handler. Callback signature::
|
||||
|
||||
async def callback(update: Update, context: CallbackContext)
|
||||
async def callback(update: str, context: CallbackContext)
|
||||
|
||||
The return value of the callback is usually ignored except for the special case of
|
||||
:class:`telegram.ext.ConversationHandler`.
|
||||
@@ -98,8 +98,8 @@ class StringCommandHandler(BaseHandler[str, CCT]):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: CCT,
|
||||
update: str,
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]",
|
||||
update: str, # noqa: ARG002
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002
|
||||
check_result: Optional[List[str]],
|
||||
) -> None:
|
||||
"""Add text after the command to :attr:`CallbackContext.args` as list, split on single
|
||||
|
||||
@@ -52,7 +52,7 @@ class StringRegexHandler(BaseHandler[str, CCT]):
|
||||
called when :meth:`check_update` has determined that an update should be processed by
|
||||
this handler. Callback signature::
|
||||
|
||||
async def callback(update: Update, context: CallbackContext)
|
||||
async def callback(update: str, context: CallbackContext)
|
||||
|
||||
The return value of the callback is usually ignored except for the special case of
|
||||
:class:`telegram.ext.ConversationHandler`.
|
||||
@@ -103,8 +103,8 @@ class StringRegexHandler(BaseHandler[str, CCT]):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: CCT,
|
||||
update: str,
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]",
|
||||
update: str, # noqa: ARG002
|
||||
application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002
|
||||
check_result: Optional[Match[str]],
|
||||
) -> None:
|
||||
"""Add the result of ``re.match(pattern, update)`` to :attr:`CallbackContext.matches` as
|
||||
|
||||
@@ -43,7 +43,7 @@ class TypeHandler(BaseHandler[UT, CCT]):
|
||||
called when :meth:`check_update` has determined that an update should be processed by
|
||||
this handler. Callback signature::
|
||||
|
||||
async def callback(update: Update, context: CallbackContext)
|
||||
async def callback(update: object, context: CallbackContext)
|
||||
|
||||
The return value of the callback is usually ignored except for the special case of
|
||||
:class:`telegram.ext.ConversationHandler`.
|
||||
|
||||
@@ -31,9 +31,9 @@ try:
|
||||
except ImportError:
|
||||
APS_AVAILABLE = False
|
||||
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.repr import build_repr_with_selected_attrs
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.ext._extbot import ExtBot
|
||||
from telegram.ext._utils.types import CCT, JobCallback
|
||||
|
||||
@@ -45,6 +45,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
_ALL_DAYS = tuple(range(7))
|
||||
_LOGGER = get_logger(__name__, class_name="JobQueue")
|
||||
|
||||
|
||||
class JobQueue(Generic[CCT]):
|
||||
@@ -587,13 +588,6 @@ class JobQueue(Generic[CCT]):
|
||||
queue.
|
||||
|
||||
"""
|
||||
# TODO: After v20.0, we should remove this warning.
|
||||
if days != tuple(range(7)): # checks if user passed a custom value
|
||||
warn(
|
||||
"Prior to v20.0 the `days` parameter was not aligned to that of cron's weekday "
|
||||
"scheme. We recommend double checking if the passed value is correct.",
|
||||
stacklevel=2,
|
||||
)
|
||||
if not job_kwargs:
|
||||
job_kwargs = {}
|
||||
|
||||
@@ -961,7 +955,16 @@ class Job(Generic[CCT]):
|
||||
self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]"
|
||||
) -> None:
|
||||
try:
|
||||
context = application.context_types.context.from_job(self, application)
|
||||
try:
|
||||
context = application.context_types.context.from_job(self, application)
|
||||
except Exception as exc:
|
||||
_LOGGER.critical(
|
||||
"Error while building CallbackContext for job %s. Job will not be run.",
|
||||
self._job,
|
||||
exc_info=exc,
|
||||
)
|
||||
return
|
||||
|
||||
await context.refresh_data()
|
||||
await self.callback(context)
|
||||
except Exception as exc:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user