Compare commits

...

99 Commits

Author SHA1 Message Date
Hinrich Mahler 28afeccf70 Bump version to v20.0b0 2022-12-15 15:54:00 +01:00
Bibo-Joshi 9467847d74 Documentation Improvements (#3386)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Viicos <65306057+Viicos@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-12-15 15:20:04 +01:00
Bibo-Joshi b11a0c7778 Make TelegramObject Immutable (#3249) 2022-12-15 15:00:36 +01:00
Bibo-Joshi ff645c6fe2 Reduce Code Duplication in Testing Defaults (#3419) 2022-12-12 10:51:33 +01:00
dependabot[bot] 9c3053b3f9 Bump pytest-xdist from 3.0.2 to 3.1.0 (#3415) 2022-12-11 15:28:12 +01:00
dependabot[bot] 5a6c9cc777 Bump pytest-asyncio from 0.20.2 to 0.20.3 (#3417) 2022-12-11 15:27:51 +01:00
pre-commit-ci[bot] 6e4a1f0a21 pre-commit autoupdate (#3409)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2022-12-06 11:28:47 +01:00
Aditya f8be97c12c Add Notes and Warnings About Optional Dependencies (#3393) 2022-12-02 12:08:11 +01:00
Harshil 4123e7aa57 Simplify Internals of Bot Methods (#3396) 2022-12-01 19:26:01 +01:00
Dmitry Kolomatskiy 637cc574ab Reduce Code Duplication in Several Bot Methods (#3385) 2022-11-26 19:05:44 +01:00
Hinrich Mahler 3042f187ed Bump version to v20.0a6 2022-11-24 12:32:43 +01:00
Bibo-Joshi 867f742d08 Only Persist Arbitrary callback_data if ExtBot.callback_data_cache is Present (#3384) 2022-11-24 12:13:54 +01:00
Harshil 1724212458 Improve Backwards Compatibility of TelegramObjects Pickle Behavior (#3382)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-11-24 12:11:37 +01:00
Bibo-Joshi 05c6ca06f8 Fix Naming and Keyword Arguments of File.download_* Methods (#3380) 2022-11-24 12:09:51 +01:00
Poolitzer 8c03f0e2eb Fix Return Value Annotation of Chat.create_forum_topic (#3381)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
2022-11-23 13:21:10 +01:00
Hinrich Mahler 20c3532e01 Bump version to v20.0a5 2022-11-22 12:51:57 +01:00
Dmitry Kolomatskiy 6cba7f164e Merge ChatDescriptionLimit Enum Into ChatLimit (#3377) 2022-11-22 12:09:44 +01:00
Dmitry Kolomatskiy c3f8fcd7b7 Add Several New Enums To Constants (#3351) 2022-11-22 11:07:42 +01:00
Harshil caacafa090 API 6.3 (#3346)
Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Clot <69784758+clot27@users.noreply.github.com>
2022-11-22 10:43:50 +01:00
Bibo-Joshi 0a614e4bab Documentation Improvements (#3370, #3376, #3366)
Co-authored-by: Viicos <65306057+Viicos@users.noreply.github.com>
2022-11-22 10:39:20 +01:00
dependabot[bot] c12a04c224 Update httpx requirement from ~=0.23.0 to ~=0.23.1 (#3373) 2022-11-20 18:00:52 +01:00
Bibo-Joshi 5c3b06f015 Update Meta Config (#3365) 2022-11-15 17:47:24 +01:00
Bibo-Joshi 9520c6eeba Documentation Improvements (#3214, #3217, #3218, #3271, #3289, #3292, #3303, #3312, #3306, #3319, #3326, #3314)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Simon Fong <44134941+simonfongnt@users.noreply.github.com>
Co-authored-by: Piotr Rogulski <rivinek@gmail.com>
Co-authored-by: poolitzer <25934244+Poolitzer@users.noreply.github.com>
Co-authored-by: Or Bin <or@raftt.io>
Co-authored-by: Sandro <j32g7f67hb@liamekaens.com>
Co-authored-by: Hatim Zahid <63000127+HatimZ@users.noreply.github.com>
Co-authored-by: Robi <53259730+RobiMez@users.noreply.github.com>
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
2022-11-15 09:06:23 +01:00
dependabot[bot] 70aa674226 Bump pytest-asyncio from 0.20.1 to 0.20.2 (#3359) 2022-11-14 20:19:00 +01:00
Bibo-Joshi 422aa86874 Fix Defaults Handling in Bot.answer_web_app_query (#3362) 2022-11-14 20:08:16 +01:00
Harshil b44af136e7 Update PR Template (#3361) 2022-11-13 21:37:20 +01:00
Harshil e54c6a04de Handle Lists and Tuples and Datetimes Directly in TelegramObject.to_dict (#3353) 2022-11-13 21:28:41 +01:00
Harshil e1d56178c8 Fix DeepSource Issues (#3357) 2022-11-11 18:18:42 +01:00
Harshil 1d1d774d9f Flaky Unit Tests: Use pytest Marker (#3354) 2022-11-09 20:43:27 +01:00
Bibo-Joshi 8dead11a25 Improve Unit Tests Regarding ChatMemberUpdated.difference (#3352) 2022-11-08 17:56:39 +01:00
Bibo-Joshi 53c3a130ab Add Three New Test Bots (#3347) 2022-11-06 20:34:12 +01:00
Harshil 834568d7f4 Add a Test for MessageAttachmentType (#3335) 2022-11-06 16:04:01 +01:00
Dmitry Kolomatskiy d2c6c4b369 Add Shortcut Parameters caption, parse_mode and caption_entities to Bot.send_media_group (#3295) 2022-11-02 08:32:40 +01:00
Poolitzer 636654cb71 Split File.download Into File.download_to_drive And File.download_to_memory (#3223) 2022-11-02 08:28:41 +01:00
Biruk Alamirew 55106d6d57 Add constants.MessageLimit.DEEP_LINK_LENGTH (#3315) 2022-11-01 17:58:58 +01:00
pre-commit-ci[bot] a1e6a6e779 pre-commit autoupdate (#3325) 2022-11-01 12:59:06 +01:00
Bibo-Joshi e58cbcdb17 Make Almost All 3rd Party Dependencies Optional (#3267) 2022-10-31 10:12:18 +01:00
Bibo-Joshi 9e42dab184 Don't Edit Objects In-Place When Inserting ext.Defaults (#3311) 2022-10-31 09:46:56 +01:00
miles 25dc87a633 Add Methods Chat.mention_{html, markdown, markdown_v2} (#3308) 2022-10-31 09:45:21 +01:00
Bibo-Joshi f68663af7e Overhaul String Representation of TelegramObject (#3234) 2022-10-30 11:21:19 +01:00
dependabot[bot] 07f8dd1cb1 Bump pytest from 7.1.3 to 7.2.0 (#3318) 2022-10-29 16:05:55 +02:00
dependabot[bot] 18c15ed8d1 Bump pytest-xdist from 2.5.0 to 3.0.2 (#3317) 2022-10-29 14:56:31 +02:00
Harshil 959e6a8470 Update Test Matrix to Use Stable Python 3.11 (#3313) 2022-10-27 09:24:23 +02:00
dependabot[bot] 76c2fc1776 Bump sphinx from 5.2.3 to 5.3.0 (#3300)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-10-23 14:59:27 +02:00
dependabot[bot] 6340d6652a Bump pytest-asyncio from 0.19.0 to 0.20.1 (#3299) 2022-10-23 14:58:56 +02:00
Harshil 87b2e29d60 Run Unit Tests in Parallel (#3283) 2022-10-23 14:25:49 +02:00
Harshil 24d390e1aa Add recursive Parameter to TelegramObject.to_dict() (#3276) 2022-10-19 10:31:55 +02:00
Harshil 210f9afd66 Type Hinting Fix for Message.effective_attachment (#3294) 2022-10-17 20:38:53 +02:00
Harshil eb818da93f Add Two Constants Related to Local Bot API Servers (#3296) 2022-10-17 19:58:28 +02:00
Bibo-Joshi 1c20ff3fb9 Introduce TelegramObject.api_kwargs (#3233) 2022-10-07 11:51:53 +02:00
Bibo-Joshi fb87418473 Read-Only CallbackDataCache (#3266) 2022-10-07 10:18:08 +02:00
pre-commit-ci[bot] 870a20e834 pre-commit autoupdate (#3282) 2022-10-06 15:26:42 +02:00
dependabot[bot] 5b7356d905 Bump actions/stale from 5 to 6 (#3277) 2022-10-03 10:14:49 +02:00
Bibo-Joshi 918c486c65 Skip JobQueue Tests on Windows Again (#3280) 2022-10-03 10:12:08 +02:00
miles 26e7cd2afb Add chat_id and username Parameters to ChatJoinRequestHandler (#3261) 2022-10-02 17:54:30 +02:00
dependabot[bot] 2eda63e9ae Bump furo from 2022.6.21 to 2022.9.29 (#3268) 2022-10-01 22:33:55 +02:00
dependabot[bot] b2902a0789 Bump sphinx from 5.1.1 to 5.2.3 (#3269) 2022-10-01 13:41:45 +02:00
Bibo-Joshi edc3e2be84 Make Job.job a Property and Make Jobs Hashable (#3250) 2022-09-28 21:33:15 +02:00
Bibo-Joshi c6721a799d Fix CallbackQueryHandler Not Handling Non-String Data Correctly With Regex Patterns (#3252) 2022-09-22 20:30:30 +02:00
Bibo-Joshi fdfbcdf51e Explicit local_mode Setting (#3154) 2022-09-19 22:31:23 +02:00
Bibo-Joshi aed8e68fca Add Properties for API Settings of Bot (#3247) 2022-09-18 15:42:12 +02:00
Harshil 50249206df Bump Python 3.11 to RC2 in Test Matrix (#3246) 2022-09-17 15:09:41 +02:00
pre-commit-ci[bot] 5480be4c25 pre-commit Updates (#3221) 2022-09-17 15:08:54 +02:00
Bibo-Joshi 436b5ff7a8 Switch from Stale Bot to GitHub Actions (#3243) 2022-09-16 22:42:45 +02:00
Harshil 3536bb247e Improve Warning About Unknown ConversationHandler States (#3242) 2022-09-16 22:13:11 +02:00
dependabot[bot] a80a053b0a Bump pytest from 7.1.2 to 7.1.3 (#3228) 2022-09-11 10:37:43 +02:00
Hinrich Mahler 2642ecc737 Bump version to v20.0a4 2022-08-27 13:25:57 +02:00
Bibo-Joshi abfcf72a56 Fix setup.py Regarding Optional Dependencies (#3209) 2022-08-27 13:23:17 +02:00
Hinrich Mahler 0e044804d2 Bump version to v20.0a3 2022-08-27 12:39:38 +02:00
Bibo-Joshi 5b9afd5329 Type Hinting Fixes (#3202) 2022-08-27 11:58:28 +02:00
Bibo-Joshi a983a89964 Documentation Improvements (#3139, #3153, #3135)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Poolitzer <github@poolitzer.eu>
Co-authored-by: Pawan <pawanrai9999@gmail.com>
Co-authored-by: Aditya Yadav <69784758+aditya-yadav-27@users.noreply.github.com>
2022-08-27 11:46:51 +02:00
Bibo-Joshi 741a50ab97 New Rate Limiting Mechanism (#3148) 2022-08-26 06:50:03 +02:00
Poolitzer cf6c298b82 API 6.2 (#3195)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-08-25 19:36:55 +02:00
Harshil 90c0fe948b Add Python 3.11 to Test Suite & Adapt Enum Behaviour (#3168) 2022-08-17 18:24:50 +02:00
dependabot[bot] 2c84122654 Bump sphinx from 5.0.2 to 5.1.1 (#3177)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-03 22:03:00 +02:00
Harshil 143db5fc9d Drop Manual Token Validation (#3167) 2022-08-03 08:16:48 +02:00
pre-commit-ci[bot] c28ad86214 Update pre-commit Dependencies (#3085)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-08-02 08:26:36 +02:00
dependabot[bot] 15f153474a Bump pytest-asyncio from 0.18.3 to 0.19.0 (#3158)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-17 13:34:08 +02:00
Harshil 55d66a9ea3 Fix helpers.mention_markdown for Markdown V1 and Improve Related Unit Tests (#3155)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-07-17 13:07:21 +02:00
dependabot[bot] 14c86daf23 Update tornado requirement from ~=6.1 to ~=6.2 (#3149)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-07-12 20:16:22 +02:00
Bibo-Joshi 460aaf8bb6 Make chat/user_data Available in Error Handler for Errors in Jobs (#3152) 2022-07-11 07:54:03 +02:00
Harshil 1e703a0be5 Simplify Unit Tests for Bot.send_chat_action (#3151) 2022-07-10 17:14:45 +02:00
Bibo-Joshi 142e3c0177 Add api_kwargs Paramater to Bot.log_out and Improve Related Unit Tests (#3147) 2022-07-10 15:37:12 +02:00
Bibo-Joshi d4b7a2b3e9 Drop pre-commit Dependencies from requirements-dev.txt (#3120)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-07-09 23:12:07 +02:00
dependabot[bot] dac6d03666 Bump black from 22.3.0 to 22.6.0 (#3132)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-07-08 00:13:57 +02:00
dependabot[bot] 3bfd58dfd9 Bump actions/setup-python from 3 to 4 (#3131)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-07 23:21:20 +02:00
Bibo-Joshi 2d6459b290 Make Bot.delete_my_commands a Coroutine Function (#3136) 2022-07-04 19:33:45 +02:00
Alex 1f0f6a8d3d Add Application.post_shutdown (#3126)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-07-03 15:22:50 +02:00
Bibo-Joshi 2ecb8d5413 Fix ConversationHandler.check_update not respecting per_user (#3128) 2022-07-03 15:21:04 +02:00
Bibo-Joshi f1d03393de Change Default Values for concurrent_updates and connection_pool_size (#3127) 2022-06-29 21:38:03 +02:00
Hinrich Mahler df07148e2d Bump version to v20.0a2 2022-06-27 19:19:54 +02:00
Bibo-Joshi 2d2cede442 Documentation Improvements (#3103, #3121, #3098)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: David <dsb321mp@gmail.com>
Co-authored-by: Harshil Mehta <37377066+harshil21@users.noreply.github.com>
Co-authored-by: poolitzer <github@poolitzer.eu>
Co-authored-by: Alex <53974096+ExalFabu@users.noreply.github.com>
2022-06-27 18:58:51 +02:00
Poolitzer 08e223ba90 API 6.1 (#3112)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-27 18:54:11 +02:00
Bibo-Joshi 01d643913e Stabilize CI (#3119) 2022-06-27 18:46:52 +02:00
Aditya Yadav 755945172d Add Additional Shortcut Methods to Chat (#3115) 2022-06-27 18:45:30 +02:00
dependabot[bot] 24b4de9f10 Bump pyupgrade from 2.32.1 to 2.34.0 (#3096)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-25 11:52:39 +02:00
David 76bfe8ceff Mermaid-based Example State Diagrams (#3090)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-06-24 18:15:10 +02:00
dependabot[bot] b498786d7c Bump furo from 2022.6.4 to 2022.6.4.1 (#3095)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-19 17:12:54 +02:00
dependabot[bot] bfe30048e8 Bump mypy from 0.960 to 0.961 (#3093)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-19 17:12:26 +02:00
334 changed files with 18602 additions and 7083 deletions
+12 -3
View File
@@ -13,7 +13,7 @@ Setting things up
.. code-block:: bash
$ git clone https://github.com/<your username>/python-telegram-bot --recursive
$ git clone https://github.com/<your username>/python-telegram-bot
$ cd python-telegram-bot
3. Add a track to the original repository:
@@ -26,7 +26,7 @@ Setting things up
.. code-block:: bash
$ pip install -r requirements.txt -r requirements-dev.txt
$ pip install -r requirements-all.txt
5. Install pre-commit hooks:
@@ -82,7 +82,7 @@ Here's how to make a one-off code change.
- Documenting types of global variables and complex types of class members can be done using the Sphinx docstring convention.
- In addition, PTB uses the `Black`_ coder formatting. Plugins for Black exist for some `popular editors`_. You can use those instead of manually formatting everything.
- In addition, PTB uses some formatting/styling and linting tools in the pre-commit setup. Some of those tools also have command line tools that can help to run these tools outside of the pre-commit step. If you'd like to leverage that, please have a look at the `pre-commit config file`_ for an overview of which tools (and which versions of them) are used. For example, we use `Black`_ for code formatting. Plugins for Black exist for some `popular editors`_. You can use those instead of manually formatting everything.
- Please ensure that the code you write is well-tested.
@@ -98,6 +98,13 @@ Here's how to make a one-off code change.
$ pytest -v
Since the tests can take a while to run, you can speed things up by running them in parallel
using `pytest-xdist`_ (note that this may effect the result of the test in some rare cases):
.. code-block:: bash
$ pytest -v -n auto --dist=loadfile
To run ``test_official`` (particularly useful if you made API changes), run
.. code-block:: bash
@@ -273,9 +280,11 @@ break the API classes. For example:
.. _AUTHORS.rst: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/AUTHORS.rst
.. _`MyPy`: https://mypy.readthedocs.io/en/stable/index.html
.. _`here`: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
.. _`pre-commit config file`: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.pre-commit-config.yaml
.. _`Black`: https://black.readthedocs.io/en/stable/index.html
.. _`popular editors`: https://black.readthedocs.io/en/stable/integrations/editors.html
.. _`RTD`: https://docs.python-telegram-bot.org/
.. _`RTD build`: https://docs.python-telegram-bot.org/en/doc-fixes
.. _`CSI`: https://standards.mousepawmedia.com/en/stable/csi.html
.. _`section`: #documenting
.. _`pytest-xdist`: https://github.com/pytest-dev/pytest-xdist
+5 -4
View File
@@ -15,14 +15,14 @@ Hey! You're PRing? Cool! Please have a look at the below checklist. It's here to
* New classes:
- [ ] Added `self._id_attrs` and corresponding documentation
- [ ] `__init__` accepts `**_kwargs`
- [ ] `__init__` accepts `api_kwargs` as kw-only
* Added new shortcuts:
- [ ] In `Chat` & `User` for all methods that accept `chat/user_id`
- [ ] In `Message` for all methods that accept `chat_id` and `message_id`
- [ ] For new `Message` shortcuts: Added `quote` argument if methods accepts `reply_to_message_id`
- [ ] In `CallbackQuery` for all methods that accept either `chat_id` and `message_id` or `inline_message_id`
* If relevant:
- [ ] Added new constants at `telegram.constants` and shortcuts to them as class variables
@@ -32,6 +32,7 @@ Hey! You're PRing? Cool! Please have a look at the below checklist. It's here to
- [ ] Add the handlers to the warning loop in the `ConversationHandler`
- [ ] Added new filters for new message (sub)types
- [ ] Added or updated documentation for the changed class(es) and/or method(s)
- [ ] Added the new method(s) to `_extbot.py`
- [ ] Added or updated `bot_methods.rst`
- [ ] Updated the Bot API version number in all places: `README.rst` and `README_RAW.rst` (including the badge), as well as `telegram.constants.BOT_API_VERSION`
- [ ] Updated the Bot API version number in all places: `README.rst` and `README_RAW.rst` (including the badge), as well as `telegram.constants.BOT_API_VERSION_INFO`
- [ ] Added logic for arbitrary callback data in `tg.ext.Bot` for new methods that either accept a `reply_markup` in some form or have a return type that is/contains `telegram.Message`
-14
View File
@@ -1,14 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 3
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 2
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: question
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: false
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been automatically closed due to inactivity. Feel free to comment in order to reopen
or ask again in our Telegram support group at https://t.me/pythontelegrambotgroup.
+2 -4
View File
@@ -16,14 +16,12 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -r requirements.txt
python -W ignore -m pip install -r requirements-dev.txt
python -W ignore -m pip install -r docs/requirements-docs.txt
python -W ignore -m pip install -r requirements-all.txt
- name: Check Links
run: sphinx-build docs/source docs/build/html -W --keep-going -j auto -b linkcheck
+2 -4
View File
@@ -21,14 +21,12 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -r requirements.txt
python -W ignore -m pip install -r requirements-dev.txt
python -W ignore -m pip install -r docs/requirements-docs.txt
python -W ignore -m pip install -r requirements-all.txt
- name: Build docs
run: sphinx-build docs/source docs/build/html -W --keep-going -j auto
@@ -3,7 +3,7 @@ on:
pull_request_target:
paths:
- requirements.txt
- requirements-dev.txt
- requirements-opts.txt
- .pre-commit-config.yaml
permissions:
pull-requests: write
@@ -15,5 +15,5 @@ jobs:
- name: running the check
uses: Poolitzer/notifier-action@master
with:
notify-message: Hey! Looks like you edited the (dev) requirements or the pre-commit hooks. I'm just a friendly reminder to keep the pre-commit hook versions in sync with the dev requirements and the additional dependencies for the hooks in sync with the requirements :)
notify-message: Hey! Looks like you edited the (optional) requirements or the pre-commit hooks. I'm just a friendly reminder to keep the additional dependencies for the hooks in sync with the requirements :)
repo-token: ${{ secrets.GITHUB_TOKEN }}
+19
View File
@@ -0,0 +1,19 @@
name: 'Mark & close stale questions'
on:
schedule:
- cron: '42 2 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v6
with:
# PRs never get stale
days-before-stale: 3
days-before-close: 2
days-before-pr-stale: -1
stale-issue-label: 'stale'
only-labels: 'question'
stale-issue-message: ''
close-issue-message: 'This issue has been automatically closed due to inactivity. Feel free to comment in order to reopen or ask again in our Telegram support group at https://t.me/pythontelegrambotgroup.'
+49 -19
View File
@@ -4,7 +4,7 @@ on:
branches:
- master
push:
branches:
branches:
- master
schedule:
# Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions
@@ -16,13 +16,13 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: ['3.7', '3.8', '3.9', '3.10']
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
os: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: False
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
@@ -31,31 +31,60 @@ jobs:
python -W ignore -m pip install -U codecov pytest-cov
python -W ignore -m pip install -r requirements.txt
python -W ignore -m pip install -r requirements-dev.txt
python -W ignore -m pip install pytest-xdist[psutil]
- name: Test with pytest
# We run 3 different suites here
# We run 4 different suites here
# 1. Test just utils.datetime.py without pytz being installed
# 2. Test just test_no_passport.py without passport dependencies being installed
# 3. Test everything else
# 3. Test just test_rate_limiter.py without passport dependencies being installed
# 4. Test everything else
# The first & second one are achieved by mocking the corresponding import
# See test_helpers.py & test_no_passport.py for details
run: |
# Test without passport
pytest -v --cov -k test_no_passport.py
no_passport_exit=$?
export TEST_NO_PASSPORT='false'
pytest -v --cov --cov-append -k test_helpers.py
no_pytz_exit=$?
export TEST_NO_PYTZ='false'
pytest -v --cov --cov-append
full_exit=$?
special_exit=$(( no_pytz_exit > no_passport_exit ? no_pytz_exit : no_passport_exit ))
global_exit=$(( special_exit > full_exit ? special_exit : full_exit ))
exit ${global_exit}
status=$?
# test without pytz
pytest -v --cov --cov-append -k test_datetime.py
status=$(( $? > status ? $? : status))
pytest -v --cov --cov-append -k test_defaults.py
status=$(( $? > status ? $? : status))
# test without pytz & jobqueue
pytest -v --cov --cov-append -k test_jobqueue.py
pytest -v --cov --cov-append -k test_applicationbuilder.py
status=$(( $? > status ? $? : status))
# Test without ratelimiter
pytest -v --cov --cov-append -k test_ratelimiter.py
status=$(( $? > status ? $? : status))
# Test without webhooks
pytest -v --cov --cov-append -k test_updater.py
status=$(( $? > status ? $? : status))
# Test without callback-data
pytest -v --cov --cov-append -k test_callbackdatacache.py
status=$(( $? > status ? $? : status))
# Test without socks
pytest -v --cov --cov-append -k test_request.py
status=$(( $? > status ? $? : status))
# Test the rest
export TEST_WITH_OPT_DEPS='true'
pip install -r requirements-opts.txt
# `-n auto --dist loadfile` uses pytest-xdist to run each test file on a different CPU
# worker
pytest -v --cov --cov-append -n auto --dist loadfile
status=$(( $? > status ? $? : status))
exit ${status}
env:
JOB_INDEX: ${{ strategy.job-index }}
BOTS: W3sidG9rZW4iOiAiNjk2MTg4NzMyOkFBR1Z3RUtmSEhsTmpzY3hFRE5LQXdraEdzdFpfa28xbUMwIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WldGaU1UUmxNbVF5TnpNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMi43IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMzkwOTgzOTk3IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzI3X2JvdCJ9LCB7InRva2VuIjogIjY3MTQ2ODg4NjpBQUdQR2ZjaVJJQlVORmU4MjR1SVZkcTdKZTNfWW5BVE5HdyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpHWXdPVGxrTXpNeE4yWTIiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTQ0NjAyMjUyMiIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zNF9ib3QifSwgeyJ0b2tlbiI6ICI2MjkzMjY1Mzg6QUFGUnJaSnJCN29CM211ekdzR0pYVXZHRTVDUXpNNUNVNG8iLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpNbU01WVdKaFl6a3hNMlUxIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgQ1B5dGhvbiAzLjUiLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDE0OTY5MTc3NTAiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX2NweXRob25fMzVfYm90In0sIHsidG9rZW4iOiAiNjQwMjA4OTQzOkFBRmhCalFwOXFtM1JUeFN6VXBZekJRakNsZS1Kano1aGNrIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WXpoa1pUZzFOamMxWXpWbCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMy42IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMzMzODcxNDYxIiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzM2X2JvdCJ9LCB7InRva2VuIjogIjY5NTEwNDA4ODpBQUhmenlsSU9qU0lJUy1lT25JMjB5MkUyMEhvZEhzZnotMCIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk9HUTFNRGd3WmpJd1pqRmwiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNyIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTQ3ODI5MzcxNCIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zN19ib3QifSwgeyJ0b2tlbiI6ICI2OTE0MjM1NTQ6QUFGOFdrakNaYm5IcVBfaTZHaFRZaXJGRWxackdhWU9oWDAiLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpZamM1TlRoaU1tUXlNV1ZoIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgUHlQeSAyLjciLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDEzNjM5MzI1NzMiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX3B5cHlfMjdfYm90In0sIHsidG9rZW4iOiAiNjg0MzM5OTg0OkFBRk1nRUVqcDAxcjVyQjAwN3lDZFZOc2c4QWxOc2FVLWNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TVRBek1UWTNNR1V5TmpnMCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIFB5UHkgMy41IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDA3ODM2NjA1IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19weXB5XzM1X2JvdCJ9LCB7InRva2VuIjogIjY5MDA5MTM0NzpBQUZMbVI1cEFCNVljcGVfbU9oN3pNNEpGQk9oMHozVDBUbyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpEaGxOekU1TURrd1lXSmkiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIEFwcFZleW9yIHVzaW5nIENQeXRob24gMy40IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMjc5NjAwMDI2IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX2FwcHZleW9yX2NweXRob25fMzRfYm90In0sIHsidG9rZW4iOiAiNjk0MzA4MDUyOkFBRUIyX3NvbkNrNTVMWTlCRzlBTy1IOGp4aVBTNTVvb0JBIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WW1aaVlXWm1NakpoWkdNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gQXBwVmV5b3IgdXNpbmcgQ1B5dGhvbiAyLjciLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDEyOTMwNzkxNjUiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfYXBwdmV5b3JfY3B5dGhvbl8yN19ib3QifSwgeyJ0b2tlbiI6ICIxMDU1Mzk3NDcxOkFBRzE4bkJfUzJXQXd1SjNnN29oS0JWZ1hYY2VNbklPeVNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TmpBd056QXpZalZpTkdOayIsICJuYW1lIjogIlBUQiB0ZXN0cyBbMF0iLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDExODU1MDk2MzYiLCAidXNlcm5hbWUiOiAicHRiXzBfYm90In0sIHsidG9rZW4iOiAiMTA0NzMyNjc3MTpBQUY4bk90ODFGcFg4bGJidno4VWV3UVF2UmZUYkZmQnZ1SSIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOllUVTFOVEk0WkdSallqbGkiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzFdIiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDg0Nzk3NjEyIiwgInVzZXJuYW1lIjogInB0Yl8xX2JvdCJ9LCB7InRva2VuIjogIjk3MTk5Mjc0NTpBQUdPa09hVzBOSGpnSXY1LTlqUWJPajR2R3FkaFNGLVV1cyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk5XWmtNV1ZoWWpsallqVTUiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzJdIiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDAyMjU1MDcwIiwgInVzZXJuYW1lIjogInB0Yl8yX2JvdCJ9XQ==
TEST_NO_PYTZ : "true"
TEST_NO_PASSPORT: "true"
BOTS: W3sidG9rZW4iOiAiNjk2MTg4NzMyOkFBR1Z3RUtmSEhsTmpzY3hFRE5LQXdraEdzdFpfa28xbUMwIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WldGaU1UUmxNbVF5TnpNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMi43IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMzkwOTgzOTk3IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzI3X2JvdCJ9LCB7InRva2VuIjogIjY3MTQ2ODg4NjpBQUdQR2ZjaVJJQlVORmU4MjR1SVZkcTdKZTNfWW5BVE5HdyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpHWXdPVGxrTXpNeE4yWTIiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTQ0NjAyMjUyMiIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zNF9ib3QifSwgeyJ0b2tlbiI6ICI2MjkzMjY1Mzg6QUFGUnJaSnJCN29CM211ekdzR0pYVXZHRTVDUXpNNUNVNG8iLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpNbU01WVdKaFl6a3hNMlUxIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgQ1B5dGhvbiAzLjUiLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDE0OTY5MTc3NTAiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX2NweXRob25fMzVfYm90In0sIHsidG9rZW4iOiAiNjQwMjA4OTQzOkFBRmhCalFwOXFtM1JUeFN6VXBZekJRakNsZS1Kano1aGNrIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WXpoa1pUZzFOamMxWXpWbCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMy42IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMzMzODcxNDYxIiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzM2X2JvdCJ9LCB7InRva2VuIjogIjY5NTEwNDA4ODpBQUhmenlsSU9qU0lJUy1lT25JMjB5MkUyMEhvZEhzZnotMCIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk9HUTFNRGd3WmpJd1pqRmwiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNyIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTQ3ODI5MzcxNCIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zN19ib3QifSwgeyJ0b2tlbiI6ICI2OTE0MjM1NTQ6QUFGOFdrakNaYm5IcVBfaTZHaFRZaXJGRWxackdhWU9oWDAiLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpZamM1TlRoaU1tUXlNV1ZoIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgUHlQeSAyLjciLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDEzNjM5MzI1NzMiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX3B5cHlfMjdfYm90In0sIHsidG9rZW4iOiAiNjg0MzM5OTg0OkFBRk1nRUVqcDAxcjVyQjAwN3lDZFZOc2c4QWxOc2FVLWNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TVRBek1UWTNNR1V5TmpnMCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIFB5UHkgMy41IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDA3ODM2NjA1IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19weXB5XzM1X2JvdCJ9LCB7InRva2VuIjogIjY5MDA5MTM0NzpBQUZMbVI1cEFCNVljcGVfbU9oN3pNNEpGQk9oMHozVDBUbyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpEaGxOekU1TURrd1lXSmkiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIEFwcFZleW9yIHVzaW5nIENQeXRob24gMy40IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMjc5NjAwMDI2IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX2FwcHZleW9yX2NweXRob25fMzRfYm90In0sIHsidG9rZW4iOiAiNjk0MzA4MDUyOkFBRUIyX3NvbkNrNTVMWTlCRzlBTy1IOGp4aVBTNTVvb0JBIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WW1aaVlXWm1NakpoWkdNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gQXBwVmV5b3IgdXNpbmcgQ1B5dGhvbiAyLjciLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDEyOTMwNzkxNjUiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfYXBwdmV5b3JfY3B5dGhvbl8yN19ib3QifSwgeyJ0b2tlbiI6ICIxMDU1Mzk3NDcxOkFBRzE4bkJfUzJXQXd1SjNnN29oS0JWZ1hYY2VNbklPeVNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TmpBd056QXpZalZpTkdOayIsICJuYW1lIjogIlBUQiB0ZXN0cyBbMF0iLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDExODU1MDk2MzYiLCAidXNlcm5hbWUiOiAicHRiXzBfYm90In0sIHsidG9rZW4iOiAiMTA0NzMyNjc3MTpBQUY4bk90ODFGcFg4bGJidno4VWV3UVF2UmZUYkZmQnZ1SSIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOllUVTFOVEk0WkdSallqbGkiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzFdIiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDg0Nzk3NjEyIiwgInVzZXJuYW1lIjogInB0Yl8xX2JvdCJ9LCB7InRva2VuIjogIjk3MTk5Mjc0NTpBQUdPa09hVzBOSGpnSXY1LTlqUWJPajR2R3FkaFNGLVV1cyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk5XWmtNV1ZoWWpsallqVTUiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzJdIiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDAyMjU1MDcwIiwgInVzZXJuYW1lIjogInB0Yl8yX2JvdCJ9LCB7InRva2VuIjogIjU1MTg2NDU0MTE6QUFHdzBxaEs3ZTRHbmoxWjJjc1BBQzdaYWtvTWs1NkVKZmsiLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpNRE0wT1RCbE9UUXpNVEU1IiwgIm5hbWUiOiAiUFRCIFRlc3QgQm90IFszXSIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTgwMzgxMDE5NiIsICJ1c2VybmFtZSI6ICJwdGJfdGVzdF8wM19ib3QifSwgeyJ0b2tlbiI6ICI1NzM3MDE4MzU2OkFBSDEzOFN1aUtRRjBMRENXc2ZnV2VYZmpKNWQ2M2tDV0xBIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TjJWaVpqUmxaak01TlRNdyIsICJuYW1lIjogIlBUQiBUZXN0IEJvdCBbNF0iLCAidXNlcm5hbWUiOiAicHRiX3Rlc3RfMDRfYm90IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxODQyNDM5NjQxIn0sIHsidG9rZW4iOiAiNTc0NDY0NDUyMjpBQUVBZHNyRjBoQzZwNkhVTzBQMDFROGJfakNoVTUyWEctTSIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpqSmtZVGd5TmpnMlpHRTAiLCAibmFtZSI6ICJQVEIgVGVzdCBCb3QgWzVdIiwgInVzZXJuYW1lIjogInB0Yl90ZXN0XzA1X2JvdCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTg1NTM2MDk4NiJ9XQ==
TEST_WITH_OPT_DEPS : "false"
TEST_BUILD: "true"
shell: bash --noprofile --norc {0}
@@ -76,13 +105,14 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -r requirements.txt
python -W ignore -m pip install -r requirements-opts.txt
python -W ignore -m pip install -r requirements-dev.txt
- name: Compare to official api
run: |
+12 -13
View File
@@ -1,6 +1,4 @@
# Make sure that
# * the revs specified here match requirements-dev.txt
# * the additional_dependencies here match requirements.txt
# Make sure that the additional_dependencies here match requirements.txt
ci:
autofix_prs: false
@@ -11,18 +9,18 @@ ci:
repos:
- repo: https://github.com/psf/black
rev: 22.3.0
rev: 22.10.0
hooks:
- id: black
args:
- --diff
- --check
- repo: https://gitlab.com/pycqa/flake8
rev: 4.0.1
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
- repo: https://github.com/PyCQA/pylint
rev: v2.13.9
rev: v2.15.8
hooks:
- id: pylint
files: ^(telegram|examples)/.*\.py$
@@ -34,25 +32,26 @@ repos:
additional_dependencies:
- httpx~=0.23.0
- tornado~=6.1
- tornado~=6.2
- APScheduler~=3.9.1
- cachetools~=5.2.0
- aiolimiter~=1.0.0
- . # this basically does `pip install -e .`
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.960
rev: v0.991
hooks:
- id: mypy
name: mypy-ptb
files: ^telegram/.*\.py$
additional_dependencies:
- types-ujson
- types-pytz
- types-cryptography
- types-cachetools
- httpx~=0.23.0
- tornado~=6.1
- tornado~=6.2
- APScheduler~=3.9.1
- cachetools~=5.2.0
- aiolimiter~=1.0.0
- . # this basically does `pip install -e .`
- id: mypy
name: mypy-examples
@@ -61,12 +60,12 @@ repos:
- --no-strict-optional
- --follow-imports=silent
additional_dependencies:
- tornado~=6.1
- tornado~=6.2
- APScheduler~=3.9.1
- cachetools~=5.2.0
- . # this basically does `pip install -e .`
- repo: https://github.com/asottile/pyupgrade
rev: v2.32.1
rev: v3.3.0
hooks:
- id: pyupgrade
files: ^(telegram|examples|tests)/.*\.py$
+26 -1
View File
@@ -21,6 +21,31 @@ python:
- requirements: docs/requirements-docs.txt
build:
os: ubuntu-20.04
os: ubuntu-22.04
tools:
python: "3" # latest stable cpython version
search:
ranking: # bump up rank of commonly searched pages: (default: 0, values range from -10 to 10)
telegram.bot.html: 7
telegram.message.html: 3
telegram.update.html: 3
telegram.user.html: 2
telegram.chat.html: 2
telegram.ext.application.html: 3
telegram.ext.filters.html: 3
telegram.ext.callbackcontext.html: 2
telegram.ext.inlinekeyboardbutton.html: 1
telegram.passport*.html: -7
ignore:
- changelog.html
- coc.html
- bot_methods.html#
- bot_methods.html
# Defaults
- search.html
- search/index.html
- 404.html
- 404/index.html'
+7
View File
@@ -9,6 +9,8 @@ The current development team includes
- `Poolitzer <https://github.com/Poolitzer>`_ (community liaison)
- `Shivam <https://github.com/Starry69>`_
- `Harshil <https://github.com/harshil21>`_
- `Dmitry Kolomatskiy <https://github.com/lemontree210>`_
- `Aditya <https://github.com/clot27>`_
Emeritus maintainers include
`Jannes Höke <https://github.com/jh0ker>`_ (`@jh0ker <https://t.me/jh0ker>`_ on Telegram),
@@ -28,7 +30,9 @@ The following wonderful people contributed directly or indirectly to this projec
- `Avanatiker <https://github.com/Avanatiker>`_
- `Balduro <https://github.com/Balduro>`_
- `Bibo-Joshi <https://github.com/Bibo-Joshi>`_
- `Biruk Alamirew <https://github.com/BAcode-X>`_
- `bimmlerd <https://github.com/bimmlerd>`_
- `cyc8 <https://github.com/cyc8>`_
- `d-qoi <https://github.com/d-qoi>`_
- `daimajia <https://github.com/daimajia>`_
- `Daniel Reed <https://github.com/nmlorg>`_
@@ -45,6 +49,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Evan Haberecht <https://github.com/habereet>`_
- `Evgeny Denisov <https://github.com/eIGato>`_
- `evgfilim1 <https://github.com/evgfilim1>`_
- `ExalFabu <https://github.com/ExalFabu>`_
- `franciscod <https://github.com/franciscod>`_
- `gamgi <https://github.com/gamgi>`_
- `Gauthamram Ravichandran <https://github.com/GauthamramRavichandran>`_
@@ -70,6 +75,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `macrojames <https://github.com/macrojames>`_
- `Matheus Lemos <https://github.com/mlemosf>`_
- `Michael Elovskikh <https://github.com/wronglink>`_
- `miles <https://github.com/miles170>`_
- `Mischa Krüger <https://github.com/Makman2>`_
- `naveenvhegde <https://github.com/naveenvhegde>`_
- `neurrone <https://github.com/neurrone>`_
@@ -84,6 +90,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Paradox <https://github.com/paradox70>`_
- `Patrick Hofmann <https://github.com/PH89>`_
- `Paul Larsen <https://github.com/PaulSonOfLars>`_
- `Pawan <https://github.com/pawanrai9999>`_
- `Pieter Schutz <https://github.com/eldinnie>`_
- `Piraty <https://github.com/piraty>`_
- `Poolitzer <https://github.com/Poolitzer>`_
+329
View File
@@ -1,6 +1,335 @@
=========
Changelog
=========
Version 20.0b0
==============
*Released 2022-12-15*
This is the technical changelog for version 20.0b0. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Make `TelegramObject` Immutable (`#3249`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Reduce Code Duplication in Testing ``Defaults`` (`#3419`_)
- Add Notes and Warnings About Optional Dependencies (`#3393`_)
- Simplify Internals of ``Bot`` Methods (`#3396`_)
- Reduce Code Duplication in Several ``Bot`` Methods (`#3385`_)
- Documentation Improvements (`#3386`_, `#3395`_, `#3398`_, `#3403`_)
Dependencies
------------
- Bump ``pytest-xdist`` from 3.0.2 to 3.1.0 (`#3415`_)
- Bump ``pytest-asyncio`` from 0.20.2 to 0.20.3 (`#3417`_)
- ``pre-commit`` autoupdate (`#3409`_)
.. _`#3249`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3249
.. _`#3419`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3419
.. _`#3393`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3393
.. _`#3396`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3396
.. _`#3385`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3385
.. _`#3386`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3386
.. _`#3395`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3395
.. _`#3398`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3398
.. _`#3403`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3403
.. _`#3415`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3415
.. _`#3417`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3417
.. _`#3409`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3409
Version 20.0a6
==============
*Released 2022-11-24*
This is the technical changelog for version 20.0a6. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Bug Fixes
---------
- Only Persist Arbitrary ``callback_data`` if ``ExtBot.callback_data_cache`` is Present (`#3384`_)
- Improve Backwards Compatibility of ``TelegramObjects`` Pickle Behavior (`#3382`_)
- Fix Naming and Keyword Arguments of ``File.download_*`` Methods (`#3380`_)
- Fix Return Value Annotation of ``Chat.create_forum_topic`` (`#3381`_)
.. _`#3384`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3384
.. _`#3382`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3382
.. _`#3380`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3380
.. _`#3381`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3381
Version 20.0a5
==============
*Released 2022-11-22*
This is the technical changelog for version 20.0a5. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- API 6.3 (`#3346`_, `#3343`_, `#3342`_, `#3360`_)
- Explicit ``local_mode`` Setting (`#3154`_)
- Make Almost All 3rd Party Dependencies Optional (`#3267`_)
- Split ``File.download`` Into ``File.download_to_drive`` And ``File.download_to_memory`` (`#3223`_)
New Features
------------
- Add Properties for API Settings of ``Bot`` (`#3247`_)
- Add ``chat_id`` and ``username`` Parameters to ``ChatJoinRequestHandler`` (`#3261`_)
- Introduce ``TelegramObject.api_kwargs`` (`#3233`_)
- Add Two Constants Related to Local Bot API Servers (`#3296`_)
- Add ``recursive`` Parameter to ``TelegramObject.to_dict()`` (`#3276`_)
- Overhaul String Representation of ``TelegramObject`` (`#3234`_)
- Add Methods ``Chat.mention_{html, markdown, markdown_v2}`` (`#3308`_)
- Add ``constants.MessageLimit.DEEP_LINK_LENGTH`` (`#3315`_)
- Add Shortcut Parameters ``caption``, ``parse_mode`` and ``caption_entities`` to ``Bot.send_media_group`` (`#3295`_)
- Add Several New Enums To Constants (`#3351`_)
Bug Fixes
---------
- Fix ``CallbackQueryHandler`` Not Handling Non-String Data Correctly With Regex Patterns (`#3252`_)
- Fix Defaults Handling in ``Bot.answer_web_app_query`` (`#3362`_)
Documentation Improvements
--------------------------
- Update PR Template (`#3361`_)
- Document Dunder Methods of ``TelegramObject`` (`#3319`_)
- Add Several References to Wiki pages (`#3306`_)
- Overhaul Search bar (`#3218`_)
- Unify Documentation of Arguments and Attributes of Telegram Classes (`#3217`_, `#3292`_, `#3303`_, `#3312`_, `#3314`_)
- Several Smaller Improvements (`#3214`_, `#3271`_, `#3289`_, `#3326`_, `#3370`_, `#3376`_, `#3366`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Improve Warning About Unknown ``ConversationHandler`` States (`#3242`_)
- Switch from Stale Bot to ``GitHub`` Actions (`#3243`_)
- Bump Python 3.11 to RC2 in Test Matrix (`#3246`_)
- Make ``Job.job`` a Property and Make ``Jobs`` Hashable (`#3250`_)
- Skip ``JobQueue`` Tests on Windows Again (`#3280`_)
- Read-Only ``CallbackDataCache`` (`#3266`_)
- Type Hinting Fix for ``Message.effective_attachment`` (`#3294`_)
- Run Unit Tests in Parallel (`#3283`_)
- Update Test Matrix to Use Stable Python 3.11 (`#3313`_)
- Don't Edit Objects In-Place When Inserting ``ext.Defaults`` (`#3311`_)
- Add a Test for ``MessageAttachmentType`` (`#3335`_)
- Add Three New Test Bots (`#3347`_)
- Improve Unit Tests Regarding ``ChatMemberUpdated.difference`` (`#3352`_)
- Flaky Unit Tests: Use ``pytest`` Marker (`#3354`_)
- Fix ``DeepSource`` Issues (`#3357`_)
- Handle Lists and Tuples and Datetimes Directly in ``TelegramObject.to_dict`` (`#3353`_)
- Update Meta Config (`#3365`_)
- Merge ``ChatDescriptionLimit`` Enum Into ``ChatLimit`` (`#3377`_)
Dependencies
------------
- Bump ``pytest`` from 7.1.2 to 7.1.3 (`#3228`_)
- ``pre-commit`` Updates (`#3221`_)
- Bump ``sphinx`` from 5.1.1 to 5.2.3 (`#3269`_)
- Bump ``furo`` from 2022.6.21 to 2022.9.29 (`#3268`_)
- Bump ``actions/stale`` from 5 to 6 (`#3277`_)
- ``pre-commit`` autoupdate (`#3282`_)
- Bump ``sphinx`` from 5.2.3 to 5.3.0 (`#3300`_)
- Bump ``pytest-asyncio`` from 0.19.0 to 0.20.1 (`#3299`_)
- Bump ``pytest`` from 7.1.3 to 7.2.0 (`#3318`_)
- Bump ``pytest-xdist`` from 2.5.0 to 3.0.2 (`#3317`_)
- ``pre-commit`` autoupdate (`#3325`_)
- Bump ``pytest-asyncio`` from 0.20.1 to 0.20.2 (`#3359`_)
- Update ``httpx`` requirement from ~=0.23.0 to ~=0.23.1 (`#3373`_)
.. _`#3346`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3346
.. _`#3343`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3343
.. _`#3342`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3342
.. _`#3360`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3360
.. _`#3154`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3154
.. _`#3267`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3267
.. _`#3223`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3223
.. _`#3247`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3247
.. _`#3261`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3261
.. _`#3233`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3233
.. _`#3296`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3296
.. _`#3276`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3276
.. _`#3234`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3234
.. _`#3308`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3308
.. _`#3315`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3315
.. _`#3295`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3295
.. _`#3351`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3351
.. _`#3252`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3252
.. _`#3362`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3362
.. _`#3361`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3361
.. _`#3319`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3319
.. _`#3306`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3306
.. _`#3218`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3218
.. _`#3217`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3217
.. _`#3292`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3292
.. _`#3303`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3303
.. _`#3312`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3312
.. _`#3314`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3314
.. _`#3214`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3214
.. _`#3271`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3271
.. _`#3289`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3289
.. _`#3326`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3326
.. _`#3370`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3370
.. _`#3376`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3376
.. _`#3366`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3366
.. _`#3242`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3242
.. _`#3243`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3243
.. _`#3246`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3246
.. _`#3250`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3250
.. _`#3280`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3280
.. _`#3266`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3266
.. _`#3294`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3294
.. _`#3283`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3283
.. _`#3313`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3313
.. _`#3311`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3311
.. _`#3335`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3335
.. _`#3347`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3347
.. _`#3352`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3352
.. _`#3354`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3354
.. _`#3357`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3357
.. _`#3353`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3353
.. _`#3365`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3365
.. _`#3377`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3377
.. _`#3228`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3228
.. _`#3221`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3221
.. _`#3269`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3269
.. _`#3268`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3268
.. _`#3277`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3277
.. _`#3282`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3282
.. _`#3300`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3300
.. _`#3299`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3299
.. _`#3318`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3318
.. _`#3317`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3317
.. _`#3325`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3325
.. _`#3359`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3359
.. _`#3373`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3373
Version 20.0a4
==============
*Released 2022-08-27*
This is the technical changelog for version 20.0a4. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Hot Fixes
---------
* Fix a Bug in ``setup.py`` Regarding Optional Dependencies (`#3209`_)
.. _`#3209`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3209
Version 20.0a3
==============
*Released 2022-08-27*
This is the technical changelog for version 20.0a3. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for API 6.2 (`#3195`_)
New Features
------------
- New Rate Limiting Mechanism (`#3148`_)
- Make ``chat/user_data`` Available in Error Handler for Errors in Jobs (`#3152`_)
- Add ``Application.post_shutdown`` (`#3126`_)
Bug Fixes
---------
- Fix ``helpers.mention_markdown`` for Markdown V1 and Improve Related Unit Tests (`#3155`_)
- Add ``api_kwargs`` Parameter to ``Bot.log_out`` and Improve Related Unit Tests (`#3147`_)
- Make ``Bot.delete_my_commands`` a Coroutine Function (`#3136`_)
- Fix ``ConversationHandler.check_update`` not respecting ``per_user`` (`#3128`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Add Python 3.11 to Test Suite & Adapt Enum Behaviour (`#3168`_)
- Drop Manual Token Validation (`#3167`_)
- Simplify Unit Tests for ``Bot.send_chat_action`` (`#3151`_)
- Drop ``pre-commit`` Dependencies from ``requirements-dev.txt`` (`#3120`_)
- Change Default Values for ``concurrent_updates`` and ``connection_pool_size`` (`#3127`_)
- Documentation Improvements (`#3139`_, `#3153`_, `#3135`_)
- Type Hinting Fixes (`#3202`_)
Dependencies
------------
- Bump ``sphinx`` from 5.0.2 to 5.1.1 (`#3177`_)
- Update ``pre-commit`` Dependencies (`#3085`_)
- Bump ``pytest-asyncio`` from 0.18.3 to 0.19.0 (`#3158`_)
- Update ``tornado`` requirement from ~=6.1 to ~=6.2 (`#3149`_)
- Bump ``black`` from 22.3.0 to 22.6.0 (`#3132`_)
- Bump ``actions/setup-python`` from 3 to 4 (`#3131`_)
.. _`#3195`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3195
.. _`#3148`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3148
.. _`#3152`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3152
.. _`#3126`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3126
.. _`#3155`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3155
.. _`#3147`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3147
.. _`#3136`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3136
.. _`#3128`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3128
.. _`#3168`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3168
.. _`#3167`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3167
.. _`#3151`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3151
.. _`#3120`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3120
.. _`#3127`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3127
.. _`#3139`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3139
.. _`#3153`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3153
.. _`#3135`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3135
.. _`#3202`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3202
.. _`#3177`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3177
.. _`#3085`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3085
.. _`#3158`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3158
.. _`#3149`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3149
.. _`#3132`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3132
.. _`#3131`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3131
Version 20.0a2
==============
*Released 2022-06-27*
This is the technical changelog for version 20.0a2. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for API 6.1 (`#3112`_)
New Features
------------
- Add Additional Shortcut Methods to ``Chat`` (`#3115`_)
- Mermaid-based Example State Diagrams (`#3090`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Documentation Improvements (`#3103`_, `#3121`_, `#3098`_)
- Stabilize CI (`#3119`_)
- Bump ``pyupgrade`` from 2.32.1 to 2.34.0 (`#3096`_)
- Bump ``furo`` from 2022.6.4 to 2022.6.4.1 (`#3095`_)
- Bump ``mypy`` from 0.960 to 0.961 (`#3093`_)
.. _`#3112`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3112
.. _`#3115`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3115
.. _`#3090`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3090
.. _`#3103`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3103
.. _`#3121`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3121
.. _`#3098`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3098
.. _`#3119`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3119
.. _`#3096`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3096
.. _`#3095`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3095
.. _`#3093`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3093
Version 20.0a1
==============
+1 -1
View File
@@ -1 +1 @@
include LICENSE LICENSE.lesser Makefile requirements.txt README_RAW.rst telegram/py.typed
include LICENSE LICENSE.lesser requirements.txt requirements-opts.txt README_RAW.rst telegram/py.typed
+21 -11
View File
@@ -14,7 +14,7 @@
:target: https://pypi.org/project/python-telegram-bot/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-6.0-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.3-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions
@@ -34,7 +34,7 @@
:target: https://github.com/python-telegram-bot/python-telegram-bot/
:alt: Github Actions workflow
.. image:: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
:target: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
:alt: Code coverage
@@ -93,7 +93,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 **6.0** are supported.
All types and methods of the Telegram Bot API **6.2** are supported.
Installing
==========
@@ -119,25 +119,35 @@ Dependencies & Their Versions
``python-telegram-bot`` tries to use as few 3rd party dependencies as possible.
However, for some features using a 3rd party library is more sane than implementing the functionality again.
The dependencies are:
As these features are *optional*, the corresponding 3rd party dependencies are not installed by default.
Instead, they are listed as optional dependencies.
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
* `httpx ~= 0.23.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend
* `tornado~=6.1 <https://www.tornadoweb.org/en/stable/>`_ for ``telegram.ext.Updater.start_webhook``
* `cachetools~=5.2.0 <https://cachetools.readthedocs.io/en/latest/>`_ for ``telegram.ext.CallbackDataCache``
* `APScheduler~=3.9.1 <https://apscheduler.readthedocs.io/en/3.x/>`_ for ``telegram.ext.JobQueue``
The only required dependency is `httpx ~= 0.23.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend.
``python-telegram-bot`` is most useful when used along with additional libraries.
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the dependencies.
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
On the other hand, we have to ensure stability of ``python-telegram-bot``, which is why we do apply version bounds.
If you encounter dependency conflicts due to these bounds, feel free to reach out.
Optional Dependencies
---------------------
#####################
PTB can be installed with optional dependencies:
* ``pip install python-telegram-bot[passport]`` installs the `cryptography>=3.0 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot[socks]`` installs ``httpx[socks]``. Use this, if you want to work behind a Socks5 server.
* ``pip install python-telegram-bot[rate-limiter]`` installs ``aiolimiter~=1.0.0``. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
* ``pip install python-telegram-bot[webhooks]`` installs the `tornado~=6.2 <https://www.tornadoweb.org/en/stable/>`_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.start_webhook``.
* ``pip install python-telegram-bot[callback-data]`` installs the `cachetools~=5.2.0 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
* ``pip install python-telegram-bot[job-queue]`` installs the `APScheduler~=3.9.1 <https://apscheduler.readthedocs.io/en/3.x/>`_ library and enforces `pytz>=2018.6 <https://pypi.org/project/pytz/>`_, where ``pytz`` is a dependency of ``APScheduler``. Use this, if you want to use the ``telegram.ext.JobQueue``.
To install multiple optional dependencies, separate them by commas, e.g. ``pip install python-telegram-bot[socks,webhooks]``.
Additionally, two shortcuts are provided:
* ``pip install python-telegram-bot[all]`` installs all optional dependencies.
* ``pip install python-telegram-bot[ext]`` installs all optional dependencies that are related to ``telegram.ext``, i.e. ``[rate-limiter, webhooks, callback-data, job-queue]``.
Quick Start
===========
@@ -149,7 +159,7 @@ Resources
=========
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
It contains descriptions of all available classes, modules, methods and arguments.
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
- The `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ is home to number of more elaborate introductions of the different features of ``python-telegram-bot`` and other useful resources that go beyond the technical documentation.
- Our `examples section <https://docs.python-telegram-bot.org/examples.html>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
Even if it is not your approach for learning, please take a look at ``echobot.py``. It is the de facto base for most of the bots out there.
+17 -11
View File
@@ -14,7 +14,7 @@
:target: https://pypi.org/project/python-telegram-bot-raw/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-6.0-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.3-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions
@@ -34,7 +34,7 @@
:target: https://github.com/python-telegram-bot/python-telegram-bot/
:alt: Github Actions workflow
.. image:: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
.. image:: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
:target: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
:alt: Code coverage
@@ -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 **6.0** are supported.
All types and methods of the Telegram Bot API **6.2** are supported.
Installing
==========
@@ -120,22 +120,28 @@ Dependencies & Their Versions
``python-telegram-bot`` tries to use as few 3rd party dependencies as possible.
However, for some features using a 3rd party library is more sane than implementing the functionality again.
The dependencies are:
As these features are *optional*, the corresponding 3rd party dependencies are not installed by default.
Instead, they are listed as optional dependencies.
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
* `httpx ~= 0.23.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend
The only required dependency is `httpx ~= 0.23.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend.
``python-telegram-bot`` is most useful when used along with additional libraries.
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the dependencies.
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
On the other hand, we have to ensure stability of ``python-telegram-bot``, which is why we do apply version bounds.
If you encounter dependency conflicts due to these bounds, feel free to reach out.
Optional Dependencies
---------------------
#####################
``python-telegram-bot-raw`` can be installed with optional dependencies:
PTB can be installed with optional dependencies:
* ``pip install python-telegram-bot[passport]`` installs the `cryptography <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot[socks]`` installs the `PySocks <https://pypi.org/project/PySocks/>`_ library. Use this, if you want to work behind a Socks5 server.
* ``pip install python-telegram-bot-raw[passport]`` installs the `cryptography>=3.0 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot-raw[socks]`` installs ``httpx[socks]``. Use this, if you want to work behind a Socks5 server.
To install multiple optional dependencies, separate them by commas, e.g. ``pip install python-telegram-bot-raw[passport,socks]``.
Additionally, the shortcut ``pip install python-telegram-bot-raw[all]`` installs all optional dependencies.
Quick Start
===========
@@ -146,7 +152,7 @@ Resources
=========
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
It contains descriptions of all available classes, modules, methods and arguments.
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
- The `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ is home to number of more elaborate introductions of the different features of ``python-telegram-bot`` and other useful resources that go beyond the technical documentation.
- Our `examples section <https://docs.python-telegram-bot.org/examples.html>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
Even if it is not your approach for learning, please take a look at ``echobot.py``. It is the de facto base for most of the bots out there.
+5 -3
View File
@@ -1,4 +1,6 @@
sphinx==5.0.1
sphinx==5.3.0
sphinx-pypi-upload
furo==2022.6.4
sphinx-paramlinks==0.5.4
furo==2022.12.7
git+https://github.com/harshil21/furo-sphinx-search@be5cfa221a01f6e259bb2bb1f76d6ede7ffc1f11#egg=furo-sphinx-search
sphinx-paramlinks==0.5.4
sphinxcontrib-mermaid==0.7.1
@@ -0,0 +1,3 @@
.mermaid svg {
height: auto;
}
+109 -12
View File
@@ -5,7 +5,7 @@ import subprocess
import sys
from enum import Enum
from pathlib import Path
from typing import Tuple
from typing import List, Tuple
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -29,12 +29,12 @@ author = "Leandro Toledo"
# built documents.
#
# The short X.Y version.
version = "20.0a1" # telegram.__version__[:3]
version = "20.0b0" # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = "20.0a1" # telegram.__version__
release = "20.0b0" # telegram.__version__
# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = "4.5.0"
needs_sphinx = "5.1.1"
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -45,6 +45,8 @@ extensions = [
"sphinx.ext.intersphinx",
"sphinx.ext.linkcode",
"sphinx_paramlinks",
"sphinxcontrib.mermaid",
"sphinx_search.extension",
]
# Use intersphinx to reference the python builtin library docs
@@ -63,6 +65,9 @@ source_suffix = ".rst"
# The master toctree document.
master_doc = "index"
# Global substitutions
rst_prolog = (Path.cwd() / "../substitutions/global.rst").read_text(encoding="utf-8")
# -- Extension settings ------------------------------------------------
napoleon_use_admonition_for_examples = True
@@ -211,8 +216,9 @@ html_favicon = "ptb-logo_1024.ico"
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_css_files = ["style_external_link.css"]
html_permalinks_icon = "" # Furo's default permalink icon is `#`` which doesn't look great imo.
html_css_files = ["style_external_link.css", "style_mermaid_diagrams.css"]
html_permalinks_icon = "" # Furo's default permalink icon is `#` which doesn't look great imo.
# Output file base name for HTML help builder.
htmlhelp_basename = "python-telegram-bot-doc"
@@ -253,6 +259,7 @@ latex_logo = "ptb-logo_1024.png"
# (source start file, name, description, authors, manual section).
man_pages = [(master_doc, "python-telegram-bot", "python-telegram-bot Documentation", [author], 1)]
# rtd_sphinx_search_file_type = "un-minified" # Configuration for furo-sphinx-search
# -- Options for Texinfo output -------------------------------------------
@@ -288,7 +295,7 @@ class TGConstXRefRole(PyXRefRole):
Example:
:tg-const:`telegram.constants.MessageLimit.TEXT_LENGTH` renders as `4096` but links to the
:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` renders as `4096` but links to the
constant.
"""
@@ -371,12 +378,98 @@ line_numbers = {}
file_root = Path(inspect.getsourcefile(telegram)).parent.parent.resolve()
import telegram.ext # Needed for checking if an object is a BaseFilter
keyword_args = [
":keyword _sphinx_paramlinks_telegram.Bot.{method}.read_timeout: Value to pass to :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to {read_timeout}.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.read_timeout: {read_timeout_type}, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.write_timeout: Value to pass to :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to {write_timeout}.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.write_timeout: :obj:`float` | :obj:`None`, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.connect_timeout: Value to pass to :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.connect_timeout: :obj:`float` | :obj:`None`, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.pool_timeout: Value to pass to :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.pool_timeout: :obj:`float` | :obj:`None`, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.api_kwargs: Arbitrary keyword arguments to be passed to the Telegram API.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.api_kwargs: :obj:`dict`, optional",
"",
]
def autodoc_process_docstring(app: Sphinx, what, name: str, obj: object, options, lines):
"""We misuse this autodoc hook to get the file names & line numbers because we have access
to the actual object here.
write_timeout_sub = [":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`", "``20``"]
read_timeout_sub = [
":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
"``2``. :paramref:`timeout` will be added to this value",
]
read_timeout_type = [":obj:`float` | :obj:`None`", ":obj:`float`"]
def find_insert_pos(lines: List[str]) -> int:
"""Finds the correct position to insert the keyword arguments and returns the index."""
for idx, value in reversed(list(enumerate(lines))): # reversed since :returns: is at the end
if value.startswith(":returns:"):
return idx
else:
return False
def is_write_timeout_20(obj: object) -> int:
"""inspects the default value of write_timeout parameter of the bot method."""
sig = inspect.signature(obj)
return 1 if (sig.parameters["write_timeout"].default == 20) else 0
def check_timeout_and_api_kwargs_presence(obj: object) -> int:
"""Checks if the method has timeout and api_kwargs keyword only parameters."""
sig = inspect.signature(obj)
params_to_check = (
"read_timeout",
"write_timeout",
"connect_timeout",
"pool_timeout",
"api_kwargs",
)
return all(
param in sig.parameters and sig.parameters[param].kind == inspect.Parameter.KEYWORD_ONLY
for param in params_to_check
)
def autodoc_process_docstring(
app: Sphinx, what, name: str, obj: object, options, lines: List[str]
):
"""We do two things:
1) Use this method to automatically insert the Keyword Args for the Bot methods.
2) Misuse this autodoc hook to get the file names & line numbers because we have access
to the actual object here.
"""
# Ce can't properly handle ordinary attributes.
# 1) Insert the Keyword Args for the Bot methods
method_name = name.split(".")[-1]
if (
name.startswith("telegram.Bot.")
and what == "method"
and method_name.islower()
and check_timeout_and_api_kwargs_presence(obj)
):
insert_index = find_insert_pos(lines)
if not insert_index:
raise ValueError(
f"Couldn't find the correct position to insert the keyword args for {obj}."
)
long_write_timeout = is_write_timeout_20(obj)
get_updates_sub = 1 if (method_name == "get_updates") else 0
# The below can be done in 1 line with itertools.chain, but this must be modified in-place
for i in range(insert_index, insert_index + len(keyword_args)):
lines.insert(
i,
keyword_args[i - insert_index].format(
method=method_name,
write_timeout=write_timeout_sub[long_write_timeout],
read_timeout=read_timeout_sub[get_updates_sub],
read_timeout_type=read_timeout_type[get_updates_sub],
),
)
# 2) Get the file names & line numbers
# We can't properly handle ordinary attributes.
# In linkcode_resolve we'll resolve to the `__init__` or module instead
if what == "attribute":
return
@@ -474,6 +567,10 @@ def autodoc_process_bases(app, name, obj, option, bases: list):
bases.insert(0, ":class:`str`")
continue
if "IntEnum" in base:
bases[idx] = ":class:`enum.IntEnum`"
continue
# Drop generics (at least for now)
if base.endswith("]"):
base = base.split("[", maxsplit=1)[0]
@@ -482,7 +579,7 @@ def autodoc_process_bases(app, name, obj, option, bases: list):
# Now convert `telegram._message.Message` to `telegram.Message` etc
match = re.search(pattern=r"(telegram(\.ext|))\.[_\w\.]+", string=base)
if not match or "_utils" in base:
return
continue
parts = match.group(0).split(".")
+1 -2
View File
@@ -10,5 +10,4 @@
State Diagram
-------------
.. image:: ../../examples/conversationbot.png
.. mermaid:: ../../examples/conversationbot.mmd
+1 -2
View File
@@ -10,5 +10,4 @@
State Diagram
-------------
.. image:: ../../examples/conversationbot2.png
.. mermaid:: ../../examples/conversationbot2.mmd
@@ -10,5 +10,4 @@
State Diagram
-------------
.. image:: ../../examples/nestedconversationbot.png
.. mermaid:: ../../examples/nestedconversationbot.mmd
+4 -1
View File
@@ -40,6 +40,7 @@ up a job to send a message to that user after 30 seconds. The user can
also cancel the timer by sending ``/unset``. To learn more about the
``JobQueue``, read `this wiki
article <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-JobQueue>`__.
Note: To use ``JobQueue``, you must install PTB via ``pip install python-telegram-bot[job-queue]``
:any:`examples.conversationbot`
-------------------------------
@@ -49,7 +50,7 @@ this library, we introduced the
:class:`telegram.ext.ConversationHandler`
for that exact purpose. This example uses it to retrieve
user-information in a conversation-like style. To get a better
understanding, take a look at the :ref:`state diagrem <conversationbot-diagram>`.
understanding, take a look at the :ref:`state diagram <conversationbot-diagram>`.
:any:`examples.conversationbot2`
--------------------------------
@@ -115,6 +116,7 @@ Dont forget to enable and configure payments with
`@BotFather <https://telegram.me/BotFather>`_. Check out this
`guide <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Telegram-Passport>`__
on Telegram passports in PTB.
Note: To use Telegram Passport, you must install PTB via ``pip install python-telegram-bot[passport]``
:any:`examples.paymentbot`
--------------------------
@@ -162,6 +164,7 @@ combination with ``telegram.ext.Application``.
This example showcases how PTBs “arbitrary callback data” feature can be
used.
Note: To use arbitrary callback data, you must install PTB via ``pip install python-telegram-bot[callback-data]``
Pure API
--------
@@ -0,0 +1,7 @@
.. tip::
When combining ``python-telegram-bot`` with other :mod:`asyncio` based frameworks, using this
method is likely not the best choice, as it blocks the event loop until it receives a stop
signal as described above.
Instead, you can manually call the methods listed below to start and shut down the application
and the :attr:`~telegram.ext.Application.updater`.
Keeping the event loop running and listening for a stop signal is then up to you.
@@ -206,6 +206,8 @@
- Used for getting a sticker set
* - :meth:`~telegram.Bot.upload_sticker_file`
- Used for uploading a sticker file
* - :meth:`~telegram.Bot.get_custom_emoji_stickers`
- Used for getting custom emoji files based on their IDs
.. raw:: html
@@ -254,6 +256,35 @@
</details>
<br>
.. raw:: html
<details>
<summary>Forum topic management</summary>
.. list-table::
:align: left
:widths: 1 4
* - :meth:`~telegram.Bot.close_forum_topic`
- Used for closing a forum topic
* - :meth:`~telegram.Bot.create_forum_topic`
- Used to create a topic
* - :meth:`~telegram.Bot.delete_forum_topic`
- Used for deleting a forum topic
* - :meth:`~telegram.Bot.edit_forum_topic`
- Used to edit a topic
* - :meth:`~telegram.Bot.reopen_forum_topic`
- Used to reopen a topic
* - :meth:`~telegram.Bot.get_forum_topic_icon_stickers`
- Used to get custom emojis to use as topic icons
* - :meth:`~telegram.Bot.unpin_all_forum_topic_messages`
- Used to unpin all messages in a forum topic
.. raw:: html
</details>
<br>
.. raw:: html
<details>
@@ -263,6 +294,8 @@
:align: left
:widths: 1 4
* - :meth:`~telegram.Bot.create_invoice_link`
- Used to generate an HTTP link for an invoice
* - :meth:`~telegram.Bot.close`
- Used for closing server instance when switching to another local server
* - :meth:`~telegram.Bot.log_out`
@@ -286,6 +319,10 @@
:align: left
:widths: 1 4
* - :attr:`~telegram.Bot.base_file_url`
- Telegram Bot API file URL
* - :attr:`~telegram.Bot.base_url`
- Telegram Bot API service URL
* - :attr:`~telegram.Bot.bot`
- The user instance of the bot as returned by :meth:`~telegram.Bot.get_me`
* - :attr:`~telegram.Bot.can_join_groups`
@@ -300,12 +337,18 @@
- The first name of the bot
* - :attr:`~telegram.Bot.last_name`
- The last name of the bot
* - :attr:`~telegram.Bot.local_mode`
- Whether the bot is running in local mode
* - :attr:`~telegram.Bot.username`
- The username of the bot, without leading ``@``
* - :attr:`~telegram.Bot.link`
- The t.me link of the bot
* - :attr:`~telegram.Bot.private_key`
- Deserialized private key for decryption of telegram passport data
* - :attr:`~telegram.Bot.supports_inline_queries`
- Whether the bot supports inline queries
* - :attr:`~telegram.Bot.token`
- Bot's unique authentication token
.. raw:: html
+10
View File
@@ -0,0 +1,10 @@
.. tip::
When making requests to the Bot API in an asynchronous fashion (e.g. via
:attr:`block=False <telegram.ext.BaseHandler.block>`, :meth:`Application.create_task <telegram.ext.Application.create_task>`,
:meth:`~telegram.ext.ApplicationBuilder.concurrent_updates` or the :class:`~telegram.ext.JobQueue`), it can happen that more requests
are being made in parallel than there are connections in the pool.
If the number of requests is much higher than the number of connections, even setting
:meth:`~telegram.ext.ApplicationBuilder.pool_timeout` to a larger value may not always be enough to prevent pool
timeouts.
You should therefore set :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, :meth:`~telegram.ext.ApplicationBuilder.connection_pool_size` and
:meth:`~telegram.ext.ApplicationBuilder.pool_timeout` to values that make sense for your setup.
+87
View File
@@ -0,0 +1,87 @@
Available Types
---------------
.. toctree::
:titlesonly:
telegram.animation
telegram.audio
telegram.botcommand
telegram.botcommandscope
telegram.botcommandscopeallchatadministrators
telegram.botcommandscopeallgroupchats
telegram.botcommandscopeallprivatechats
telegram.botcommandscopechat
telegram.botcommandscopechatadministrators
telegram.botcommandscopechatmember
telegram.botcommandscopedefault
telegram.callbackquery
telegram.chat
telegram.chatadministratorrights
telegram.chatinvitelink
telegram.chatjoinrequest
telegram.chatlocation
telegram.chatmember
telegram.chatmemberadministrator
telegram.chatmemberbanned
telegram.chatmemberleft
telegram.chatmembermember
telegram.chatmemberowner
telegram.chatmemberrestricted
telegram.chatmemberupdated
telegram.chatpermissions
telegram.chatphoto
telegram.contact
telegram.dice
telegram.document
telegram.file
telegram.forcereply
telegram.forumtopic
telegram.forumtopicclosed
telegram.forumtopiccreated
telegram.forumtopicreopened
telegram.inlinekeyboardbutton
telegram.inlinekeyboardmarkup
telegram.inputfile
telegram.inputmedia
telegram.inputmediaanimation
telegram.inputmediaaudio
telegram.inputmediadocument
telegram.inputmediaphoto
telegram.inputmediavideo
telegram.keyboardbutton
telegram.keyboardbuttonpolltype
telegram.location
telegram.loginurl
telegram.menubutton
telegram.menubuttoncommands
telegram.menubuttondefault
telegram.menubuttonwebapp
telegram.message
telegram.messageautodeletetimerchanged
telegram.messageentity
telegram.messageid
telegram.photosize
telegram.poll
telegram.pollanswer
telegram.polloption
telegram.proximityalerttriggered
telegram.replykeyboardmarkup
telegram.replykeyboardremove
telegram.sentwebappmessage
telegram.telegramobject
telegram.update
telegram.user
telegram.userprofilephotos
telegram.venue
telegram.video
telegram.videochatended
telegram.videochatparticipantsinvited
telegram.videochatscheduled
telegram.videochatstarted
telegram.videonote
telegram.voice
telegram.webappdata
telegram.webappinfo
telegram.webhookinfo
+1 -1
View File
@@ -3,4 +3,4 @@ telegram.Dice
.. autoclass:: telegram.Dice
:members:
:show-inheritance:
:show-inheritance:
+8
View File
@@ -0,0 +1,8 @@
Arbitrary Callback Data
-----------------------
.. toctree::
:titlesonly:
telegram.ext.callbackdatacache
telegram.ext.invalidcallbackdata
@@ -0,0 +1,6 @@
telegram.ext.AIORateLimiter
============================
.. autoclass:: telegram.ext.AIORateLimiter
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
telegram.ext.BaseRateLimiter
============================
.. autoclass:: telegram.ext.BaseRateLimiter
:members:
:show-inheritance:
+1 -2
View File
@@ -3,5 +3,4 @@ telegram.ext.ExtBot
.. autoclass:: telegram.ext.ExtBot
:show-inheritance:
.. autofunction:: telegram.ext.ExtBot.insert_callback_data
:members: insert_callback_data, defaults, rate_limiter, initialize, shutdown, callback_data_cache
@@ -0,0 +1,24 @@
Handlers
--------
.. toctree::
:titlesonly:
telegram.ext.basehandler
telegram.ext.callbackqueryhandler
telegram.ext.chatjoinrequesthandler
telegram.ext.chatmemberhandler
telegram.ext.choseninlineresulthandler
telegram.ext.commandhandler
telegram.ext.conversationhandler
telegram.ext.filters
telegram.ext.inlinequeryhandler
telegram.ext.messagehandler
telegram.ext.pollanswerhandler
telegram.ext.pollhandler
telegram.ext.precheckoutqueryhandler
telegram.ext.prefixhandler
telegram.ext.shippingqueryhandler
telegram.ext.stringcommandhandler
telegram.ext.stringregexhandler
telegram.ext.typehandler
@@ -0,0 +1,10 @@
Persistence
-----------
.. toctree::
:titlesonly:
telegram.ext.basepersistence
telegram.ext.dictpersistence
telegram.ext.persistenceinput
telegram.ext.picklepersistence
@@ -0,0 +1,8 @@
Rate Limiting
-------------
.. toctree::
:titlesonly:
telegram.ext.baseratelimiter
telegram.ext.aioratelimiter
+5 -42
View File
@@ -2,6 +2,7 @@ telegram.ext package
====================
.. toctree::
:titlesonly:
telegram.ext.application
telegram.ext.applicationbuilder
@@ -13,45 +14,7 @@ telegram.ext package
telegram.ext.job
telegram.ext.jobqueue
telegram.ext.updater
Handlers
--------
.. toctree::
telegram.ext.basehandler
telegram.ext.callbackqueryhandler
telegram.ext.chatjoinrequesthandler
telegram.ext.chatmemberhandler
telegram.ext.choseninlineresulthandler
telegram.ext.commandhandler
telegram.ext.conversationhandler
telegram.ext.filters
telegram.ext.inlinequeryhandler
telegram.ext.messagehandler
telegram.ext.pollanswerhandler
telegram.ext.pollhandler
telegram.ext.precheckoutqueryhandler
telegram.ext.prefixhandler
telegram.ext.shippingqueryhandler
telegram.ext.stringcommandhandler
telegram.ext.stringregexhandler
telegram.ext.typehandler
Persistence
-----------
.. toctree::
telegram.ext.basepersistence
telegram.ext.dictpersistence
telegram.ext.persistenceinput
telegram.ext.picklepersistence
Arbitrary Callback Data
-----------------------
.. toctree::
telegram.ext.callbackdatacache
telegram.ext.invalidcallbackdata
telegram.ext.handlers-tree.rst
telegram.ext.persistence-tree.rst
telegram.ext.acd-tree.rst
telegram.ext.rate-limiting-tree.rst
+6
View File
@@ -0,0 +1,6 @@
telegram.ForumTopic
===================
.. autoclass:: telegram.ForumTopic
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
telegram.ForumTopicClosed
=========================
.. autoclass:: telegram.ForumTopicClosed
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
telegram.ForumTopicCreated
==========================
.. autoclass:: telegram.ForumTopicCreated
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
telegram.ForumTopicReopened
===========================
.. autoclass:: telegram.ForumTopicReopened
:members:
:show-inheritance:
+9
View File
@@ -0,0 +1,9 @@
Games
-----
.. toctree::
:titlesonly:
telegram.callbackgame
telegram.game
telegram.gamehighscore
+35
View File
@@ -0,0 +1,35 @@
Inline Mode
-----------
.. toctree::
:titlesonly:
telegram.choseninlineresult
telegram.inlinequery
telegram.inlinequeryresult
telegram.inlinequeryresultarticle
telegram.inlinequeryresultaudio
telegram.inlinequeryresultcachedaudio
telegram.inlinequeryresultcacheddocument
telegram.inlinequeryresultcachedgif
telegram.inlinequeryresultcachedmpeg4gif
telegram.inlinequeryresultcachedphoto
telegram.inlinequeryresultcachedsticker
telegram.inlinequeryresultcachedvideo
telegram.inlinequeryresultcachedvoice
telegram.inlinequeryresultcontact
telegram.inlinequeryresultdocument
telegram.inlinequeryresultgame
telegram.inlinequeryresultgif
telegram.inlinequeryresultlocation
telegram.inlinequeryresultmpeg4gif
telegram.inlinequeryresultphoto
telegram.inlinequeryresultvenue
telegram.inlinequeryresultvideo
telegram.inlinequeryresultvoice
telegram.inputmessagecontent
telegram.inputtextmessagecontent
telegram.inputlocationmessagecontent
telegram.inputvenuemessagecontent
telegram.inputcontactmessagecontent
telegram.inputinvoicemessagecontent
+28
View File
@@ -0,0 +1,28 @@
Passport
--------
.. toctree::
:titlesonly:
telegram.credentials
telegram.datacredentials
telegram.encryptedcredentials
telegram.encryptedpassportelement
telegram.filecredentials
telegram.iddocumentdata
telegram.passportdata
telegram.passportelementerror
telegram.passportelementerrordatafield
telegram.passportelementerrorfile
telegram.passportelementerrorfiles
telegram.passportelementerrorfrontside
telegram.passportelementerrorreverseside
telegram.passportelementerrorselfie
telegram.passportelementerrortranslationfile
telegram.passportelementerrortranslationfiles
telegram.passportelementerrorunspecified
telegram.passportfile
telegram.personaldetails
telegram.residentialaddress
telegram.securedata
telegram.securevalue
+14
View File
@@ -0,0 +1,14 @@
Payments
--------
.. toctree::
:titlesonly:
telegram.invoice
telegram.labeledprice
telegram.orderinfo
telegram.precheckoutquery
telegram.shippingaddress
telegram.shippingoption
telegram.shippingquery
telegram.successfulpayment
+2
View File
@@ -4,6 +4,8 @@ telegram.request Module
.. versionadded:: 20.0
.. toctree::
:titlesonly:
telegram.request.baserequest
telegram.request.requestdata
telegram.request.httpxrequest
+9 -172
View File
@@ -7,180 +7,17 @@ Version Constants
.. automodule:: telegram
:members: __version__, __version_info__, __bot_api_version__, __bot_api_version_info__
Available Types
---------------
Classes in this package
-----------------------
.. toctree::
:titlesonly:
telegram.animation
telegram.audio
telegram.bot
telegram.botcommand
telegram.botcommandscope
telegram.botcommandscopeallchatadministrators
telegram.botcommandscopeallgroupchats
telegram.botcommandscopeallprivatechats
telegram.botcommandscopechat
telegram.botcommandscopechatadministrators
telegram.botcommandscopechatmember
telegram.botcommandscopedefault
telegram.callbackquery
telegram.chat
telegram.chatadministratorrights
telegram.chatinvitelink
telegram.chatjoinrequest
telegram.chatlocation
telegram.chatmember
telegram.chatmemberadministrator
telegram.chatmemberbanned
telegram.chatmemberleft
telegram.chatmembermember
telegram.chatmemberowner
telegram.chatmemberrestricted
telegram.chatmemberupdated
telegram.chatpermissions
telegram.chatphoto
telegram.contact
telegram.dice
telegram.document
telegram.file
telegram.forcereply
telegram.inlinekeyboardbutton
telegram.inlinekeyboardmarkup
telegram.inputfile
telegram.inputmedia
telegram.inputmediaanimation
telegram.inputmediaaudio
telegram.inputmediadocument
telegram.inputmediaphoto
telegram.inputmediavideo
telegram.keyboardbutton
telegram.keyboardbuttonpolltype
telegram.location
telegram.loginurl
telegram.menubutton
telegram.menubuttoncommands
telegram.menubuttondefault
telegram.menubuttonwebapp
telegram.message
telegram.messageautodeletetimerchanged
telegram.messageentity
telegram.messageid
telegram.photosize
telegram.poll
telegram.pollanswer
telegram.polloption
telegram.proximityalerttriggered
telegram.replykeyboardmarkup
telegram.replykeyboardremove
telegram.sentwebappmessage
telegram.telegramobject
telegram.update
telegram.user
telegram.userprofilephotos
telegram.venue
telegram.video
telegram.videochatended
telegram.videochatparticipantsinvited
telegram.videochatscheduled
telegram.videochatstarted
telegram.videonote
telegram.voice
telegram.webappdata
telegram.webappinfo
telegram.webhookinfo
telegram.at-tree.rst
telegram.stickers-tree.rst
telegram.inline-tree.rst
telegram.payments-tree.rst
telegram.games-tree.rst
telegram.passport-tree.rst
Stickers
--------
.. toctree::
telegram.maskposition
telegram.sticker
telegram.stickerset
Inline Mode
-----------
.. toctree::
telegram.choseninlineresult
telegram.inlinequery
telegram.inlinequeryresult
telegram.inlinequeryresultarticle
telegram.inlinequeryresultaudio
telegram.inlinequeryresultcachedaudio
telegram.inlinequeryresultcacheddocument
telegram.inlinequeryresultcachedgif
telegram.inlinequeryresultcachedmpeg4gif
telegram.inlinequeryresultcachedphoto
telegram.inlinequeryresultcachedsticker
telegram.inlinequeryresultcachedvideo
telegram.inlinequeryresultcachedvoice
telegram.inlinequeryresultcontact
telegram.inlinequeryresultdocument
telegram.inlinequeryresultgame
telegram.inlinequeryresultgif
telegram.inlinequeryresultlocation
telegram.inlinequeryresultmpeg4gif
telegram.inlinequeryresultphoto
telegram.inlinequeryresultvenue
telegram.inlinequeryresultvideo
telegram.inlinequeryresultvoice
telegram.inputmessagecontent
telegram.inputtextmessagecontent
telegram.inputlocationmessagecontent
telegram.inputvenuemessagecontent
telegram.inputcontactmessagecontent
telegram.inputinvoicemessagecontent
Payments
--------
.. toctree::
telegram.invoice
telegram.labeledprice
telegram.orderinfo
telegram.precheckoutquery
telegram.shippingaddress
telegram.shippingoption
telegram.shippingquery
telegram.successfulpayment
Games
-----
.. toctree::
telegram.callbackgame
telegram.game
telegram.gamehighscore
Passport
--------
.. toctree::
telegram.credentials
telegram.datacredentials
telegram.encryptedcredentials
telegram.encryptedpassportelement
telegram.filecredentials
telegram.iddocumentdata
telegram.passportdata
telegram.passportelementerror
telegram.passportelementerrordatafield
telegram.passportelementerrorfile
telegram.passportelementerrorfiles
telegram.passportelementerrorfrontside
telegram.passportelementerrorreverseside
telegram.passportelementerrorselfie
telegram.passportelementerrortranslationfile
telegram.passportelementerrortranslationfiles
telegram.passportelementerrorunspecified
telegram.passportfile
telegram.personaldetails
telegram.residentialaddress
telegram.securedata
telegram.securevalue
+9
View File
@@ -0,0 +1,9 @@
Stickers
--------
.. toctree::
:titlesonly:
telegram.maskposition
telegram.sticker
telegram.stickerset
+1
View File
@@ -4,3 +4,4 @@ telegram.TelegramObject
.. autoclass:: telegram.TelegramObject
:members:
:show-inheritance:
:special-members: __repr__, __getitem__, __eq__, __hash__, __setstate__, __getstate__, __deepcopy__, __setattr__, __delattr__
+1
View File
@@ -2,6 +2,7 @@ Auxiliary modules
=================
.. toctree::
:titlesonly:
telegram.constants
telegram.error
+49
View File
@@ -0,0 +1,49 @@
.. |uploadinput| replace:: To upload a file, you can either pass a :term:`file object` (e.g. ``open("filename", "rb")``), the file contents as bytes or the path of the file (as string or :class:`pathlib.Path` object). In the latter case, the file contents will either be read as bytes or the file path will be passed to Telegram, depending on the :paramref:`~telegram.Bot.local_mode` setting.
.. |uploadinputnopath| replace:: To upload a file, you can either pass a :term:`file object` (e.g. ``open("filename", "rb")``) or the file contents as bytes. If the bot is running in :paramref:`~telegram.Bot.local_mode`, passing the path of the file (as string or :class:`pathlib.Path` object) is supported as well.
.. |fileinputbase| replace:: Pass a ``file_id`` as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one.
.. |fileinput| replace:: |fileinputbase| |uploadinput|
.. |fileinputnopath| replace:: |fileinputbase| |uploadinputnopath|
.. |thumbdocstringbase| replace:: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file.
.. |thumbdocstring| replace:: |thumbdocstringbase| |uploadinput|
.. |thumbdocstringnopath| replace:: |thumbdocstringbase| |uploadinputnopath|
.. |editreplymarkup| replace:: It is currently only possible to edit messages without :attr:`telegram.Message.reply_markup` or with inline keyboards.
.. |toapikwargsbase| replace:: These arguments are also considered by :meth:`~telegram.TelegramObject.to_dict` and :meth:`~telegram.TelegramObject.to_json`, i.e. when passing objects to Telegram. Passing them to Telegram is however not guaranteed to work for all kinds of objects, e.g. this will fail for objects that can not directly be JSON serialized.
.. |toapikwargsarg| replace:: Arbitrary keyword arguments. Can be used to store data for which there are no dedicated attributes. |toapikwargsbase|
.. |toapikwargsattr| replace:: Optional. Arbitrary keyword arguments. Used to store data for which there are no dedicated attributes. |toapikwargsbase|
.. |chat_id_channel| replace:: Unique identifier for the target chat or username of the target channel (in the format ``@channelusername``).
.. |chat_id_group| replace:: Unique identifier for the target chat or username of the target supergroup (in the format ``@supergroupusername``).
.. |message_thread_id| replace:: Unique identifier for the target message thread of the forum topic.
.. |message_thread_id_arg| replace:: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only.
.. |parse_mode| replace:: Mode for parsing entities. See :class:`telegram.constants.ParseMode` and `formatting options <https://core.telegram.org/bots/api#formatting-options>`__ for more details.
.. |allow_sending_without_reply| replace:: Pass :obj:`True`, if the message should be sent even if the specified replied-to message is not found.
.. |caption_entities| replace:: List of special entities that appear in the caption, which can be specified instead of ``parse_mode``.
.. |protect_content| replace:: Protects the contents of the sent message from forwarding and saving.
.. |disable_notification| replace:: Sends the message silently. Users will receive a notification with no sound.
.. |reply_to_msg_id| replace:: If the message is a reply, ID of the original message.
.. |sequenceclassargs| replace:: Accepts any :class:`collections.abc.Sequence` as input instead of just a list. The input is converted to a tuple.
.. |tupleclassattrs| replace:: This attribute is now an immutable tuple.
.. |alwaystuple| replace:: This attribute is now always a tuple, that may be empty.
+4
View File
@@ -6,6 +6,10 @@
For detailed info on arbitrary callback data, see the wiki page at
https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data
Note:
To use arbitrary callback data, you must install PTB via
`pip install python-telegram-bot[callback-data]`
"""
import logging
from typing import List, Tuple, cast
+21
View File
@@ -0,0 +1,21 @@
flowchart TB
%% Documentation: https://mermaid-js.github.io/mermaid/#/flowchart
A(("/start")):::entryPoint -->|Hi! My name is Professor Bot...| B((GENDER)):::state
B --> |"- Boy <br /> - Girl <br /> - Other"|C("(choice)"):::userInput
C --> |I see! Please send me a photo...| D((PHOTO)):::state
D --> E("/skip"):::userInput
D --> F("(photo)"):::userInput
E --> |I bet you look great!| G[\ /]:::userInput
F --> |Gorgeous!| G[\ /]
G --> |"Now, send me your location .."| H((LOCATION)):::state
H --> I("/skip"):::userInput
H --> J("(location)"):::userInput
I --> |You seem a bit paranoid!| K[\" "/]:::userInput
J --> |Maybe I can visit...| K
K --> |"Tell me about yourself..."| L(("BIO")):::state
L --> M("(text)"):::userInput
M --> |"Thanks and bye!"| End(("END")):::termination
classDef userInput fill:#2a5279, color:#ffffff, stroke:#ffffff
classDef state fill:#222222, color:#ffffff, stroke:#ffffff
classDef entryPoint fill:#009c11, stroke:#42FF57, color:#ffffff
classDef termination fill:#bb0007, stroke:#E60109, color:#ffffff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

+2 -2
View File
@@ -23,7 +23,7 @@ try:
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
if __version_info__ < (20, 0, 0, "alpha", 5):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
@@ -81,7 +81,7 @@ async def photo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Stores the photo and asks for a location."""
user = update.message.from_user
photo_file = await update.message.photo[-1].get_file()
await photo_file.download("user_photo.jpg")
await photo_file.download_to_drive("user_photo.jpg")
logger.info("Photo of %s: %s", user.first_name, "user_photo.jpg")
await update.message.reply_text(
"Gorgeous! Now, send me your location please, or send /skip if you don't want to."
+17
View File
@@ -0,0 +1,17 @@
flowchart TB
%% Documentation: https://mermaid-js.github.io/mermaid/#/flowchart
A(("/start")):::entryPoint -->|Hi! My name is Doctor Botter...| B((CHOOSING)):::state
B --> C("Something else..."):::userInput
C --> |What category?| D((TYPING_CHOICE)):::state
D --> E("(text)"):::userInput
E --> |"[save choice] <br /> I'd love to hear about that!"| F((TYPING_REPLY)):::state
F --> G("(text)"):::userInput
G --> |"[save choice: text] <br /> Neat! <br /> (List of facts) <br /> More?"| B
B --> H("- Age <br /> - Favourite colour <br /> - Number of siblings"):::userInput
H --> |"[save choice] <br /> I'd love to hear about that!"| F
B --> I("Done"):::userInput
I --> |"I learned these facts about you: <br /> ..."| End(("END")):::termination
classDef userInput fill:#2a5279, color:#ffffff, stroke:#ffffff
classDef state fill:#222222, color:#ffffff, stroke:#ffffff
classDef entryPoint fill:#009c11, stroke:#42FF57, color:#ffffff
classDef termination fill:#bb0007, stroke:#E60109, color:#ffffff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

+1 -1
View File
@@ -115,7 +115,7 @@ def main() -> None:
application = Application.builder().token("TOKEN").build()
# More info on what deep linking actually is (read this first if it's unclear to you):
# https://core.telegram.org/bots#deep-linking
# https://core.telegram.org/bots/features#deep-linking
# Register a deep-linking handler
application.add_handler(
+43
View File
@@ -0,0 +1,43 @@
flowchart TB
%% Documentation: https://mermaid-js.github.io/mermaid/#/flowchart
A(("/start")):::entryPoint -->|Hi! I'm FamilyBot...| B((SELECTING_ACTION)):::state
B --> C("Show Data"):::userInput
C --> |"(List of gathered data)"| D((SHOWING)):::state
D --> E("Back"):::userInput
E --> B
B --> F("Add Yourself"):::userInput
F --> G(("DESCRIBING_SELF")):::state
G --> H("Add info"):::userInput
H --> I((SELECT_FEATURE)):::state
I --> |"Please select a feature to update. <br /> - Name <br /> - Age <br /> - Done"|J("(choice)"):::userInput
J --> |"Okay, tell me."| K((TYPING)):::state
K --> L("(text)"):::userInput
L --> |"[saving]"|I
I --> M("Done"):::userInput
M --> B
B --> N("Add family member"):::userInput
R --> I
W --> |"See you around!"|End(("END")):::termination
Y(("ANY STATE")):::state --> Z("/stop"):::userInput
Z -->|"Okay, bye."| End
B --> W("Done"):::userInput
subgraph nestedConversation[Nested Conversation: Add Family Member]
direction BT
N --> O(("SELECT_LEVEL")):::state
O --> |"Add... <br /> - Add Parent <br /> - Add Child <br />"|P("(choice)"):::userInput
P --> Q(("SELECT_GENDER")):::state
Q --> |"- Mother <br /> - Father <br /> / <br /> - Sister <br /> - Brother"| R("(choice)"):::userInput
Q --> V("Show Data"):::userInput
Q --> T(("SELECTING_ACTION")):::state
Q --> U("Back"):::userInput
U --> T
O --> U
O --> V
V --> S(("SHOWING")):::state
V --> T
end
classDef userInput fill:#2a5279, color:#ffffff, stroke:#ffffff
classDef state fill:#222222, color:#ffffff, stroke:#ffffff
classDef entryPoint fill:#009c11, stroke:#42FF57, color:#ffffff
classDef termination fill:#bb0007, stroke:#E60109, color:#ffffff
style nestedConversation fill:#999999, stroke-width:2px, stroke:#333333
Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 KiB

+9 -6
View File
@@ -10,6 +10,9 @@ See https://telegram.org/blog/passport for info about what telegram passport is.
See https://github.com/python-telegram-bot/python-telegram-bot/wiki/Telegram-Passport
for how to use Telegram Passport properly with python-telegram-bot.
Note:
To use Telegram Passport, you must install PTB via
`pip install python-telegram-bot[passport]`
"""
import logging
from pathlib import Path
@@ -21,7 +24,7 @@ try:
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
if __version_info__ < (20, 0, 0, "alpha", 5):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
@@ -77,25 +80,25 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
for file in data.files:
actual_file = await file.get_file()
print(actual_file)
await actual_file.download()
await actual_file.download_to_drive()
if (
data.type in ("passport", "driver_license", "identity_card", "internal_passport")
and data.front_side
):
front_file = await data.front_side.get_file()
print(data.type, front_file)
await front_file.download()
await front_file.download_to_drive()
if data.type in ("driver_license" and "identity_card") and data.reverse_side:
reverse_file = await data.reverse_side.get_file()
print(data.type, reverse_file)
await reverse_file.download()
await reverse_file.download_to_drive()
if (
data.type in ("passport", "driver_license", "identity_card", "internal_passport")
and data.selfie
):
selfie_file = await data.selfie.get_file()
print(data.type, selfie_file)
await selfie_file.download()
await selfie_file.download_to_drive()
if data.translation and data.type in (
"passport",
"driver_license",
@@ -111,7 +114,7 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
for file in data.translation:
actual_file = await file.get_file()
print(actual_file)
await actual_file.download()
await actual_file.download_to_drive()
def main() -> None:
+4
View File
@@ -16,6 +16,10 @@ Usage:
Basic Alarm Bot example, sends a message after a set time.
Press Ctrl-C on the command line or send a signal to the process to stop the
bot.
Note:
To use arbitrary callback data, you must install ptb via
`pip install python-telegram-bot[callback-data]`
"""
import logging
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.black]
line-length = 99
target-version = ['py37', 'py38', 'py39', 'py310']
target-version = ['py37', 'py38', 'py39', 'py310', 'py311']
[tool.isort] # black config
profile = "black"
+4
View File
@@ -0,0 +1,4 @@
-r requirements.txt
-r requirements-dev.txt
-r requirements-opts.txt
-r docs/requirements-docs.txt
+3 -12
View File
@@ -1,18 +1,9 @@
# cryptography is an optional dependency, but running the tests properly requires it
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3
pre-commit
# Make sure that the versions specified here match the pre-commit settings!
black==22.3.0
flake8==4.0.1
pylint==2.13.9
mypy==0.960
pyupgrade==2.32.1
isort==5.10.1
pytest==7.1.2
pytest-asyncio==0.18.3
pytest==7.2.0
pytest-asyncio==0.20.3
pytest-timeout==2.1.0 # used to timeout tests
pytest-xdist==3.1.0 # xdist runs tests in parallel
flaky # Used for flaky tests (flaky decorator)
beautifulsoup4 # used in test_official for parsing tg docs
+26
View File
@@ -0,0 +1,26 @@
# Format:
# package_name==version # req-1, req-2, req-3!ext
# `pip install ptb-raw[req-1/2]` will install `package_name`
# `pip install ptb[req-1/2/3]` will also install `package_name`
# Make sure to install those as additional_dependencies in the
# pre-commit hooks for pylint & mypy
# Also update the readme accordingly
# When dependencies release new versions and tests succeed, we should try to expand the allowed
# versions and only increase the lower bound if necessary
httpx[socks] # socks
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=3.0 # passport
aiolimiter~=1.0.0 # rate-limiter!ext
# tornado is rather stable, but let's not allow the next mayor release without prior testing
tornado~=6.2 # webhooks!ext
# Cachetools and APS don't have a strict stability policy.
# Let's be cautious for now.
cachetools~=5.2.0 # callback-data!ext
APScheduler~=3.9.1 # job-queue!ext
# pytz is required by APS and just needs the lower bound due to #2120
pytz>=2018.6 # job-queue!ext
+1 -13
View File
@@ -6,16 +6,4 @@
# versions and only increase the lower bound if necessary
# httpx has no stable release yet, so let's be cautious for now
httpx ~= 0.23.0
# only telegram.ext: # Keep this line here; used in setup(-raw).py
# tornado is rather stable, but let's not allow the next mayor release without prior testing
tornado~=6.1
# Cachetools and APS don't have a strict stability policy.
# Let's be cautious for now.
cachetools~=5.2.0
APScheduler~=3.9.1
# pytz is required by APS and just needs the lower bound due to #2120
pytz>=2018.6
httpx ~= 0.23.1
+3 -1
View File
@@ -1,5 +1,5 @@
[metadata]
license_file = LICENSE.dual
license_files = LICENSE, LICENSE.dual, LICENSE.lesser
[build_sphinx]
source-dir = docs/source
@@ -21,6 +21,7 @@ disable = duplicate-code,too-many-arguments,too-many-public-methods,too-few-publ
missing-class-docstring,too-many-locals,too-many-lines,too-many-branches,
too-many-statements
enable=useless-suppression ; Warns about unused pylint ignores
exclude-protected=_unfrozen
[tool:pytest]
testpaths = tests
@@ -60,6 +61,7 @@ disallow_untyped_defs = True
disallow_incomplete_defs = True
disallow_untyped_decorators = True
show_error_codes = True
implicit_optional = True
# For some files, it's easier to just disable strict-optional all together instead of
# cluttering the code with `# type: ignore`s or stuff like
+31 -10
View File
@@ -2,20 +2,19 @@
"""The setup and build script for the python-telegram-bot library."""
import subprocess
import sys
from collections import defaultdict
from pathlib import Path
from setuptools import find_packages, setup
def get_requirements(raw=False):
def get_requirements():
"""Build the requirements list for this project"""
requirements_list = []
with Path("requirements.txt").open() as reqs:
for install in reqs:
if install.startswith("# only telegram.ext:"):
if raw:
break
if install.startswith("#"):
continue
requirements_list.append(install.strip())
@@ -24,7 +23,7 @@ def get_requirements(raw=False):
def get_packages_requirements(raw=False):
"""Build the package & requirements list for this project"""
reqs = get_requirements(raw=raw)
reqs = get_requirements()
exclude = ["tests*"]
if raw:
@@ -35,6 +34,31 @@ def get_packages_requirements(raw=False):
return packs, reqs
def get_optional_requirements(raw=False):
"""Build the optional dependencies"""
requirements = defaultdict(list)
with Path("requirements-opts.txt").open() as reqs:
for line in reqs:
line = line.strip()
if not line or line.startswith("#"):
continue
dependency, names = line.split("#")
dependency = dependency.strip()
for name in names.split(","):
name = name.strip()
if name.endswith("!ext"):
if raw:
continue
else:
name = name[:-4]
requirements["ext"].append(dependency)
requirements[name].append(dependency)
requirements["all"].append(dependency)
return requirements
def get_setup_kwargs(raw=False):
"""Builds a dictionary of kwargs for the setup function"""
packages, requirements = get_packages_requirements(raw=raw)
@@ -69,11 +93,7 @@ def get_setup_kwargs(raw=False):
long_description_content_type="text/x-rst",
packages=packages,
install_requires=requirements,
extras_require={
"socks": "httpx[socks]",
# 3.4-3.4.3 contained some cyclical import bugs
"passport": "cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=3.0",
},
extras_require=get_optional_requirements(raw=raw),
include_package_data=True,
classifiers=[
"Development Status :: 5 - Production/Stable",
@@ -89,6 +109,7 @@ def get_setup_kwargs(raw=False):
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
],
python_requires=">=3.7",
)
+15 -11
View File
@@ -67,6 +67,10 @@ __all__ = ( # Keep this alphabetically ordered
"File",
"FileCredentials",
"ForceReply",
"ForumTopic",
"ForumTopicClosed",
"ForumTopicCreated",
"ForumTopicReopened",
"Game",
"GameHighScore",
"helpers",
@@ -175,7 +179,7 @@ __all__ = ( # Keep this alphabetically ordered
)
from . import _version
from . import _version, constants, error, helpers, request, warnings
from ._bot import Bot
from ._botcommand import BotCommand
from ._botcommandscope import (
@@ -230,6 +234,7 @@ from ._files.video import Video
from ._files.videonote import VideoNote
from ._files.voice import Voice
from ._forcereply import ForceReply
from ._forumtopic import ForumTopic, ForumTopicClosed, ForumTopicCreated, ForumTopicReopened
from ._games.callbackgame import CallbackGame
from ._games.game import Game
from ._games.gamehighscore import GameHighScore
@@ -312,6 +317,15 @@ from ._telegramobject import TelegramObject
from ._update import Update
from ._user import User
from ._userprofilephotos import UserProfilePhotos
from ._videochat import (
VideoChatEnded,
VideoChatParticipantsInvited,
VideoChatScheduled,
VideoChatStarted,
)
from ._webappdata import WebAppData
from ._webappinfo import WebAppInfo
from ._webhookinfo import WebhookInfo
#: :obj:`str`: The version of the `python-telegram-bot` library as string.
#: To get detailed information about the version number, please use :data:`__version_info__`
@@ -335,13 +349,3 @@ __bot_api_version__ = _version.__bot_api_version__
#:
#: .. versionadded:: 20.0
__bot_api_version_info__ = _version.__bot_api_version_info__
from ._videochat import (
VideoChatEnded,
VideoChatParticipantsInvited,
VideoChatScheduled,
VideoChatStarted,
)
from ._webappdata import WebAppData
from ._webappinfo import WebAppInfo
from ._webhookinfo import WebhookInfo
+2046 -2622
View File
File diff suppressed because it is too large Load Diff
+34 -4
View File
@@ -17,9 +17,12 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Bot Command."""
from typing import Any
from typing import ClassVar
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class BotCommand(TelegramObject):
@@ -30,9 +33,12 @@ class BotCommand(TelegramObject):
considered equal, if their :attr:`command` and :attr:`description` are equal.
Args:
command (:obj:`str`): Text of the command; 1-32 characters. Can contain only lowercase
command (:obj:`str`): Text of the command; :tg-const:`telegram.BotCommand.MIN_COMMAND`-
:tg-const:`telegram.BotCommand.MAX_COMMAND` characters. Can contain only lowercase
English letters, digits and underscores.
description (:obj:`str`): Description of the command; 1-256 characters.
description (:obj:`str`): Description of the command;
:tg-const:`telegram.BotCommand.MIN_DESCRIPTION`-
:tg-const:`telegram.BotCommand.MAX_DESCRIPTION` characters.
Attributes:
command (:obj:`str`): Text of the command.
@@ -42,8 +48,32 @@ class BotCommand(TelegramObject):
__slots__ = ("description", "command")
def __init__(self, command: str, description: str, **_kwargs: Any):
def __init__(self, command: str, description: str, *, api_kwargs: JSONDict = None):
super().__init__(api_kwargs=api_kwargs)
self.command = command
self.description = description
self._id_attrs = (self.command, self.description)
self._freeze()
MIN_COMMAND: ClassVar[int] = constants.BotCommandLimit.MIN_COMMAND
""":const:`telegram.constants.BotCommandLimit.MIN_COMMAND`
.. versionadded:: 20.0
"""
MAX_COMMAND: ClassVar[int] = constants.BotCommandLimit.MAX_COMMAND
""":const:`telegram.constants.BotCommandLimit.MAX_COMMAND`
.. versionadded:: 20.0
"""
MIN_DESCRIPTION: ClassVar[int] = constants.BotCommandLimit.MIN_DESCRIPTION
""":const:`telegram.constants.BotCommandLimit.MIN_DESCRIPTION`
.. versionadded:: 20.0
"""
MAX_DESCRIPTION: ClassVar[int] = constants.BotCommandLimit.MAX_DESCRIPTION
""":const:`telegram.constants.BotCommandLimit.MAX_DESCRIPTION`
.. versionadded:: 20.0
"""
+48 -48
View File
@@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
# pylint: disable=redefined-builtin
"""This module contains objects representing Telegram bot command scopes."""
from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Type, Union
from typing import TYPE_CHECKING, ClassVar, Dict, Optional, Type, Union
from telegram import constants
from telegram._telegramobject import TelegramObject
@@ -75,10 +75,13 @@ class BotCommandScope(TelegramObject):
CHAT_MEMBER: ClassVar[str] = constants.BotCommandScopeType.CHAT_MEMBER
""":const:`telegram.constants.BotCommandScopeType.CHAT_MEMBER`"""
def __init__(self, type: str, **_kwargs: Any):
def __init__(self, type: str, *, api_kwargs: JSONDict = None):
super().__init__(api_kwargs=api_kwargs)
self.type = type
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BotCommandScope"]:
"""Converts JSON data to the appropriate :class:`BotCommandScope` object, i.e. takes
@@ -107,9 +110,9 @@ class BotCommandScope(TelegramObject):
cls.CHAT_MEMBER: BotCommandScopeChatMember,
}
if cls is BotCommandScope:
return _class_mapping.get(data["type"], cls)(**data, bot=bot)
return cls(**data)
if cls is BotCommandScope 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 BotCommandScopeDefault(BotCommandScope):
@@ -119,15 +122,15 @@ class BotCommandScopeDefault(BotCommandScope):
.. _`narrower scope`: https://core.telegram.org/bots/api#determining-list-of-commands
.. versionadded:: 13.7
Attributes:
type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.DEFAULT`.
"""
__slots__ = ()
def __init__(self, **_kwargs: Any):
super().__init__(type=BotCommandScope.DEFAULT)
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.DEFAULT, api_kwargs=api_kwargs)
self._freeze()
class BotCommandScopeAllPrivateChats(BotCommandScope):
@@ -141,38 +144,39 @@ class BotCommandScopeAllPrivateChats(BotCommandScope):
__slots__ = ()
def __init__(self, **_kwargs: Any):
super().__init__(type=BotCommandScope.ALL_PRIVATE_CHATS)
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.ALL_PRIVATE_CHATS, api_kwargs=api_kwargs)
self._freeze()
class BotCommandScopeAllGroupChats(BotCommandScope):
"""Represents the scope of bot commands, covering all group and supergroup chats.
.. versionadded:: 13.7
Attributes:
type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.ALL_GROUP_CHATS`.
"""
__slots__ = ()
def __init__(self, **_kwargs: Any):
super().__init__(type=BotCommandScope.ALL_GROUP_CHATS)
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.ALL_GROUP_CHATS, api_kwargs=api_kwargs)
self._freeze()
class BotCommandScopeAllChatAdministrators(BotCommandScope):
"""Represents the scope of bot commands, covering all group and supergroup chat administrators.
.. versionadded:: 13.7
Attributes:
type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.ALL_CHAT_ADMINISTRATORS`.
"""
__slots__ = ()
def __init__(self, **_kwargs: Any):
super().__init__(type=BotCommandScope.ALL_CHAT_ADMINISTRATORS)
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.ALL_CHAT_ADMINISTRATORS, api_kwargs=api_kwargs)
self._freeze()
class BotCommandScopeChat(BotCommandScope):
@@ -184,23 +188,22 @@ class BotCommandScopeChat(BotCommandScope):
.. versionadded:: 13.7
Args:
chat_id (:obj:`str` | :obj:`int`): Unique identifier for the target chat or username of the
target supergroup (in the format ``@supergroupusername``)
chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
Attributes:
type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT`.
chat_id (:obj:`str` | :obj:`int`): Unique identifier for the target chat or username of the
target supergroup (in the format ``@supergroupusername``)
chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
"""
__slots__ = ("chat_id",)
def __init__(self, chat_id: Union[str, int], **_kwargs: Any):
super().__init__(type=BotCommandScope.CHAT)
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self._id_attrs = (self.type, self.chat_id)
def __init__(self, chat_id: Union[str, int], *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.CHAT, api_kwargs=api_kwargs)
with self._unfrozen():
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self._id_attrs = (self.type, self.chat_id)
class BotCommandScopeChatAdministrators(BotCommandScope):
@@ -213,23 +216,21 @@ class BotCommandScopeChatAdministrators(BotCommandScope):
.. versionadded:: 13.7
Args:
chat_id (:obj:`str` | :obj:`int`): Unique identifier for the target chat or username of the
target supergroup (in the format ``@supergroupusername``)
chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
Attributes:
type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT_ADMINISTRATORS`.
chat_id (:obj:`str` | :obj:`int`): Unique identifier for the target chat or username of the
target supergroup (in the format ``@supergroupusername``)
chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
"""
__slots__ = ("chat_id",)
def __init__(self, chat_id: Union[str, int], **_kwargs: Any):
super().__init__(type=BotCommandScope.CHAT_ADMINISTRATORS)
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self._id_attrs = (self.type, self.chat_id)
def __init__(self, chat_id: Union[str, int], *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.CHAT_ADMINISTRATORS, api_kwargs=api_kwargs)
with self._unfrozen():
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self._id_attrs = (self.type, self.chat_id)
class BotCommandScopeChatMember(BotCommandScope):
@@ -242,23 +243,22 @@ class BotCommandScopeChatMember(BotCommandScope):
.. versionadded:: 13.7
Args:
chat_id (:obj:`str` | :obj:`int`): Unique identifier for the target chat or username of the
target supergroup (in the format ``@supergroupusername``)
chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
user_id (:obj:`int`): Unique identifier of the target user.
Attributes:
type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT_MEMBER`.
chat_id (:obj:`str` | :obj:`int`): Unique identifier for the target chat or username of the
target supergroup (in the format ``@supergroupusername``)
chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
user_id (:obj:`int`): Unique identifier of the target user.
"""
__slots__ = ("chat_id", "user_id")
def __init__(self, chat_id: Union[str, int], user_id: int, **_kwargs: Any):
super().__init__(type=BotCommandScope.CHAT_MEMBER)
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self.user_id = user_id
self._id_attrs = (self.type, self.chat_id, self.user_id)
def __init__(self, chat_id: Union[str, int], user_id: int, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.CHAT_MEMBER, api_kwargs=api_kwargs)
with self._unfrozen():
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self.user_id = user_id
self._id_attrs = (self.type, self.chat_id, self.user_id)
+15 -13
View File
@@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
# pylint: disable=redefined-builtin
"""This module contains an object that represents a Telegram CallbackQuery"""
from typing import TYPE_CHECKING, Any, ClassVar, List, Optional, Tuple, Union
from typing import TYPE_CHECKING, ClassVar, List, Optional, Tuple, Union
from telegram import constants
from telegram._files.location import Location
@@ -57,7 +57,7 @@ class CallbackQuery(TelegramObject):
until you call :attr:`answer`. It is, therefore, necessary to react
by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user
is needed (e.g., without specifying any of the optional parameters).
* If you're using :attr:`telegram.ext.ExtBot.arbitrary_callback_data`, :attr:`data` may be
* If you're using :attr:`telegram.ext.ExtBot.callback_data_cache`, :attr:`data` may be
an instance
of :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data
associated with the button triggering the :class:`telegram.CallbackQuery` was already
@@ -79,7 +79,6 @@ class CallbackQuery(TelegramObject):
inline mode, that originated the query.
game_short_name (:obj:`str`, optional): Short name of a Game to be returned, serves as
the unique identifier for the game
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
Attributes:
id (:obj:`str`): Unique identifier for this query.
@@ -96,7 +95,7 @@ class CallbackQuery(TelegramObject):
inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in
inline mode, that originated the query.
game_short_name (:obj:`str`): Optional. Short name of a Game to be returned.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
"""
@@ -112,16 +111,17 @@ class CallbackQuery(TelegramObject):
def __init__(
self,
id: str, # pylint: disable=invalid-name
id: str,
from_user: User,
chat_instance: str,
message: Message = None,
data: str = None,
inline_message_id: str = None,
game_short_name: str = None,
bot: "Bot" = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.id = id # pylint: disable=invalid-name
self.from_user = from_user
@@ -132,10 +132,10 @@ class CallbackQuery(TelegramObject):
self.inline_message_id = inline_message_id
self.game_short_name = game_short_name
self.set_bot(bot)
self._id_attrs = (self.id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["CallbackQuery"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -144,10 +144,10 @@ class CallbackQuery(TelegramObject):
if not data:
return None
data["from_user"] = User.de_json(data.get("from"), bot)
data["from_user"] = User.de_json(data.pop("from", None), bot)
data["message"] = Message.de_json(data.get("message"), bot)
return cls(bot=bot, **data)
return super().de_json(data=data, bot=bot)
async def answer(
self,
@@ -592,7 +592,7 @@ class CallbackQuery(TelegramObject):
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> List["GameHighScore"]:
) -> Tuple["GameHighScore", ...]:
"""Shortcut for either::
await update.callback_query.message.get_game_high_score(*args, **kwargs)
@@ -608,7 +608,7 @@ class CallbackQuery(TelegramObject):
:meth:`telegram.Message.get_game_high_scores`.
Returns:
List[:class:`telegram.GameHighScore`]
Tuple[:class:`telegram.GameHighScore`]
"""
if self.inline_message_id:
@@ -726,6 +726,7 @@ class CallbackQuery(TelegramObject):
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
reply_markup: ReplyMarkup = None,
protect_content: ODVInput[bool] = DEFAULT_NONE,
message_thread_id: int = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -763,6 +764,7 @@ class CallbackQuery(TelegramObject):
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
MAX_ANSWER_TEXT_LENGTH: ClassVar[
+701 -24
View File
File diff suppressed because it is too large Load Diff
+28 -6
View File
@@ -18,9 +18,8 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the class which represents a Telegram ChatAdministratorRights."""
from typing import Any
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class ChatAdministratorRights(TelegramObject):
@@ -30,7 +29,12 @@ class ChatAdministratorRights(TelegramObject):
considered equal, if their :attr:`is_anonymous`, :attr:`can_manage_chat`,
:attr:`can_delete_messages`, :attr:`can_manage_video_chats`, :attr:`can_restrict_members`,
:attr:`can_promote_members`, :attr:`can_change_info`, :attr:`can_invite_users`,
:attr:`can_post_messages`, :attr:`can_edit_messages`, :attr:`can_pin_messages` are equal.
:attr:`can_post_messages`, :attr:`can_edit_messages`, :attr:`can_pin_messages`,
:attr:`can_manage_topics` are equal.
.. versionchanged:: 20.0
:attr:`can_manage_topics` is considered as well when comparing objects of
this type in terms of equality.
.. seealso: :meth:`Bot.set_my_default_administrator_rights`,
:meth:`Bot.get_my_default_administrator_rights`
@@ -63,6 +67,10 @@ class ChatAdministratorRights(TelegramObject):
messages of other users.
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin
messages; groups and supergroups only.
can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to create, rename, close, and reopen forum topics; supergroups only.
.. versionadded:: 20.0
Attributes:
is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden.
@@ -90,6 +98,10 @@ class ChatAdministratorRights(TelegramObject):
messages of other users.
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
messages; groups and supergroups only.
can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to create, rename, close, and reopen forum topics; supergroups only.
.. versionadded:: 20.0
"""
__slots__ = (
@@ -104,6 +116,7 @@ class ChatAdministratorRights(TelegramObject):
"can_post_messages",
"can_edit_messages",
"can_pin_messages",
"can_manage_topics",
)
def __init__(
@@ -119,8 +132,11 @@ class ChatAdministratorRights(TelegramObject):
can_post_messages: bool = None,
can_edit_messages: bool = None,
can_pin_messages: bool = None,
**_kwargs: Any,
can_manage_topics: bool = None,
*,
api_kwargs: JSONDict = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
# Required
self.is_anonymous = is_anonymous
self.can_manage_chat = can_manage_chat
@@ -134,6 +150,7 @@ class ChatAdministratorRights(TelegramObject):
self.can_post_messages = can_post_messages
self.can_edit_messages = can_edit_messages
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
self._id_attrs = (
self.is_anonymous,
@@ -147,8 +164,11 @@ class ChatAdministratorRights(TelegramObject):
self.can_post_messages,
self.can_edit_messages,
self.can_pin_messages,
self.can_manage_topics,
)
self._freeze()
@classmethod
def all_rights(cls) -> "ChatAdministratorRights":
"""
@@ -158,7 +178,7 @@ class ChatAdministratorRights(TelegramObject):
.. versionadded:: 20.0
"""
return cls(True, True, True, True, True, True, True, True, True, True, True)
return cls(True, True, True, True, True, True, True, True, True, True, True, True)
@classmethod
def no_rights(cls) -> "ChatAdministratorRights":
@@ -168,4 +188,6 @@ class ChatAdministratorRights(TelegramObject):
.. versionadded:: 20.0
"""
return cls(False, False, False, False, False, False, False, False, False, False, False)
return cls(
False, False, False, False, False, False, False, False, False, False, False, False
)
+13 -15
View File
@@ -18,11 +18,11 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents an invite link for a chat."""
import datetime
from typing import TYPE_CHECKING, Any, Optional
from typing import TYPE_CHECKING, Optional
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.datetime import from_timestamp, to_timestamp
from telegram._utils.datetime import from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@@ -56,7 +56,8 @@ class ChatInviteLink(TelegramObject):
has been expired.
member_limit (:obj:`int`, optional): Maximum number of users that can be members of the
chat simultaneously after joining the chat via this invite link;
1-:tg-const:`telegram.constants.ChatInviteLinkLimit.MEMBER_LIMIT`.
:tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
:tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`.
name (:obj:`str`, optional): Invite link name.
0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters.
@@ -65,7 +66,6 @@ class ChatInviteLink(TelegramObject):
created using this link.
.. versionadded:: 13.8
Attributes:
invite_link (:obj:`str`): The invite link. If the link was created by another chat
administrator, then the second part of the link will be replaced with ``''``.
@@ -79,7 +79,9 @@ class ChatInviteLink(TelegramObject):
expire_date (:class:`datetime.datetime`): Optional. Date when the link will expire or
has been expired.
member_limit (:obj:`int`): Optional. Maximum number of users that can be members
of the chat simultaneously after joining the chat via this invite link; 1-99999.
of the chat simultaneously after joining the chat via this invite link;
:tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
:tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`.
name (:obj:`str`): Optional. Invite link name.
.. versionadded:: 13.8
@@ -113,8 +115,10 @@ class ChatInviteLink(TelegramObject):
member_limit: int = None,
name: str = None,
pending_join_request_count: int = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.invite_link = invite_link
self.creator = creator
@@ -137,6 +141,8 @@ class ChatInviteLink(TelegramObject):
self.is_revoked,
)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatInviteLink"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -148,12 +154,4 @@ class ChatInviteLink(TelegramObject):
data["creator"] = User.de_json(data.get("creator"), bot)
data["expire_date"] = from_timestamp(data.get("expire_date", None))
return cls(**data)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data["expire_date"] = to_timestamp(self.expire_date)
return data
return super().de_json(data=data, bot=bot)
+9 -16
View File
@@ -18,13 +18,13 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram ChatJoinRequest."""
import datetime
from typing import TYPE_CHECKING, Any, Optional
from typing import TYPE_CHECKING, Optional
from telegram._chat import Chat
from telegram._chatinvitelink import ChatInviteLink
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.datetime import from_timestamp, to_timestamp
from telegram._utils.datetime import from_timestamp
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
@@ -53,7 +53,6 @@ class ChatJoinRequest(TelegramObject):
bio (:obj:`str`, optional): Bio of the user.
invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link that was used
by the user to send the join request.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
Attributes:
chat (:class:`telegram.Chat`): Chat to which the request was sent.
@@ -74,9 +73,10 @@ class ChatJoinRequest(TelegramObject):
date: datetime.datetime,
bio: str = None,
invite_link: ChatInviteLink = None,
bot: "Bot" = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.chat = chat
self.from_user = from_user
@@ -86,9 +86,10 @@ class ChatJoinRequest(TelegramObject):
self.bio = bio
self.invite_link = invite_link
self.set_bot(bot)
self._id_attrs = (self.chat, self.from_user, self.date)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatJoinRequest"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -98,19 +99,11 @@ class ChatJoinRequest(TelegramObject):
return None
data["chat"] = Chat.de_json(data.get("chat"), bot)
data["from_user"] = User.de_json(data.get("from"), bot)
data["from_user"] = User.de_json(data.pop("from", None), bot)
data["date"] = from_timestamp(data.get("date", None))
data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot)
return cls(bot=bot, **data)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data["date"] = to_timestamp(self.date)
return data
return super().de_json(data=data, bot=bot)
async def approve(
self,
+22 -6
View File
@@ -18,8 +18,9 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a location to which a chat is connected."""
from typing import TYPE_CHECKING, Any, Optional
from typing import TYPE_CHECKING, ClassVar, Optional
from telegram import constants
from telegram._files.location import Location
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
@@ -37,9 +38,9 @@ class ChatLocation(TelegramObject):
Args:
location (:class:`telegram.Location`): The location to which the supergroup is connected.
Can't be a live location.
address (:obj:`str`): Location address; 1-64 characters, as defined by the chat owner
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
address (:obj:`str`): Location address;
:tg-const:`telegram.ChatLocation.MIN_ADDRESS`-
:tg-const:`telegram.ChatLocation.MAX_ADDRESS` characters, as defined by the chat owner
Attributes:
location (:class:`telegram.Location`): The location to which the supergroup is connected.
address (:obj:`str`): Location address, as defined by the chat owner
@@ -52,13 +53,17 @@ class ChatLocation(TelegramObject):
self,
location: Location,
address: str,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.location = location
self.address = address
self._id_attrs = (self.location,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatLocation"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -69,4 +74,15 @@ class ChatLocation(TelegramObject):
data["location"] = Location.de_json(data.get("location"), bot)
return cls(bot=bot, **data)
return super().de_json(data=data, bot=bot)
MIN_ADDRESS: ClassVar[int] = constants.LocationLimit.MIN_CHAT_LOCATION_ADDRESS
""":const:`telegram.constants.LocationLimit.MIN_CHAT_LOCATION_ADDRESS`
.. versionadded:: 20.0
"""
MAX_ADDRESS: ClassVar[int] = constants.LocationLimit.MAX_CHAT_LOCATION_ADDRESS
""":const:`telegram.constants.LocationLimit.MAX_CHAT_LOCATION_ADDRESS`
.. versionadded:: 20.0
"""
+114 -56
View File
@@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, ClassVar, Dict, Optional, Type
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.datetime import from_timestamp, to_timestamp
from telegram._utils.datetime import from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@@ -44,6 +44,9 @@ class ChatMember(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`user` and :attr:`status` are equal.
Examples:
:any:`Chat Member Bot <examples.chatmemberbot>`
.. versionchanged:: 20.0
* As of Bot API 5.3, :class:`ChatMember` is nothing but the base class for the subclasses
@@ -81,13 +84,22 @@ class ChatMember(TelegramObject):
RESTRICTED: ClassVar[str] = constants.ChatMemberStatus.RESTRICTED
""":const:`telegram.constants.ChatMemberStatus.RESTRICTED`"""
def __init__(self, user: User, status: str, **_kwargs: object):
def __init__(
self,
user: User,
status: str,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required by all subclasses
self.user = user
self.status = status
self._id_attrs = (self.user, self.status)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatMember"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -96,9 +108,6 @@ class ChatMember(TelegramObject):
if not data:
return None
data["user"] = User.de_json(data.get("user"), bot)
data["until_date"] = from_timestamp(data.get("until_date", None))
_class_mapping: Dict[str, Type["ChatMember"]] = {
cls.OWNER: ChatMemberOwner,
cls.ADMINISTRATOR: ChatMemberAdministrator,
@@ -108,18 +117,14 @@ class ChatMember(TelegramObject):
cls.BANNED: ChatMemberBanned,
}
if cls is ChatMember:
return _class_mapping.get(data["status"], cls)(**data, bot=bot)
return cls(**data)
if cls is ChatMember and data.get("status") in _class_mapping:
return _class_mapping[data.pop("status")].de_json(data=data, bot=bot)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data["user"] = User.de_json(data.get("user"), bot)
if "until_date" in data:
data["until_date"] = from_timestamp(data["until_date"])
if data.get("until_date", False):
data["until_date"] = to_timestamp(data["until_date"])
return data
return super().de_json(data=data, bot=bot)
class ChatMemberOwner(ChatMember):
@@ -152,11 +157,13 @@ class ChatMemberOwner(ChatMember):
user: User,
is_anonymous: bool,
custom_title: str = None,
**_kwargs: object,
*,
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.OWNER, user=user)
self.is_anonymous = is_anonymous
self.custom_title = custom_title
super().__init__(status=ChatMember.OWNER, user=user, api_kwargs=api_kwargs)
with self._unfrozen():
self.is_anonymous = is_anonymous
self.custom_title = custom_title
class ChatMemberAdministrator(ChatMember):
@@ -165,9 +172,12 @@ class ChatMemberAdministrator(ChatMember):
.. versionadded:: 13.7
.. versionchanged:: 20.0
Argument and attribute ``can_manage_voice_chats`` were renamed to
:paramref:`can_manage_video_chats` and :attr:`can_manage_video_chats` in accordance to
Bot API 6.0.
* Argument and attribute ``can_manage_voice_chats`` were renamed to
:paramref:`can_manage_video_chats` and :attr:`can_manage_video_chats` in accordance to
Bot API 6.0.
* The argument :paramref:`can_manage_topics` was added, which changes the position of the
optional argument :paramref:`custom_title`.
Args:
user (:class:`telegram.User`): Information about the user.
@@ -202,6 +212,10 @@ class ChatMemberAdministrator(ChatMember):
messages; channels only.
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to pin messages; groups and supergroups only.
can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to create, rename, close, and reopen forum topics; supergroups only.
.. versionadded:: 20.0
custom_title (:obj:`str`, optional): Custom title for this user.
Attributes:
@@ -239,6 +253,10 @@ class ChatMemberAdministrator(ChatMember):
messages; channels only.
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to pin messages; groups and supergroups only.
can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to create, rename, close, and reopen forum topics; supergroups only
.. versionadded:: 20.0
custom_title (:obj:`str`): Optional. Custom title for this user.
"""
@@ -255,6 +273,7 @@ class ChatMemberAdministrator(ChatMember):
"can_post_messages",
"can_edit_messages",
"can_pin_messages",
"can_manage_topics",
"custom_title",
)
@@ -273,23 +292,27 @@ class ChatMemberAdministrator(ChatMember):
can_post_messages: bool = None,
can_edit_messages: bool = None,
can_pin_messages: bool = None,
can_manage_topics: bool = None,
custom_title: str = None,
**_kwargs: object,
*,
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.ADMINISTRATOR, user=user)
self.can_be_edited = can_be_edited
self.is_anonymous = is_anonymous
self.can_manage_chat = can_manage_chat
self.can_delete_messages = can_delete_messages
self.can_manage_video_chats = can_manage_video_chats
self.can_restrict_members = can_restrict_members
self.can_promote_members = can_promote_members
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_post_messages = can_post_messages
self.can_edit_messages = can_edit_messages
self.can_pin_messages = can_pin_messages
self.custom_title = custom_title
super().__init__(status=ChatMember.ADMINISTRATOR, user=user, api_kwargs=api_kwargs)
with self._unfrozen():
self.can_be_edited = can_be_edited
self.is_anonymous = is_anonymous
self.can_manage_chat = can_manage_chat
self.can_delete_messages = can_delete_messages
self.can_manage_video_chats = can_manage_video_chats
self.can_restrict_members = can_restrict_members
self.can_promote_members = can_promote_members
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_post_messages = can_post_messages
self.can_edit_messages = can_edit_messages
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
self.custom_title = custom_title
class ChatMemberMember(ChatMember):
@@ -311,8 +334,14 @@ class ChatMemberMember(ChatMember):
__slots__ = ()
def __init__(self, user: User, **_kwargs: object):
super().__init__(status=ChatMember.MEMBER, user=user)
def __init__(
self,
user: User,
*,
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.MEMBER, user=user, api_kwargs=api_kwargs)
self._freeze()
class ChatMemberRestricted(ChatMember):
@@ -321,6 +350,9 @@ class ChatMemberRestricted(ChatMember):
in the chat. Supergroups only.
.. versionadded:: 13.7
.. versionchanged:: 20.0
The argument :paramref:`can_manage_topics` was added, which changes the position of the
optional argument :paramref:`until_date`.
Args:
user (:class:`telegram.User`): Information about the user.
@@ -342,6 +374,10 @@ class ChatMemberRestricted(ChatMember):
to send animations, games, stickers and use inline bots.
can_add_web_page_previews (:obj:`bool`): :obj:`True`, if the user is
allowed to add web page previews to their messages.
can_manage_topics (:obj:`bool`): :obj:`True`, if the user is allowed to create
forum topics.
.. versionadded:: 20.0
until_date (:class:`datetime.datetime`): Date when restrictions
will be lifted for this user.
@@ -367,6 +403,10 @@ class ChatMemberRestricted(ChatMember):
to send animations, games, stickers and use inline bots.
can_add_web_page_previews (:obj:`bool`): :obj:`True`, if the user is
allowed to add web page previews to their messages.
can_manage_topics (:obj:`bool`): :obj:`True`, if the user is allowed to create
forum topics.
.. versionadded:: 20.0
until_date (:class:`datetime.datetime`): Date when restrictions
will be lifted for this user.
@@ -382,6 +422,7 @@ class ChatMemberRestricted(ChatMember):
"can_send_polls",
"can_send_other_messages",
"can_add_web_page_previews",
"can_manage_topics",
"until_date",
)
@@ -397,20 +438,24 @@ class ChatMemberRestricted(ChatMember):
can_send_polls: bool,
can_send_other_messages: bool,
can_add_web_page_previews: bool,
can_manage_topics: bool,
until_date: datetime.datetime,
**_kwargs: object,
*,
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.RESTRICTED, user=user)
self.is_member = is_member
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_pin_messages = can_pin_messages
self.can_send_messages = can_send_messages
self.can_send_media_messages = can_send_media_messages
self.can_send_polls = can_send_polls
self.can_send_other_messages = can_send_other_messages
self.can_add_web_page_previews = can_add_web_page_previews
self.until_date = until_date
super().__init__(status=ChatMember.RESTRICTED, user=user, api_kwargs=api_kwargs)
with self._unfrozen():
self.is_member = is_member
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_pin_messages = can_pin_messages
self.can_send_messages = can_send_messages
self.can_send_media_messages = can_send_media_messages
self.can_send_polls = can_send_polls
self.can_send_other_messages = can_send_other_messages
self.can_add_web_page_previews = can_add_web_page_previews
self.can_manage_topics = can_manage_topics
self.until_date = until_date
class ChatMemberLeft(ChatMember):
@@ -431,8 +476,14 @@ class ChatMemberLeft(ChatMember):
__slots__ = ()
def __init__(self, user: User, **_kwargs: object):
super().__init__(status=ChatMember.LEFT, user=user)
def __init__(
self,
user: User,
*,
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.LEFT, user=user, api_kwargs=api_kwargs)
self._freeze()
class ChatMemberBanned(ChatMember):
@@ -458,6 +509,13 @@ class ChatMemberBanned(ChatMember):
__slots__ = ("until_date",)
def __init__(self, user: User, until_date: datetime.datetime, **_kwargs: object):
super().__init__(status=ChatMember.BANNED, user=user)
self.until_date = until_date
def __init__(
self,
user: User,
until_date: datetime.datetime,
*,
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.BANNED, user=user, api_kwargs=api_kwargs)
with self._unfrozen():
self.until_date = until_date
+12 -14
View File
@@ -18,14 +18,14 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram ChatMemberUpdated."""
import datetime
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
from typing import TYPE_CHECKING, Dict, Optional, Tuple, Union
from telegram._chat import Chat
from telegram._chatinvitelink import ChatInviteLink
from telegram._chatmember import ChatMember
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.datetime import from_timestamp, to_timestamp
from telegram._utils.datetime import from_timestamp
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@@ -44,6 +44,9 @@ class ChatMemberUpdated(TelegramObject):
Note:
In Python :keyword:`from` is a reserved word use :paramref:`from_user` instead.
Examples:
:any:`Chat Member Bot <examples.chatmemberbot>`
Args:
chat (:class:`telegram.Chat`): Chat the user belongs to.
from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
@@ -83,8 +86,10 @@ class ChatMemberUpdated(TelegramObject):
old_chat_member: ChatMember,
new_chat_member: ChatMember,
invite_link: ChatInviteLink = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.chat = chat
self.from_user = from_user
@@ -103,6 +108,8 @@ class ChatMemberUpdated(TelegramObject):
self.new_chat_member,
)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatMemberUpdated"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -112,22 +119,13 @@ class ChatMemberUpdated(TelegramObject):
return None
data["chat"] = Chat.de_json(data.get("chat"), bot)
data["from_user"] = User.de_json(data.get("from"), bot)
data["from_user"] = User.de_json(data.pop("from", None), bot)
data["date"] = from_timestamp(data.get("date"))
data["old_chat_member"] = ChatMember.de_json(data.get("old_chat_member"), bot)
data["new_chat_member"] = ChatMember.de_json(data.get("new_chat_member"), bot)
data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot)
return cls(**data)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
# Required
data["date"] = to_timestamp(self.date)
return data
return super().de_json(data=data, bot=bot)
def _get_attribute_difference(self, attribute: str) -> Tuple[object, object]:
try:
+29 -7
View File
@@ -18,9 +18,8 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram ChatPermission."""
from typing import Any
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class ChatPermissions(TelegramObject):
@@ -29,12 +28,17 @@ class ChatPermissions(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`can_send_messages`, :attr:`can_send_media_messages`,
:attr:`can_send_polls`, :attr:`can_send_other_messages`, :attr:`can_add_web_page_previews`,
:attr:`can_change_info`, :attr:`can_invite_users` and :attr:`can_pin_messages` are equal.
:attr:`can_change_info`, :attr:`can_invite_users`, :attr:`can_pin_messages`, and
:attr:`can_manage_topics` are equal.
.. versionchanged:: 20.0
:attr:`can_manage_topics` is considered as well when comparing objects of
this type in terms of equality.
Note:
Though not stated explicitly in the official docs, Telegram changes not only the
permissions that are set, but also sets all the others to :obj:`False`. However, since not
documented, this behaviour may change unbeknown to PTB.
documented, this behavior may change unbeknown to PTB.
Args:
can_send_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send text
@@ -55,6 +59,11 @@ class ChatPermissions(TelegramObject):
users to the chat.
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin
messages. Ignored in public supergroups.
can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to create forum topics. If omitted defaults to the value of
:attr:`can_pin_messages`.
.. versionadded:: 20.0
Attributes:
can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text
@@ -75,6 +84,11 @@ class ChatPermissions(TelegramObject):
new users to the chat.
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
messages. Ignored in public supergroups.
can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to create forum topics. If omitted defaults to the value of
:attr:`can_pin_messages`.
.. versionadded:: 20.0
"""
@@ -87,6 +101,7 @@ class ChatPermissions(TelegramObject):
"can_change_info",
"can_pin_messages",
"can_add_web_page_previews",
"can_manage_topics",
)
def __init__(
@@ -99,8 +114,11 @@ class ChatPermissions(TelegramObject):
can_change_info: bool = None,
can_invite_users: bool = None,
can_pin_messages: bool = None,
**_kwargs: Any,
can_manage_topics: bool = None,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.can_send_messages = can_send_messages
self.can_send_media_messages = can_send_media_messages
@@ -110,6 +128,7 @@ class ChatPermissions(TelegramObject):
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
self._id_attrs = (
self.can_send_messages,
@@ -120,8 +139,11 @@ class ChatPermissions(TelegramObject):
self.can_change_info,
self.can_invite_users,
self.can_pin_messages,
self.can_manage_topics,
)
self._freeze()
@classmethod
def all_permissions(cls) -> "ChatPermissions":
"""
@@ -132,7 +154,7 @@ class ChatPermissions(TelegramObject):
.. versionadded:: 20.0
"""
return cls(True, True, True, True, True, True, True, True)
return cls(True, True, True, True, True, True, True, True, True)
@classmethod
def no_permissions(cls) -> "ChatPermissions":
@@ -142,4 +164,4 @@ class ChatPermissions(TelegramObject):
.. versionadded:: 20.0
"""
return cls(False, False, False, False, False, False, False, False)
return cls(False, False, False, False, False, False, False, False, False)
+9 -5
View File
@@ -19,7 +19,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram ChosenInlineResult."""
from typing import TYPE_CHECKING, Any, Optional
from typing import TYPE_CHECKING, Optional
from telegram._files.location import Location
from telegram._telegramobject import TelegramObject
@@ -52,7 +52,6 @@ class ChosenInlineResult(TelegramObject):
only if there is an inline keyboard attached to the message. Will be also received in
callback queries and can be used to edit the message.
query (:obj:`str`): The query that was used to obtain the result.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
result_id (:obj:`str`): The unique identifier for the result that was chosen.
@@ -72,8 +71,11 @@ class ChosenInlineResult(TelegramObject):
query: str,
location: Location = None,
inline_message_id: str = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.result_id = result_id
self.from_user = from_user
@@ -84,6 +86,8 @@ class ChosenInlineResult(TelegramObject):
self._id_attrs = (self.result_id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChosenInlineResult"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -93,8 +97,8 @@ class ChosenInlineResult(TelegramObject):
return None
# Required
data["from_user"] = User.de_json(data.pop("from"), bot)
data["from_user"] = User.de_json(data.pop("from", None), bot)
# Optionals
data["location"] = Location.de_json(data.get("location"), bot)
return cls(**data)
return super().de_json(data=data, bot=bot)
+76 -17
View File
@@ -17,10 +17,11 @@
# 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 Dice."""
from typing import Any, ClassVar, List
from typing import ClassVar, List
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class Dice(TelegramObject):
@@ -33,30 +34,43 @@ class Dice(TelegramObject):
considered equal, if their :attr:`value` and :attr:`emoji` are equal.
Note:
If :attr:`emoji` is "🎯", a value of 6 currently represents a bullseye, while a value of 1
indicates that the dartboard was missed. However, this behaviour is undocumented and might
be changed by Telegram.
If :attr:`emoji` is :tg-const:`telegram.Dice.DARTS`, a value of 6 currently
represents a bullseye, while a value of 1 indicates that the dartboard was missed.
However, this behaviour is undocumented and might be changed by Telegram.
If :attr:`emoji` is "🏀", a value of 4 or 5 currently score a basket, while a value of 1 to
3 indicates that the basket was missed. However, this behaviour is undocumented and might
be changed by Telegram.
If :attr:`emoji` is :tg-const:`telegram.Dice.BASKETBALL`, a value of 4 or 5
currently score a basket, while a value of 1 to 3 indicates that the basket was missed.
However, this behaviour is undocumented and might be changed by Telegram.
If :attr:`emoji` is "", a value of 4 to 5 currently scores a goal, while a value of 1 to
3 indicates that the goal was missed. However, this behaviour is undocumented and might
be changed by Telegram.
If :attr:`emoji` is :tg-const:`telegram.Dice.FOOTBALL`, a value of 4 to 5
currently scores a goal, while a value of 1 to 3 indicates that the goal was missed.
However, this behaviour is undocumented and might be changed by Telegram.
If :attr:`emoji` is "🎳", a value of 6 knocks all the pins, while a value of 1 means all
the pins were missed. However, this behaviour is undocumented and might be changed by
Telegram.
If :attr:`emoji` is :tg-const:`telegram.Dice.BOWLING`, a value of 6 knocks
all the pins, while a value of 1 means all the pins were missed.
However, this behaviour is undocumented and might be changed by Telegram.
If :attr:`emoji` is "🎰", each value corresponds to a unique combination of symbols, which
If :attr:`emoji` is :tg-const:`telegram.Dice.SLOT_MACHINE`, each value
corresponds to a unique combination of symbols, which
can be found at our `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki\
/Code-snippets#map-a-slot-machine-dice-value-to-the-corresponding-symbols>`_.
However, this behaviour is undocumented and might be changed by Telegram.
..
In args, some links for limits of `value` intentionally point to constants for only
one emoji of a group to avoid duplication. For example, maximum value for Dice, Darts and
Bowling is linked to a constant for Bowling.
Args:
value (:obj:`int`): Value of the dice. 1-6 for dice, darts and bowling balls, 1-5 for
basketball and football/soccer ball, 1-64 for slot machine.
value (:obj:`int`): Value of the dice.
:tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BOWLING`
for :tg-const:`telegram.Dice.DICE`, :tg-const:`telegram.Dice.DARTS` and
:tg-const:`telegram.Dice.BOWLING` base emoji,
:tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BASKETBALL`
for :tg-const:`telegram.Dice.BASKETBALL` and :tg-const:`telegram.Dice.FOOTBALL`
base emoji,
:tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_SLOT_MACHINE`
for :tg-const:`telegram.Dice.SLOT_MACHINE` base emoji.
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
Attributes:
@@ -67,12 +81,15 @@ class Dice(TelegramObject):
__slots__ = ("emoji", "value")
def __init__(self, value: int, emoji: str, **_kwargs: Any):
def __init__(self, value: int, emoji: str, *, api_kwargs: JSONDict = None):
super().__init__(api_kwargs=api_kwargs)
self.value = value
self.emoji = emoji
self._id_attrs = (self.value, self.emoji)
self._freeze()
DICE: ClassVar[str] = constants.DiceEmoji.DICE # skipcq: PTC-W0052
""":const:`telegram.constants.DiceEmoji.DICE`"""
DARTS: ClassVar[str] = constants.DiceEmoji.DARTS
@@ -91,3 +108,45 @@ class Dice(TelegramObject):
"""
ALL_EMOJI: ClassVar[List[str]] = list(constants.DiceEmoji)
"""List[:obj:`str`]: A list of all available dice emoji."""
MIN_VALUE: ClassVar[int] = constants.DiceLimit.MIN_VALUE
""":const:`telegram.constants.DiceLimit.MIN_VALUE`
.. versionadded:: 20.0
"""
MAX_VALUE_BOWLING: ClassVar[int] = constants.DiceLimit.MAX_VALUE_BOWLING
""":const:`telegram.constants.DiceLimit.MAX_VALUE_BOWLING`
.. versionadded:: 20.0
"""
MAX_VALUE_DARTS: ClassVar[int] = constants.DiceLimit.MAX_VALUE_DARTS
""":const:`telegram.constants.DiceLimit.MAX_VALUE_DARTS`
.. versionadded:: 20.0
"""
MAX_VALUE_DICE: ClassVar[int] = constants.DiceLimit.MAX_VALUE_DICE
""":const:`telegram.constants.DiceLimit.MAX_VALUE_DICE`
.. versionadded:: 20.0
"""
MAX_VALUE_BASKETBALL: ClassVar[int] = constants.DiceLimit.MAX_VALUE_BASKETBALL
""":const:`telegram.constants.DiceLimit.MAX_VALUE_BASKETBALL`
.. versionadded:: 20.0
"""
MAX_VALUE_FOOTBALL: ClassVar[int] = constants.DiceLimit.MAX_VALUE_FOOTBALL
""":const:`telegram.constants.DiceLimit.MAX_VALUE_FOOTBALL`
.. versionadded:: 20.0
"""
MAX_VALUE_SLOT_MACHINE: ClassVar[int] = constants.DiceLimit.MAX_VALUE_SLOT_MACHINE
""":const:`telegram.constants.DiceLimit.MAX_VALUE_SLOT_MACHINE`
.. versionadded:: 20.0
"""
+11 -6
View File
@@ -24,7 +24,7 @@ from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING:
from telegram import Bot, File
from telegram import File
class _BaseMedium(TelegramObject):
@@ -39,7 +39,6 @@ class _BaseMedium(TelegramObject):
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`int`, optional): File size.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
Attributes:
file_id (:obj:`str`): File identifier.
@@ -47,21 +46,27 @@ class _BaseMedium(TelegramObject):
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`int`): Optional. File size.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
__slots__ = ("file_id", "file_size", "file_unique_id")
def __init__(
self, file_id: str, file_unique_id: str, file_size: int = None, bot: "Bot" = None
self,
file_id: str,
file_unique_id: str,
file_size: int = None,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.file_id: str = str(file_id)
self.file_unique_id = str(file_unique_id)
# Optionals
self.file_size = file_size
self.set_bot(bot)
self._id_attrs = (self.file_unique_id,)
@@ -74,7 +79,7 @@ class _BaseMedium(TelegramObject):
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> "File":
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
"""Convenience wrapper over :meth:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+11 -6
View File
@@ -45,7 +45,6 @@ class _BaseThumbedMedium(_BaseMedium):
Can't be used to download or reuse the file.
file_size (:obj:`int`, optional): File size.
thumb (:class:`telegram.PhotoSize`, optional): Thumbnail as defined by sender.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
Attributes:
file_id (:obj:`str`): File identifier.
@@ -54,7 +53,7 @@ class _BaseThumbedMedium(_BaseMedium):
Can't be used to download or reuse the file.
file_size (:obj:`int`): Optional. File size.
thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail as defined by sender.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@@ -66,10 +65,14 @@ class _BaseThumbedMedium(_BaseMedium):
file_unique_id: str,
file_size: int = None,
thumb: PhotoSize = None,
bot: "Bot" = None,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id, file_unique_id=file_unique_id, file_size=file_size, bot=bot
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
api_kwargs=api_kwargs,
)
self.thumb = thumb
@@ -83,6 +86,8 @@ class _BaseThumbedMedium(_BaseMedium):
if not data:
return None
data["thumb"] = PhotoSize.de_json(data.get("thumb"), bot)
# In case this wasn't already done by the subclass
if not isinstance(data.get("thumb"), PhotoSize):
data["thumb"] = PhotoSize.de_json(data.get("thumb"), bot)
return cls(bot=bot, **data)
return super().de_json(data=data, bot=bot)
+13 -17
View File
@@ -17,13 +17,10 @@
# 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 Animation."""
from typing import TYPE_CHECKING, Any
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.photosize import PhotoSize
if TYPE_CHECKING:
from telegram import Bot
from telegram._utils.types import JSONDict
class Animation(_BaseThumbedMedium):
@@ -45,8 +42,6 @@ class Animation(_BaseThumbedMedium):
file_name (:obj:`str`, optional): Original animation filename as defined by sender.
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
file_size (:obj:`int`, optional): File size in bytes.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): File identifier.
@@ -60,7 +55,7 @@ class Animation(_BaseThumbedMedium):
file_name (:obj:`str`): Optional. Original animation filename as defined by sender.
mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender.
file_size (:obj:`int`): Optional. File size in bytes.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@@ -77,20 +72,21 @@ class Animation(_BaseThumbedMedium):
file_name: str = None,
mime_type: str = None,
file_size: int = None,
bot: "Bot" = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
api_kwargs=api_kwargs,
)
# Required
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
self.file_name = file_name
with self._unfrozen():
# Required
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
self.file_name = file_name
+14 -18
View File
@@ -18,13 +18,9 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Audio."""
from typing import TYPE_CHECKING, Any
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.photosize import PhotoSize
if TYPE_CHECKING:
from telegram import Bot
from telegram._utils.types import JSONDict
class Audio(_BaseThumbedMedium):
@@ -33,6 +29,7 @@ class Audio(_BaseThumbedMedium):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`file_unique_id` is equal.
Args:
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
@@ -47,8 +44,6 @@ class Audio(_BaseThumbedMedium):
file_size (:obj:`int`, optional): File size in bytes.
thumb (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to
which the music file belongs.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): Identifier for this file.
@@ -64,7 +59,7 @@ class Audio(_BaseThumbedMedium):
file_size (:obj:`int`): Optional. File size in bytes.
thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to
which the music file belongs.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@@ -80,21 +75,22 @@ class Audio(_BaseThumbedMedium):
mime_type: str = None,
file_size: int = None,
thumb: PhotoSize = None,
bot: "Bot" = None,
file_name: str = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
api_kwargs=api_kwargs,
)
# Required
self.duration = duration
# Optional
self.performer = performer
self.title = title
self.mime_type = mime_type
self.file_name = file_name
with self._unfrozen():
# Required
self.duration = duration
# Optional
self.performer = performer
self.title = title
self.mime_type = mime_type
self.file_name = file_name
+50 -28
View File
@@ -17,14 +17,15 @@
# 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 ChatPhoto."""
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, ClassVar
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING:
from telegram import Bot, File
from telegram import File
class ChatPhoto(TelegramObject):
@@ -35,32 +36,39 @@ class ChatPhoto(TelegramObject):
equal.
Args:
small_file_id (:obj:`str`): Unique file identifier of small (160x160) chat photo. This
file_id can be used only for photo download and only for as long
small_file_id (:obj:`str`): Unique file identifier of small
(:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
chat photo. This file_id can be used only for photo download and only for as long
as the photo is not changed.
small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo,
which is supposed to be the same over time and for different bots.
small_file_unique_id (:obj:`str`): Unique file identifier of small
(:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
chat photo, which is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
big_file_id (:obj:`str`): Unique file identifier of big (640x640) chat photo. This file_id
can be used only for photo download and only for as long as the photo is not changed.
big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo,
which is supposed to be the same over time and for different bots.
big_file_id (:obj:`str`): Unique file identifier of big
(:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
chat photo. This file_id can be used only for photo download and only for as long as
the photo is not changed.
big_file_unique_id (:obj:`str`): Unique file identifier of big
(:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
chat photo, which is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
small_file_id (:obj:`str`): File identifier of small (160x160) chat photo.
This file_id can be used only for photo download and only for as long
small_file_id (:obj:`str`): File identifier of small
(:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
chat photo. This file_id can be used only for photo download and only for as long
as the photo is not changed.
small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo,
which is supposed to be the same over time and for different bots.
small_file_unique_id (:obj:`str`): Unique file identifier of small
(:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
chat photo, which is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
big_file_id (:obj:`str`): File identifier of big (640x640) chat photo.
This file_id can be used only for photo download and only for as long as
big_file_id (:obj:`str`): File identifier of big
(:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
chat photo. This file_id can be used only for photo download and only for as long as
the photo is not changed.
big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo,
which is supposed to be the same over time and for different bots.
big_file_unique_id (:obj:`str`): Unique file identifier of big
(:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
chat photo, which is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
"""
@@ -78,21 +86,22 @@ class ChatPhoto(TelegramObject):
small_file_unique_id: str,
big_file_id: str,
big_file_unique_id: str,
bot: "Bot" = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.small_file_id = small_file_id
self.small_file_unique_id = small_file_unique_id
self.big_file_id = big_file_id
self.big_file_unique_id = big_file_unique_id
self.set_bot(bot)
self._id_attrs = (
self.small_file_unique_id,
self.big_file_unique_id,
)
self._freeze()
async def get_small_file(
self,
*,
@@ -102,8 +111,9 @@ class ChatPhoto(TelegramObject):
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> "File":
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
small (160x160) chat photo
"""Convenience wrapper over :meth:`telegram.Bot.get_file` for getting the small
(:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
chat photo
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
@@ -132,8 +142,9 @@ class ChatPhoto(TelegramObject):
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> "File":
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
big (640x640) chat photo
"""Convenience wrapper over :meth:`telegram.Bot.get_file` for getting the
big (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
chat photo
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
@@ -152,3 +163,14 @@ class ChatPhoto(TelegramObject):
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
SIZE_SMALL: ClassVar[int] = constants.ChatPhotoSize.SMALL
""":const:`telegram.constants.ChatPhotoSize.SMALL`
.. versionadded:: 20.0
"""
SIZE_BIG: ClassVar[int] = constants.ChatPhotoSize.BIG
""":const:`telegram.constants.ChatPhotoSize.BIG`
.. versionadded:: 20.0
"""
+6 -4
View File
@@ -18,9 +18,8 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Contact."""
from typing import Any
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class Contact(TelegramObject):
@@ -35,7 +34,6 @@ class Contact(TelegramObject):
last_name (:obj:`str`, optional): Contact's last name.
user_id (:obj:`int`, optional): Contact's user identifier in Telegram.
vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
phone_number (:obj:`str`): Contact's phone number.
@@ -55,8 +53,10 @@ class Contact(TelegramObject):
last_name: str = None,
user_id: int = None,
vcard: str = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.phone_number = str(phone_number)
self.first_name = first_name
@@ -66,3 +66,5 @@ class Contact(TelegramObject):
self.vcard = vcard
self._id_attrs = (self.phone_number,)
self._freeze()
+9 -14
View File
@@ -18,13 +18,9 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Document."""
from typing import TYPE_CHECKING, Any
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.photosize import PhotoSize
if TYPE_CHECKING:
from telegram import Bot
from telegram._utils.types import JSONDict
class Document(_BaseThumbedMedium):
@@ -43,8 +39,6 @@ class Document(_BaseThumbedMedium):
file_name (:obj:`str`, optional): Original filename as defined by sender.
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
file_size (:obj:`int`, optional): File size in bytes.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): File identifier.
@@ -55,7 +49,7 @@ class Document(_BaseThumbedMedium):
file_name (:obj:`str`): Original filename.
mime_type (:obj:`str`): Optional. MIME type of the file.
file_size (:obj:`int`): Optional. File size in bytes.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@@ -69,16 +63,17 @@ class Document(_BaseThumbedMedium):
file_name: str = None,
mime_type: str = None,
file_size: int = None,
bot: "Bot" = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
api_kwargs=api_kwargs,
)
# Optional
self.mime_type = mime_type
self.file_name = file_name
with self._unfrozen():
# Optional
self.mime_type = mime_type
self.file_name = file_name
+161 -65
View File
@@ -21,32 +21,36 @@ import shutil
import urllib.parse as urllib_parse
from base64 import b64decode
from pathlib import Path
from typing import IO, TYPE_CHECKING, Any, Optional, Union
from typing import TYPE_CHECKING, BinaryIO, Optional
from telegram._passport.credentials import decrypt
from telegram._telegramobject import TelegramObject
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.files import is_local_file
from telegram._utils.types import FilePathInput, ODVInput
from telegram._utils.types import FilePathInput, JSONDict, ODVInput
if TYPE_CHECKING:
from telegram import Bot, FileCredentials
from telegram import FileCredentials
class File(TelegramObject):
"""
This object represents a file ready to be downloaded. The file can be downloaded with
:attr:`download`. It is guaranteed that the link will be valid for at least 1 hour. When the
link expires, a new one can be requested by calling :meth:`telegram.Bot.get_file`.
This object represents a file ready to be downloaded. The file can be e.g. downloaded with
:attr:`download_to_drive`. It is guaranteed that the link will be valid for at least 1 hour.
When the link expires, a new one can be requested by calling :meth:`telegram.Bot.get_file`.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`file_unique_id` is equal.
.. versionchanged:: 20.0:
``download`` was split into :meth:`download_to_drive` and :meth:`download_to_memory`.
Note:
* Maximum file size to download is
:tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD`.
:tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD`.
* If you obtain an instance of this class from :attr:`telegram.PassportFile.get_file`,
then it will automatically be decrypted as it downloads when you call :meth:`download()`.
then it will automatically be decrypted as it downloads when you call e.g.
:meth:`download_to_drive`.
Args:
file_id (:obj:`str`): Identifier for this file, which can be used to download
@@ -55,9 +59,8 @@ class File(TelegramObject):
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`int`, optional): Optional. File size in bytes, if known.
file_path (:obj:`str`, optional): File path. Use :attr:`download` to get the file.
bot (:obj:`telegram.Bot`, optional): Bot to use with shortcut method.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
file_path (:obj:`str`, optional): File path. Use e.g. :meth:`download_to_drive` to get the
file.
Attributes:
file_id (:obj:`str`): Identifier for this file.
@@ -65,8 +68,8 @@ class File(TelegramObject):
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`str`): Optional. File size in bytes.
file_path (:obj:`str`): Optional. File path. Use :meth:`download` to get the file.
file_path (:obj:`str`): Optional. File path. Use e.g. :meth:`download_to_drive` to get
the file.
"""
__slots__ = (
@@ -81,54 +84,76 @@ class File(TelegramObject):
self,
file_id: str,
file_unique_id: str,
bot: "Bot" = None,
file_size: int = None,
file_path: str = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.file_id = str(file_id)
self.file_unique_id = str(file_unique_id)
# Optionals
self.file_size = file_size
self.file_path = file_path
self.set_bot(bot)
self._credentials: Optional["FileCredentials"] = None
self._id_attrs = (self.file_unique_id,)
async def download(
self._freeze()
def _get_encoded_url(self) -> str:
"""Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string."""
sres = urllib_parse.urlsplit(str(self.file_path))
return urllib_parse.urlunsplit(
urllib_parse.SplitResult(
sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment
)
)
def _prepare_decrypt(self, buf: bytes) -> bytes:
return decrypt(b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf)
async def download_to_drive(
self,
custom_path: FilePathInput = None,
out: IO = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
) -> Union[Path, IO]:
) -> Path:
"""
Download this file. By default, the file is saved in the current working directory with its
original filename as reported by Telegram. If the file has no filename, it the file ID will
be used as filename. If a :paramref:`custom_path` is supplied, it will be saved to that
path instead. If :paramref:`out` is defined, the file contents will be saved to that object
using the ``out.write`` method.
original filename as reported by Telegram. If the file has no filename, the file ID will
be used as filename. If :paramref:`custom_path` is supplied as a :obj:`str` or
:obj:`pathlib.Path`, it will be saved to that path.
Note:
* :paramref:`custom_path` and :paramref:`out` are mutually exclusive.
* If neither :paramref:`custom_path` nor :paramref:`out` is provided and
:attr:`file_path` is the path of a local file (which is the case when a Bot API
Server is running in local mode), this method will just return the path.
If :paramref:`custom_path` isn't provided and :attr:`file_path` is the path of a
local file (which is the case when a Bot API Server is running in local mode), this
method will just return the path.
The only exception to this are encrypted files (e.g. a passport file). For these, a
file with the prefix `decrypted_` will be created in the same directory as the
original file in order to decrypt the file without changing the existing one
in-place.
.. versionchanged:: 20.0
* :paramref:`custom_path` parameter now also accepts :class:`pathlib.Path` as argument.
* Returns :class:`pathlib.Path` object in cases where previously a :obj:`str` was
returned.
* This method was previously called ``download``. It was split into
:meth:`download_to_drive` and :meth:`download_to_memory`.
Args:
custom_path (:class:`pathlib.Path` | :obj:`str`, optional): Custom path.
out (:obj:`io.BufferedWriter`, optional): A file-like object. Must be opened for
writing in binary mode, if applicable.
custom_path (:class:`pathlib.Path` | :obj:`str` , optional): The path where the file
will be saved to. If not specified, will be saved in the current working directory.
Keyword Args:
read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
@@ -143,32 +168,22 @@ class File(TelegramObject):
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
Returns:
:class:`pathlib.Path` | :obj:`io.BufferedWriter`: The same object as :paramref:`out` if
specified. Otherwise, returns the filename downloaded to or the file path of the
local file.
Raises:
ValueError: If both :paramref:`custom_path` and :paramref:`out` are passed.
:class:`pathlib.Path`: Returns the Path object the file was downloaded to.
"""
if custom_path is not None and out is not None:
raise ValueError("`custom_path` and `out` are mutually exclusive")
local_file = is_local_file(self.file_path)
url = None if local_file else self._get_encoded_url()
path = Path(self.file_path) if local_file else None
if out:
if local_file:
buf = path.read_bytes()
# if _credentials exists we want to decrypt the file
if local_file and self._credentials:
file_to_decrypt = Path(self.file_path)
buf = self._prepare_decrypt(file_to_decrypt.read_bytes())
if custom_path is not None:
path = Path(custom_path)
else:
buf = await self.get_bot().request.retrieve(url)
if self._credentials:
buf = decrypt(
b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf
)
out.write(buf)
return out
path = Path(str(file_to_decrypt.parent) + "/decrypted_" + file_to_decrypt.name)
path.write_bytes(buf)
return path
if custom_path is not None and local_file:
shutil.copyfile(self.file_path, str(custom_path))
@@ -191,38 +206,119 @@ class File(TelegramObject):
pool_timeout=pool_timeout,
)
if self._credentials:
buf = decrypt(
b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf
)
buf = self._prepare_decrypt(buf)
filename.write_bytes(buf)
return filename
def _get_encoded_url(self) -> str:
"""Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string."""
sres = urllib_parse.urlsplit(str(self.file_path))
return urllib_parse.urlunsplit(
urllib_parse.SplitResult(
sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment
)
)
async def download_to_memory(
self,
out: BinaryIO,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
) -> None:
"""
Download this file into memory. :paramref:`out` needs to be supplied with a
:obj:`io.BufferedIOBase`, the file contents will be saved to that object using the
:obj:`out.write<io.BufferedIOBase.write>` method.
async def download_as_bytearray(self, buf: bytearray = None) -> bytearray:
.. versionadded:: 20.0
Args:
out (:obj:`io.BufferedIOBase`): A file-like object. Must be opened for writing in
binary mode.
Keyword Args:
read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
"""
local_file = is_local_file(self.file_path)
url = None if local_file else self._get_encoded_url()
path = Path(self.file_path) if local_file else None
if local_file:
buf = path.read_bytes()
else:
buf = await self.get_bot().request.retrieve(
url,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
)
if self._credentials:
buf = self._prepare_decrypt(buf)
out.write(buf)
async def download_as_bytearray(
self,
buf: bytearray = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
) -> bytearray:
"""Download this file and return it as a bytearray.
Args:
buf (:obj:`bytearray`, optional): Extend the given bytearray with the downloaded data.
Keyword Args:
read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
.. versionadded:: 20.0
write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
.. versionadded:: 20.0
connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
.. versionadded:: 20.0
pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
:paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
.. versionadded:: 20.0
Returns:
:obj:`bytearray`: The same object as :paramref:`buf` if it was specified. Otherwise a
newly allocated :obj:`bytearray`.
newly allocated :obj:`bytearray`.
"""
if buf is None:
buf = bytearray()
if is_local_file(self.file_path):
buf.extend(Path(self.file_path).read_bytes())
bytes_data = Path(self.file_path).read_bytes()
else:
buf.extend(await self.get_bot().request.retrieve(self._get_encoded_url()))
bytes_data = await self.get_bot().request.retrieve(
self._get_encoded_url(),
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
)
if self._credentials:
buf.extend(self._prepare_decrypt(bytes_data))
else:
buf.extend(bytes_data)
return buf
def set_credentials(self, credentials: "FileCredentials") -> None:
+4 -9
View File
@@ -20,10 +20,10 @@
import logging
import mimetypes
from pathlib import Path
from typing import IO, Optional, Union
from uuid import uuid4
from telegram._utils.files import load_file
from telegram._utils.types import FieldTuple
_DEFAULT_MIME_TYPE = "application/octet-stream"
@@ -75,15 +75,10 @@ class InputFile:
elif isinstance(obj, str):
self.input_file_content = obj.encode("utf-8")
else:
self.input_file_content = obj.read()
self.attach_name: Optional[str] = "attached" + uuid4().hex if attach else None
reported_filename, self.input_file_content = load_file(obj)
filename = filename or reported_filename
if (
not filename
and hasattr(obj, "name")
and not isinstance(obj.name, int) # type: ignore[union-attr]
):
filename = Path(obj.name).name # type: ignore[union-attr]
self.attach_name: Optional[str] = "attached" + uuid4().hex if attach else None
if filename:
self.mimetype = mimetypes.guess_type(filename, strict=False)[0] or _DEFAULT_MIME_TYPE
+202 -143
View File
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Base class for Telegram InputMedia Objects."""
from typing import List, Optional, Tuple, Union
from typing import Optional, Sequence, Union
from telegram._files.animation import Animation
from telegram._files.audio import Audio
@@ -27,6 +27,7 @@ from telegram._files.photosize import PhotoSize
from telegram._files.video import Video
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.files import parse_file_input
from telegram._utils.types import FileInput, JSONDict, ODVInput
@@ -48,28 +49,32 @@ class InputMedia(TelegramObject):
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
:class:`telegram.Animation` | :class:`telegram.Audio` | \
:class:`telegram.Document` | :class:`telegram.PhotoSize` | \
:class:`telegram.Video`):
File to send. Pass a file_id to send a file that exists on the Telegram servers
(recommended), pass an HTTP URL for Telegram to get a file from the Internet.
:class:`telegram.Video`): File to send.
|fileinputnopath|
Lastly you can pass an existing telegram media object of the corresponding type
to send.
caption (:obj:`str`, optional): Caption of the media to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
parsing.
caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
entities that appear in the caption, which can be specified instead of
:paramref:`parse_mode`.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
in :class:`telegram.constants.ParseMode` for the available modes.
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
parse_mode (:obj:`str`, optional): |parse_mode|
Attributes:
type (:obj:`str`): Type of the input media.
media (:obj:`str` | :class:`telegram.InputFile`): Media to send.
caption (:obj:`str`): Optional. Caption of the media to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
"""
__slots__ = ("caption", "caption_entities", "media", "parse_mode", "type")
@@ -79,27 +84,27 @@ class InputMedia(TelegramObject):
media_type: str,
media: Union[str, InputFile, MediaType],
caption: str = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.type = media_type
self.media = media
self.caption = caption
self.caption_entities = caption_entities
self.caption_entities = parse_sequence_arg(caption_entities)
self.parse_mode = parse_mode
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
if self.caption_entities:
data["caption_entities"] = [ce.to_dict() for ce in self.caption_entities]
return data
self._freeze()
@staticmethod
def _parse_thumb_input(thumb: Optional[FileInput]) -> Optional[Union[str, InputFile]]:
return parse_file_input(thumb, attach=True) if thumb is not None else thumb
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
return (
parse_file_input(thumb, attach=True, local_mode=True) if thumb is not None else thumb
)
class InputMediaAnimation(InputMedia):
@@ -112,10 +117,8 @@ class InputMediaAnimation(InputMedia):
Args:
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
:class:`telegram.Animation`): File to send. Pass a
file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
URL for Telegram to get a file from the Internet. Lastly you can pass an existing
:class:`telegram.Animation` object to send.
:class:`telegram.Animation`): File to send. |fileinputnopath|
Lastly you can pass an existing :class:`telegram.Animation` object to send.
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
@@ -123,25 +126,21 @@ class InputMediaAnimation(InputMedia):
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of
the file sent; can be ignored if
thumbnail generation for the file is supported server-side. The thumbnail should be
in JPEG format and less than ``200`` kB in size. A thumbnail's width and height should
not exceed ``320``. Ignored if the file is not uploaded using multipart/form-data.
Thumbnails can't be reused and can be only uploaded as a new file.
.. versionadded:: 13.1
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
optional): |thumbdocstringnopath|
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
caption (:obj:`str`, optional): Caption of the animation to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
after entities parsing.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
in :class:`telegram.constants.ParseMode` for the available modes.
caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
entities that appear in the caption, which can be specified instead of
:paramref:`parse_mode`.
parse_mode (:obj:`str`, optional): |parse_mode|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
width (:obj:`int`, optional): Animation width.
height (:obj:`int`, optional): Animation height.
duration (:obj:`int`, optional): Animation duration in seconds.
@@ -151,8 +150,13 @@ class InputMediaAnimation(InputMedia):
media (:obj:`str` | :class:`telegram.InputFile`): Animation to send.
caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
width (:obj:`int`): Optional. Animation width.
height (:obj:`int`): Optional. Animation height.
@@ -171,8 +175,10 @@ class InputMediaAnimation(InputMedia):
width: int = None,
height: int = None,
duration: int = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
):
if isinstance(media, Animation):
width = media.width if width is None else width
@@ -180,13 +186,23 @@ class InputMediaAnimation(InputMedia):
duration = media.duration if duration is None else duration
media = media.file_id
else:
media = parse_file_input(media, filename=filename, attach=True)
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
super().__init__(InputMediaType.ANIMATION, media, caption, caption_entities, parse_mode)
self.thumb = self._parse_thumb_input(thumb)
self.width = width
self.height = height
self.duration = duration
super().__init__(
InputMediaType.ANIMATION,
media,
caption,
caption_entities,
parse_mode,
api_kwargs=api_kwargs,
)
with self._unfrozen():
self.thumb = self._parse_thumb_input(thumb)
self.width = width
self.height = height
self.duration = duration
class InputMediaPhoto(InputMedia):
@@ -194,10 +210,8 @@ class InputMediaPhoto(InputMedia):
Args:
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
:class:`telegram.PhotoSize`): File to send. Pass a
file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
URL for Telegram to get a file from the Internet. Lastly you can pass an existing
:class:`telegram.PhotoSize` object to send.
:class:`telegram.PhotoSize`): File to send. |fileinputnopath|
Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
@@ -205,24 +219,27 @@ class InputMediaPhoto(InputMedia):
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionadded:: 13.1
caption (:obj:`str`, optional ): Caption of the photo to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
in :class:`telegram.constants.ParseMode` for the available modes.
caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
entities that appear in the caption, which can be specified instead of
:paramref:`parse_mode`.
parse_mode (:obj:`str`, optional): |parse_mode|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.PHOTO`.
media (:obj:`str` | :class:`telegram.InputFile`): Photo to send.
caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
"""
@@ -233,11 +250,24 @@ class InputMediaPhoto(InputMedia):
media: Union[FileInput, PhotoSize],
caption: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
):
media = parse_file_input(media, PhotoSize, filename=filename, attach=True)
super().__init__(InputMediaType.PHOTO, media, caption, caption_entities, parse_mode)
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, PhotoSize, filename=filename, attach=True, local_mode=True)
super().__init__(
InputMediaType.PHOTO,
media,
caption,
caption_entities,
parse_mode,
api_kwargs=api_kwargs,
)
self._freeze()
class InputMediaVideo(InputMedia):
@@ -253,10 +283,8 @@ class InputMediaVideo(InputMedia):
Args:
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
:class:`telegram.Video`): File to send. Pass a
file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
URL for Telegram to get a file from the Internet. Lastly you can pass an existing
:class:`telegram.Video` object to send.
:class:`telegram.Video`): File to send. |fileinputnopath|
Lastly you can pass an existing :class:`telegram.Video` object to send.
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
@@ -264,27 +292,23 @@ class InputMediaVideo(InputMedia):
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionadded:: 13.1
caption (:obj:`str`, optional): Caption of the video to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
in :class:`telegram.constants.ParseMode` for the available modes.
caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
entities that appear in the caption, which can be specified instead of
:paramref:`parse_mode`.
parse_mode (:obj:`str`, optional): |parse_mode|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
width (:obj:`int`, optional): Video width.
height (:obj:`int`, optional): Video height.
duration (:obj:`int`, optional): Video duration in seconds.
supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is
suitable for streaming.
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of
the file sent; can be ignored if
thumbnail generation for the file is supported server-side. The thumbnail should be
in JPEG format and less than ``200`` kB in size. A thumbnail's width and height should
not exceed ``320``. Ignored if the file is not uploaded using multipart/form-data.
Thumbnails can't be reused and can be only uploaded as a new file.
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
optional): |thumbdocstringnopath|
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
@@ -294,8 +318,12 @@ class InputMediaVideo(InputMedia):
media (:obj:`str` | :class:`telegram.InputFile`): Video file to send.
caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
width (:obj:`int`): Optional. Video width.
height (:obj:`int`): Optional. Video height.
duration (:obj:`int`): Optional. Video duration in seconds.
@@ -317,8 +345,10 @@ class InputMediaVideo(InputMedia):
supports_streaming: bool = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb: FileInput = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
):
if isinstance(media, Video):
@@ -327,14 +357,24 @@ class InputMediaVideo(InputMedia):
duration = duration if duration is not None else media.duration
media = media.file_id
else:
media = parse_file_input(media, filename=filename, attach=True)
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
super().__init__(InputMediaType.VIDEO, media, caption, caption_entities, parse_mode)
self.width = width
self.height = height
self.duration = duration
self.thumb = self._parse_thumb_input(thumb)
self.supports_streaming = supports_streaming
super().__init__(
InputMediaType.VIDEO,
media,
caption,
caption_entities,
parse_mode,
api_kwargs=api_kwargs,
)
with self._unfrozen():
self.width = width
self.height = height
self.duration = duration
self.thumb = self._parse_thumb_input(thumb)
self.supports_streaming = supports_streaming
class InputMediaAudio(InputMedia):
@@ -347,11 +387,8 @@ class InputMediaAudio(InputMedia):
Args:
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
:class:`telegram.Audio`):
File to send. Pass a
file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
URL for Telegram to get a file from the Internet. Lastly you can pass an existing
:class:`telegram.Audio` object to send.
:class:`telegram.Audio`): File to send. |fileinputnopath|
Lastly you can pass an existing :class:`telegram.Audio` object to send.
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
@@ -359,26 +396,22 @@ class InputMediaAudio(InputMedia):
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionadded:: 13.1
caption (:obj:`str`, optional): Caption of the audio to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
in :class:`telegram.constants.ParseMode` for the available modes.
caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
entities that appear in the caption, which can be specified instead of
:paramref:`parse_mode`.
parse_mode (:obj:`str`, optional): |parse_mode|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio
tags.
title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags.
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of
the file sent; can be ignored if
thumbnail generation for the file is supported server-side. The thumbnail should be
in JPEG format and less than ``200`` kB in size. A thumbnail's width and height should
not exceed ``320``. Ignored if the file is not uploaded using multipart/form-data.
Thumbnails can't be reused and can be only uploaded as a new file.
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
optional): |thumbdocstringnopath|
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
@@ -388,8 +421,12 @@ class InputMediaAudio(InputMedia):
media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
duration (:obj:`int`): Duration of the audio in seconds.
performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio
tags.
@@ -409,8 +446,10 @@ class InputMediaAudio(InputMedia):
duration: int = None,
performer: str = None,
title: str = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
):
if isinstance(media, Audio):
duration = media.duration if duration is None else duration
@@ -418,13 +457,23 @@ class InputMediaAudio(InputMedia):
title = media.title if title is None else title
media = media.file_id
else:
media = parse_file_input(media, filename=filename, attach=True)
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
super().__init__(InputMediaType.AUDIO, media, caption, caption_entities, parse_mode)
self.thumb = self._parse_thumb_input(thumb)
self.duration = duration
self.title = title
self.performer = performer
super().__init__(
InputMediaType.AUDIO,
media,
caption,
caption_entities,
parse_mode,
api_kwargs=api_kwargs,
)
with self._unfrozen():
self.thumb = self._parse_thumb_input(thumb)
self.duration = duration
self.title = title
self.performer = performer
class InputMediaDocument(InputMedia):
@@ -432,10 +481,8 @@ class InputMediaDocument(InputMedia):
Args:
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
:class:`telegram.Document`): File to send. Pass a
file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
URL for Telegram to get a file from the Internet. Lastly you can pass an existing
:class:`telegram.Document` object to send.
:class:`telegram.Document`): File to send. |fileinputnopath|
Lastly you can pass an existing :class:`telegram.Document` object to send.
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
@@ -443,22 +490,18 @@ class InputMediaDocument(InputMedia):
new file. Convenience parameter, useful e.g. when sending files generated by the
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionadded:: 13.1
caption (:obj:`str`, optional): Caption of the document to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
entities parsing.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
in :class:`telegram.constants.ParseMode` for the available modes.
caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
entities that appear in the caption, which can be specified instead of
:paramref:`parse_mode`.
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of
the file sent; can be ignored if
thumbnail generation for the file is supported server-side. The thumbnail should be
in JPEG format and less than ``200`` kB in size. A thumbnail's width and height should
not exceed ``320``. Ignored if the file is not uploaded using multipart/form-data.
Thumbnails can't be reused and can be only uploaded as a new file.
parse_mode (:obj:`str`, optional): |parse_mode|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
optional): |thumbdocstringnopath|
.. versionchanged:: 13.2
Accept :obj:`bytes` as input.
@@ -471,8 +514,12 @@ class InputMediaDocument(InputMedia):
media (:obj:`str` | :class:`telegram.InputFile`): File to send.
caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
disable_content_type_detection (:obj:`bool`): Optional. Disables automatic server-side
content type detection for files uploaded using multipart/form-data. Always true, if
@@ -489,10 +536,22 @@ class InputMediaDocument(InputMedia):
caption: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_content_type_detection: bool = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
):
media = parse_file_input(media, Document, filename=filename, attach=True)
super().__init__(InputMediaType.DOCUMENT, media, caption, caption_entities, parse_mode)
self.thumb = self._parse_thumb_input(thumb)
self.disable_content_type_detection = disable_content_type_detection
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
media = parse_file_input(media, Document, filename=filename, attach=True, local_mode=True)
super().__init__(
InputMediaType.DOCUMENT,
media,
caption,
caption_entities,
parse_mode,
api_kwargs=api_kwargs,
)
with self._unfrozen():
self.thumb = self._parse_thumb_input(thumb)
self.disable_content_type_detection = disable_content_type_detection
+27 -5
View File
@@ -18,9 +18,11 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Location."""
from typing import Any
from typing import ClassVar
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class Location(TelegramObject):
@@ -33,14 +35,14 @@ class Location(TelegramObject):
longitude (:obj:`float`): Longitude as defined by sender.
latitude (:obj:`float`): Latitude as defined by sender.
horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location,
measured in meters; 0-:tg-const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`.
measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
live_period (:obj:`int`, optional): Time relative to the message sending date, during which
the location can be updated, in seconds. For active live locations only.
heading (:obj:`int`, optional): The direction in which user is moving, in degrees;
1-:tg-const:`telegram.constants.LocationLimit.HEADING`. For active live locations only.
:tg-const:`telegram.Location.MIN_HEADING`-:tg-const:`telegram.Location.MAX_HEADING`.
For active live locations only.
proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts about
approaching another chat member, in meters. For sent live locations only.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
longitude (:obj:`float`): Longitude as defined by sender.
@@ -73,8 +75,10 @@ class Location(TelegramObject):
live_period: int = None,
heading: int = None,
proximity_alert_radius: int = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.longitude = longitude
self.latitude = latitude
@@ -88,3 +92,21 @@ class Location(TelegramObject):
)
self._id_attrs = (self.longitude, self.latitude)
self._freeze()
HORIZONTAL_ACCURACY: ClassVar[int] = constants.LocationLimit.HORIZONTAL_ACCURACY
""":const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`
.. versionadded:: 20.0
"""
MIN_HEADING: ClassVar[int] = constants.LocationLimit.MIN_HEADING
""":const:`telegram.constants.LocationLimit.MIN_HEADING`
.. versionadded:: 20.0
"""
MAX_HEADING: ClassVar[int] = constants.LocationLimit.MAX_HEADING
""":const:`telegram.constants.LocationLimit.MAX_HEADING`
.. versionadded:: 20.0
"""
+12 -14
View File
@@ -18,12 +18,8 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram PhotoSize."""
from typing import TYPE_CHECKING, Any
from telegram._files._basemedium import _BaseMedium
if TYPE_CHECKING:
from telegram import Bot
from telegram._utils.types import JSONDict
class PhotoSize(_BaseMedium):
@@ -41,8 +37,6 @@ class PhotoSize(_BaseMedium):
width (:obj:`int`): Photo width.
height (:obj:`int`): Photo height.
file_size (:obj:`int`, optional): File size in bytes.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): Identifier for this file.
@@ -52,7 +46,7 @@ class PhotoSize(_BaseMedium):
width (:obj:`int`): Photo width.
height (:obj:`int`): Photo height.
file_size (:obj:`int`): Optional. File size in bytes.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@@ -65,12 +59,16 @@ class PhotoSize(_BaseMedium):
width: int,
height: int,
file_size: int = None,
bot: "Bot" = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id, file_unique_id=file_unique_id, file_size=file_size, bot=bot
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
api_kwargs=api_kwargs,
)
# Required
self.width = width
self.height = height
with self._unfrozen():
# Required
self.width = width
self.height = height
+109 -46
View File
@@ -17,13 +17,14 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects that represent stickers."""
from typing import TYPE_CHECKING, Any, ClassVar, List, Optional
from typing import TYPE_CHECKING, ClassVar, Optional, Sequence
from telegram import constants
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.file import File
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:
@@ -53,6 +54,11 @@ class Sticker(_BaseThumbedMedium):
is_video (:obj:`bool`): :obj:`True`, if the sticker is a video sticker.
.. versionadded:: 13.11
type (:obj:`str`): Type of the sticker. Currently one of :attr:`REGULAR`,
:attr:`MASK`, :attr:`CUSTOM_EMOJI`. The type of the sticker is independent from its
format, which is determined by the fields :attr:`is_animated` and :attr:`is_video`.
.. versionadded:: 20.0
thumb (:class:`telegram.PhotoSize`, optional): Sticker thumbnail in the ``.WEBP`` or
``.JPG`` format.
emoji (:obj:`str`, optional): Emoji associated with the sticker
@@ -61,8 +67,15 @@ class Sticker(_BaseThumbedMedium):
mask_position (:class:`telegram.MaskPosition`, optional): For mask stickers, the
position where the mask should be placed.
file_size (:obj:`int`, optional): File size in bytes.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
_kwargs (:obj:`dict`): Arbitrary keyword arguments.
premium_animation (:class:`telegram.File`, optional): For premium regular stickers,
premium animation for the sticker.
.. versionadded:: 20.0
custom_emoji_id (:obj:`str`, optional): For custom emoji stickers, unique identifier of the
custom emoji.
.. versionadded:: 20.0
Attributes:
file_id (:obj:`str`): Identifier for this file.
@@ -75,6 +88,11 @@ class Sticker(_BaseThumbedMedium):
is_video (:obj:`bool`): :obj:`True`, if the sticker is a video sticker.
.. versionadded:: 13.11
type (:obj:`str`): Type of the sticker. Currently one of :attr:`REGULAR`,
:attr:`MASK`, :attr:`CUSTOM_EMOJI`. The type of the sticker is independent from its
format, which is determined by the fields :attr:`is_animated` and :attr:`is_video`.
.. versionadded:: 20.0
thumb (:class:`telegram.PhotoSize`): Optional. Sticker thumbnail in the ``.WEBP`` or
``.JPG`` format.
emoji (:obj:`str`): Optional. Emoji associated with the sticker.
@@ -82,8 +100,15 @@ class Sticker(_BaseThumbedMedium):
mask_position (:class:`telegram.MaskPosition`): Optional. For mask stickers, the position
where the mask should be placed.
file_size (:obj:`int`): Optional. File size in bytes.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
premium_animation (:class:`telegram.File`): Optional. For premium regular stickers,
premium animation for the sticker.
.. versionadded:: 20.0
custom_emoji_id (:obj:`str`): Optional. For custom emoji stickers, unique identifier of the
custom emoji.
.. versionadded:: 20.0
"""
__slots__ = (
@@ -94,6 +119,9 @@ class Sticker(_BaseThumbedMedium):
"mask_position",
"set_name",
"width",
"premium_animation",
"type",
"custom_emoji_id",
)
def __init__(
@@ -104,30 +132,44 @@ class Sticker(_BaseThumbedMedium):
height: int,
is_animated: bool,
is_video: bool,
type: str, # pylint: disable=redefined-builtin
thumb: PhotoSize = None,
emoji: str = None,
file_size: int = None,
set_name: str = None,
mask_position: "MaskPosition" = None,
bot: "Bot" = None,
**_kwargs: Any,
premium_animation: "File" = None,
custom_emoji_id: str = None,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
api_kwargs=api_kwargs,
)
# Required
self.width = width
self.height = height
self.is_animated = is_animated
self.is_video = is_video
# Optional
self.emoji = emoji
self.set_name = set_name
self.mask_position = mask_position
with self._unfrozen():
# Required
self.width = width
self.height = height
self.is_animated = is_animated
self.is_video = is_video
self.type = type
# Optional
self.emoji = emoji
self.set_name = set_name
self.mask_position = mask_position
self.premium_animation = premium_animation
self.custom_emoji_id = custom_emoji_id
REGULAR: ClassVar[str] = constants.StickerType.REGULAR
""":const:`telegram.constants.StickerType.REGULAR`"""
MASK: ClassVar[str] = constants.StickerType.MASK
""":const:`telegram.constants.StickerType.MASK`"""
CUSTOM_EMOJI: ClassVar[str] = constants.StickerType.CUSTOM_EMOJI
""":const:`telegram.constants.StickerType.CUSTOM_EMOJI`"""
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Sticker"]:
@@ -139,8 +181,9 @@ class Sticker(_BaseThumbedMedium):
data["thumb"] = PhotoSize.de_json(data.get("thumb"), bot)
data["mask_position"] = MaskPosition.de_json(data.get("mask_position"), bot)
data["premium_animation"] = File.de_json(data.get("premium_animation"), bot)
return cls(bot=bot, **data)
return super().de_json(data=data, bot=bot)
class StickerSet(TelegramObject):
@@ -154,6 +197,9 @@ class StickerSet(TelegramObject):
arguments had to be changed. Use keyword arguments to make sure that the arguments are
passed correctly.
.. versionchanged:: 20.0:
The parameter ``contains_masks`` has been removed. Use :paramref:`sticker_type` instead.
Args:
name (:obj:`str`): Sticker set name.
title (:obj:`str`): Sticker set title.
@@ -161,8 +207,16 @@ class StickerSet(TelegramObject):
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
.. versionadded:: 13.11
contains_masks (:obj:`bool`): :obj:`True`, if the sticker set contains masks.
stickers (List[:class:`telegram.Sticker`]): List of all set stickers.
stickers (Sequence[:class:`telegram.Sticker`]): List of all set stickers.
.. versionchanged:: 20.0
|sequenceclassargs|
sticker_type (:obj:`str`): Type of stickers in the set, currently one of
:attr:`telegram.Sticker.REGULAR`, :attr:`telegram.Sticker.MASK`,
:attr:`telegram.Sticker.CUSTOM_EMOJI`.
.. versionadded:: 20.0
thumb (:class:`telegram.PhotoSize`, optional): Sticker set thumbnail in the ``.WEBP``,
``.TGS``, or ``.WEBM`` format.
@@ -173,21 +227,27 @@ class StickerSet(TelegramObject):
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
.. versionadded:: 13.11
contains_masks (:obj:`bool`): :obj:`True`, if the sticker set contains masks.
stickers (List[:class:`telegram.Sticker`]): List of all set stickers.
stickers (Tuple[:class:`telegram.Sticker`]): List of all set stickers.
.. versionchanged:: 20.0
|tupleclassattrs|
sticker_type (:obj:`str`): Type of stickers in the set.
.. versionadded:: 20.0
thumb (:class:`telegram.PhotoSize`): Optional. Sticker set thumbnail in the ``.WEBP``,
``.TGS`` or ``.WEBM`` format.
"""
__slots__ = (
"contains_masks",
"is_animated",
"is_video",
"name",
"stickers",
"thumb",
"title",
"sticker_type",
)
def __init__(
@@ -195,23 +255,27 @@ class StickerSet(TelegramObject):
name: str,
title: str,
is_animated: bool,
contains_masks: bool,
stickers: List[Sticker],
stickers: Sequence[Sticker],
is_video: bool,
sticker_type: str,
thumb: PhotoSize = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.name = name
self.title = title
self.is_animated = is_animated
self.is_video = is_video
self.contains_masks = contains_masks
self.stickers = stickers
self.stickers = parse_sequence_arg(stickers)
self.sticker_type = sticker_type
# Optional
self.thumb = thumb
self._id_attrs = (self.name,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["StickerSet"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -221,15 +285,13 @@ class StickerSet(TelegramObject):
data["thumb"] = PhotoSize.de_json(data.get("thumb"), bot)
data["stickers"] = Sticker.de_list(data.get("stickers"), bot)
return cls(bot=bot, **data)
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 "contains_masks" in data:
api_kwargs["contains_masks"] = data.pop("contains_masks")
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data["stickers"] = [s.to_dict() for s in data.get("stickers")] # type: ignore[union-attr]
return data
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
class MaskPosition(TelegramObject):
@@ -272,7 +334,16 @@ class MaskPosition(TelegramObject):
CHIN: ClassVar[str] = constants.MaskPosition.CHIN
""":const:`telegram.constants.MaskPosition.CHIN`"""
def __init__(self, point: str, x_shift: float, y_shift: float, scale: float, **_kwargs: Any):
def __init__(
self,
point: str,
x_shift: float,
y_shift: float,
scale: float,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.point = point
self.x_shift = x_shift
self.y_shift = y_shift
@@ -280,12 +351,4 @@ class MaskPosition(TelegramObject):
self._id_attrs = (self.point, self.x_shift, self.y_shift, self.scale)
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MaskPosition"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
if data is None:
return None
return cls(**data)
self._freeze()
+8 -4
View File
@@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Venue."""
from typing import TYPE_CHECKING, Any, Optional
from typing import TYPE_CHECKING, Optional
from telegram._files.location import Location
from telegram._telegramobject import TelegramObject
@@ -49,7 +49,6 @@ class Venue(TelegramObject):
google_place_type (:obj:`str`, optional): Google Places type of the venue. (See
`supported types <https://developers.google.com/maps/documentation/places/web-service\
/supported_types>`_.)
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
location (:class:`telegram.Location`): Venue location.
@@ -81,8 +80,11 @@ class Venue(TelegramObject):
foursquare_type: str = None,
google_place_id: str = None,
google_place_type: str = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.location = location
self.title = title
@@ -95,6 +97,8 @@ class Venue(TelegramObject):
self._id_attrs = (self.location, self.title)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Venue"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -105,4 +109,4 @@ class Venue(TelegramObject):
data["location"] = Location.de_json(data.get("location"), bot)
return cls(**data)
return super().de_json(data=data, bot=bot)
+13 -18
View File
@@ -18,13 +18,9 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Video."""
from typing import TYPE_CHECKING, Any
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.photosize import PhotoSize
if TYPE_CHECKING:
from telegram import Bot
from telegram._utils.types import JSONDict
class Video(_BaseThumbedMedium):
@@ -46,8 +42,6 @@ class Video(_BaseThumbedMedium):
file_name (:obj:`str`, optional): Original filename as defined by sender.
mime_type (:obj:`str`, optional): MIME type of a file as defined by sender.
file_size (:obj:`int`, optional): File size in bytes.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): Identifier for this file.
@@ -61,7 +55,7 @@ class Video(_BaseThumbedMedium):
file_name (:obj:`str`): Optional. Original filename as defined by sender.
mime_type (:obj:`str`): Optional. MIME type of a file as defined by sender.
file_size (:obj:`int`): Optional. File size in bytes.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@@ -77,21 +71,22 @@ class Video(_BaseThumbedMedium):
thumb: PhotoSize = None,
mime_type: str = None,
file_size: int = None,
bot: "Bot" = None,
file_name: str = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
api_kwargs=api_kwargs,
)
# Required
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
self.file_name = file_name
with self._unfrozen():
# Required
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
self.file_name = file_name
+8 -14
View File
@@ -18,13 +18,9 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram VideoNote."""
from typing import TYPE_CHECKING, Any
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.photosize import PhotoSize
if TYPE_CHECKING:
from telegram import Bot
from telegram._utils.types import JSONDict
class VideoNote(_BaseThumbedMedium):
@@ -44,8 +40,6 @@ class VideoNote(_BaseThumbedMedium):
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
thumb (:class:`telegram.PhotoSize`, optional): Video thumbnail.
file_size (:obj:`int`, optional): File size in bytes.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): Identifier for this file.
@@ -56,7 +50,6 @@ class VideoNote(_BaseThumbedMedium):
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
thumb (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
file_size (:obj:`int`): Optional. File size in bytes.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@@ -70,16 +63,17 @@ class VideoNote(_BaseThumbedMedium):
duration: int,
thumb: PhotoSize = None,
file_size: int = None,
bot: "Bot" = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
api_kwargs=api_kwargs,
)
# Required
self.length = length
self.duration = duration
with self._unfrozen():
# Required
self.length = length
self.duration = duration
+9 -15
View File
@@ -18,12 +18,8 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Voice."""
from typing import TYPE_CHECKING, Any
from telegram._files._basemedium import _BaseMedium
if TYPE_CHECKING:
from telegram import Bot
from telegram._utils.types import JSONDict
class Voice(_BaseMedium):
@@ -41,8 +37,6 @@ class Voice(_BaseMedium):
duration (:obj:`int`, optional): Duration of the audio in seconds as defined by sender.
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
file_size (:obj:`int`, optional): File size in bytes.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): Identifier for this file.
@@ -52,7 +46,6 @@ class Voice(_BaseMedium):
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender.
file_size (:obj:`int`): Optional. File size in bytes.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@@ -65,16 +58,17 @@ class Voice(_BaseMedium):
duration: int,
mime_type: str = None,
file_size: int = None,
bot: "Bot" = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
bot=bot,
api_kwargs=api_kwargs,
)
# Required
self.duration = duration
# Optional
self.mime_type = mime_type
with self._unfrozen():
# Required
self.duration = duration
# Optional
self.mime_type = mime_type
+23 -5
View File
@@ -18,9 +18,11 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram ForceReply."""
from typing import Any
from typing import ClassVar
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class ForceReply(TelegramObject):
@@ -47,12 +49,13 @@ class ForceReply(TelegramObject):
original message.
input_field_placeholder (:obj:`str`, optional): The placeholder to be shown in the input
field when the reply is active; 1-64 characters.
field when the reply is active;
:tg-const:`telegram.ForceReply.MIN_INPUT_FIELD_PLACEHOLDER`-
:tg-const:`telegram.ForceReply.MAX_INPUT_FIELD_PLACEHOLDER`
characters.
.. versionadded:: 13.7
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
force_reply (:obj:`True`): Shows reply interface to the user, as if they manually selected
the bots message and tapped 'Reply'.
@@ -70,10 +73,25 @@ class ForceReply(TelegramObject):
self,
selective: bool = None,
input_field_placeholder: str = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.force_reply = True
self.selective = selective
self.input_field_placeholder = input_field_placeholder
self._id_attrs = (self.selective,)
self._freeze()
MIN_INPUT_FIELD_PLACEHOLDER: ClassVar[int] = constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER
""":const:`telegram.constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER`
.. versionadded:: 20.0
"""
MAX_INPUT_FIELD_PLACEHOLDER: ClassVar[int] = constants.ReplyLimit.MAX_INPUT_FIELD_PLACEHOLDER
""":const:`telegram.constants.ReplyLimit.MAX_INPUT_FIELD_PLACEHOLDER`
.. versionadded:: 20.0
"""

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