Compare commits

...

79 Commits

Author SHA1 Message Date
Hinrich Mahler 171953f109 Bump version to v20.0 2023-01-01 17:20:54 +01:00
Harshil 606773d8f0 API 6.4 (#3449)
Co-authored-by: poolitzer <github@poolitzer.eu>
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-01-01 17:00:49 +01:00
Bibo-Joshi f408b1a2dd Documentation Improvements (#3428, #3423, #3429, #3441, #3404, #3443)
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>
Co-authored-by: Eisberge <22561095+Eisberge@users.noreply.github.com>
Co-authored-by: Joshua Tang <joshuaystang@gmail.com>
2023-01-01 16:24:00 +01:00
Harshil 3e7ab7e7af Downgrade sphinx to 5.3.0 to Fix Search (#3457) 2023-01-01 15:48:48 +01:00
Aditya 456b81d22a Allow Sequence Input for Bot Methods (#3412)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-01-01 14:24:30 +01:00
Bibo-Joshi cb90814829 Update Link-Check CI and Replace a Dead Link (#3456) 2023-01-01 13:48:24 +01:00
Bibo-Joshi 7b61a30fb1 Freeze Classes Without Arguments (#3453) 2023-01-01 13:04:37 +01:00
dependabot[bot] f3a9b74445 Bump sphinx from 5.3.0 to 6.0.0 (#3450)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2022-12-31 16:59:49 +01:00
Dmitry Kolomatskiy d996e8f9c9 Add New Constants (#3444) 2022-12-30 14:09:06 +01:00
Bibo-Joshi 0a6725852f Override Bot.__deepcopy__ to Raise TypeError (#3446) 2022-12-30 10:50:49 +01:00
Bibo-Joshi b8fbb89fae Add Log Decorator to Bot.get_webhook_info (#3442) 2022-12-27 19:02:50 +01:00
Bibo-Joshi f3650364b9 Add Documention On Verifying Releases (#3436) 2022-12-21 16:55:58 +01:00
Bibo-Joshi 5b629ede56 Drop Undocumented Job.__lt__ (#3432) 2022-12-19 18:32:53 +01:00
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
330 changed files with 15156 additions and 7269 deletions
+9 -1
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:
@@ -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
@@ -280,3 +287,4 @@ break the API classes. For example:
.. _`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.
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: [3.7]
python-version: [3.9]
os: [ubuntu-latest]
fail-fast: False
steps:
+2 -2
View File
@@ -5,7 +5,7 @@ on:
- master
- doc-fixes
push:
branches:
branches:
- master
- doc-fixes
@@ -15,7 +15,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: [3.7]
python-version: [3.9]
os: [ubuntu-latest]
fail-fast: False
steps:
+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.'
File diff suppressed because one or more lines are too long
+5 -5
View File
@@ -9,18 +9,18 @@ ci:
repos:
- repo: https://github.com/psf/black
rev: 22.6.0
rev: 22.10.0
hooks:
- id: black
args:
- --diff
- --check
- repo: https://github.com/PyCQA/flake8
rev: 5.0.2
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$
@@ -38,7 +38,7 @@ repos:
- aiolimiter~=1.0.0
- . # this basically does `pip install -e .`
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.971
rev: v0.991
hooks:
- id: mypy
name: mypy-ptb
@@ -65,7 +65,7 @@ repos:
- cachetools~=5.2.0
- . # this basically does `pip install -e .`
- repo: https://github.com/asottile/pyupgrade
rev: v2.37.3
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'
+5
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,6 +30,7 @@ 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>`_
@@ -71,7 +74,9 @@ The following wonderful people contributed directly or indirectly to this projec
- `LRezende <https://github.com/lrezende>`_
- `macrojames <https://github.com/macrojames>`_
- `Matheus Lemos <https://github.com/mlemosf>`_
- `Michael Dix <https://github.com/Eisberge>`_
- `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>`_
+257
View File
@@ -2,6 +2,263 @@
Changelog
=========
Version 20.0
============
*Released 2023-01-01*
This is the technical changelog for version 20.0. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support For Bot API 6.4 (`#3449`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Documentation Improvements (`#3428`_, `#3423`_, `#3429`_, `#3441`_, `#3404`_, `#3443`_)
- Allow ``Sequence`` Input for Bot Methods (`#3412`_)
- Update Link-Check CI and Replace a Dead Link (`#3456`_)
- Freeze Classes Without Arguments (`#3453`_)
- Add New Constants (`#3444`_)
- Override ``Bot.__deepcopy__`` to Raise ``TypeError`` (`#3446`_)
- Add Log Decorator to ``Bot.get_webhook_info`` (`#3442`_)
- Add Documentation On Verifying Releases (`#3436`_)
- Drop Undocumented ``Job.__lt__`` (`#3432`_)
Dependencies
------------
- Downgrade ``sphinx`` to 5.3.0 to Fix Search (`#3457`_)
- Bump ``sphinx`` from 5.3.0 to 6.0.0 (`#3450`_)
.. _`#3449`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3449
.. _`#3428`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3428
.. _`#3423`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3423
.. _`#3429`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3429
.. _`#3441`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3441
.. _`#3404`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3404
.. _`#3443`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3443
.. _`#3412`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3412
.. _`#3456`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3456
.. _`#3453`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3453
.. _`#3444`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3444
.. _`#3446`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3446
.. _`#3442`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3442
.. _`#3436`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3436
.. _`#3432`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3432
.. _`#3457`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3457
.. _`#3450`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3450
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*
+1 -1
View File
@@ -1 +1 @@
include LICENSE LICENSE.lesser Makefile requirements.txt requirements-opts.txt README_RAW.rst telegram/py.typed
include LICENSE LICENSE.lesser requirements.txt requirements-opts.txt README_RAW.rst telegram/py.typed
+32 -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.2-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.4-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions
@@ -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.2** are supported.
All types and methods of the Telegram Bot API **6.4** are supported.
Installing
==========
@@ -114,31 +114,52 @@ You can also install ``python-telegram-bot`` from source, though this is usually
$ cd python-telegram-bot
$ python setup.py install
Verifying Releases
------------------
We sign all the releases with a GPG key.
The signatures are uploaded to both the `GitHub releases page <https://github.com/python-telegram-bot/python-telegram-bot/releases>`_ and the `PyPI project <https://pypi.org/project/python-telegram-bot/>`_ and end with a suffix ``.asc``.
Please find the public keys `here <https://github.com/python-telegram-bot/python-telegram-bot/tree/master/public_keys>`_.
The keys are named in the format ``<first_version>-<last_version>.gpg`` or ``<first_version>-current.gpg`` if the key is currently being used for new releases.
In addition, the GitHub release page also contains the sha1 hashes of the release files in the files with the suffix ``.sha1``.
This allows you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team.
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.2 <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[socks]`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
* ``pip install python-telegram-bot[rate-limiter]`` installs `aiolimiter~=1.0.0 <https://aiolimiter.readthedocs.io/en/stable/>`_. 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.run_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
===========
+28 -10
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.2-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.4-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
.. 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
@@ -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.2** are supported.
All types and methods of the Telegram Bot API **6.4** are supported.
Installing
==========
@@ -115,27 +115,45 @@ Note
Installing the ``.tar.gz`` archive available on PyPi directly via ``pip`` will *not* work as expected, as ``pip`` does not recognize that it should use ``setup-raw.py`` instead of ``setup.py``.
Verifying Releases
------------------
We sign all the releases with a GPG key.
The signatures are uploaded to both the `GitHub releases page <https://github.com/python-telegram-bot/python-telegram-bot/releases>`_ and the `PyPI project <https://pypi.org/project/python-telegram-bot/>`_ and end with a suffix ``.asc``.
Please find the public keys `here <https://github.com/python-telegram-bot/python-telegram-bot/tree/master/public_keys>`_.
The keys are named in the format ``<first_version>-<last_version>.gpg`` or ``<first_version>-current.gpg`` if the key is currently being used for new releases.
In addition, the GitHub release page also contains the sha1 hashes of the release files in the files with the suffix ``.sha1``.
This allows you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team.
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] <https://www.python-httpx.org/#dependencies>`_. 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
===========
+3 -2
View File
@@ -1,5 +1,6 @@
sphinx==5.1.1
sphinx==5.3.0
sphinx-pypi-upload
furo==2022.6.21
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
+107 -14
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.0a4" # telegram.__version__[:3]
version = "20.0" # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = "20.0a4" # telegram.__version__
release = "20.0" # 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
@@ -44,10 +44,15 @@ extensions = [
"sphinx.ext.napoleon",
"sphinx.ext.intersphinx",
"sphinx.ext.linkcode",
"sphinx.ext.extlinks",
"sphinx_paramlinks",
"sphinxcontrib.mermaid",
"sphinx_search.extension",
]
# For shorter links to Wiki in docstrings
extlinks = {"wiki": ("https://github.com/python-telegram-bot/python-telegram-bot/wiki/%s", "%s")}
# Use intersphinx to reference the python builtin library docs
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
@@ -64,6 +69,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
@@ -212,11 +220,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",
"style_mermaid_diagrams.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"
@@ -257,6 +263,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 -------------------------------------------
@@ -292,7 +299,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.
"""
@@ -375,12 +382,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
+3
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`
-------------------------------
@@ -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.
+49
View File
@@ -256,6 +256,45 @@
</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.close_general_forum_topic`
- Used for closing the general 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.edit_general_forum_topic`
- Used to edit the general topic
* - :meth:`~telegram.Bot.get_forum_topic_icon_stickers`
- Used to get custom emojis to use as topic icons
* - :meth:`~telegram.Bot.hide_general_forum_topic`
- Used to hide the general topic
* - :meth:`~telegram.Bot.unhide_general_forum_topic`
- Used to unhide the general topic
* - :meth:`~telegram.Bot.reopen_forum_topic`
- Used to reopen a topic
* - :meth:`~telegram.Bot.reopen_general_forum_topic`
- Used to reopen the general topic
* - :meth:`~telegram.Bot.unpin_all_forum_topic_messages`
- Used to unpin all messages in a forum topic
.. raw:: html
</details>
<br>
.. raw:: html
<details>
@@ -290,6 +329,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`
@@ -304,12 +347,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
+91
View File
@@ -0,0 +1,91 @@
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.forumtopicedited
telegram.forumtopicreopened
telegram.generalforumtopichidden
telegram.generalforumtopicunhidden
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.writeaccessallowed
+2 -1
View File
@@ -3,4 +3,5 @@ telegram.Bot
.. autoclass:: telegram.Bot
:members:
:show-inheritance:
:show-inheritance:
:special-members: __reduce__, __deepcopy__
+1 -1
View File
@@ -3,4 +3,4 @@ telegram.Dice
.. autoclass:: telegram.Dice
:members:
:show-inheritance:
:show-inheritance:
+1
View File
@@ -2,6 +2,7 @@ Arbitrary Callback Data
-----------------------
.. toctree::
:titlesonly:
telegram.ext.callbackdatacache
telegram.ext.invalidcallbackdata
+1 -1
View File
@@ -3,4 +3,4 @@ telegram.ext.ExtBot
.. autoclass:: telegram.ext.ExtBot
:show-inheritance:
:members: insert_callback_data, defaults, rate_limiter, initialize, shutdown
:members: insert_callback_data, defaults, rate_limiter, initialize, shutdown, callback_data_cache
@@ -2,6 +2,7 @@ Handlers
--------
.. toctree::
:titlesonly:
telegram.ext.basehandler
telegram.ext.callbackqueryhandler
@@ -2,6 +2,7 @@ Persistence
-----------
.. toctree::
:titlesonly:
telegram.ext.basepersistence
telegram.ext.dictpersistence
@@ -2,6 +2,7 @@ Rate Limiting
-------------
.. toctree::
:titlesonly:
telegram.ext.baseratelimiter
telegram.ext.aioratelimiter
+1
View File
@@ -2,6 +2,7 @@ telegram.ext package
====================
.. toctree::
:titlesonly:
telegram.ext.application
telegram.ext.applicationbuilder
+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.ForumTopicEdited
=========================
.. autoclass:: telegram.ForumTopicEdited
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
telegram.ForumTopicReopened
===========================
.. autoclass:: telegram.ForumTopicReopened
:members:
:show-inheritance:
+1
View File
@@ -2,6 +2,7 @@ Games
-----
.. toctree::
:titlesonly:
telegram.callbackgame
telegram.game
@@ -0,0 +1,6 @@
telegram.GeneralForumTopicHidden
================================
.. autoclass:: telegram.GeneralForumTopicHidden
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
telegram.GeneralForumTopicUnhidden
==================================
.. autoclass:: telegram.GeneralForumTopicUnhidden
:members:
:show-inheritance:
+1
View File
@@ -2,6 +2,7 @@ Inline Mode
-----------
.. toctree::
:titlesonly:
telegram.choseninlineresult
telegram.inlinequery
+1
View File
@@ -2,6 +2,7 @@ Passport
--------
.. toctree::
:titlesonly:
telegram.credentials
telegram.datacredentials
+1
View File
@@ -2,6 +2,7 @@ Payments
--------
.. toctree::
:titlesonly:
telegram.invoice
telegram.labeledprice
+2
View File
@@ -4,6 +4,8 @@ telegram.request Module
.. versionadded:: 20.0
.. toctree::
:titlesonly:
telegram.request.baserequest
telegram.request.requestdata
telegram.request.httpxrequest
+4 -78
View File
@@ -7,88 +7,14 @@ 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
+1
View File
@@ -2,6 +2,7 @@ Stickers
--------
.. toctree::
:titlesonly:
telegram.maskposition
telegram.sticker
+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__
@@ -0,0 +1,6 @@
telegram.WriteAccessAllowed
===========================
.. autoclass:: telegram.WriteAccessAllowed
:members:
:show-inheritance:
+1
View File
@@ -2,6 +2,7 @@ Auxiliary modules
=================
.. toctree::
:titlesonly:
telegram.constants
telegram.error
+53
View File
@@ -0,0 +1,53 @@
.. |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:: Sequence 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:: |sequenceargs| 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.
.. |sequenceargs| replace:: Accepts any :class:`collections.abc.Sequence` as input instead of just a list.
.. |captionentitiesattr| replace:: Tuple of special entities that appear in the caption, which can be specified instead of ``parse_mode``.
+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
+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."
+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(
+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
+65
View File
@@ -0,0 +1,65 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBF6AWOIBEAClMRtGdbm2yKAo1GdeybmasMpsCBmGI952/z5VvjSgDlu+ktPJ
QauWkARWrq4Eab2uZEIQrHUw01+9/Ugfu7qHu4safZjc177Tq4Fp0hJDHFRFVdqb
68Rv5mH0xjr7At0eNys2Rx8m7H1dBYQCz4aroUQ0q0TB4qSeKU9FzUzOZZ7/pYri
KFyNdaIjhrBeY/WXbn+7L2/cFJtafJHqkZlyfIgQzpmONfIrtJLnG0nxdBPIxg3m
CYxzrJKCkPPrl8b4TNV0LCO9c4r8zXGiZ6ZOQMAGjgb2Do67AvHTLI3YYd8+iY25
112noIFASabxbW9jBb+nlyMc8nz5kW19JWq6sBfMJYzWaVpI6ofNpiZtKWupIt2V
4GcViZmE/Kh4hBQjrBIAeqLUz6ABidERrhWu6/wP3huNe+R6eMQTfEdYlYeD3LXG
5Upl46/wnodWQeW4llMVBhjkS+5ExtvlVBD9Yz8iQMUsXUSu8+UPRgjy6YIRsvtF
bzGKFXkn4tFWCyQsXJDf8f+lQCtB1XF/DN2IVZF9OjQOvrpRwJk3h3CiQboN5lf7
Mj7I11MusPKzn34vg+3f6loOOQ++GUa+WH2B6Dx6AH3C0BI0V2sh6axu6HYJNo3o
stOXzhhWysPKp9pj41fmaFTcF8bYYlnHoLA17IapttsYo0WuFaBF5UW90QARAQAB
tCpIaW5yaWNoIE1haGxlciA8aGlucmljaC5tYWhsZXJAZnJlZW5ldC5kZT6JAk4E
EwEKADgWIQRlW7T1bNsODkUAz1cung4SfvPygwUCXoBY4gIbAwULCQgHAgYVCgkI
CwIEFgIDAQIeAQIXgAAKCRAung4SfvPyg3fXD/9IMuDgYGl+T98JvN/VHLcrA9rT
idIWr5vDSxjniQaYe8Kc3oTqje1xmRcIR7z3WFKgxErx8yEf3AOUCPqQh53MjS0q
rXNDCoRWqlljpeY2EHZh2xPSvin2pUgOd334BRFeBqyvIfb/IQmwUNDoUp1FxKEq
4veT4XPDnKZlZs/OwRMD1f0v64mtTy60fQzJyM9ICLWzZdCKZULGTKCBLms63l0h
wqznU6RA7qEpKeLEwwZs454maPdDraOebyhBYqf2EbATo1Rf1faqNzjL2T7KtyZg
PB1RDah/tCrsRi2ueFbOakyDms+98Km94lC8cZ0Wp7wlXaBLQHbRgylt49dN5KLP
cgjUxnBDOxM/4iCrwLQ3GxqZksOkwuzkZE3v1BkRy51XPRiaEov+57zhua686BzY
/rQjG6xWEawmodydUPd7qZ8LbO0bGpw+euqVd+FDEmHi4ytB1vyZMQ3Zt7gZjbBm
Wxd0x4TSKz0CQ4XuGxXvVx0ZXv3zbOXE2g06UmxijHbCwNZQazAzOw5EVaZiZPvK
4HzxssBskp49xh+8T8Pgmc085ujstW2+b1XiZcqnVhIkOqEynxKhPghP/5ODtY7/
13dkqbVgAfTZ8JU6Q+jTo5bhaoFohnb8XeEg7O8aLf06WpKvorJ+O8XGKICn1tnD
odL5XTa9xX8WMwiI3bQ9SGlucmljaCBNYWhsZXIgPDIyMzY2NTU3K0JpYm8tSm9z
aGlAdXNlcnMubm9yZXBseS5naXRodWIuY29tPokCTgQTAQoAOBYhBGVbtPVs2w4O
RQDPVy6eDhJ+8/KDBQJjm4maAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJ
EC6eDhJ+8/KDKTcP/ja9/nVePimncHGvrT70Ek53qBheSTujurDtNE6mfUOxOgr8
7m/fcZo3j/3FUssN81ijoNthS6HuhE0kyc+jbL1q4cv9oOeqgniV0P2GxlCOLwrJ
k3BjLNA04P8qSXfS1eefyRgr+dtNaOw2ARetOZm3yja34EW8II6p7Bd7DTRoGOAQ
cwi0Xz0AGyz9drLS0vDZ3VJfB0xIUToS/I/PBjUsIg0eD9M2bEOznFHK422CQMJV
r4pdHJgMfzX7XmwqMQP31oz8zNljsLWYZqpMR9Lw3B2XKziaZlptXgwC9uulcojG
lZv1OTXFKudjKmuOgzd9tW0nwMX/XnNGC7rzCpJCi5//8LeqbLxFqHoK8fXGs/9k
U7EBd3srEnGZHp3ROCsEGmNERTTIIN/rWS3lywnQCQ5kyk8HjT3WztfyLuAIiU+q
fiGQvvkehFF31ONa6tA5Xsm/0ch8rFx9ON8K72KY0fHLJ4FMz0rIdUa47GDYKDAr
n8q+drVCGBVSOWqHYhSZ5C/NCtRr6TebGCsxmhsVuqcXpJSM8CqG8f2xYeQeRw54
bGSrCGMB5TlcMUKQ9wmQWHDHa+khobvYrGBtZaHMt/exnBYqwPna88rp1pWyhIqw
bBiCzKPYOUvzW+nUL0ogCVTfq5XKMJAQh1d1FPPbSLIb/0LYSHC4FavvrmJ3uQIN
BF6AWOIBEADUaTuRBlOcwBBZAFYHgXNM22+TdU+JcYVbdn96A0NPJy0z91SLHotM
w8fr9Sbd/g+xhG8byeFDpdEwTz+sH3GN3SjaSRV3CYIueWApiAFC4ybIoR46kcri
DQJWaTL8YtofBQs7GTtmZ/IbKaxRC/nKXalBnUh3nPgWCLUcIu8axmloBfHP9zFz
+Vn37JrClM66V2TLeJp5/C3Sw2lR2Dj13G65LkSAOX+naoL//PWSSmnfiDef2DA6
Ucd3vh2BoTVkmZoDeLkIP93MfDM23I7NRq9rQSptcvYmtdxo3f3IU25sfjYBi+3g
HIWzbFq2SBeGAbWBufcFkj+kvoP4LzxJ63hVhpA0ql3WWgi5eKOeuhtnBSNaejhC
Axq8ktdAFUpyLMjA53bMUnD7Xkb09tMwW0OcUFPxVz3LG7TT8aQSwA46u/nBFIDN
4D5R14OdAysLHcVp536NSApfvzc/E5OCIx+0TPihq+8EnSEyHMvNXA0QLeGcSn8a
CoIjRK9p7IpKknGNCBx/H54rHGWi0XdPZPNbGHGFypualEB2uIRELFFkCquO2DTi
rYnrYM2Xf/u1ahp1vLNGgM1F6L9u+mC6gUUMGmyBklsz1jTGkTB4HmiMDLBDhAQM
/5UPJQhAdxuZwdfyveGxWYBJSSMtGbR+yOfT7NuTEhtBj0WG4h6tPwARAQABiQI2
BBgBCgAgFiEEZVu09WzbDg5FAM9XLp4OEn7z8oMFAl6AWOICGwwACgkQLp4OEn7z
8oOZ1g/+NE9vZSoxB9yw8uLRthjUUScES2wpA4VBVgpcA0QNEqtq5xE82xXUMhIb
1td6E00+lESoXGo66xoIFQdWEMyr0Df6kfFSTgh2FL4DA5NSSQgiM9u4O8yayu2x
AmBQzRz42V3AquVSH7gu/WhwPcYROq+gYaQT7D/l6Mg/mRUfMS/zvkFIsTJktp+q
yvcuf8ybqoCetDbOw6Uo12IjfxqT1pj8gUVrN/ePlI3HXDzOS6bCiYCgRjCU/Ujj
zcXOupKjA4mvN6LCslgwREciZgDE5W31Ghnjd3tT4OL9TSixugRFD67jr7ZsXpcl
ZReF+nbEsTZlKMXKVDnvwgvrVD4BolSj9rBpPcyftcZtFeuBPSVUE1c6pd5Vo7HJ
I+QDHQA32/hk8dDdqrdVHCn24+yZUkpkuzvNovVJINqt/4GgIRUZot0e5MupFuj9
D+Nn90ffKvFe1YjmRkJ1hblHG9Lh2I4LQOjF2qGKRL+CmtgA3NbO4BKLuTEAJnJz
PeR4FOX756R40p9Z7e0XhUqF4D/GvRyfxYhxkMKbIGEXbfgPjcNvVCDJxElBBtMz
mu6lniNOz/rViivD28dWHIro3ScaGsB4vAo2Eq+4VWTUtvoPo0OHbfX8PDbpcTuU
3a3DN3/RD8DQe+Pm5clbVCpDHzKThq9TpHFC0Iozh6d7QY+hQac=
=VeuH
-----END PGP PUBLIC KEY BLOCK-----
+53
View File
@@ -0,0 +1,53 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGOgNtUBEAC9CnrQYcKeHOVQatup9batI7lOSoXhqnS4v41LmWKt2GgVpiSn
CpWre04UMg+s/oCFto6af97vGxSsGbb2b23mTVHECvUoUBsiM2CMHopvNpMiPG3s
85gIaqQPOyVorET+MgPw96N+Ik/8sevOTb7u6+tUP4wdZcplVXBo5q+3EeK5GDb3
g+WNYbcwZ+x+3jwgphQmryHAXAis4PrdAfuaAXxclN/prJ23245IaAQxWID1Mcxi
ZaT/vZSqDEKbjj3wyzlJBfe5DuAG2IqAqEbWZCYUjjdUrsrGVdjh6Al1CqA+V8px
PYCF+qK6c3M7ilbQSXv9dDjiH1shM7DPrXop657zFandVrmaFVcf7/WLLNSX0KwM
kuYdFXYQXXoptpLsB6edB8Od39l6uETObDDVXiKQdeBypFlkWaqDv2soBY04+o0h
NvQBWT3EPS2zUXGwo7j2pd1Q4j1qC0ceKW64rxF8UqtZXOG2mJrVKeKvbprhq3kF
3+vXHqTgr6ZgjplHkVZmcv31UOBlwGnN+xBi5ooD/brF0rxZ9Pcr0BXdtBhG80V+
q1vxVh9D2K0RFJ7pLaxFdExZoevOwHdtwT411I9VfWdICc3w9KYnH4xSwjoR+Cm2
Jy9aTlft+TkQXfOxWD83QUtu/zE/MYwp2xhHLsJoOTzSLHcRHMOWC4yfrQARAQAB
tG9IaW5yaWNoIE1haGxlciAoS2V5IGZvciBzaWduaW5nIHJlbGVhc2VzIG9mIHB5
dGhvbi10ZWxlZ3JhbS1ib3QpIDwyMjM2NjU1NytCaWJvLUpvc2hpQHVzZXJzLm5v
cmVwbHkuZ2l0aHViLmNvbT6JAk4EEwEKADgWIQRMulGIRwROKJVIvZ+iuYSpBzAi
sgUCY6A21QIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCiuYSpBzAisgG+
EACXEqRSzuMI/Ca4vs9Q0teaUskjDbmb3tpt/vlPtgtWVBxIwixIrBXXt6VF58pc
4PjnmWd0TQVWHXysVtV1JBdFHJPf7CXD1OXAzDYLS3s0gZJ8Y32oG+94FKVtdcjp
M9XV2ip0DZFd0k8ln0bVultFPR441Q7DVpJFctAvICvccC//TkgD0vMWAV+zKD/9
xctkIa1t0ZQ2xHA+NPDTLEGzs9rADwJTK/OOE528mo8ki37RTM7Ou6kGF9Xb+A5P
iaO2FBDp3b6QyprMvaOF2Xgt18h+wembzsXwVwep3OpjZHYsaImoWn6821HmsS7H
MTjR71aG6BrGZTjFtsWNd9Anu2aYfyZgpZZmeTMC6o81x428YEA9Mr7+yAgFAfd7
BTyShNsyP1LcbMpPoYciFPiL9ieMqfNPOpdluV56Xb4W27/EJ39wx+PQPEs/5A2n
RUfKdtJtqxrGGOWtoLORS0pr+s7JS6WP1dfR/VWeTMiVNG506crAvCkN7VvTlpI0
ASqnRvFeu82cgOiP8toZJ/seRDq5JdRy/dV6EMD442mE6si7RUFJ3ShQsAMdukGw
lCDdUfLATJ/rrMCsoaInIbqWBa49OqEKcpOxyR2qR/91wxS1LDhfkmtumGgIxkjj
utt2XKLSaLNaXIPjX19RMqmFntzMrU2Mk+0HD40dd30bTbkCDQRjoDbVARAA1tN/
R2PhQ++bbLCtqeIjmkx/k5nmLK5P52lOu1zR142XVDC1ByZ8FEMzgnU+n660HN2g
62/p7lrMi1I12RuPZJBvalsRfGVx2DtbX06AEEg8bjABXB48uF1xU35gLOt1nhDp
bEinY0Kx4uBQcXlKme83ceyG2vmZvW0C+2JyLFFjwpUvOwzlzjSMkBFdbDzMBL93
A8gTt36WxcA+IbZlEwYte6w8FE5HcEZgGXsYXCvKEEN2wn3scXg+1R8bXOyQeRCo
KqblMDRO6Qsb/QL3a86so7MBWX4VmW+7714kaQYhMC+DKZq5u7yO//UqnEElHrYw
W8T5KGCYTizXcrM+4giAecdeukdPpeLwOmLhKQ1YfwWkHolsruwjg15vW4QE85dV
LRSTdgH1Is6NCqweOMIozH6uIAYz3b1u1r3C9hlgMqFN1oujI12MjOURLtLUtrN/
LeosSZEUgL3T7a1bmO4ykcVvhWvGrcU0HfR/CX5nXMymhkjGk2x47elottK/O3BP
evinQWPSiF+ABH3605KZQB2cWcr0oH1rLMAIwcYtMdCmGJY9we1fRF2lf/BTcoui
nDqsuuIJJpHg9FIIR167fW1tQH0DYbQBvsDCG6jv5pZ7V4Rl8zJ30Am5h1XZzpIk
/3wPvouskdfsEF1CahpzKF/rdtIB5aaynWO0xHkAEQEAAYkCNgQYAQoAIBYhBEy6
UYhHBE4olUi9n6K5hKkHMCKyBQJjoDbVAhsMAAoJEKK5hKkHMCKypCcP/3pvvpP/
axelSKUgdsmU+mcUK4AHWtPXZxJcLoIGhMEOiNOdeX64XhHYGO0gKDvPn1Bv/ygI
ef49+NGAXWZmaSOqXSKfSWaWwQqlGLuqL76Hes5EqTbAlo4qEEbZoWx/x52zbXz6
1fbcH+rU+3dYVFIzvq2UG2t3L6v+PQXoZL20CWxIAWLGjVmnUPV/7/XJJATg2x1J
IEb7iG9h8XLvC4/+whRWG5J48kPRRPE3vy1kgeUtvHCIsvujoFCosAxRhLR62+5x
F4rREUyY2WKAsuymVCJPEKE/g3LoTtn+f78ucECm6MJNhJpZqdjlqib0mGhjWGeR
XPNHL3iEL4wFlU/DRt25GE7YKTHoPFcjet4wWOUdj9OHdV2DHgsgETEAVxaFwH7W
hnPBtyc9TDLsTtJ1NphxofSiehsesNrfX5sneQVBpUclb5HS8vYqJxLC0KLOulNU
emDwYaQdM4chy1QfKHJhj9uSbqRcoUcms59mLINUlTmdwez2Vbmnh8sLYfuz2S0L
7OANYTUOOmwlw9cQJjF2hgtgvn7lRK/zD38nVesHSBU4dmlYISV5/jnByhIDaIdo
Afq07AF3OUKAI2FfAquDjV2P66GS1K2cWEQAAd3wgze3Qlt7xvifGTxHEXXesfP3
toI3+U6jDIfsuoL4ynzcPdz0IsFwu+yX6bxw
=gtS+
-----END PGP PUBLIC KEY BLOCK-----
+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"
+3 -2
View File
@@ -1,8 +1,9 @@
pre-commit
pytest==7.1.2
pytest-asyncio==0.19.0
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
+20 -1
View File
@@ -2,6 +2,25 @@
# 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
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.2
# 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
+7 -6
View File
@@ -8,15 +8,13 @@ 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())
@@ -25,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:
@@ -42,7 +40,8 @@ def get_optional_requirements(raw=False):
with Path("requirements-opts.txt").open() as reqs:
for line in reqs:
if line.startswith("#"):
line = line.strip()
if not line or line.startswith("#"):
continue
dependency, names = line.split("#")
dependency = dependency.strip()
@@ -53,7 +52,9 @@ def get_optional_requirements(raw=False):
continue
else:
name = name[:-4]
requirements["ext"].append(dependency)
requirements[name].append(dependency)
requirements["all"].append(dependency)
return requirements
+28 -11
View File
@@ -67,8 +67,15 @@ __all__ = ( # Keep this alphabetically ordered
"File",
"FileCredentials",
"ForceReply",
"ForumTopic",
"ForumTopicClosed",
"ForumTopicCreated",
"ForumTopicEdited",
"ForumTopicReopened",
"Game",
"GameHighScore",
"GeneralForumTopicHidden",
"GeneralForumTopicUnhidden",
"helpers",
"IdDocumentData",
"InlineKeyboardButton",
@@ -172,10 +179,11 @@ __all__ = ( # Keep this alphabetically ordered
"WebAppData",
"WebAppInfo",
"WebhookInfo",
"WriteAccessAllowed",
)
from . import _version
from . import _version, constants, error, helpers, request, warnings
from ._bot import Bot
from ._botcommand import BotCommand
from ._botcommandscope import (
@@ -230,6 +238,15 @@ 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,
ForumTopicEdited,
ForumTopicReopened,
GeneralForumTopicHidden,
GeneralForumTopicUnhidden,
)
from ._games.callbackgame import CallbackGame
from ._games.game import Game
from ._games.gamehighscore import GameHighScore
@@ -312,6 +329,16 @@ 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
from ._writeaccessallowed import WriteAccessAllowed
#: :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 +362,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
+2129 -2773
View File
File diff suppressed because it is too large Load Diff
+40 -6
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,20 +33,51 @@ 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.
description (:obj:`str`): Description of the command.
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;
:tg-const:`telegram.BotCommand.MIN_DESCRIPTION`-
:tg-const:`telegram.BotCommand.MAX_DESCRIPTION` characters.
"""
__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)
+27 -21
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, Optional, Sequence, 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
@@ -78,25 +78,28 @@ 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, serves as
the unique identifier for the game
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
the unique identifier for the game.
Attributes:
id (:obj:`str`): Unique identifier for this query.
from_user (:class:`telegram.User`): Sender.
chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which
the message with the callback button was sent.
the message with the callback button was sent. Useful for high scores in games.
message (:class:`telegram.Message`): Optional. Message with the callback button that
originated the query.
originated the query. Note that message content and message date will not be available
if the message is too old.
data (:obj:`str` | :obj:`object`): Optional. Data associated with the callback button.
Be aware that the message, which originated the query, can contain no callback buttons
with this data.
Tip:
The value here is the same as the value passed in
:paramref:`telegram.InlineKeyboardButton.callback_data`.
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.
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.
"""
@@ -112,16 +115,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 +136,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 +148,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,
@@ -192,7 +196,7 @@ class CallbackQuery(TelegramObject):
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "InlineKeyboardMarkup" = None,
entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
entities: Sequence["MessageEntity"] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -252,7 +256,7 @@ class CallbackQuery(TelegramObject):
caption: str = None,
reply_markup: "InlineKeyboardMarkup" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
caption_entities: Sequence["MessageEntity"] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -592,7 +596,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 +612,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:
@@ -720,12 +724,13 @@ class CallbackQuery(TelegramObject):
chat_id: Union[int, str],
caption: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None,
caption_entities: Sequence["MessageEntity"] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
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 +768,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[
+647 -36
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
)
+14 -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,8 +79,11 @@ 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.
0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters.
.. versionadded:: 13.8
pending_join_request_count (:obj:`int`): Optional. Number of pending join requests
@@ -113,8 +116,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 +142,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 +155,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,
+26 -7
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,12 +38,15 @@ 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
Can't be a live location.
address (:obj:`str`): Location address;
:tg-const:`telegram.ChatLocation.MIN_ADDRESS`-
:tg-const:`telegram.ChatLocation.MAX_ADDRESS` characters, as defined by the chat owner.
"""
@@ -52,13 +56,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 +77,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
"""
+117 -58
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,7 +44,8 @@ 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.
.. seealso:: `Chat Member Example <examples.chatmemberbot.html>`_
Examples:
:any:`Chat Member Bot <examples.chatmemberbot>`
.. versionchanged:: 20.0
@@ -64,7 +65,10 @@ class ChatMember(TelegramObject):
Attributes:
user (:class:`telegram.User`): Information about the user.
status (:obj:`str`): The member's status in the chat.
status (:obj:`str`): The member's status in the chat. Can be
:attr:`~telegram.ChatMember.ADMINISTRATOR`, :attr:`~telegram.ChatMember.OWNER`,
:attr:`~telegram.ChatMember.BANNED`, :attr:`~telegram.ChatMember.LEFT`,
:attr:`~telegram.ChatMember.MEMBER` or :attr:`~telegram.ChatMember.RESTRICTED`.
"""
@@ -83,13 +87,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`."""
@@ -98,9 +111,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,
@@ -110,18 +120,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):
@@ -154,11 +160,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):
@@ -167,9 +175,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.
@@ -204,6 +215,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:
@@ -241,6 +256,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.
"""
@@ -257,6 +276,7 @@ class ChatMemberAdministrator(ChatMember):
"can_post_messages",
"can_edit_messages",
"can_pin_messages",
"can_manage_topics",
"custom_title",
)
@@ -275,23 +295,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):
@@ -313,8 +337,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):
@@ -323,6 +353,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.
@@ -344,6 +377,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.
@@ -369,6 +406,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.
@@ -384,6 +425,7 @@ class ChatMemberRestricted(ChatMember):
"can_send_polls",
"can_send_other_messages",
"can_add_web_page_previews",
"can_manage_topics",
"until_date",
)
@@ -399,20 +441,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):
@@ -433,8 +479,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):
@@ -460,6 +512,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
+13 -15
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.
@@ -62,7 +65,7 @@ class ChatMemberUpdated(TelegramObject):
old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member.
new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link, which was used
by the user to join the chat.
by the user to join the chat. For joining by invite link events only.
"""
@@ -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)
+14 -7
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,13 +52,15 @@ 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.
from_user (:class:`telegram.User`): The user that chose the result.
location (:class:`telegram.Location`): Optional. Sender location.
inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message.
location (:class:`telegram.Location`): Optional. Sender location, only for bots that
require user location.
inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message. Available
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.
"""
@@ -72,8 +74,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 +89,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 +100,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)
+90 -23
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,46 +34,70 @@ 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 "🏀", 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 "🎳", 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
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>`_.
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 :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 :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 :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 :tg-const:`telegram.Dice.SLOT_MACHINE`, each value
corresponds to a unique combination of symbols, which
can be found in our
:wiki:`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:
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.
"""
__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 +116,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)
+15 -18
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,11 +42,10 @@ 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.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
@@ -60,7 +56,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 +73,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
+19 -23
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,15 +44,13 @@ 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.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
duration (:obj:`int`): Duration of the audio in seconds.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
the same over time and for different bots. Can't be used to download or reuse the file.
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.
@@ -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`): 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`): 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()
+15 -21
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,19 +39,16 @@ 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.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
thumb (:class:`telegram.PhotoSize`): Optional. Document thumbnail.
file_name (:obj:`str`): Original filename.
mime_type (:obj:`str`): Optional. MIME type of the file.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
the same over time and for different bots. Can't be used to download or reuse the file.
thumb (:class:`telegram.PhotoSize`): Optional. Document thumbnail as defined by sender.
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.
"""
@@ -69,16 +62,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
+167 -66
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`.
* 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
@@ -54,19 +58,19 @@ class File(TelegramObject):
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`int`, 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_size (:obj:`int`, optional): File size in bytes, if known.
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.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`str`): Optional. File size in bytes.
file_path (:obj:`str`): Optional. File path. Use :meth:`download` to get the file.
file_size (:obj:`int`): Optional. File size in bytes, if known.
file_path (:obj:`str`): Optional. File path. Use e.g. :meth:`download_to_drive` to get the
file.
"""
__slots__ = (
@@ -81,54 +85,78 @@ 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 :obj:`out.write<io.BufferedWriter.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.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. 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 +171,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,27 +209,99 @@ 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:
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. 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`.
@@ -219,10 +309,21 @@ class File(TelegramObject):
"""
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
+276 -167
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
@@ -39,37 +40,45 @@ class InputMedia(TelegramObject):
"""
Base class for Telegram InputMedia Objects.
.. versionchanged:: 20.0:
.. versionchanged:: 20.0
Added arguments and attributes :attr:`type`, :attr:`media`, :attr:`caption`,
:attr:`caption_entities`, :paramref:`parse_mode`.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
Args:
media_type (:obj:`str`): Type of media that the instance represents.
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 (:obj:`str`): Optional. Caption of the media to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
parsing.
parse_mode (:obj:`str`): Optional. |parse_mode|
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
"""
__slots__ = ("caption", "caption_entities", "media", "parse_mode", "type")
@@ -79,27 +88,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):
@@ -110,12 +119,12 @@ class InputMediaAnimation(InputMedia):
width, height and duration from that video, unless otherwise specified with the optional
arguments.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
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,44 +132,53 @@ 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.
has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the animation needs to be covered
with a spoiler animation.
.. versionadded:: 20.0
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.ANIMATION`.
media (:obj:`str` | :class:`telegram.InputFile`): Animation to send.
caption (:obj:`str`): Optional. Caption of the document to be sent.
thumb (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
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. The parse mode to use for text formatting.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
width (:obj:`int`): Optional. Animation width.
height (:obj:`int`): Optional. Animation height.
duration (:obj:`int`): Optional. Animation duration in seconds.
has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the animation is covered with a
spoiler animation.
.. versionadded:: 20.0
"""
__slots__ = ("duration", "height", "thumb", "width")
__slots__ = ("duration", "height", "thumb", "width", "has_spoiler")
def __init__(
self,
@@ -171,8 +189,11 @@ 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,
has_spoiler: bool = None,
*,
api_kwargs: JSONDict = None,
):
if isinstance(media, Animation):
width = media.width if width is None else width
@@ -180,24 +201,35 @@ 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
self.has_spoiler = has_spoiler
class InputMediaPhoto(InputMedia):
"""Represents a photo to be sent.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
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,44 +237,73 @@ 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|
has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the photo needs to be covered
with a spoiler animation.
.. versionadded:: 20.0
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 (: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. |parse_mode|
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the photo is covered with a
spoiler animation.
.. versionadded:: 20.0
"""
__slots__ = ()
__slots__ = ("has_spoiler",)
def __init__(
self,
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,
has_spoiler: bool = 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,
)
with self._unfrozen():
self.has_spoiler = has_spoiler
class InputMediaVideo(InputMedia):
"""Represents a video to be sent.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
Note:
* When using a :class:`telegram.Video` for the :attr:`media` attribute, it will take the
width, height and duration from that video, unless otherwise specified with the optional
@@ -253,10 +314,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,48 +323,57 @@ 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.
has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the video needs to be covered
with a spoiler animation.
.. versionadded:: 20.0
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.VIDEO`.
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 (: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. |parse_mode|
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
.. 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.
supports_streaming (:obj:`bool`): Optional. Pass :obj:`True`, if the uploaded video is
supports_streaming (:obj:`bool`): Optional. :obj:`True`, if the uploaded video is
suitable for streaming.
thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
thumb (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the video is covered with a
spoiler animation.
.. versionadded:: 20.0
"""
__slots__ = ("duration", "height", "thumb", "supports_streaming", "width")
__slots__ = ("duration", "height", "thumb", "supports_streaming", "width", "has_spoiler")
def __init__(
self,
@@ -317,8 +385,11 @@ 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,
has_spoiler: bool = None,
*,
api_kwargs: JSONDict = None,
):
if isinstance(media, Video):
@@ -327,19 +398,32 @@ 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
self.has_spoiler = has_spoiler
class InputMediaAudio(InputMedia):
"""Represents an audio file to be treated as music to be sent.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
Note:
When using a :class:`telegram.Audio` for the :attr:`media` attribute, it will take the
duration, performer and title from that video, unless otherwise specified with the
@@ -347,11 +431,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 +440,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`.
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
parse_mode (:obj:`str`, optional): |parse_mode|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
duration (:obj:`int`, optional): 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.
@@ -386,15 +463,21 @@ class InputMediaAudio(InputMedia):
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.AUDIO`.
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.
duration (:obj:`int`): Duration of the audio in seconds.
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. |parse_mode|
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
duration (:obj:`int`): Optional. Duration of the audio in seconds.
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 (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
thumb (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
"""
@@ -409,8 +492,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,24 +503,34 @@ 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):
"""Represents a general file to be sent.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
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 +538,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.
@@ -469,14 +560,20 @@ class InputMediaDocument(InputMedia):
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.DOCUMENT`.
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.
thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
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. |parse_mode|
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
thumb (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
disable_content_type_detection (:obj:`bool`): Optional. Disables automatic server-side
content type detection for files uploaded using multipart/form-data. Always true, if
the document is sent as part of an album.
content type detection for files uploaded using multipart/form-data. Always
:obj:`True`, if the document is sent as part of an album.
"""
@@ -489,10 +586,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
+30 -7
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,23 +35,24 @@ 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.
latitude (:obj:`float`): Latitude as defined by sender.
horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location,
measured in meters.
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.
heading (:obj:`int`): Optional. The direction in which user is moving, in degrees;
: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.
@@ -73,8 +76,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 +93,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
"""
+14 -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 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,18 +37,17 @@ 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.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
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 +60,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
+71 -56
View File
@@ -17,14 +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:
@@ -62,24 +62,23 @@ class Sticker(_BaseThumbedMedium):
thumb (:class:`telegram.PhotoSize`, optional): Sticker thumbnail in the ``.WEBP`` or
``.JPG`` format.
emoji (:obj:`str`, optional): Emoji associated with the sticker
set_name (:obj:`str`, optional): Name of the sticker set to which the sticker
belongs.
mask_position (:class:`telegram.MaskPosition`, optional): For mask stickers, the
position where the mask should be placed.
set_name (:obj:`str`, optional): Name of the sticker set to which the sticker belongs.
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 (:obj:`str`, optional): For custom emoji stickers, unique identifier of the
custom_emoji_id (:obj:`str`, optional): For custom emoji stickers, unique identifier of the
custom emoji.
.. versionadded:: 20.0
_kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): Identifier for this file.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
@@ -101,12 +100,12 @@ 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 (:obj:`str`): Optional. For custom emoji stickers, unique identifier of the
custom_emoji_id (:obj:`str`): Optional. For custom emoji stickers, unique identifier of the
custom emoji.
.. versionadded:: 20.0
@@ -139,30 +138,31 @@ class Sticker(_BaseThumbedMedium):
file_size: int = None,
set_name: str = None,
mask_position: "MaskPosition" = None,
bot: "Bot" = None,
premium_animation: "File" = None,
custom_emoji_id: 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.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
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`"""
@@ -183,7 +183,7 @@ class Sticker(_BaseThumbedMedium):
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):
@@ -197,7 +197,7 @@ class StickerSet(TelegramObject):
arguments had to be changed. Use keyword arguments to make sure that the arguments are
passed correctly.
.. versionchanged:: 20.0:
.. versionchanged:: 20.0
The parameter ``contains_masks`` has been removed. Use :paramref:`sticker_type` instead.
Args:
@@ -207,7 +207,11 @@ class StickerSet(TelegramObject):
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
.. versionadded:: 13.11
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`.
@@ -223,12 +227,18 @@ class StickerSet(TelegramObject):
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
.. versionadded:: 13.11
stickers (List[:class:`telegram.Sticker`]): List of all set stickers.
sticker_type (:obj:`str`): Type of stickers in the set.
stickers (Tuple[:class:`telegram.Sticker`]): List of all set stickers.
.. versionchanged:: 20.0
|tupleclassattrs|
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.
``.TGS``, or ``.WEBM`` format.
"""
@@ -247,23 +257,27 @@ class StickerSet(TelegramObject):
name: str,
title: str,
is_animated: 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.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`."""
@@ -273,15 +287,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):
@@ -306,9 +318,11 @@ class MaskPosition(TelegramObject):
point (:obj:`str`): The part of the face relative to which the mask should be placed.
One of :attr:`FOREHEAD`, :attr:`EYES`, :attr:`MOUTH`, or :attr:`CHIN`.
x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face
size, from left to right.
size, from left to right. For example, choosing ``-1.0`` will place mask just to the
left of the default mask position.
y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face
size, from top to bottom.
size, from top to bottom. For example, ``1.0`` will place the mask just below the
default mask position.
scale (:obj:`float`): Mask scaling coefficient. For example, ``2.0`` means double size.
"""
@@ -324,7 +338,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
@@ -332,12 +355,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()
+13 -6
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,16 +49,18 @@ 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.
title (:obj:`str`): Name of the venue.
address (:obj:`str`): Address of the venue.
foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue.
foursquare_type (:obj:`str`): Optional. Foursquare type of the venue.
foursquare_type (:obj:`str`): Optional. Foursquare type of the venue. (For example,
"arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".)
google_place_id (:obj:`str`): Optional. Google Places identifier of the venue.
google_place_type (:obj:`str`): Optional. Google Places type of the venue.
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>`_.)
"""
@@ -81,8 +83,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 +100,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 +112,4 @@ class Venue(TelegramObject):
data["location"] = Location.de_json(data.get("location"), bot)
return cls(**data)
return super().de_json(data=data, bot=bot)
+14 -19
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,11 +42,10 @@ 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.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
@@ -61,7 +56,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.
"""
@@ -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
+12 -16
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,19 +40,18 @@ 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.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
length (:obj:`int`): Video width and height as defined by sender.
length (:obj:`int`): Video width and height (diameter of the video message) as defined
by sender.
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 +65,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
+12 -17
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):
@@ -38,21 +34,19 @@ class Voice(_BaseMedium):
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
duration (:obj:`int`, optional): Duration of the audio in seconds as defined by sender.
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.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
file_id (:obj:`str`): Identifier for this file.
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
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 +59,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
+34 -8
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,18 +49,27 @@ 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'.
selective (:obj:`bool`): Optional. Force reply from specific users only.
input_field_placeholder (:obj:`str`): Optional. The placeholder shown in the input
field when the reply is active.
selective (:obj:`bool`): Optional. Force reply from specific users only. Targets:
1) Users that are @mentioned in the :attr:`~telegram.Message.text` of the
:class:`telegram.Message` object.
2) If the bot's message is a reply (has ``reply_to_message_id``), sender of the
original message.
input_field_placeholder (:obj:`str`): Optional. The placeholder to be shown in the input
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
@@ -70,10 +81,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
"""
+214
View File
@@ -0,0 +1,214 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2022
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects related to Telegram forum topics."""
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class ForumTopic(TelegramObject):
"""
This object represents a forum topic.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`message_thread_id`, :attr:`name` and :attr:`icon_color`
are equal.
.. versionadded:: 20.0
Args:
message_thread_id (:obj:`int`): Unique identifier of the forum topic
name (:obj:`str`): Name of the topic
icon_color (:obj:`int`): Color of the topic icon in RGB format
icon_custom_emoji_id (:obj:`str`, optional): Unique identifier of the custom emoji shown
as the topic icon.
Attributes:
message_thread_id (:obj:`int`): Unique identifier of the forum topic
name (:obj:`str`): Name of the topic
icon_color (:obj:`int`): Color of the topic icon in RGB format
icon_custom_emoji_id (:obj:`str`): Optional. Unique identifier of the custom emoji shown
as the topic icon.
"""
__slots__ = ("message_thread_id", "name", "icon_color", "icon_custom_emoji_id")
def __init__(
self,
message_thread_id: int,
name: str,
icon_color: int,
icon_custom_emoji_id: str = None,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.message_thread_id = message_thread_id
self.name = name
self.icon_color = icon_color
self.icon_custom_emoji_id = icon_custom_emoji_id
self._id_attrs = (self.message_thread_id, self.name, self.icon_color)
self._freeze()
class ForumTopicCreated(TelegramObject):
"""
This object represents the content of a service message about a new forum topic created in
the chat.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`name` and :attr:`icon_color` are equal.
.. versionadded:: 20.0
Args:
name (:obj:`str`): Name of the topic
icon_color (:obj:`int`): Color of the topic icon in RGB format
icon_custom_emoji_id (:obj:`str`, optional): Unique identifier of the custom emoji shown
as the topic icon.
Attributes:
name (:obj:`str`): Name of the topic
icon_color (:obj:`int`): Color of the topic icon in RGB format
icon_custom_emoji_id (:obj:`str`): Optional. Unique identifier of the custom emoji shown
as the topic icon.
"""
__slots__ = ("name", "icon_color", "icon_custom_emoji_id")
def __init__(
self,
name: str,
icon_color: int,
icon_custom_emoji_id: str = None,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.name = name
self.icon_color = icon_color
self.icon_custom_emoji_id = icon_custom_emoji_id
self._id_attrs = (self.name, self.icon_color)
self._freeze()
class ForumTopicClosed(TelegramObject):
"""
This object represents a service message about a forum topic closed in the chat.
Currently holds no information.
.. versionadded:: 20.0
"""
__slots__ = ()
def __init__(self, *, api_kwargs: JSONDict = None) -> None:
super().__init__(api_kwargs=api_kwargs)
self._freeze()
class ForumTopicReopened(TelegramObject):
"""
This object represents a service message about a forum topic reopened in the chat.
Currently holds no information.
.. versionadded:: 20.0
"""
__slots__ = ()
def __init__(self, *, api_kwargs: JSONDict = None) -> None:
super().__init__(api_kwargs=api_kwargs)
self._freeze()
class ForumTopicEdited(TelegramObject):
"""
This object represents a service message about an edited forum topic.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`name` and :attr:`icon_custom_emoji_id` are equal.
.. versionadded:: 20.0
Args:
name (:obj:`str`, optional): New name of the topic, if it was edited.
icon_custom_emoji_id (:obj:`str`, optional): New identifier of the custom emoji shown as
the topic icon, if it was edited; an empty string if the icon was removed.
Attributes:
name (:obj:`str`): Optional. New name of the topic, if it was edited.
icon_custom_emoji_id (:obj:`str`): Optional. New identifier of the custom emoji shown as
the topic icon, if it was edited; an empty string if the icon was removed.
"""
__slots__ = ("name", "icon_custom_emoji_id")
def __init__(
self,
name: str = None,
icon_custom_emoji_id: str = None,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.name = name
self.icon_custom_emoji_id = icon_custom_emoji_id
self._id_attrs = (self.name, self.icon_custom_emoji_id)
self._freeze()
class GeneralForumTopicHidden(TelegramObject):
"""
This object represents a service message about General forum topic hidden in the chat.
Currently holds no information.
.. versionadded:: 20.0
"""
__slots__ = ()
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(api_kwargs=api_kwargs)
self._freeze()
class GeneralForumTopicUnhidden(TelegramObject):
"""
This object represents a service message about General forum topic unhidden in the chat.
Currently holds no information.
.. versionadded:: 20.0
"""
__slots__ = ()
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(api_kwargs=api_kwargs)
self._freeze()
+6
View File
@@ -19,9 +19,15 @@
"""This module contains an object that represents a Telegram CallbackGame."""
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class CallbackGame(TelegramObject):
"""A placeholder, currently holds no information. Use BotFather to set up your game."""
__slots__ = ()
def __init__(self, *, api_kwargs: JSONDict = None) -> None:
super().__init__(api_kwargs=api_kwargs)
self._freeze()
+37 -29
View File
@@ -17,14 +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 an object that represents a Telegram Game."""
import sys
from typing import TYPE_CHECKING, Any, Dict, List, Optional
from typing import TYPE_CHECKING, Dict, List, Optional, Sequence
from telegram._files.animation import Animation
from telegram._files.photosize import PhotoSize
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@@ -42,30 +42,47 @@ class Game(TelegramObject):
Args:
title (:obj:`str`): Title of the game.
description (:obj:`str`): Description of the game.
photo (List[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game message
in chats.
photo (Sequence[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game
message in chats.
.. versionchanged:: 20.0
|sequenceclassargs|
text (:obj:`str`, optional): Brief description of the game or high scores included in the
game message. Can be automatically edited to include current high scores for the game
when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited
using :meth:`telegram.Bot.edit_message_text`.
0-:tg-const:`telegram.constants.MessageLimit.TEXT_LENGTH` characters.
text_entities (List[:class:`telegram.MessageEntity`], optional): Special entities that
0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that
appear in text, such as usernames, URLs, bot commands, etc.
.. versionchanged:: 20.0
|sequenceclassargs|
animation (:class:`telegram.Animation`, optional): Animation that will be displayed in the
game message in chats. Upload via `BotFather <https://t.me/BotFather>`_.
Attributes:
title (:obj:`str`): Title of the game.
description (:obj:`str`): Description of the game.
photo (List[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game message
in chats.
photo (Tuple[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game
message in chats.
.. versionchanged:: 20.0
|tupleclassattrs|
text (:obj:`str`): Optional. Brief description of the game or high scores included in the
game message. Can be automatically edited to include current high scores for the game
when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited
using :meth:`telegram.Bot.edit_message_text`.
text_entities (List[:class:`telegram.MessageEntity`]): Special entities that
0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
text_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. Special entities that
appear in text, such as usernames, URLs, bot commands, etc.
This list is empty if the message does not contain text entities.
This tuple is empty if the message does not contain text entities.
.. versionchanged:: 20.0
|tupleclassattrs|
animation (:class:`telegram.Animation`): Optional. Animation that will be displayed in the
game message in chats. Upload via `BotFather <https://t.me/BotFather>`_.
@@ -84,23 +101,27 @@ class Game(TelegramObject):
self,
title: str,
description: str,
photo: List[PhotoSize],
photo: Sequence[PhotoSize],
text: str = None,
text_entities: List[MessageEntity] = None,
text_entities: Sequence[MessageEntity] = None,
animation: Animation = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.title = title
self.description = description
self.photo = photo
self.photo = parse_sequence_arg(photo)
# Optionals
self.text = text
self.text_entities = text_entities or []
self.text_entities = parse_sequence_arg(text_entities)
self.animation = animation
self._id_attrs = (self.title, self.description, self.photo)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Game"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -113,17 +134,7 @@ class Game(TelegramObject):
data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot)
data["animation"] = Animation.de_json(data.get("animation"), bot)
return cls(**data)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data["photo"] = [p.to_dict() for p in self.photo]
if self.text_entities:
data["text_entities"] = [x.to_dict() for x in self.text_entities]
return data
return super().de_json(data=data, bot=bot)
def parse_text_entity(self, entity: MessageEntity) -> str:
"""Returns the text from a given :class:`telegram.MessageEntity`.
@@ -186,6 +197,3 @@ class Game(TelegramObject):
for entity in self.text_entities
if entity.type in types
}
def __hash__(self) -> int:
return hash((self.title, self.description, tuple(p for p in self.photo)))
+5 -2
View File
@@ -48,13 +48,16 @@ class GameHighScore(TelegramObject):
__slots__ = ("position", "user", "score")
def __init__(self, position: int, user: User, score: int):
def __init__(self, position: int, user: User, score: int, *, api_kwargs: JSONDict = None):
super().__init__(api_kwargs=api_kwargs)
self.position = position
self.user = user
self.score = score
self._id_attrs = (self.position, self.user, self.score)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["GameHighScore"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -65,4 +68,4 @@ class GameHighScore(TelegramObject):
data["user"] = User.de_json(data.get("user"), bot)
return cls(**data)
return super().de_json(data=data, bot=bot)
+58 -25
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 Telegram InlineKeyboardButton."""
from typing import TYPE_CHECKING, Any, Optional, Union
from typing import TYPE_CHECKING, ClassVar, Optional, Union
from telegram import constants
from telegram._games.callbackgame import CallbackGame
from telegram._loginurl import LoginUrl
from telegram._telegramobject import TelegramObject
@@ -62,9 +63,11 @@ class InlineKeyboardButton(TelegramObject):
* After Bot API 6.1, only ``HTTPS`` links will be allowed in :paramref:`login_url`.
.. seealso:: `Inline Keyboard Example 1 <examples.inlinekeyboard.html>`_,
`Inline Keyboard Example 2 <examples.inlinekeyboard2.html>`_,
:class:`telegram.InlineKeyboardMarkup`
Examples:
* :any:`Inline Keyboard 1 <examples.inlinekeyboard>`
* :any:`Inline Keyboard 2 <examples.inlinekeyboard2>`
.. seealso:: :class:`telegram.InlineKeyboardMarkup`
.. versionchanged:: 20.0
:attr:`web_app` is considered as well when comparing objects of this type in terms of
@@ -84,12 +87,16 @@ class InlineKeyboardButton(TelegramObject):
Caution:
Only ``HTTPS`` links are allowed after Bot API 6.1.
callback_data (:obj:`str` | :obj:`object`, optional): Data to be sent in a callback query
to the bot when button is pressed, UTF-8 1-64 bytes. If the bot instance allows
arbitrary callback data, anything can be passed.
to the bot when button is pressed, UTF-8
:tg-const:`telegram.InlineKeyboardButton.MIN_CALLBACK_DATA`-
:tg-const:`telegram.InlineKeyboardButton.MAX_CALLBACK_DATA` bytes.
If the bot instance allows arbitrary callback data, anything can be passed.
Tip:
The value entered here will be available in :attr:`telegram.CallbackQuery.data`.
.. seealso:: :wiki:`Arbitrary callback_data <Arbitrary-callback_data>`
web_app (:obj:`telegram.WebAppInfo`, optional): Description of the `Web App
<https://core.telegram.org/bots/webapps>`_ that will be launched when the user presses
the button. The Web App will be able to send an arbitrary message on behalf of the user
@@ -102,7 +109,7 @@ class InlineKeyboardButton(TelegramObject):
specified inline query in the input field. Can be empty, in which case just the bot's
username will be inserted. This offers an easy way for users to start using your bot
in inline mode when they are currently in a private chat with it. Especially useful
when combined with switch_pm* actions - in this case the user will be automatically
when combined with ``switch_pm*`` actions - in this case the user will be automatically
returned to the chat they switched from, skipping the chat selection screen.
switch_inline_query_current_chat (:obj:`str`, optional): If set, pressing the button will
insert the bot's username and the specified inline query in the current chat's input
@@ -110,12 +117,11 @@ class InlineKeyboardButton(TelegramObject):
offers a quick way for the user to open your bot in inline mode in the same chat - good
for selecting something from multiple options.
callback_game (:class:`telegram.CallbackGame`, optional): Description of the game that will
be launched when the user presses the button. This type of button must always be
the ``first`` button in the first row.
be launched when the user presses the button. This type of button **must** always be
the **first** button in the first row.
pay (:obj:`bool`, optional): Specify :obj:`True`, to send a Pay button. This type of button
must always be the `first` button in the first row and can only be used in invoice
messages.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
**must** always be the **first** button in the first row and can only be used in
invoice messages.
Attributes:
text (:obj:`str`): Label text on the button.
@@ -131,7 +137,9 @@ class InlineKeyboardButton(TelegramObject):
Caution:
Only ``HTTPS`` links are allowed after Bot API 6.1.
callback_data (:obj:`str` | :obj:`object`): Optional. Data to be sent in a callback query
to the bot when button is pressed, UTF-8 1-64 bytes.
to the bot when button is pressed, UTF-8
:tg-const:`telegram.InlineKeyboardButton.MIN_CALLBACK_DATA`-
:tg-const:`telegram.InlineKeyboardButton.MAX_CALLBACK_DATA` bytes.
web_app (:obj:`telegram.WebAppInfo`): Optional. Description of the `Web App
<https://core.telegram.org/bots/webapps>`_ that will be launched when the user presses
the button. The Web App will be able to send an arbitrary message on behalf of the user
@@ -139,15 +147,24 @@ class InlineKeyboardButton(TelegramObject):
private chats between a user and the bot.
.. versionadded:: 20.0
switch_inline_query (:obj:`str`): Optional. Will prompt the user to select one of their
chats, open that chat and insert the bot's username and the specified inline query in
the input field. Can be empty, in which case just the bot's username will be inserted.
switch_inline_query_current_chat (:obj:`str`): Optional. Will insert the bot's username and
the specified inline query in the current chat's input field. Can be empty, in which
case just the bot's username will be inserted.
switch_inline_query (:obj:`str`): Optional. If set, pressing the button will prompt the
user to select one of their chats, open that chat and insert the bot's username and the
specified inline query in the input field. Can be empty, in which case just the bot's
username will be inserted. This offers an easy way for users to start using your bot
in inline mode when they are currently in a private chat with it. Especially useful
when combined with ``switch_pm*`` actions - in this case the user will be automatically
returned to the chat they switched from, skipping the chat selection screen.
switch_inline_query_current_chat (:obj:`str`): Optional. If set, pressing the button will
insert the bot's username and the specified inline query in the current chat's input
field. Can be empty, in which case only the bot's username will be inserted. This
offers a quick way for the user to open your bot in inline mode in the same chat - good
for selecting something from multiple options.
callback_game (:class:`telegram.CallbackGame`): Optional. Description of the game that will
be launched when the user presses the button.
pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button.
be launched when the user presses the button. This type of button **must** always be
the **first** button in the first row.
pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button. This type of button
**must** always be the **first** button in the first row and can only be used in
invoice messages.
"""
@@ -174,8 +191,10 @@ class InlineKeyboardButton(TelegramObject):
pay: bool = None,
login_url: LoginUrl = None,
web_app: WebAppInfo = None,
**_kwargs: Any,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.text = text
@@ -191,6 +210,8 @@ class InlineKeyboardButton(TelegramObject):
self._id_attrs = ()
self._set_id_attrs()
self._freeze()
def _set_id_attrs(self) -> None:
self._id_attrs = (
self.text,
@@ -216,7 +237,7 @@ class InlineKeyboardButton(TelegramObject):
data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
data["callback_game"] = CallbackGame.de_json(data.get("callback_game"), bot)
return cls(**data)
return super().de_json(data=data, bot=bot)
def update_callback_data(self, callback_data: Union[str, object]) -> None:
"""
@@ -228,5 +249,17 @@ class InlineKeyboardButton(TelegramObject):
Args:
callback_data (:class:`object`): The new callback data.
"""
self.callback_data = callback_data
self._set_id_attrs()
with self._unfrozen():
self.callback_data = callback_data
self._set_id_attrs()
MIN_CALLBACK_DATA: ClassVar[int] = constants.InlineKeyboardButtonLimit.MIN_CALLBACK_DATA
""":const:`telegram.constants.InlineKeyboardButtonLimit.MIN_CALLBACK_DATA`
.. versionadded:: 20.0
"""
MAX_CALLBACK_DATA: ClassVar[int] = constants.InlineKeyboardButtonLimit.MAX_CALLBACK_DATA
""":const:`telegram.constants.InlineKeyboardButtonLimit.MAX_CALLBACK_DATA`
.. versionadded:: 20.0
"""
+42 -39
View File
@@ -17,8 +17,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram InlineKeyboardMarkup."""
from typing import TYPE_CHECKING, Any, List, Optional
from typing import TYPE_CHECKING, Optional, Sequence
from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton
from telegram._telegramobject import TelegramObject
@@ -36,48 +35,52 @@ class InlineKeyboardMarkup(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their size of :attr:`inline_keyboard` and all the buttons are equal.
.. seealso:: `Inline Keyboard Example 1 <examples.inlinekeyboard.html>`_,
`Inline Keyboard Example 2 <examples.inlinekeyboard2.html>`_
Examples:
* :any:`Inline Keyboard 1 <examples.inlinekeyboard>`
* :any:`Inline Keyboard 2 <examples.inlinekeyboard2>`
Args:
inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows,
each represented by a list of InlineKeyboardButton objects.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
inline_keyboard (Sequence[Sequence[:class:`telegram.InlineKeyboardButton`]]): Sequence of
button rows, each represented by a sequence of :class:`~telegram.InlineKeyboardButton`
objects.
.. versionchanged:: 20.0
|sequenceclassargs|
Attributes:
inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows,
each represented by a list of InlineKeyboardButton objects.
inline_keyboard (Tuple[Tuple[:class:`telegram.InlineKeyboardButton`]]): Tuple of
button rows, each represented by a tuple of :class:`~telegram.InlineKeyboardButton`
objects.
.. versionchanged:: 20.0
|tupleclassattrs|
"""
__slots__ = ("inline_keyboard",)
def __init__(self, inline_keyboard: List[List[InlineKeyboardButton]], **_kwargs: Any):
def __init__(
self,
inline_keyboard: Sequence[Sequence[InlineKeyboardButton]],
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
if not check_keyboard_type(inline_keyboard):
raise ValueError(
"The parameter `inline_keyboard` should be a list of "
"list of InlineKeyboardButtons"
"The parameter `inline_keyboard` should be a sequence of sequences of "
"InlineKeyboardButtons"
)
# Required
self.inline_keyboard = inline_keyboard
self.inline_keyboard = tuple(tuple(row) for row in inline_keyboard)
self._id_attrs = (self.inline_keyboard,)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data["inline_keyboard"] = []
for inline_keyboard in self.inline_keyboard:
data["inline_keyboard"].append([x.to_dict() for x in inline_keyboard])
return data
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["InlineKeyboardMarkup"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
if not data:
return None
@@ -102,14 +105,13 @@ class InlineKeyboardMarkup(TelegramObject):
Args:
button (:class:`telegram.InlineKeyboardButton`): The button to use in the markup
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
"""
return cls([[button]], **kwargs)
return cls([[button]], **kwargs) # type: ignore[arg-type]
@classmethod
def from_row(
cls, button_row: List[InlineKeyboardButton], **kwargs: object
cls, button_row: Sequence[InlineKeyboardButton], **kwargs: object
) -> "InlineKeyboardMarkup":
"""Shortcut for::
@@ -118,16 +120,18 @@ class InlineKeyboardMarkup(TelegramObject):
Return an InlineKeyboardMarkup from a single row of InlineKeyboardButtons
Args:
button_row (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the
markup
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
button_row (Sequence[:class:`telegram.InlineKeyboardButton`]): The button to use
in the markup
.. versionchanged:: 20.0
|sequenceargs|
"""
return cls([button_row], **kwargs)
return cls([button_row], **kwargs) # type: ignore[arg-type]
@classmethod
def from_column(
cls, button_column: List[InlineKeyboardButton], **kwargs: object
cls, button_column: Sequence[InlineKeyboardButton], **kwargs: object
) -> "InlineKeyboardMarkup":
"""Shortcut for::
@@ -136,13 +140,12 @@ class InlineKeyboardMarkup(TelegramObject):
Return an InlineKeyboardMarkup from a single column of InlineKeyboardButtons
Args:
button_column (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the
markup
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
button_column (Sequence[:class:`telegram.InlineKeyboardButton`]): The button to use
in the markup
.. versionchanged:: 20.0
|sequenceargs|
"""
button_grid = [[button] for button in button_column]
return cls(button_grid, **kwargs)
def __hash__(self) -> int:
return hash(tuple(tuple(button for button in row) for row in self.inline_keyboard))
return cls(button_grid, **kwargs) # type: ignore[arg-type]
+42 -21
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 InlineQuery."""
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Optional, Sequence, Union
from typing import TYPE_CHECKING, Callable, ClassVar, Optional, Sequence, Union
from telegram import constants
from telegram._files.location import Location
@@ -44,16 +44,16 @@ class InlineQuery(TelegramObject):
In Python :keyword:`from` is a reserved word use :paramref:`from_user` instead.
.. versionchanged:: 20.0
* The following are now keyword-only arguments in Bot methods:
``{read, write, connect, pool}_timeout``, :paramref:`answer.api_kwargs`,
``auto_pagination``. Use a named argument for those,
and notice that some positional arguments changed position as a result.
The following are now keyword-only arguments in Bot methods:
``{read, write, connect, pool}_timeout``, :paramref:`answer.api_kwargs`,
``auto_pagination``. Use a named argument for those,
and notice that some positional arguments changed position as a result.
Args:
id (:obj:`str`): Unique identifier for this query.
from_user (:class:`telegram.User`): Sender.
query (:obj:`str`): Text of the query (up to 256 characters).
query (:obj:`str`): Text of the query (up to
:tg-const:`telegram.InlineQuery.MAX_QUERY_LENGTH` characters).
offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot.
chat_type (:obj:`str`, optional): Type of the chat, from which the inline query was sent.
Can be either :tg-const:`telegram.Chat.SENDER` for a private chat with the inline query
@@ -65,19 +65,23 @@ class InlineQuery(TelegramObject):
.. versionadded:: 13.5
location (:class:`telegram.Location`, optional): Sender location, only for bots that
request user location.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
id (:obj:`str`): Unique identifier for this query.
from_user (:class:`telegram.User`): Sender.
query (:obj:`str`): Text of the query (up to 256 characters).
query (:obj:`str`): Text of the query (up to
:tg-const:`telegram.InlineQuery.MAX_QUERY_LENGTH` characters).
offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot.
location (:class:`telegram.Location`): Optional. Sender location, only for bots that
request user location.
chat_type (:obj:`str`, optional): Type of the chat, from which the inline query was sent.
chat_type (:obj:`str`): Optional. Type of the chat, from which the inline query was sent.
Can be either :tg-const:`telegram.Chat.SENDER` for a private chat with the inline query
sender, :tg-const:`telegram.Chat.PRIVATE`, :tg-const:`telegram.Chat.GROUP`,
:tg-const:`telegram.Chat.SUPERGROUP` or :tg-const:`telegram.Chat.CHANNEL`. The chat
type should be always known for requests sent from official clients and most
third-party clients, unless the request was sent from a secret chat.
.. versionadded:: 13.5
location (:class:`telegram.Location`): Optional. Sender location, only for bots that
request user location.
"""
@@ -85,15 +89,16 @@ class InlineQuery(TelegramObject):
def __init__(
self,
id: str, # pylint: disable=redefined-builtin, invalid-name
id: str, # pylint: disable=redefined-builtin
from_user: User,
query: str,
offset: str,
location: Location = None,
bot: "Bot" = None,
chat_type: str = 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
@@ -104,9 +109,10 @@ class InlineQuery(TelegramObject):
self.location = location
self.chat_type = chat_type
self.set_bot(bot)
self._id_attrs = (self.id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["InlineQuery"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -115,10 +121,10 @@ class InlineQuery(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["location"] = Location.de_json(data.get("location"), bot)
return cls(bot=bot, **data)
return super().de_json(data=data, bot=bot)
async def answer(
self,
@@ -188,8 +194,23 @@ class InlineQuery(TelegramObject):
.. versionadded:: 13.2
"""
MAX_SWITCH_PM_TEXT_LENGTH: ClassVar[int] = constants.InlineQueryLimit.SWITCH_PM_TEXT_LENGTH
""":const:`telegram.constants.InlineQueryLimit.SWITCH_PM_TEXT_LENGTH`
MIN_SWITCH_PM_TEXT_LENGTH: ClassVar[int] = constants.InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH
""":const:`telegram.constants.InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH`
.. versionadded:: 20.0
"""
MAX_SWITCH_PM_TEXT_LENGTH: ClassVar[int] = constants.InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH
""":const:`telegram.constants.InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH`
.. versionadded:: 20.0
"""
MAX_OFFSET_LENGTH: ClassVar[int] = constants.InlineQueryLimit.MAX_OFFSET_LENGTH
""":const:`telegram.constants.InlineQueryLimit.MAX_OFFSET_LENGTH`
.. versionadded:: 20.0
"""
MAX_QUERY_LENGTH: ClassVar[int] = constants.InlineQueryLimit.MAX_QUERY_LENGTH
""":const:`telegram.constants.InlineQueryLimit.MAX_QUERY_LENGTH`
.. versionadded:: 20.0
"""
+24 -17
View File
@@ -19,8 +19,9 @@
# pylint: disable=redefined-builtin
"""This module contains the classes that represent Telegram InlineQueryResult."""
from typing import Any
from typing import ClassVar
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
@@ -35,37 +36,43 @@ class InlineQueryResult(TelegramObject):
All URLs passed in inline query results will be available to end users and therefore must
be assumed to be *public*.
Examples:
:any:`Inline Bot <examples.inlinebot>`
Args:
type (:obj:`str`): Type of the result.
id (:obj:`str`): Unique identifier for this result, 1-64 Bytes.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
id (:obj:`str`): Unique identifier for this result,
:tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
:tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
Attributes:
type (:obj:`str`): Type of the result.
id (:obj:`str`): Unique identifier for this result, 1-64 Bytes.
id (:obj:`str`): Unique identifier for this result,
:tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
:tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
"""
__slots__ = ("type", "id")
def __init__(self, type: str, id: str, **_kwargs: Any): # pylint: disable=invalid-name
def __init__(self, type: str, id: str, *, api_kwargs: JSONDict = None):
super().__init__(api_kwargs=api_kwargs)
# Required
self.type = type
self.id = str(id) # pylint: disable=invalid-name
self._id_attrs = (self.id,)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
self._freeze()
# pylint: disable=no-member
if (
hasattr(self, "caption_entities")
and self.caption_entities # type: ignore[attr-defined]
):
data["caption_entities"] = [
ce.to_dict() for ce in self.caption_entities # type: ignore[attr-defined]
]
MIN_ID_LENGTH: ClassVar[int] = constants.InlineQueryResultLimit.MIN_ID_LENGTH
""":const:`telegram.constants.InlineQueryResultLimit.MIN_ID_LENGTH`
return data
.. versionadded:: 20.0
"""
MAX_ID_LENGTH: ClassVar[int] = constants.InlineQueryResultLimit.MAX_ID_LENGTH
""":const:`telegram.constants.InlineQueryResultLimit.MAX_ID_LENGTH`
.. versionadded:: 20.0
"""

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